diff --git a/.github/actions/setup-create-base64-config-live-testnets/action.yml b/.github/actions/setup-create-base64-config-live-testnets/action.yml new file mode 100644 index 0000000000..5ba8150989 --- /dev/null +++ b/.github/actions/setup-create-base64-config-live-testnets/action.yml @@ -0,0 +1,130 @@ +name: Create Base64 Config +description: A composite action that creates a base64-encoded config to be used by integration tests + +inputs: + runId: + description: The run id + testLogCollect: + description: Whether to always collect logs, even for passing tests + default: "false" + chainlinkImage: + description: The chainlink image to use + default: "public.ecr.aws/chainlink/chainlink" + chainlinkVersion: + description: The git commit sha to use for the image tag + pyroscopeServer: + description: URL of Pyroscope server + pyroscopeEnvironment: + description: Name of Pyroscope environment + pyroscopeKey: + description: Pyroscope server key + lokiEndpoint: + description: Loki push endpoint + lokiTenantId: + description: Loki tenant id + lokiBasicAuth: + description: Loki basic auth + logstreamLogTargets: + description: Where to send logs (e.g. file, loki) + grafanaUrl: + description: Grafana URL + grafanaDashboardUrl: + description: Grafana dashboard URL + network: + description: Network to run tests on + httpEndpoints: + description: HTTP endpoints to use for network + wsEndpoints: + description: WS endpoints to use for network + fundingKeys: + description: Funding keys to use for network + +runs: + using: composite + steps: + - name: Prepare Base64 TOML override + shell: bash + id: base64-config-override + env: + RUN_ID: ${{ inputs.runId }} + PYROSCOPE_SERVER: ${{ inputs.pyroscopeServer }} + PYROSCOPE_ENVIRONMENT: ${{ inputs.pyroscopeEnvironment }} + PYROSCOPE_KEY: ${{ inputs.pyroscopeKey }} + CHAINLINK_IMAGE: ${{ inputs.chainlinkImage }} + CHAINLINK_VERSION: ${{ inputs.chainlinkVersion }} + LOKI_ENDPOINT: ${{ inputs.lokiEndpoint }} + LOKI_TENANT_ID: ${{ inputs.lokiTenantId }} + LOKI_BASIC_AUTH: ${{ inputs.lokiBasicAuth }} + LOGSTREAM_LOG_TARGETS: ${{ inputs.logstreamLogTargets }} + GRAFANA_URL: ${{ inputs.grafanaUrl }} + GRAFANA_DASHBOARD_URL: ${{ inputs.grafanaDashboardUrl }} + NETWORK: ${{ inputs.network }} + HTTP_ENDPOINTS: ${{ inputs.httpEndpoints }} + WS_ENDPOINTS: ${{ inputs.wsEndpoints }} + FUNDING_KEYS: ${{ inputs.fundingKeys }} + run: | + convert_to_toml_array() { + local IFS=',' + local input_array=($1) + local toml_array_format="[" + + for element in "${input_array[@]}"; do + toml_array_format+="\"$element\"," + done + + toml_array_format="${toml_array_format%,}]" + echo "$toml_array_format" + } + + if [ -n "$PYROSCOPE_SERVER" ]; then + pyroscope_enabled=true + else + pyroscope_enabled=false + fi + + cat << EOF > config.toml + [Common] + chainlink_node_funding=0.5 + + [ChainlinkImage] + image="$CHAINLINK_IMAGE" + version="$CHAINLINK_VERSION" + + [Pyroscope] + enabled=$pyroscope_enabled + server_url="$PYROSCOPE_SERVER" + environment="$PYROSCOPE_ENVIRONMENT" + key="$PYROSCOPE_KEY" + + [Logging] + run_id="$RUN_ID" + + [Logging.LogStream] + log_targets=$(convert_to_toml_array "$LOGSTREAM_LOG_TARGETS") + + [Logging.Loki] + tenant_id="$LOKI_TENANT_ID" + endpoint="$LOKI_URL" + basic_auth="$LOKI_BASIC_AUTH" + + [Logging.Grafana] + base_url="$GRAFANA_URL" + dasboard_url="$GRAFANA_DASHBOARD_URL" + + [Network] + selected_networks=["$NETWORK"] + + [Network.RpcHttpUrls] + "$NETWORK" = $(convert_to_toml_array "$HTTP_ENDPOINTS") + + [Network.RpcWsUrls] + "$NETWORK" = $(convert_to_toml_array "$WS_ENDPOINTS") + + [Network.WalletKeys] + "$NETWORK" = $(convert_to_toml_array "$FUNDING_KEYS") + EOF + + BASE64_CONFIG_OVERRIDE=$(cat config.toml | base64 -w 0) + echo ::add-mask::$BASE64_CONFIG_OVERRIDE + echo "BASE64_CONFIG_OVERRIDE=$BASE64_CONFIG_OVERRIDE" >> $GITHUB_ENV + touch .root_dir diff --git a/.github/actions/setup-create-base64-config/action.yml b/.github/actions/setup-create-base64-config/action.yml new file mode 100644 index 0000000000..eafd670226 --- /dev/null +++ b/.github/actions/setup-create-base64-config/action.yml @@ -0,0 +1,122 @@ +name: Create Base64 Config +description: A composite action that creates a base64-encoded config to be used by integration tests + +inputs: + runId: + description: The run id + testLogCollect: + description: Whether to always collect logs, even for passing tests + default: "false" + selectedNetworks: + description: The networks to run tests against + chainlinkImage: + description: The chainlink image to use + default: "public.ecr.aws/chainlink/chainlink" + chainlinkVersion: + description: The git commit sha to use for the image tag + pyroscopeServer: + description: URL of Pyroscope server + pyroscopeEnvironment: + description: Name of Pyroscope environment + pyroscopeKey: + description: Pyroscope server key + lokiEndpoint: + description: Loki push endpoint + lokiTenantId: + description: Loki tenant id + lokiBasicAuth: + description: Loki basic auth + logstreamLogTargets: + description: Where to send logs (e.g. file, loki) + grafanaUrl: + description: Grafana URL + grafanaDashboardUrl: + description: Grafana dashboard URL + +runs: + using: composite + steps: + - name: Prepare Base64 TOML override + shell: bash + id: base64-config-override + env: + RUN_ID: ${{ inputs.runId }} + TEST_LOG_COLLECT: ${{ inputs.testLogCollect }} + SELECTED_NETWORKS: ${{ inputs.selectedNetworks }} + PYROSCOPE_SERVER: ${{ inputs.pyroscopeServer }} + PYROSCOPE_ENVIRONMENT: ${{ inputs.pyroscopeEnvironment }} + PYROSCOPE_KEY: ${{ inputs.pyroscopeKey }} + CHAINLINK_IMAGE: ${{ inputs.chainlinkImage }} + CHAINLINK_VERSION: ${{ inputs.chainlinkVersion }} + LOKI_ENDPOINT: ${{ inputs.lokiEndpoint }} + LOKI_TENANT_ID: ${{ inputs.lokiTenantId }} + LOKI_BASIC_AUTH: ${{ inputs.lokiBasicAuth }} + LOGSTREAM_LOG_TARGETS: ${{ inputs.logstreamLogTargets }} + GRAFANA_URL: ${{ inputs.grafanaUrl }} + GRAFANA_DASHBOARD_URL: ${{ inputs.grafanaDashboardUrl }} + run: | + echo ::add-mask::$CHAINLINK_IMAGE + function convert_to_toml_array() { + local IFS=',' + local input_array=($1) + local toml_array_format="[" + + for element in "${input_array[@]}"; do + toml_array_format+="\"$element\"," + done + + toml_array_format="${toml_array_format%,}]" + echo "$toml_array_format" + } + + selected_networks=$(convert_to_toml_array "$SELECTED_NETWORKS") + log_targets=$(convert_to_toml_array "$LOGSTREAM_LOG_TARGETS") + + if [ -n "$PYROSCOPE_SERVER" ]; then + pyroscope_enabled=true + else + pyroscope_enabled=false + fi + + if [ -n "$TEST_LOG_COLLECT" ]; then + test_log_collect=true + else + test_log_collect=false + fi + + cat << EOF > config.toml + [Network] + selected_networks=$selected_networks + + [ChainlinkImage] + image="$CHAINLINK_IMAGE" + version="$CHAINLINK_VERSION" + + [Pyroscope] + enabled=$pyroscope_enabled + server_url="$PYROSCOPE_SERVER" + environment="$PYROSCOPE_ENVIRONMENT" + key="$PYROSCOPE_KEY" + + [Logging] + test_log_collect=$test_log_collect + run_id="$RUN_ID" + + [Logging.LogStream] + log_targets=$log_targets + + [Logging.Loki] + tenant_id="$LOKI_TENANT_ID" + endpoint="$LOKI_ENDPOINT" + basic_auth="$LOKI_BASIC_AUTH" + # legacy, you only need this to access the cloud version + # bearer_token="bearer_token" + + [Logging.Grafana] + base_url="$GRAFANA_URL" + dasboard_url="$GRAFANA_DASHBOARD_URL" + EOF + + BASE64_CONFIG_OVERRIDE=$(cat config.toml | base64 -w 0) + echo ::add-mask::$BASE64_CONFIG_OVERRIDE + echo "BASE64_CONFIG_OVERRIDE=$BASE64_CONFIG_OVERRIDE" >> $GITHUB_ENV diff --git a/.github/actions/setup-create-base64-upgrade-config /action.yml b/.github/actions/setup-create-base64-upgrade-config /action.yml new file mode 100644 index 0000000000..f3acde2ea9 --- /dev/null +++ b/.github/actions/setup-create-base64-upgrade-config /action.yml @@ -0,0 +1,61 @@ +name: Create Base64 Upgrade Config +description: A composite action that creates a base64-encoded config to be used by Chainlink version upgrade tests + +inputs: + selectedNetworks: + description: The networks to run tests against + chainlinkImage: + description: The chainlink image to upgrade from + default: "public.ecr.aws/chainlink/chainlink" + chainlinkVersion: + description: The git commit sha to use for the image tag + upgradeImage: + description: The chainlink image to upgrade to + default: "public.ecr.aws/chainlink/chainlink" + upgradeVersion: + description: The git commit sha to use for the image tag + +runs: + using: composite + steps: + - name: Prepare Base64 TOML override + shell: bash + id: base64-config-override + env: + SELECTED_NETWORKS: ${{ inputs.selectedNetworks }} + CHAINLINK_IMAGE: ${{ inputs.chainlinkImage }} + CHAINLINK_VERSION: ${{ inputs.chainlinkVersion }} + UPGRADE_IMAGE: ${{ inputs.upgradeImage }} + UPGRADE_VERSION: ${{ inputs.upgradeVersion }} + run: | + function convert_to_toml_array() { + local IFS=',' + local input_array=($1) + local toml_array_format="[" + + for element in "${input_array[@]}"; do + toml_array_format+="\"$element\"," + done + + toml_array_format="${toml_array_format%,}]" + echo "$toml_array_format" + } + + selected_networks=$(convert_to_toml_array "$SELECTED_NETWORKS") + + cat << EOF > config.toml + [Network] + selected_networks=$selected_networks + + [ChainlinkImage] + image="$CHAINLINK_IMAGE" + version="$CHAINLINK_VERSION" + + [ChainlinkUpgradeImage] + image="$UPGRADE_IMAGE" + version="$UPGRADE_VERSION" + EOF + + BASE64_CONFIG_OVERRIDE=$(cat config.toml | base64 -w 0) + echo ::add-mask::$BASE64_CONFIG_OVERRIDE + echo "BASE64_CONFIG_OVERRIDE=$BASE64_CONFIG_OVERRIDE" >> $GITHUB_ENV diff --git a/.github/actions/setup-merge-base64-config/action.yml b/.github/actions/setup-merge-base64-config/action.yml new file mode 100644 index 0000000000..e5bf2a7d27 --- /dev/null +++ b/.github/actions/setup-merge-base64-config/action.yml @@ -0,0 +1,54 @@ +name: Merge Base64 Config +description: A composite action that merges user-provided Base64-encoded config with repository's secrets + +inputs: + base64Config: + description: Base64-encoded config to decode + +runs: + using: composite + steps: + - name: Add masks and export base64 config + shell: bash + run: | + BASE64_CONFIG_OVERRIDE=$(jq -r '.inputs.base64Config' $GITHUB_EVENT_PATH) + echo ::add-mask::$BASE64_CONFIG_OVERRIDE + echo "BASE64_CONFIG_OVERRIDE=$BASE64_CONFIG_OVERRIDE" >> $GITHUB_ENV + + decoded_toml=$(echo $BASE64_CONFIG_OVERRIDE | base64 -d) + CHAINLINK_IMAGE=$(echo "$decoded_toml" | awk -F'=' '/^[[:space:]]*image[[:space:]]*=/ {gsub(/^[[:space:]]+|[[:space:]]+$/, "", $2); print $2}' 2>/dev/null) + echo ::add-mask::$CHAINLINK_IMAGE + CHAINLINK_VERSION=$(echo "$decoded_toml" | awk -F'=' '/^[[:space:]]*version[[:space:]]*=/ {gsub(/^[[:space:]]+|[[:space:]]+$/, "", $2); print $2}' 2>/dev/null) + NETWORKS=$(echo "$decoded_toml" | awk -F'=' '/^[[:space:]]*selected_networks[[:space:]]*=/ {gsub(/^[[:space:]]+|[[:space:]]+$/, "", $2); print $2}' 2>/dev/null) + + if [ -n "$CHAINLINK_IMAGE" ]; then + echo "CHAINLINK_IMAGE=$CHAINLINK_IMAGE" >> $GITHUB_ENV + else + echo "No Chainlink Image found in base64-ed config. Exiting" + exit 1 + fi + if [ -n "$CHAINLINK_VERSION" ]; then + echo "CHAINLINK_VERSION=$CHAINLINK_VERSION" >> $GITHUB_ENV + else + echo "No Chainlink Version found in base64-ed config. Exiting" + exit 1 + fi + if [ -n "$NETWORKS" ]; then + echo "NETWORKS=$NETWORKS" >> $GITHUB_ENV + fi + + # use Loki config from GH secrets and merge it with base64 input + cat << EOF > config.toml + [Logging.Loki] + tenant_id="$LOKI_TENANT_ID" + endpoint="$LOKI_URL" + basic_auth="$LOKI_BASIC_AUTH" + # legacy, you only need this to access the cloud version + # bearer_token="bearer_token" + EOF + + echo "$decoded_toml" >> final_config.toml + cat config.toml >> final_config.toml + BASE64_CONFIG_OVERRIDE=$(cat final_config.toml | base64 -w 0) + echo ::add-mask::$BASE64_CONFIG_OVERRIDE + echo "BASE64_CONFIG_OVERRIDE=$BASE64_CONFIG_OVERRIDE" >> $GITHUB_ENV \ No newline at end of file diff --git a/.github/actions/setup-parse-base64-config/action.yml b/.github/actions/setup-parse-base64-config/action.yml new file mode 100644 index 0000000000..a744abae9e --- /dev/null +++ b/.github/actions/setup-parse-base64-config/action.yml @@ -0,0 +1,38 @@ +name: Parse Base64 Config +description: A composite action that extracts the chainlink image, version and network from a base64-encoded config + +inputs: + base64Config: + description: Base64-encoded config to decode + +runs: + using: composite + steps: + - name: Add masks and export base64 config + shell: bash + run: | + decoded_toml=$(echo $BASE64_CONFIG_OVERRIDE | base64 -d) + CHAINLINK_IMAGE=$(echo "$decoded_toml" | awk -F'=' '/^[[:space:]]*image[[:space:]]*=/ {gsub(/^[[:space:]]+|[[:space:]]+$/, "", $2); print $2}' 2>/dev/null) + echo ::add-mask::$CHAINLINK_IMAGE + CHAINLINK_VERSION=$(echo "$decoded_toml" | awk -F'=' '/^[[:space:]]*version[[:space:]]*=/ {gsub(/^[[:space:]]+|[[:space:]]+$/, "", $2); print $2}' 2>/dev/null) + NETWORKS=$(echo "$decoded_toml" | awk -F'=' '/^[[:space:]]*selected_networks[[:space:]]*=/ {gsub(/^[[:space:]]+|[[:space:]]+$/, "", $2); print $2}' 2>/dev/null) + ETH2_EL_CLIENT=$(echo "$decoded_toml" | awk -F'=' '/^[[:space:]]*execution_layer[[:space:]]*=/ {gsub(/^[[:space:]]+|[[:space:]]+$/, "", $2); print $2}' 2>/dev/null) + + if [ -n "$CHAINLINK_IMAGE" ]; then + echo "CHAINLINK_IMAGE=$CHAINLINK_IMAGE" >> $GITHUB_ENV + else + echo "No Chainlink Image found in base64-ed config. Exiting" + exit 1 + fi + if [ -n "$CHAINLINK_VERSION" ]; then + echo "CHAINLINK_VERSION=$CHAINLINK_VERSION" >> $GITHUB_ENV + else + echo "No Chainlink Version found in base64-ed config. Exiting" + exit 1 + fi + if [ -n "$NETWORKS" ]; then + echo "NETWORKS=$NETWORKS" >> $GITHUB_ENV + fi + if [ -n "$ETH2_EL_CLIENT" ]; then + echo "ETH2_EL_CLIENT=$ETH2_EL_CLIENT" >> $GITHUB_ENV + fi \ No newline at end of file diff --git a/.github/scripts/functions.sh b/.github/scripts/functions.sh new file mode 100644 index 0000000000..53b5339226 --- /dev/null +++ b/.github/scripts/functions.sh @@ -0,0 +1,17 @@ +#!/bin/bash + +# Function to convert a comma-separated list into a TOML array format. +# Usage: convert_to_toml_array "elem1,elem2,elem3" +# Effect: "a,b,c" -> ["a","b","c"] +function convert_to_toml_array() { + local IFS=',' + local input_array=($1) + local toml_array_format="[" + + for element in "${input_array[@]}"; do + toml_array_format+="\"$element\"," + done + + toml_array_format="${toml_array_format%,}]" + echo "$toml_array_format" +} \ No newline at end of file diff --git a/.github/tracing/README.md b/.github/tracing/README.md index 04f0216e25..06b2eef665 100644 --- a/.github/tracing/README.md +++ b/.github/tracing/README.md @@ -9,8 +9,18 @@ One way to generate traces locally today is with the OCR2 basic smoke test. 1. navigate to `.github/tracing/` and then run `docker compose --file local-smoke-docker-compose.yaml up` 2. setup a local docker registry at `127.0.0.1:5000` (https://www.docker.com/blog/how-to-use-your-own-registry-2/) 3. run `make build_push_plugin_docker_image` in `chainlink/integration-tests/Makefile` -4. run `SELECTED_NETWORKS=SIMULATED CHAINLINK_IMAGE="127.0.0.1:5000/chainlink" CHAINLINK_VERSION="develop" go test -run TestOCRv2Basic ./smoke/ocr2_test.go` -5. navigate to `localhost:3000/explore` in a web browser to query for traces +4. preapre your `overrides.toml` file with selected network and CL image name and version and place it anywhere +inside `integration-tests` directory. Sample `overrides.toml` file: +```toml +[ChainlinkImage] +image="127.0.0.1:5000/chainlink" +version="develop" + +[Network] +selected_networks=["simulated"] +``` +5. run `go test -run TestOCRv2Basic ./smoke/ocr2_test.go` +6. navigate to `localhost:3000/explore` in a web browser to query for traces Core and the median plugins are 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. diff --git a/.github/workflows/automation-benchmark-tests.yml b/.github/workflows/automation-benchmark-tests.yml index efe6d2eb59..740975ae5e 100644 --- a/.github/workflows/automation-benchmark-tests.yml +++ b/.github/workflows/automation-benchmark-tests.yml @@ -2,52 +2,20 @@ name: Automation Benchmark Test on: workflow_dispatch: inputs: - chainlinkVersion: - description: Chainlink image version to use + testType: + description: Type of test to run (benchmark, soak) required: true + default: benchmark type: string - default: 2.6.0 - chainlinkImage: - description: Chainlink image repo to use + base64Config: + description: base64-ed config required: true type: string - default: public.ecr.aws/chainlink/chainlink - network: - description: Network to run tests on - required: true - type: choice - options: - - SIMULATED - - SIMULATED_NONDEV - - GOERLI - - ARBITRUM_GOERLI - - OPTIMISM_GOERLI - - MUMBAI - - SEPOLIA - - BASE_GOERLI - - ARBITRUM_SEPOLIA - TestInputs: - description: TestInputs - 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 slackMemberID: description: Notifies test results (Not your @) required: true default: U02Q14G80TY type: string - fundingPrivateKey: - description: Private funding key (Skip for Simulated) - required: false - type: string - jobs: automation_benchmark: environment: integration @@ -56,52 +24,40 @@ jobs: pull-requests: write id-token: write contents: read - name: ${{ inputs.network }} Automation Benchmark Test + name: Automation Benchmark Test runs-on: ubuntu20.04-16cores-64GB env: - SELECTED_NETWORKS: ${{ inputs.network }} SLACK_API_KEY: ${{ secrets.QA_SLACK_API_KEY }} SLACK_CHANNEL: C03KJ5S7KEK - TEST_INPUTS: ${{ inputs.TestInputs }} CHAINLINK_ENV_USER: ${{ github.actor }} REF_NAME: ${{ github.head_ref || github.ref_name }} steps: - - name: Setup Push Tag - shell: bash - run: | - echo "### chainlink image used for this test run :link:" >>$GITHUB_STEP_SUMMARY - echo "\`${{ inputs.chainlinkVersion }}\`" >>$GITHUB_STEP_SUMMARY - echo "### chainlink-tests image tag for this test run :ship:" >>$GITHUB_STEP_SUMMARY - echo "\`${GITHUB_SHA}\`" >>$GITHUB_STEP_SUMMARY - - - name: Add mask + - name: Checkout the repo + uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + with: + ref: ${{ env.REF_NAME }} + - name: Get Slack config and mask base64 config 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) SLACK_USER=$(jq -r '.inputs.slackMemberID' $GITHUB_EVENT_PATH) - echo ::add-mask::$EVM_URLS - echo ::add-mask::$EVM_HTTP_URLS - echo ::add-mask::$EVM_KEYS echo ::add-mask::$SLACK_USER - echo EVM_URLS=$EVM_URLS >> $GITHUB_ENV - echo EVM_HTTP_URLS=$EVM_HTTP_URLS >> $GITHUB_ENV - echo EVM_KEYS=$EVM_KEYS >> $GITHUB_ENV echo SLACK_USER=$SLACK_USER >> $GITHUB_ENV - while IFS=',' read -ra EVM_URLS_2; do - for i in "${EVM_URLS_2[@]}"; do - echo ::add-mask::$i - done - done <<< "$EVM_URLS" - while IFS=',' read -ra EVM_HTTP_URLS_2; do - for i in "${EVM_HTTP_URLS_2[@]}"; do - echo ::add-mask::$i - done - done <<< "$EVM_HTTP_URLS" - - name: Checkout the repo - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + + BASE64_CONFIG_OVERRIDE=$(jq -r '.inputs.base64Config' $GITHUB_EVENT_PATH) + echo ::add-mask::$BASE64_CONFIG_OVERRIDE + echo "BASE64_CONFIG_OVERRIDE=$BASE64_CONFIG_OVERRIDE" >> $GITHUB_ENV + - name: Parse base64 config + uses: ./.github/actions/setup-parse-base64-config with: - ref: ${{ env.REF_NAME }} + base64Config: ${{ env.BASE64_CONFIG_OVERRIDE }} + - name: Send details to Step Summary + shell: bash + run: | + echo "### chainlink image used for this test run :link:" >>$GITHUB_STEP_SUMMARY + echo "\`${{ env.CHAINLINK_IMAGE }}\`" >>$GITHUB_STEP_SUMMARY + echo "### chainlink-tests image tag for this test run :ship:" >>$GITHUB_STEP_SUMMARY + echo "\`${GITHUB_SHA}\`" >>$GITHUB_STEP_SUMMARY + echo "### Networks on which test was run" >>$GITHUB_STEP_SUMMARY + echo "\`${{ env.NETWORKS }}\`" >>$GITHUB_STEP_SUMMARY - name: Build Test Image uses: ./.github/actions/build-test-image with: @@ -117,11 +73,13 @@ jobs: TEST_ARGS: -test.timeout 720h ENV_JOB_IMAGE: ${{ secrets.QA_AWS_ACCOUNT_NUMBER }}.dkr.ecr.${{ secrets.QA_AWS_REGION }}.amazonaws.com/chainlink-tests:${{ github.sha }} INTERNAL_DOCKER_REPO: ${{ secrets.QA_AWS_ACCOUNT_NUMBER }}.dkr.ecr.${{ secrets.QA_AWS_REGION }}.amazonaws.com + TEST_TYPE: ${{ github.event.inputs.testType }} + TEST_TEST_TYPE: ${{ github.event.inputs.testType }} with: test_command_to_run: cd integration-tests && go test -timeout 30m -v -run ^TestAutomationBenchmark$ ./benchmark -count=1 test_download_vendor_packages_command: make gomod - cl_repo: ${{ inputs.chainlinkImage }} - cl_image_tag: ${{ inputs.chainlinkVersion }} + cl_repo: ${{ env.CHAINLINK_IMAGE }} + cl_image_tag: ${{ env.CHAINLINK_VERSION }} token: ${{ secrets.GITHUB_TOKEN }} should_cleanup: false go_mod_path: ./integration-tests/go.mod @@ -135,6 +93,6 @@ jobs: with: basic-auth: ${{ secrets.GRAFANA_CLOUD_BASIC_AUTH }} hostname: ${{ secrets.GRAFANA_CLOUD_HOST }} - this-job-name: ${{ inputs.network }} Automation Benchmark Test + this-job-name: Automation Benchmark Test test-results-file: '{"testType":"go","filePath":"/tmp/gotest.log"}' continue-on-error: true diff --git a/.github/workflows/automation-load-tests.yml b/.github/workflows/automation-load-tests.yml index 96dffa01db..583314f438 100644 --- a/.github/workflows/automation-load-tests.yml +++ b/.github/workflows/automation-load-tests.yml @@ -2,30 +2,10 @@ name: Automation Load Test on: workflow_dispatch: inputs: - chainlinkVersion: - description: Chainlink image version to use + base64Config: + description: base64-ed config required: true - type: string - default: 2.6.0 - chainlinkImage: - description: Chainlink image repo to use - required: true - type: string - default: public.ecr.aws/chainlink/chainlink - network: - description: Network to run tests on - required: true - type: choice - options: - - SIMULATED - TestInputs: - description: TestInputs - required: false - type: string - ConfigOverride: - description: ConfigOverride - required: false - type: string + type: string slackMemberID: description: Notifies test results (Not your @) required: true @@ -40,34 +20,40 @@ jobs: pull-requests: write id-token: write contents: read - name: ${{ inputs.network }} Automation Load Test + name: Automation Load Test runs-on: ubuntu20.04-16cores-64GB env: - SELECTED_NETWORKS: ${{ inputs.network }} SLACK_API_KEY: ${{ secrets.QA_SLACK_API_KEY }} SLACK_CHANNEL: C03KJ5S7KEK - TEST_INPUTS: ${{ inputs.TestInputs }} - CONFIG_OVERRIDE: ${{ inputs.ConfigOverride }} CHAINLINK_ENV_USER: ${{ github.actor }} REF_NAME: ${{ github.head_ref || github.ref_name }} steps: - - name: Setup Push Tag - shell: bash - run: | - echo "### chainlink image used for this test run :link:" >>$GITHUB_STEP_SUMMARY - echo "\`${{ inputs.chainlinkVersion }}\`" >>$GITHUB_STEP_SUMMARY - echo "### chainlink-tests image tag for this test run :ship:" >>$GITHUB_STEP_SUMMARY - echo "\`${GITHUB_SHA}\`" >>$GITHUB_STEP_SUMMARY - - - name: Add mask + - name: Checkout the repo + uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + with: + ref: ${{ env.REF_NAME }} + - name: Get Slack config and mask base64 config run: | SLACK_USER=$(jq -r '.inputs.slackMemberID' $GITHUB_EVENT_PATH) echo ::add-mask::$SLACK_USER echo SLACK_USER=$SLACK_USER >> $GITHUB_ENV - - name: Checkout the repo - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + + BASE64_CONFIG_OVERRIDE=$(jq -r '.inputs.base64Config' $GITHUB_EVENT_PATH) + echo ::add-mask::$BASE64_CONFIG_OVERRIDE + echo "BASE64_CONFIG_OVERRIDE=$BASE64_CONFIG_OVERRIDE" >> $GITHUB_ENV + - name: Parse base64 config + uses: ./.github/actions/setup-parse-base64-config with: - ref: ${{ env.REF_NAME }} + base64Config: ${{ env.BASE64_CONFIG_OVERRIDE }} + - name: Send details to Step Summary + shell: bash + run: | + echo "### chainlink image used for this test run :link:" >>$GITHUB_STEP_SUMMARY + echo "\`${{ env.CHAINLINK_IMAGE }}\`" >>$GITHUB_STEP_SUMMARY + echo "### chainlink-tests image tag for this test run :ship:" >>$GITHUB_STEP_SUMMARY + echo "\`${GITHUB_SHA}\`" >>$GITHUB_STEP_SUMMARY + echo "### Networks on which test was run" >>$GITHUB_STEP_SUMMARY + echo "\`${{ env.NETWORKS }}\`" >>$GITHUB_STEP_SUMMARY - name: Build Test Image uses: ./.github/actions/build-test-image with: @@ -90,8 +76,8 @@ jobs: with: test_command_to_run: cd integration-tests && go test -timeout 1h -v -run TestLogTrigger ./load/automationv2_1 -count=1 test_download_vendor_packages_command: make gomod - cl_repo: ${{ inputs.chainlinkImage }} - cl_image_tag: ${{ inputs.chainlinkVersion }} + cl_repo: ${{ env.CHAINLINK_IMAGE }} + cl_image_tag: ${{ env.CHAINLINK_VERSION }} token: ${{ secrets.GITHUB_TOKEN }} should_cleanup: false go_mod_path: ./integration-tests/go.mod @@ -105,6 +91,6 @@ jobs: with: basic-auth: ${{ secrets.GRAFANA_CLOUD_BASIC_AUTH }} hostname: ${{ secrets.GRAFANA_CLOUD_HOST }} - this-job-name: ${{ inputs.network }} Automation Load Test + this-job-name: Automation Load Test test-results-file: '{"testType":"go","filePath":"/tmp/gotest.log"}' continue-on-error: true diff --git a/.github/workflows/automation-nightly-tests.yml b/.github/workflows/automation-nightly-tests.yml index 9fa3746f3d..9d45ec99e7 100644 --- a/.github/workflows/automation-nightly-tests.yml +++ b/.github/workflows/automation-nightly-tests.yml @@ -71,13 +71,18 @@ jobs: uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 with: ref: ${{ github.head_ref || github.ref_name }} + - name: Prepare Base64 TOML override + uses: ./.github/actions/setup-create-base64-upgrade-config + with: + selectedNetworks: ${{ env.SELECTED_NETWORKS }} + chainlinkImage: "public.ecr.aws/chainlink/chainlink" + chainlinkVersion: "latest" + upgradeImage: ${{ env.UPGRADE_IMAGE }} + upgradeVersion: ${{ env.UPGRADE_VERSION }} - name: Run Tests uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/run-tests@e865e376b8c2d594028c8d645dd6c47169b72974 # v2.2.16 env: - SELECTED_NETWORKS: ${{ matrix.tests.network }} TEST_SUITE: ${{ matrix.tests.suite }} - UPGRADE_VERSION: ${{ github.sha }} - UPGRADE_IMAGE: ${{ env.CHAINLINK_IMAGE }} with: test_command_to_run: 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 diff --git a/.github/workflows/automation-ondemand-tests.yml b/.github/workflows/automation-ondemand-tests.yml index e023006d58..ddf26d5607 100644 --- a/.github/workflows/automation-ondemand-tests.yml +++ b/.github/workflows/automation-ondemand-tests.yml @@ -162,25 +162,70 @@ jobs: echo "upgrade_version=${{ github.sha }}" >>$GITHUB_OUTPUT echo "upgrade_image=${{ env.CHAINLINK_IMAGE }}" >>$GITHUB_OUTPUT else - echo "image=${{ inputs.chainlinkImage }}" >>$GITHUB_OUTPUT + READ_CL_IMAGE=$(jq -r '.inputs.chainlinkImage' $GITHUB_EVENT_PATH) + echo ::add-mask::$READ_CL_IMAGE + echo "image=$READ_CL_IMAGE" >>$GITHUB_OUTPUT echo "version=${{ inputs.chainlinkVersion }}" >>$GITHUB_OUTPUT echo "upgrade_version=${{ inputs.chainlinkVersion }}" >>$GITHUB_OUTPUT - echo "upgrade_image=${{ inputs.chainlinkImage }}" >>$GITHUB_OUTPUT + echo "upgrade_image=$READ_CL_IMAGE" >>$GITHUB_OUTPUT fi if [[ "${{ matrix.tests.name }}" == "upgrade" ]]; then - echo "image=${{ inputs.chainlinkImageUpdate }}" >>$GITHUB_OUTPUT + READ_CL_UPGR_IMAGE=$(jq -r '.inputs.chainlinkImageUpdate' $GITHUB_EVENT_PATH) + echo ::add-mask::$READ_CL_UPGR_IMAGE + echo "image=$READ_CL_UPGR_IMAGE" >>$GITHUB_OUTPUT echo "version=${{ inputs.chainlinkVersionUpdate }}" >>$GITHUB_OUTPUT fi - - name: Run Tests - uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/run-tests@e865e376b8c2d594028c8d645dd6c47169b72974 # v2.2.16 + - name: Prepare Base64 TOML config env: - PYROSCOPE_SERVER: ${{ matrix.tests.pyroscope_env == '' && '' || !startsWith(github.ref, 'refs/tags/') && '' || secrets.QA_PYROSCOPE_INSTANCE }} # Avoid sending blank envs https://github.com/orgs/community/discussions/25725 - PYROSCOPE_ENVIRONMENT: ${{ matrix.tests.pyroscope_env }} - PYROSCOPE_KEY: ${{ secrets.QA_PYROSCOPE_KEY }} SELECTED_NETWORKS: ${{ matrix.tests.network }} - TEST_SUITE: ${{ matrix.tests.suite }} + OLD_IMAGE: ${{ steps.determine-build.outputs.image }} + OLD_VERSION: ${{ steps.determine-build.outputs.version }} UPGRADE_VERSION: ${{ steps.determine-build.outputs.upgrade_version }} UPGRADE_IMAGE: ${{ steps.determine-build.outputs.upgrade_image }} + PYROSCOPE_SERVER: ${{ matrix.tests.pyroscope_env == '' && '' || !startsWith(github.ref, 'refs/tags/') && '' || secrets.QA_PYROSCOPE_INSTANCE }} # Avoid sending blank envs https://github.com/orgs/community/discussions/25725 + PYROSCOPE_ENVIRONMENT: ${{ matrix.tests.pyroscope_env }} + PYROSCOPE_KEY: ${{ secrets.QA_PYROSCOPE_KEY }} + run: | + echo ::add-mask::$UPGRADE_IMAGE + echo ::add-mask::$OLD_IMAGE + + # load reusable functions + source ./.github/scripts/functions.sh + + selected_networks=$(convert_to_toml_array "$SELECTED_NETWORKS") + + if [ -n "$PYROSCOPE_SERVER" ]; then + pyroscope_enabled=true + else + pyroscope_enabled=false + fi + + cat << EOF > config.toml + [Network] + selected_networks=$selected_networks + + [ChainlinkImage] + image="$OLD_IMAGE" + version="$OLD_VERSION" + + [ChainlinkUpgradeImage] + image="$UPGRADE_IMAGE" + version="$UPGRADE_VERSION" + + [Pyroscope] + enabled=$pyroscope_enabled + server_url="$PYROSCOPE_SERVER" + environment="$PYROSCOPE_ENVIRONMENT" + key="$PYROSCOPE_KEY" + EOF + + BASE64_CONFIG_OVERRIDE=$(cat config.toml | base64 -w 0) + echo ::add-mask::$BASE64_CONFIG_OVERRIDE + echo "BASE64_CONFIG_OVERRIDE=$BASE64_CONFIG_OVERRIDE" >> $GITHUB_ENV + - name: Run Tests + uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/run-tests@e865e376b8c2d594028c8d645dd6c47169b72974 # v2.2.16 + env: + TEST_SUITE: ${{ matrix.tests.suite }} with: test_command_to_run: 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 diff --git a/.github/workflows/build-publish-pr.yml b/.github/workflows/build-publish-pr.yml index 43b76ef0ce..18d43f7cc5 100644 --- a/.github/workflows/build-publish-pr.yml +++ b/.github/workflows/build-publish-pr.yml @@ -22,6 +22,9 @@ jobs: env: ECR_IMAGE_NAME: crib-chainlink-untrusted steps: + - name: Checkout repository + uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + - name: Git Short SHA shell: bash env: @@ -38,10 +41,6 @@ jobs: AWS_REGION: ${{ secrets.AWS_REGION }} AWS_ROLE_TO_ASSUME: ${{ secrets.AWS_OIDC_IAM_ROLE_PUBLISH_PR_ARN }} - - name: Checkout repository - if: steps.check-image.outputs.exists == 'false' - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - - name: Build and publish chainlink image if: steps.check-image.outputs.exists == 'false' uses: ./.github/actions/build-sign-publish-chainlink diff --git a/.github/workflows/ccip-existing-deployment-tests.yml b/.github/workflows/ccip-existing-deployment-tests.yml deleted file mode 100644 index ad1f105a6d..0000000000 --- a/.github/workflows/ccip-existing-deployment-tests.yml +++ /dev/null @@ -1,220 +0,0 @@ -name: CCIP Soak Tests on Existing Deployment -on: - workflow_dispatch: - inputs: - network1: - description: Network A - type: choice - default: "SEPOLIA" - options: - - "SEPOLIA" - - "OPTIMISM_GOERLI" - - "AVALANCHE_FUJI" - - "ARBITRUM_GOERLI" - - "MUMBAI" - - "ETHEREUM_MAINNET" - - "OPTIMISM_MAINNET" - - "AVALANCHE_MAINNET" - - "ARBITRUM_MAINNET" - - "POLYGON_MAINNET" - network2: - description: Network B - type: choice - default: "AVALANCHE_FUJI" - options: - - "SEPOLIA" - - "OPTIMISM_GOERLI" - - "AVALANCHE_FUJI" - - "ARBITRUM_GOERLI" - - "MUMBAI" - - "ETHEREUM_MAINNET" - - "OPTIMISM_MAINNET" - - "AVALANCHE_MAINNET" - - "ARBITRUM_MAINNET" - - "POLYGON_MAINNET" - wsURL1: - description: Websocket URL for Network A - type: string - default: "ws://localhost:6688/ws" - httpURL1: - description: HTTP URL for Network A - type: string - default: "http://localhost:6688" - wsURL2: - description: Websocket URL for Network B - type: string - default: "ws://localhost:6688/ws" - httpURL2: - description: HTTP URL for Network B - type: string - default: "http://localhost:6688" - ownerKey: - description: Owner Key - type: string - required: true - testDuration: - description: Test Duration - type: string - default: "1m" - send_request_rate: - description: Number of ccip-send requests to trigger per minute - required: true - default: 2 - type: number - -env: - # for run-test variables and environment - ENV_JOB_IMAGE: ${{ secrets.QA_AWS_ACCOUNT_NUMBER }}.dkr.ecr.${{ secrets.QA_AWS_REGION }}.amazonaws.com/chainlink-ccip-tests:${{ github.sha }} - CHAINLINK_IMAGE: ${{ secrets.QA_AWS_ACCOUNT_NUMBER }}.dkr.ecr.${{ secrets.QA_AWS_REGION }}.amazonaws.com/chainlink - TEST_SUITE: load - TEST_ARGS: -test.timeout 900h - INTERNAL_DOCKER_REPO: ${{ secrets.QA_AWS_ACCOUNT_NUMBER }}.dkr.ecr.${{ secrets.QA_AWS_REGION }}.amazonaws.com - -jobs: - build-chainlink: - environment: integration - permissions: - id-token: write - contents: read - name: Build Chainlink Image - runs-on: ubuntu20.04-16cores-64GB - steps: - - name: Collect Metrics - id: collect-gha-metrics - uses: smartcontractkit/push-gha-metrics-action@90fcbaac8ebf86da9c4d55dba24f6fe3029f0e0b - with: - basic-auth: ${{ secrets.GRAFANA_CLOUD_BASIC_AUTH }} - hostname: ${{ secrets.GRAFANA_CLOUD_HOST }} - this-job-name: Build Chainlink Image - continue-on-error: true - - name: Checkout the repo - uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3 - - name: Check if image exists - id: check-image - uses: smartcontractkit/chainlink-github-actions/docker/image-exists@ad22fbd6f4d108b82aaf49b527bcf40f32babea8 # v2.2.1 - with: - repository: chainlink - tag: ${{ github.sha }} - AWS_REGION: ${{ secrets.QA_AWS_REGION }} - AWS_ROLE_TO_ASSUME: ${{ secrets.QA_AWS_ROLE_TO_ASSUME }} - - name: Build Image - if: steps.check-image.outputs.exists == 'false' - uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/build-image@ad22fbd6f4d108b82aaf49b527bcf40f32babea8 # v2.2.1 - with: - cl_repo: smartcontractkit/chainlink - cl_ref: ${{ github.sha }} - should_checkout: 'false' - cl_dockerfile: core/chainlink.Dockerfile - push_tag: ${{ env.CHAINLINK_IMAGE }}:${{ github.sha }} - QA_AWS_REGION: ${{ secrets.QA_AWS_REGION }} - QA_AWS_ROLE_TO_ASSUME: ${{ secrets.QA_AWS_ROLE_TO_ASSUME }} - - name: Print Chainlink Image Built - run: | - echo "### chainlink node image tag used for this test run :link:" >>$GITHUB_STEP_SUMMARY - echo "\`${GITHUB_SHA}\`" >>$GITHUB_STEP_SUMMARY - - build-test-image: - environment: integration - permissions: - id-token: write - contents: read - name: Build Test Image - runs-on: ubuntu20.04-16cores-64GB - steps: - - name: Collect Metrics - if: needs.changes.outputs.src == 'true' - id: collect-gha-metrics - uses: smartcontractkit/push-gha-metrics-action@90fcbaac8ebf86da9c4d55dba24f6fe3029f0e0b - with: - basic-auth: ${{ secrets.GRAFANA_CLOUD_BASIC_AUTH }} - hostname: ${{ secrets.GRAFANA_CLOUD_HOST }} - this-job-name: Build Test Image - continue-on-error: true - - name: Checkout the repo - uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3 - - name: Build Test Image - uses: ./.github/actions/build-test-image - with: - QA_AWS_ROLE_TO_ASSUME: ${{ secrets.QA_AWS_ROLE_TO_ASSUME }} - QA_AWS_REGION: ${{ secrets.QA_AWS_REGION }} - QA_AWS_ACCOUNT_NUMBER: ${{ secrets.QA_AWS_ACCOUNT_NUMBER }} - - ccip-soak-tests-existing-deployment: - environment: integration - permissions: - issues: read - checks: write - pull-requests: write - id-token: write - contents: read - needs: [build-chainlink, build-test-image] - env: - SELECTED_NETWORKS: SIMULATED,${{ inputs.network1 }},${{ inputs.network2 }} - CHAINLINK_COMMIT_SHA: ${{ github.sha }} - CHAINLINK_ENV_USER: ${{ github.actor }} - CCIP_TEST_DURATION: ${{ inputs.testDuration }} - CCIP_PHASE_VALIDATION_TIMEOUT: 50m - CCIP_LOAD_TEST_RATE: ${{ inputs.send_request_rate }} - CCIP_LOAD_TEST_RATEUNIT: 1m - CCIP_MSG_TYPE: WithToken - CCIP_CHAINLINK_NODE_FUNDING: 20 - CCIP_TESTS_ON_EXISTING_DEPLOYMENT: True - CCIP_NO_OF_NETWORKS: 2 - CCIP_KEEP_ENV_TTL: 720h - CCIP_REUSE_CONTRACTS: True - TEST_LOG_LEVEL: info - KEEP_ENVIRONMENTS: ONFAIL - DATABASE_URL: postgresql://postgres:node@localhost:5432/chainlink_test?sslmode=disable - REF_NAME: ${{ github.head_ref || github.ref_name }} - TEST_LOKI_TOKEN: ${{ secrets.LOKI_TOKEN }} - TEST_LOKI_URL: ${{ secrets.LOKI_URL }} - runs-on: ubuntu20.04-16cores-64GB - name: CCIP Soak Test - steps: - - name: Collect Metrics - id: collect-gha-metrics - uses: smartcontractkit/push-gha-metrics-action@8163dcea2f01a0a8fec84b284406ff7af1d2e1c0 - with: - basic-auth: ${{ secrets.GRAFANA_CLOUD_BASIC_AUTH }} - hostname: ${{ secrets.GRAFANA_CLOUD_HOST }} - this-job-name: ${{ inputs.networks }} CCIP Load Test - continue-on-error: true - - name: Checkout the repo - uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3 - with: - ref: ${{ env.REF_NAME }} - - name: Sets env vars - shell: bash - run: | - EVM_KEYS=$(jq -r '.inputs.ownerKey' $GITHUB_EVENT_PATH) - EVM_URLS_1=$(jq -r '.inputs.wsURL1' $GITHUB_EVENT_PATH) - EVM_HTTP_URLS_1=$(jq -r '.inputs.httpURL1' $GITHUB_EVENT_PATH) - EVM_URLS_2=$(jq -r '.inputs.wsURL2' $GITHUB_EVENT_PATH) - EVM_HTTP_URLS_2=$(jq -r '.inputs.httpURL2' $GITHUB_EVENT_PATH) - - echo ::add-mask::$EVM_KEYS - echo ::add-mask::$EVM_URLS_1 - echo ::add-mask::$EVM_HTTP_URLS_1 - echo ::add-mask::$EVM_URLS_2 - echo ::add-mask::$EVM_HTTP_URLS_2 - - echo "EVM_KEYS=$EVM_KEYS" >> $GITHUB_ENV - echo "${{ inputs.network1 }}_URLS=$EVM_URLS_1" >> $GITHUB_ENV - echo "${{ inputs.network1 }}_HTTP_URLS=$EVM_HTTP_URLS_1" >> $GITHUB_ENV - echo "${{ inputs.network2 }}_URLS=$EVM_URLS_2" >> $GITHUB_ENV - echo "${{ inputs.network2 }}_HTTP_URLS=$EVM_HTTP_URLS_2" >> $GITHUB_ENV - - ## Run this step when changes that require tests to be run are made - - name: Run Tests - uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/run-tests@ad22fbd6f4d108b82aaf49b527bcf40f32babea8 # v2.2.1 - with: - test_command_to_run: cd ./integration-tests && go test -v -timeout 900h -count=1 -json -run ^TestLoadCCIPStableRPS$ ./load - test_download_vendor_packages_command: cd ./integration-tests && go mod download - cl_repo: ${{ env.CHAINLINK_IMAGE }} - cl_image_tag: ${{ github.sha }} - artifacts_location: ./integration-tests/load/logs/payload_ccip.json - token: ${{ secrets.GITHUB_TOKEN }} - go_mod_path: ./integration-tests/go.mod - QA_AWS_REGION: ${{ secrets.QA_AWS_REGION }} - QA_AWS_ROLE_TO_ASSUME: ${{ secrets.QA_AWS_ROLE_TO_ASSUME }} - QA_KUBECONFIG: ${{ secrets.QA_KUBECONFIG }} \ No newline at end of file diff --git a/.github/workflows/ci-core.yml b/.github/workflows/ci-core.yml index b68c7703d2..0760608608 100644 --- a/.github/workflows/ci-core.yml +++ b/.github/workflows/ci-core.yml @@ -42,7 +42,7 @@ jobs: strategy: fail-fast: false matrix: - cmd: ["go_core_tests", "go_core_race_tests"] + cmd: ["go_core_tests", "go_core_race_tests", "go_core_fuzz"] name: Core Tests (${{ matrix.cmd }}) runs-on: ubuntu20.04-64cores-256GB env: @@ -72,6 +72,17 @@ jobs: run: go build -o chainlink.test . - name: Setup DB run: ./chainlink.test local db preparetest + - name: Install LOOP Plugins + run: | + pushd $(go list -m -f "{{.Dir}}" github.com/smartcontractkit/chainlink-feeds) + go install ./cmd/chainlink-feeds + popd + pushd $(go list -m -f "{{.Dir}}" github.com/smartcontractkit/chainlink-solana) + go install ./pkg/solana/cmd/chainlink-solana + popd + pushd $(go list -m -f "{{.Dir}}" github.com/smartcontractkit/chainlink-starknet/relayer) + go install ./pkg/chainlink/cmd/chainlink-starknet + popd - name: Increase Race Timeout if: github.event.schedule != '' run: | diff --git a/.github/workflows/client-compatibility-tests.yml b/.github/workflows/client-compatibility-tests.yml index 865c72258c..0334d32cae 100644 --- a/.github/workflows/client-compatibility-tests.yml +++ b/.github/workflows/client-compatibility-tests.yml @@ -67,11 +67,12 @@ jobs: with: ref: ${{ github.event.pull_request.head.sha || github.event.merge_group.head_sha }} - name: Build Tests - uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/build-tests@912bed7e07a1df4d06ea53a031e9773bb65dc7bd # v2.3.0 + uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/build-tests@bce4caa154b1e0e652d042788e14c8870832acd2 # v2.3.0 with: test_download_vendor_packages_command: cd ./integration-tests && go mod download token: ${{ secrets.GITHUB_TOKEN }} go_mod_path: ./integration-tests/go.mod + go_tags: embed cache_key_id: core-e2e-${{ env.MOD_CACHE_VERSION }} cache_restore_only: "true" binary_name: tests @@ -100,43 +101,51 @@ jobs: test: TestOCRBasic file: ocr client: geth + timeout: 30m pyroscope_env: ci-smoke-ocr-geth-simulated # Uncomment, when https://smartcontract-it.atlassian.net/browse/TT-753 is DONE # - name: ocr-nethermind # test: TestOCRBasic # file: ocr # client: nethermind + # timeout: 30m # pyroscope_env: ci-smoke-ocr-nethermind-simulated - name: ocr-besu test: TestOCRBasic file: ocr client: besu + timeout: 30m pyroscope_env: ci-smoke-ocr-besu-simulated - name: ocr-erigon test: TestOCRBasic file: ocr client: erigon + timeout: 30m pyroscope_env: ci-smoke-ocr-erigon-simulated - name: ocr2-geth test: TestOCRv2Basic file: ocr2 client: geth + timeout: 30m pyroscope_env: ci-smoke-ocr2-geth-simulated # Uncomment, when https://smartcontract-it.atlassian.net/browse/TT-753 is DONE # - name: ocr2-nethermind # test: TestOCRv2Basic # file: ocr2 # client: nethermind + # timeout: 30m # pyroscope_env: ci-smoke-nethermind-evm-simulated - name: ocr2-besu test: TestOCRv2Basic file: ocr2 - client: besu + client: besu + timeout: 30m pyroscope_env: ci-smoke-ocr2-besu-simulated - name: ocr2-erigon test: TestOCRv2Basic file: ocr2 - client: erigon + client: erigon + timeout: 60m pyroscope_env: ci-smoke-ocr2-erigon-simulated runs-on: ubuntu-latest name: Client Compatibility Test ${{ matrix.name }} @@ -145,15 +154,79 @@ jobs: uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # v3.0.2 with: name: tests - - name: Run Tests - uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/run-tests-binary@912bed7e07a1df4d06ea53a031e9773bb65dc7bd # v2.3.0 + - name: Prepare Base64 TOML config env: + SELECTED_NETWORKS: SIMULATED,SIMULATED_1,SIMULATED_2 PYROSCOPE_SERVER: ${{ secrets.QA_PYROSCOPE_INSTANCE }} PYROSCOPE_ENVIRONMENT: ci-client-compatability-${{ matrix.client }}-testnet PYROSCOPE_KEY: ${{ secrets.QA_PYROSCOPE_KEY }} ETH2_EL_CLIENT: ${{matrix.client}} + CHAINLINK_VERSION: ${{ github.sha }} + run: | + convert_to_toml_array() { + local IFS=',' + local input_array=($1) + local toml_array_format="[" + + for element in "${input_array[@]}"; do + toml_array_format+="\"$element\"," + done + + toml_array_format="${toml_array_format%,}]" + echo "$toml_array_format" + } + + selected_networks=$(convert_to_toml_array "$SELECTED_NETWORKS") + + if [ -n "$ETH2_EL_CLIENT" ]; then + execution_layer="$ETH2_EL_CLIENT" + else + execution_layer="geth" + fi + + if [ -n "$PYROSCOPE_SERVER" ]; then + pyroscope_enabled=true + else + pyroscope_enabled=false + fi + + cat << EOF > config.toml + [Network] + selected_networks=$selected_networks + + [ChainlinkImage] + image="$CHAINLINK_IMAGE" + version="$CHAINLINK_VERSION" + + [Pyroscope] + enabled=$pyroscope_enabled + server_url="$PYROSCOPE_SERVER" + environment="$PYROSCOPE_ENVIRONMENT" + key="$PYROSCOPE_KEY" + + [PrivateEthereumNetwork] + consensus_type="pos" + consensus_layer="prysm" + execution_layer="$execution_layer" + wait_for_finalization=false + + [PrivateEthereumNetwork.EthereumChainConfig] + chain_id=1337 + genesis_delay=15 + seconds_per_slot=3 + validator_count=8 + slots_per_epoch=2 + addresses_to_fund=["0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266"] + EOF + + BASE64_CONFIG_OVERRIDE=$(cat config.toml | base64 -w 0) + echo ::add-mask::$BASE64_CONFIG_OVERRIDE + echo "BASE64_CONFIG_OVERRIDE=$BASE64_CONFIG_OVERRIDE" >> $GITHUB_ENV + touch .root_dir + - name: Run Tests + uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/run-tests-binary@912bed7e07a1df4d06ea53a031e9773bb65dc7bd # v2.3.0 with: - test_command_to_run: ./tests -test.timeout 30m -test.run ${{ matrix.test }} + test_command_to_run: ./tests -test.timeout ${{ matrix.timeout }} -test.run ${{ matrix.test }} binary_name: tests cl_repo: ${{ env.CHAINLINK_IMAGE }} cl_image_tag: ${{ github.sha }} @@ -207,7 +280,7 @@ jobs: "type": "section", "text": { "type": "mrkdwn", - "text": "${{ contains(join(needs.*.result, ','), 'failure') && 'Some tests failed, notifying <@U01Q4N37KFG> and <@U060CGGPY8H>' || 'All Good!' }}" + "text": "${{ contains(join(needs.*.result, ','), 'failure') && 'Some tests failed, notifying <@U060CGGPY8H>' || 'All Good!' }}" } }, { diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index 5b846d8708..fea4260fdc 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -13,7 +13,7 @@ on: jobs: analyze: name: Analyze ${{ matrix.language }} - runs-on: ubuntu20.04-4cores-16GB + runs-on: ubuntu-latest strategy: fail-fast: false diff --git a/.github/workflows/integration-chaos-tests.yml b/.github/workflows/integration-chaos-tests.yml index 2b25076875..8fa0aba971 100644 --- a/.github/workflows/integration-chaos-tests.yml +++ b/.github/workflows/integration-chaos-tests.yml @@ -12,7 +12,6 @@ # ENV_JOB_IMAGE: ${{ secrets.QA_AWS_ACCOUNT_NUMBER }}.dkr.ecr.${{ secrets.QA_AWS_REGION }}.amazonaws.com/chainlink-tests:${{ github.sha }} # TEST_SUITE: chaos # TEST_ARGS: -test.timeout 1h -# SELECTED_NETWORKS: SIMULATED # CHAINLINK_COMMIT_SHA: ${{ github.sha }} # CHAINLINK_ENV_USER: ${{ github.actor }} # TEST_LOG_LEVEL: debug @@ -108,6 +107,24 @@ # continue-on-error: true # - name: Checkout the repo # uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 +# - name: Prepare Base64 TOML config +# env: +# CHAINLINK_VERSION: ${{ github.sha }} +# run: | +# echo ::add-mask::$CHAINLINK_IMAGE +# +# cat << EOF > config.toml +# [Network] +# selected_networks=["SIMULATED"] +# +# [ChainlinkImage] +# image="$CHAINLINK_IMAGE" +# version="$CHAINLINK_VERSION" +# EOF +# +# BASE64_CONFIG_OVERRIDE=$(cat config.toml | base64 -w 0) +# echo ::add-mask::$BASE64_CONFIG_OVERRIDE +# echo "BASE64_CONFIG_OVERRIDE=$BASE64_CONFIG_OVERRIDE" >> $GITHUB_ENV # - name: Run Tests # uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/run-tests@e865e376b8c2d594028c8d645dd6c47169b72974 # v2.2.16 # with: @@ -129,4 +146,3 @@ # name: Test Results Log # path: /tmp/gotest.log # retention-days: 7 - diff --git a/.github/workflows/integration-staging-tests.yml b/.github/workflows/integration-staging-tests.yml index 2abb9a3cfa..24e4acfe0f 100644 --- a/.github/workflows/integration-staging-tests.yml +++ b/.github/workflows/integration-staging-tests.yml @@ -1,3 +1,4 @@ +# NEEDS ADJUSTING TO TOML CONFIG BEFORE USING!! name: E2E Functions staging tests on: @@ -41,18 +42,86 @@ jobs: env: LOKI_URL: ${{ secrets.LOKI_URL }} LOKI_TOKEN: ${{ secrets.LOKI_TOKEN }} - SELECTED_NETWORKS: ${{ inputs.network }} SELECTED_TEST: ${{ inputs.test_type }} MUMBAI_URLS: ${{ secrets.FUNCTIONS_STAGING_MUMBAI_URLS }} MUMBAI_KEYS: ${{ secrets.FUNCTIONS_STAGING_MUMBAI_KEYS }} - WASP_LOG_LEVEL: info steps: - name: Checkout code uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 with: fetch-depth: 0 + - name: Prepare Base64 TOML override + env: + PYROSCOPE_SERVER: ${{ secrets.QA_PYROSCOPE_INSTANCE }} + PYROSCOPE_ENVIRONMENT: ci-smoke-${{ matrix.product }}-sepolia + PYROSCOPE_KEY: ${{ secrets.QA_PYROSCOPE_KEY }} + run: | + convert_to_toml_array() { + local IFS=',' + local input_array=($1) + local toml_array_format="[" + + for element in "${input_array[@]}"; do + toml_array_format+="\"$element\"," + done + + toml_array_format="${toml_array_format%,}]" + echo "$toml_array_format" + } + + if [ -n "$PYROSCOPE_SERVER" ]; then + pyroscope_enabled=true + else + pyroscope_enabled=false + fi + + cat << EOF > config.toml + [Common] + chainlink_node_funding=0.5 + + [ChainlinkImage] + image="$CHAINLINK_IMAGE" + version="${{ github.sha }}" + + [Pyroscope] + enabled=$pyroscope_enabled + server_url="$PYROSCOPE_SERVER" + environment="$PYROSCOPE_ENVIRONMENT" + key="$PYROSCOPE_KEY" + + [Logging] + run_id="$RUN_ID" + + [Logging.LogStream] + log_targets=$log_targets + + [Logging.Loki] + tenant_id="$LOKI_TENANT_ID" + endpoint="$LOKI_URL" + basic_auth="$LOKI_BASIC_AUTH" + + [Logging.Grafana] + base_url="$GRAFANA_URL" + dasboard_url="/d/ddf75041-1e39-42af-aa46-361fe4c36e9e/ci-e2e-tests-logs" + + [Network] + selected_networks=["sepolia"] + + [Network.RpcHttpUrls] + sepolia = $(convert_to_toml_array "$SEPOLIA_HTTP_URLS") + + [Network.RpcWsUrls] + sepolia = $(convert_to_toml_array "$SEPOLIA_URLS") + + [Network.WalletKeys] + sepolia = $(convert_to_toml_array "$EVM_KEYS") + EOF + + BASE64_CONFIG_OVERRIDE=$(cat config.toml | base64 -w 0) + echo ::add-mask::$BASE64_CONFIG_OVERRIDE + echo "BASE64_CONFIG_OVERRIDE=$BASE64_CONFIG_OVERRIDE" >> $GITHUB_ENV - name: Run E2E soak tests run: | cd integration-tests/load/functions diff --git a/.github/workflows/integration-tests.yml b/.github/workflows/integration-tests.yml index 780ccef739..c0de6ed815 100644 --- a/.github/workflows/integration-tests.yml +++ b/.github/workflows/integration-tests.yml @@ -45,7 +45,7 @@ jobs: echo "should-enforce=$SHOULD_ENFORCE" >> $GITHUB_OUTPUT - name: Enforce CTF Version if: steps.condition-check.outputs.should-enforce == 'true' - uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/mod-version@e865e376b8c2d594028c8d645dd6c47169b72974 # v2.2.16 + uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/mod-version@ea889b3133bd7f16ab19ba4ba130de5d9162c669 # v2.3.4 with: go-project-path: ./integration-tests module-name: github.com/smartcontractkit/chainlink-testing-framework @@ -87,7 +87,7 @@ jobs: - name: Checkout the repo uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - name: Setup Go - uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/setup-go@e865e376b8c2d594028c8d645dd6c47169b72974 # v2.2.16 + uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/setup-go@ea889b3133bd7f16ab19ba4ba130de5d9162c669 # v2.3.4 with: test_download_vendor_packages_command: cd ./integration-tests && go mod download go_mod_path: ./integration-tests/go.mod @@ -97,7 +97,7 @@ jobs: run: | cd ./integration-tests go build ./... - SELECTED_NETWORKS=SIMULATED go test -run=^# ./... + go test -run=^# ./... - name: Lint Go uses: golangci/golangci-lint-action@3a919529898de77ec3da873e3063ca4b10e7f5cc # v3.7.0 with: @@ -121,15 +121,15 @@ jobs: - name: "" dockerfile: core/chainlink.Dockerfile tag-suffix: "" - - name: (plugins) - dockerfile: plugins/chainlink.Dockerfile - tag-suffix: -plugins + # - name: (plugins) + # dockerfile: plugins/chainlink.Dockerfile + # tag-suffix: -plugins name: Build Chainlink Image ${{ matrix.image.name }} runs-on: ubuntu20.04-16cores-64GB needs: [changes, enforce-ctf-version] steps: - name: Collect Metrics - if: needs.changes.outputs.src == 'true' + if: needs.changes.outputs.src == 'true' || github.event_name == 'workflow_dispatch' id: collect-gha-metrics uses: smartcontractkit/push-gha-metrics-action@d1618b772a97fd87e6505de97b872ee0b1f1729a # v2.0.2 with: @@ -142,7 +142,7 @@ jobs: with: ref: ${{ github.event.pull_request.head.sha || github.event.merge_group.head_sha }} - name: Build Chainlink Image - if: needs.changes.outputs.src == 'true' + if: needs.changes.outputs.src == 'true' || github.event_name == 'workflow_dispatch' uses: ./.github/actions/build-chainlink-image with: tag_suffix: ${{ matrix.image.tag-suffix }} @@ -164,7 +164,7 @@ jobs: needs: [changes] steps: - name: Collect Metrics - if: needs.changes.outputs.src == 'true' + if: needs.changes.outputs.src == 'true' || github.event_name == 'workflow_dispatch' id: collect-gha-metrics uses: smartcontractkit/push-gha-metrics-action@d1618b772a97fd87e6505de97b872ee0b1f1729a # v2.0.2 with: @@ -177,7 +177,7 @@ jobs: with: ref: ${{ github.event.pull_request.head.sha || github.event.merge_group.head_sha }} - name: Build Test Image - if: needs.changes.outputs.src == 'true' + if: needs.changes.outputs.src == 'true' || github.event_name == 'workflow_dispatch' uses: ./.github/actions/build-test-image with: QA_AWS_ROLE_TO_ASSUME: ${{ secrets.QA_AWS_ROLE_TO_ASSUME }} @@ -189,7 +189,8 @@ jobs: # runs-on: ubuntu-latest # name: Compare/Build Automation Test List # outputs: -# matrix: ${{ env.MATRIX_JSON }} +# automation-matrix: ${{ env.AUTOMATION_JOB_MATRIX_JSON }} +# lp-matrix: ${{ env.LP_JOB_MATRIX_JSON }} # steps: # - name: Check for Skip Tests Label # if: contains(join(github.event.pull_request.labels.*.name, ' '), 'skip-smoke-tests') @@ -203,6 +204,7 @@ jobs: # cd ./integration-tests # ./scripts/compareTestList.sh ./smoke/automation_test.go # ./scripts/compareTestList.sh ./smoke/keeper_test.go +# ./scripts/compareTestList.sh ./smoke/log_poller_test.go # - name: Build Test Matrix Lists # id: build-test-matrix-list # run: | @@ -211,23 +213,112 @@ jobs: # MATRIX_JSON_KEEPER=$(./scripts/buildTestMatrixList.sh ./smoke/keeper_test.go keeper ubuntu-latest 1) # COMBINED_ARRAY=$(jq -c -n "$MATRIX_JSON_AUTOMATION + $MATRIX_JSON_KEEPER") # +# LOG_POLLER_MATRIX_JSON=$(./scripts/buildTestMatrixList.sh ./smoke/log_poller_test.go log_poller ubuntu-latest 1) +# echo "LP_JOB_MATRIX_JSON=${LOG_POLLER_MATRIX_JSON}" >> $GITHUB_ENV +# # # if we running a PR against the develop branch we should only run the automation tests unless we are in the merge group event # if [[ "$GITHUB_EVENT_NAME" == "merge_group" ]]; then # echo "We are in a merge_group event, run both automation and keepers tests" -# echo "MATRIX_JSON=${COMBINED_ARRAY}" >> $GITHUB_ENV +# echo "AUTOMATION_JOB_MATRIX_JSON=${COMBINED_ARRAY}" >> $GITHUB_ENV # else # echo "we are not in a merge_group event, if this is a PR to develop run only automation tests, otherwise run everything because we could be running against a release branch" # target_branch=$(cat $GITHUB_EVENT_PATH | jq -r .pull_request.base.ref) # if [[ "$target_branch" == "develop" ]]; then # echo "only run automation tests" -# echo "MATRIX_JSON=${MATRIX_JSON_AUTOMATION}" >> $GITHUB_ENV +# echo "AUTOMATION_JOB_MATRIX_JSON=${MATRIX_JSON_AUTOMATION}" >> $GITHUB_ENV # else # echo "run both automation and keepers tests" -# echo "MATRIX_JSON=${COMBINED_ARRAY}" >> $GITHUB_ENV +# echo "AUTOMATION_JOB_MATRIX_JSON=${COMBINED_ARRAY}" >> $GITHUB_ENV # fi # fi - +# # eth-smoke-tests-matrix-automation: +# if: ${{ !contains(join(github.event.pull_request.labels.*.name, ' '), 'skip-smoke-tests') }} +# environment: integration +# permissions: +# checks: write +# pull-requests: write +# id-token: write +# contents: read +# needs: +# [build-chainlink, changes, compare-tests, build-lint-integration-tests] +# env: +# SELECTED_NETWORKS: SIMULATED,SIMULATED_1,SIMULATED_2 +# CHAINLINK_COMMIT_SHA: ${{ github.sha }} +# CHAINLINK_ENV_USER: ${{ github.actor }} +# TEST_LOG_LEVEL: debug +# strategy: +# fail-fast: false +# matrix: +# product: ${{fromJson(needs.compare-tests.outputs.automation-matrix)}} +# runs-on: ${{ matrix.product.os }} +# name: ETH Smoke Tests ${{ matrix.product.name }} +# steps: +# - name: Collect Metrics +# if: needs.changes.outputs.src == 'true' || github.event_name == 'workflow_dispatch' +# id: collect-gha-metrics +# uses: smartcontractkit/push-gha-metrics-action@d1618b772a97fd87e6505de97b872ee0b1f1729a # v2.0.2 +# 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: Checkout the repo +# uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 +# with: +# ref: ${{ github.event.pull_request.head.sha || github.event.merge_group.head_sha }} +# - name: Build Go Test Command +# id: build-go-test-command +# run: | +# # if the matrix.product.run is set, use it for a different command +# if [ "${{ matrix.product.run }}" != "" ]; then +# echo "run_command=${{ matrix.product.run }} ./smoke/${{ matrix.product.file }}_test.go" >> "$GITHUB_OUTPUT" +# else +# echo "run_command=./smoke/${{ matrix.product.name }}_test.go" >> "$GITHUB_OUTPUT" +# fi +# - name: Prepare Base64 TOML override +# uses: ./.github/actions/setup-create-base64-config +# with: +# runId: ${{ github.run_id }} +# testLogCollect: ${{ vars.TEST_LOG_COLLECT }} +# selectedNetworks: ${{ env.SELECTED_NETWORKS }} +# chainlinkImage: ${{ env.CHAINLINK_IMAGE }} +# chainlinkVersion: ${{ github.sha }} +# pyroscopeServer: ${{ matrix.product.pyroscope_env == '' && '' || !startsWith(github.ref, 'refs/tags/') && '' || secrets.QA_PYROSCOPE_INSTANCE }} # Avoid sending blank envs https://github.com/orgs/community/discussions/25725 +# pyroscopeEnvironment: ${{ matrix.product.pyroscope_env }} +# pyroscopeKey: ${{ secrets.QA_PYROSCOPE_KEY }} +# lokiEndpoint: ${{ secrets.LOKI_URL }} +# lokiTenantId: ${{ vars.LOKI_TENANT_ID }} +# lokiBasicAuth: ${{ secrets.LOKI_BASIC_AUTH }} +# logstreamLogTargets: ${{ vars.LOGSTREAM_LOG_TARGETS }} +# grafanaUrl: ${{ vars.GRAFANA_URL }} +# grafanaDashboardUrl: "/d/ddf75041-1e39-42af-aa46-361fe4c36e9e/ci-e2e-tests-logs" +# +# ## Run this step when changes that require tests to be run are made +# - name: Run Tests +# if: needs.changes.outputs.src == 'true' || github.event_name == 'workflow_dispatch' +# uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/run-tests@ea889b3133bd7f16ab19ba4ba130de5d9162c669 # v2.3.4 +# with: +# test_command_to_run: 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 }} +# aws_registries: ${{ secrets.QA_AWS_ACCOUNT_NUMBER }} +# artifacts_location: ./integration-tests/smoke/logs/ +# publish_check_name: ${{ matrix.product.name }} +# token: ${{ secrets.GITHUB_TOKEN }} +# go_mod_path: ./integration-tests/go.mod +# cache_key_id: core-e2e-${{ env.MOD_CACHE_VERSION }} +# cache_restore_only: "true" +# QA_AWS_REGION: ${{ secrets.QA_AWS_REGION }} +# QA_AWS_ROLE_TO_ASSUME: ${{ secrets.QA_AWS_ROLE_TO_ASSUME }} +# QA_KUBECONFIG: "" +# - name: Print failed test summary +# if: always() +# uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/show-test-summary@ea889b3133bd7f16ab19ba4ba130de5d9162c669 # v2.3.4 +# +# eth-smoke-tests-matrix-log-poller: # if: ${{ !(contains(join(github.event.pull_request.labels.*.name, ' '), 'skip-smoke-tests') || github.event_name == 'workflow_dispatch') }} # environment: integration # permissions: @@ -245,7 +336,7 @@ jobs: # strategy: # fail-fast: false # matrix: -# product: ${{fromJson(needs.compare-tests.outputs.matrix)}} +# product: ${{fromJson(needs.compare-tests.outputs.lp-matrix)}} # runs-on: ${{ matrix.product.os }} # name: ETH Smoke Tests ${{ matrix.product.name }} # steps: @@ -272,14 +363,27 @@ jobs: # else # echo "run_command=./smoke/${{ matrix.product.name }}_test.go" >> "$GITHUB_OUTPUT" # fi +# - name: Prepare Base64 TOML override +# uses: ./.github/actions/setup-create-base64-config +# with: +# runId: ${{ github.run_id }} +# testLogCollect: ${{ vars.TEST_LOG_COLLECT }} +# selectedNetworks: ${{ env.SELECTED_NETWORKS }} +# chainlinkImage: ${{ env.CHAINLINK_IMAGE }} +# chainlinkVersion: ${{ github.sha }} +# pyroscopeServer: ${{ matrix.product.pyroscope_env == '' && '' || !startsWith(github.ref, 'refs/tags/') && '' || secrets.QA_PYROSCOPE_INSTANCE }} # Avoid sending blank envs https://github.com/orgs/community/discussions/25725 +# pyroscopeEnvironment: ${{ matrix.product.pyroscope_env }} +# pyroscopeKey: ${{ secrets.QA_PYROSCOPE_KEY }} +# lokiEndpoint: ${{ secrets.LOKI_URL }} +# lokiTenantId: ${{ vars.LOKI_TENANT_ID }} +# lokiBasicAuth: ${{ secrets.LOKI_BASIC_AUTH }} +# logstreamLogTargets: ${{ vars.LOGSTREAM_LOG_TARGETS }} +# grafanaUrl: ${{ vars.GRAFANA_URL }} +# grafanaDashboardUrl: "/d/ddf75041-1e39-42af-aa46-361fe4c36e9e/ci-e2e-tests-logs" # ## Run this step when changes that require tests to be run are made # - name: Run Tests # if: needs.changes.outputs.src == 'true' # uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/run-tests@e865e376b8c2d594028c8d645dd6c47169b72974 # v2.2.16 -# env: -# PYROSCOPE_SERVER: ${{ matrix.product.pyroscope_env == '' && '' || !startsWith(github.ref, 'refs/tags/') && '' || secrets.QA_PYROSCOPE_INSTANCE }} # Avoid sending blank envs https://github.com/orgs/community/discussions/25725 -# PYROSCOPE_ENVIRONMENT: ${{ matrix.product.pyroscope_env }} -# PYROSCOPE_KEY: ${{ secrets.QA_PYROSCOPE_KEY }} # with: # test_command_to_run: 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 @@ -297,7 +401,7 @@ jobs: # QA_KUBECONFIG: "" eth-smoke-tests-matrix: - if: ${{ !(contains(join(github.event.pull_request.labels.*.name, ' '), 'skip-smoke-tests') || github.event_name == 'workflow_dispatch') }} + if: ${{ !contains(join(github.event.pull_request.labels.*.name, ' '), 'skip-smoke-tests') }} environment: integration permissions: checks: write @@ -352,21 +456,25 @@ jobs: os: ubuntu20.04-16cores-64GB file: ccip run: -run ^TestSmokeCCIPManuallyExecuteAfterExecutionFailingDueToInsufficientGas$ + - name: runlog + nodes: 2 + os: ubuntu-latest + pyroscope_env: "ci-smoke-runlog-evm-simulated" - name: cron - nodes: 1 + nodes: 2 os: ubuntu-latest - pyroscope_env: "" + pyroscope_env: "ci-smoke-cron-evm-simulated" - name: flux nodes: 1 os: ubuntu-latest - pyroscope_env: "" + pyroscope_env: "ci-smoke-flux-evm-simulated" - name: ocr - nodes: 1 + nodes: 2 os: ubuntu-latest file: ocr pyroscope_env: ci-smoke-ocr-evm-simulated - name: ocr2 - nodes: 1 + nodes: 6 os: ubuntu-latest run: -run TestOCRBasic file: ocr @@ -430,39 +538,35 @@ jobs: client: erigon pyroscope_env: ci-smoke-ocr2-evm-simulated - name: ocr2 - nodes: 1 + nodes: 6 os: ubuntu-latest pyroscope_env: ci-smoke-ocr2-plugins-evm-simulated tag_suffix: "-plugins" - - name: runlog - nodes: 1 - os: ubuntu-latest - pyroscope_env: "" - name: vrf - nodes: 1 + nodes: 2 os: ubuntu-latest pyroscope_env: ci-smoke-vrf-evm-simulated - name: vrfv2 - nodes: 1 + nodes: 2 os: ubuntu-latest pyroscope_env: ci-smoke-vrf2-evm-simulated - name: vrfv2plus - nodes: 1 + nodes: 3 os: ubuntu-latest pyroscope_env: ci-smoke-vrf2plus-evm-simulated - name: forwarder_ocr - nodes: 1 + nodes: 2 os: ubuntu-latest pyroscope_env: ci-smoke-forwarder-ocr-evm-simulated - name: forwarders_ocr2 - nodes: 1 + nodes: 2 os: ubuntu-latest pyroscope_env: ci-smoke-forwarder-ocr-evm-simulated runs-on: ${{ matrix.product.os }} name: ETH Smoke Tests ${{ matrix.product.name }}${{ matrix.product.tag_suffix }} steps: - name: Collect Metrics - if: needs.changes.outputs.src == 'true' + if: needs.changes.outputs.src == 'true' || github.event_name == 'workflow_dispatch' id: collect-gha-metrics uses: smartcontractkit/push-gha-metrics-action@d1618b772a97fd87e6505de97b872ee0b1f1729a # v2.0.2 with: @@ -549,21 +653,28 @@ jobs: if [ "${{ matrix.product.config_path }}" != "" ]; then echo "base_64_override=$(base64 -w 0 -i ${{ matrix.product.config_path }})" >> "$GITHUB_OUTPUT" fi + - name: Prepare Base64 TOML override + uses: ./.github/actions/setup-create-base64-config + with: + runId: ${{ github.run_id }} + testLogCollect: ${{ vars.TEST_LOG_COLLECT }} + selectedNetworks: ${{ env.SELECTED_NETWORKS }} + chainlinkImage: ${{ env.CHAINLINK_IMAGE }} + chainlinkVersion: ${{ github.sha }} + pyroscopeServer: ${{ matrix.product.pyroscope_env == '' && '' || !startsWith(github.ref, 'refs/tags/') && '' || secrets.QA_PYROSCOPE_INSTANCE }} # Avoid sending blank envs https://github.com/orgs/community/discussions/25725 + pyroscopeEnvironment: ${{ matrix.product.pyroscope_env }} + pyroscopeKey: ${{ secrets.QA_PYROSCOPE_KEY }} + lokiEndpoint: ${{ secrets.LOKI_URL }} + lokiTenantId: ${{ vars.LOKI_TENANT_ID }} + lokiBasicAuth: ${{ secrets.LOKI_BASIC_AUTH }} + logstreamLogTargets: ${{ vars.LOGSTREAM_LOG_TARGETS }} + grafanaUrl: ${{ vars.GRAFANA_URL }} + grafanaDashboardUrl: "/d/ddf75041-1e39-42af-aa46-361fe4c36e9e/ci-e2e-tests-logs" ## Run this step when changes that require tests to be run are made - name: Run Tests - if: needs.changes.outputs.src == 'true' + if: needs.changes.outputs.src == 'true' || github.event_name == 'workflow_dispatch' uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/run-tests@e865e376b8c2d594028c8d645dd6c47169b72974 # v2.2.16 env: - PYROSCOPE_SERVER: ${{ matrix.product.pyroscope_env == '' && '' || !startsWith(github.ref, 'refs/tags/') && '' || secrets.QA_PYROSCOPE_INSTANCE }} # Avoid sending blank envs https://github.com/orgs/community/discussions/25725 - PYROSCOPE_ENVIRONMENT: ${{ matrix.product.pyroscope_env }} - PYROSCOPE_KEY: ${{ secrets.QA_PYROSCOPE_KEY }} - LOKI_TENANT_ID: ${{ vars.LOKI_TENANT_ID }} - LOKI_URL: ${{ secrets.LOKI_URL }} - LOKI_BASIC_AUTH: ${{ secrets.LOKI_BASIC_AUTH }} - LOGSTREAM_LOG_TARGETS: ${{ vars.LOGSTREAM_LOG_TARGETS }} - GRAFANA_URL: ${{ vars.GRAFANA_URL }} - GRAFANA_DATASOURCE: ${{ vars.GRAFANA_DATASOURCE }} - RUN_ID: ${{ github.run_id }} BASE64_TEST_CONFIG_OVERRIDE: ${{ steps.set_override_config.outputs.base_64_override }} TEST_BASE64_TEST_CONFIG_OVERRIDE: ${{ steps.set_override_config.outputs.base_64_override }} with: @@ -572,7 +683,7 @@ jobs: cl_repo: ${{ env.CHAINLINK_IMAGE }} cl_image_tag: ${{ github.sha }}${{ matrix.product.tag_suffix }} aws_registries: ${{ secrets.QA_AWS_ACCOUNT_NUMBER }} - artifacts_name: ${{ matrix.product.name }}-test-logs + artifacts_name: ${{ matrix.product.name }}${{ matrix.product.tag_suffix }}-test-logs artifacts_location: ./integration-tests/smoke/logs/ publish_check_name: ${{ matrix.product.name }} token: ${{ secrets.GITHUB_TOKEN }} @@ -582,10 +693,10 @@ jobs: QA_AWS_REGION: ${{ secrets.QA_AWS_REGION }} QA_AWS_ROLE_TO_ASSUME: ${{ secrets.QA_AWS_ROLE_TO_ASSUME }} QA_KUBECONFIG: "" - ## Run this step when changes that do not need the test to run are made + # Run this step when changes that do not need the test to run are made - name: Run Setup if: needs.changes.outputs.src == 'false' - uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/setup-run-tests-environment@e865e376b8c2d594028c8d645dd6c47169b72974 # v2.2.16 + uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/setup-run-tests-environment@ea889b3133bd7f16ab19ba4ba130de5d9162c669 # v2.3.4 with: test_download_vendor_packages_command: cd ./integration-tests && go mod download go_mod_path: ./integration-tests/go.mod @@ -610,25 +721,9 @@ jobs: path: ./integration-tests/smoke/traces/trace-data.json - name: Print failed test summary if: always() - run: | - directory="./integration-tests/smoke/.test_summary" - files=("$directory"/*) - if [ -d "$directory" ]; then - echo "Test summary folder found" - if [ ${#files[@]} -gt 0 ]; then - first_file="${files[0]}" - echo "Name of the first test summary file: $(basename "$first_file")" - echo "### Failed Test Execution Logs Dashboard (over VPN):" >> $GITHUB_STEP_SUMMARY - cat "$first_file" | jq -r '.loki[] | "* [\(.test_name)](\(.value))"' >> $GITHUB_STEP_SUMMARY - if [ ${#files[@]} -gt 1 ]; then - echo "Found more than one test summary file. This is incorrect, there should be only one file" - fi - else - echo "Test summary directory is empty. This should not happen" - fi - else - echo "No test summary folder found. If no test failed or log collection wasn't explicitly requested this is correct. Exiting" - fi + uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/show-test-summary@ea889b3133bd7f16ab19ba4ba130de5d9162c669 # v2.3.4 + with: + test_directory: ./integration-tests/smoke/ ### Used to check the required checks box when the matrix completes eth-smoke-tests: @@ -694,7 +789,7 @@ jobs: with: ref: ${{ github.event.pull_request.head.sha || github.event.merge_group.head_sha }} - name: Run Setup - uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/setup-go@e865e376b8c2d594028c8d645dd6c47169b72974 # v2.2.16 + uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/setup-go@ea889b3133bd7f16ab19ba4ba130de5d9162c669 # v2.3.4 with: test_download_vendor_packages_command: | cd ./integration-tests @@ -741,8 +836,16 @@ jobs: - name: Name Versions run: | echo "Running migration tests from version '${{ steps.get_latest_version.outputs.latest_version }}' to: '${{ github.sha }}'" + - name: Prepare Base64 TOML override + uses: ./.github/actions/setup-create-base64-upgrade-config + with: + selectedNetworks: ${{ env.SELECTED_NETWORKS }} + chainlinkImage: ${{ env.CHAINLINK_IMAGE }} + chainlinkVersion: ${{ steps.get_latest_version.outputs.latest_version }} + upgradeImage: ${{ env.UPGRADE_IMAGE }} + upgradeVersion: ${{ env.UPGRADE_VERSION }} - name: Run Migration Tests - uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/run-tests@e865e376b8c2d594028c8d645dd6c47169b72974 # v2.2.16 + uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/run-tests@ea889b3133bd7f16ab19ba4ba130de5d9162c669 # v2.3.4 with: test_command_to_run: cd ./integration-tests && go test -timeout 30m -count=1 -json ./migration 2>&1 | tee /tmp/gotest.log | gotestfmt test_download_vendor_packages_command: cd ./integration-tests && go mod download @@ -776,7 +879,7 @@ jobs: test-results-file: '{"testType":"go","filePath":"/tmp/gotest.log"}' continue-on-error: true - ### Solana Section + ## Solana Section # get_solana_sha: # name: Get Solana Sha From Go Mod # environment: Integration @@ -854,7 +957,7 @@ jobs: # steps: # - name: Check if image exists # id: check-image -# uses: smartcontractkit/chainlink-github-actions/docker/image-exists@e865e376b8c2d594028c8d645dd6c47169b72974 # v2.2.16 +# uses: smartcontractkit/chainlink-github-actions/docker/image-exists@ea889b3133bd7f16ab19ba4ba130de5d9162c669 # v2.3.4 # with: # repository: chainlink-solana-tests # tag: ${{ needs.get_solana_sha.outputs.sha }} @@ -884,7 +987,7 @@ jobs: # FORCE_COLOR: 1 # steps: # - name: Collect Metrics -# if: needs.changes.outputs.src == 'true' +# if: needs.changes.outputs.src == 'true' || github.event_name == 'workflow_dispatch' # id: collect-gha-metrics # uses: smartcontractkit/push-gha-metrics-action@d1618b772a97fd87e6505de97b872ee0b1f1729a # v2.0.2 # with: @@ -900,8 +1003,8 @@ jobs: # repository: smartcontractkit/chainlink-solana # ref: ${{ needs.get_solana_sha.outputs.sha }} # - name: Build contracts -# if: needs.changes.outputs.src == 'true' && needs.solana-test-image-exists.outputs.exists == 'false' -# uses: smartcontractkit/chainlink-solana/.github/actions/build_contract_artifacts@23816fcf7d380a30c87b6d87e4fb0ca94419b259 # stable action on April 17 2023 +# if: (needs.changes.outputs.src == 'true' || github.event_name == 'workflow_dispatch') && needs.solana-test-image-exists.outputs.exists == 'false' +# uses: smartcontractkit/chainlink-solana/.github/actions/build_contract_artifacts@21675b3a7dcdff8e790391708d4763020cace21e # stable action on December 18 2023 # with: # ref: ${{ needs.get_solana_sha.outputs.sha }} # @@ -925,7 +1028,7 @@ jobs: # CONTRACT_ARTIFACTS_PATH: contracts/target/deploy # steps: # - name: Collect Metrics -# if: needs.changes.outputs.src == 'true' && needs.solana-test-image-exists.outputs.exists == 'false' +# if: (needs.changes.outputs.src == 'true' || github.event_name == 'workflow_dispatch') && needs.solana-test-image-exists.outputs.exists == 'false' # id: collect-gha-metrics # uses: smartcontractkit/push-gha-metrics-action@d1618b772a97fd87e6505de97b872ee0b1f1729a # v2.0.2 # with: @@ -934,13 +1037,13 @@ jobs: # this-job-name: Solana Build Test Image # continue-on-error: true # - name: Checkout the repo -# if: needs.changes.outputs.src == 'true' && needs.solana-test-image-exists.outputs.exists == 'false' +# if: (needs.changes.outputs.src == 'true' || github.event_name == 'workflow_dispatch') && needs.solana-test-image-exists.outputs.exists == 'false' # uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 # with: # repository: smartcontractkit/chainlink-solana # ref: ${{ needs.get_solana_sha.outputs.sha }} # - name: Build Test Image -# if: needs.changes.outputs.src == 'true' && needs.solana-test-image-exists.outputs.exists == 'false' +# if: (needs.changes.outputs.src == 'true' || github.event_name == 'workflow_dispatch') && needs.solana-test-image-exists.outputs.exists == 'false' # uses: ./.github/actions/build-test-image # with: # tag: ${{ needs.get_solana_sha.outputs.sha }} @@ -976,7 +1079,7 @@ jobs: # CONTRACT_ARTIFACTS_PATH: contracts/target/deploy # steps: # - name: Collect Metrics -# if: needs.changes.outputs.src == 'true' +# if: needs.changes.outputs.src == 'true' || github.event_name == 'workflow_dispatch' # id: collect-gha-metrics # uses: smartcontractkit/push-gha-metrics-action@d1618b772a97fd87e6505de97b872ee0b1f1729a # v2.0.2 # with: @@ -991,8 +1094,8 @@ jobs: # 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@e865e376b8c2d594028c8d645dd6c47169b72974 # v2.2.16 +# if: needs.changes.outputs.src == 'true' || github.event_name == 'workflow_dispatch' +# uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/setup-run-tests-environment@ea889b3133bd7f16ab19ba4ba130de5d9162c669 # v2.3.4 # with: # go_mod_path: ./integration-tests/go.mod # cache_restore_only: true @@ -1004,7 +1107,7 @@ jobs: # 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' +# if: needs.changes.outputs.src == 'true' || github.event_name == 'workflow_dispatch' # 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 @@ -1020,8 +1123,8 @@ jobs: # # 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@e865e376b8c2d594028c8d645dd6c47169b72974 # v2.2.16 +# if: needs.changes.outputs.src == 'true' || github.event_name == 'workflow_dispatch' +# uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/run-tests@ea889b3133bd7f16ab19ba4ba130de5d9162c669 # v2.3.4 # with: # test_command_to_run: export ENV_JOB_IMAGE=${{ secrets.QA_AWS_ACCOUNT_NUMBER }}.dkr.ecr.${{ secrets.QA_AWS_REGION }}.amazonaws.com/chainlink-solana-tests:${{ needs.get_solana_sha.outputs.sha }} && make test_smoke # cl_repo: ${{ env.CHAINLINK_IMAGE }} diff --git a/.github/workflows/live-testnet-tests.yml b/.github/workflows/live-testnet-tests.yml index 3298c45813..611fd3815b 100644 --- a/.github/workflows/live-testnet-tests.yml +++ b/.github/workflows/live-testnet-tests.yml @@ -1,7 +1,7 @@ # *** # This workflow is a monstrosity of copy-paste, and that's to increase legibility in reporting and running, so the code be damned. # I suspect this can be cleaned up significantly with some clever trickery of the GitHub actions matrices, but I am not that clever. -# We want each chain to run in parallel, but each test within the chain needs to be able to run sequentially +# We want each chain to run in parallel, but each test within the chain needs to be able to run sequentially # (we're trying to eliminate this as a requirement, should make it a lot easier). # Each chain can have a variety of tests to run. # We also want reporting to be clear in the start-slack-thread and post-test-results-to-slack jobs. @@ -21,52 +21,22 @@ env: INTERNAL_DOCKER_REPO: ${{ secrets.QA_AWS_ACCOUNT_NUMBER }}.dkr.ecr.${{ secrets.QA_AWS_REGION }}.amazonaws.com MOD_CACHE_VERSION: 2 CHAINLINK_NODE_FUNDING: .5 + PYROSCOPE_KEY: ${{ secrets.QA_PYROSCOPE_KEY }} + LOKI_TENANT_ID: ${{ vars.LOKI_TENANT_ID }} + LOKI_URL: ${{ secrets.LOKI_URL }} + LOKI_BASIC_AUTH: ${{ secrets.LOKI_BASIC_AUTH }} + LOGSTREAM_LOG_TARGETS: loki + GRAFANA_URL: ${{ vars.GRAFANA_URL }} + RUN_ID: ${{ github.run_id }} CHAINLINK_COMMIT_SHA: ${{ github.sha }} CHAINLINK_ENV_USER: ${{ github.actor }} TEST_LOG_LEVEL: debug - EVM_KEYS: ${{ secrets.QA_EVM_KEYS }} - - SEPOLIA_URLS: ${{ secrets.QA_SEPOLIA_URLS }} - SEPOLIA_HTTP_URLS: ${{ secrets.QA_SEPOLIA_HTTP_URLS }} - - BSC_TESTNET_URLS: ${{ secrets.QA_BSC_TESTNET_URLS }} - BSC_TESTNET_HTTP_URLS: ${{ secrets.QA_BSC_TESTNET_HTTP_URLS }} - - OPTIMISM_SEPOLIA_URLS: ${{ secrets.QA_OPTIMISM_SEPOLIA_URLS }} - OPTIMISM_SEPOLIA_HTTP_URLS: ${{ secrets.QA_OPTIMISM_SEPOLIA_HTTP_URLS }} - - ARBITRUM_SEPOLIA_URLS: ${{ secrets.QA_ARBITRUM_SEPOLIA_URLS }} - ARBITRUM_SEPOLIA_HTTP_URLS: ${{ secrets.QA_ARBITRUM_SEPOLIA_HTTP_URLS }} - - BASE_GOERLI_URLS: ${{ secrets.QA_BASE_GOERLI_URLS }} - BASE_GOERLI_HTTP_URLS: ${{ secrets.QA_BASE_GOERLI_HTTP_URLS }} - - BASE_SEPOLIA_URLS: ${{ secrets.QA_BASE_SEPOLIA_URLS }} - BASE_SEPOLIA_HTTP_URLS: ${{ secrets.QA_BASE_SEPOLIA_HTTP_URLS }} - - POLYGON_MUMBAI_URLS: ${{ secrets.QA_POLYGON_MUMBAI_URLS }} - POLYGON_MUMBAI_HTTP_URLS: ${{ secrets.QA_POLYGON_MUMBAI_HTTP_URLS }} - - AVALANCHE_FUJI_URLS: ${{ secrets.QA_AVALANCHE_FUJI_URLS }} - AVALANCHE_FUJI_HTTP_URLS: ${{ secrets.QA_AVALANCHE_FUJI_HTTP_URLS }} - - FANTOM_TESTNET_URLS: ${{ secrets.QA_FANTOM_TESTNET_URLS }} - FANTOM_TESTNET_HTTP_URLS: ${{ secrets.QA_FANTOM_TESTNET_HTTP_URLS }} - - CELO_ALFAJORES_URLS: ${{ secrets.QA_CELO_ALFAJORES_URLS }} - CELO_ALFAJORES_HTTP_URLS: ${{ secrets.QA_CELO_ALFAJORES_HTTP_URLS }} - - SCROLL_SEPOLIA_URLS: ${{ secrets.QA_SCROLL_SEPOLIA_URLS }} - SCROLL_SEPOLIA_HTTP_URLS: ${{ secrets.QA_SCROLL_SEPOLIA_HTTP_URLS }} - - LINEA_GOERLI_URLS: ${{ secrets.QA_LINEA_GOERLI_URLS }} - LINEA_GOERLI_HTTP_URLS: ${{ secrets.QA_LINEA_GOERLI_HTTP_URLS }} jobs: # Build Test Dependencies - + build-chainlink: environment: integration permissions: @@ -89,7 +59,7 @@ jobs: ref: ${{ github.event.pull_request.head.sha || github.event.merge_group.head_sha }} - name: Build Chainlink Image uses: ./.github/actions/build-chainlink-image - with: + with: tag_suffix: "" dockerfile: core/chainlink.Dockerfile git_commit_sha: ${{ github.sha }} @@ -119,11 +89,12 @@ jobs: with: ref: ${{ github.event.pull_request.head.sha || github.event.merge_group.head_sha }} - name: Build Tests - uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/build-tests@912bed7e07a1df4d06ea53a031e9773bb65dc7bd # v2.3.0 + uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/build-tests@ea889b3133bd7f16ab19ba4ba130de5d9162c669 # v2.3.4 with: test_download_vendor_packages_command: cd ./integration-tests && go mod download token: ${{ secrets.GITHUB_TOKEN }} go_mod_path: ./integration-tests/go.mod + go_tags: embed cache_key_id: core-e2e-${{ env.MOD_CACHE_VERSION }} cache_restore_only: "true" binary_name: tests @@ -144,7 +115,7 @@ jobs: id-token: write contents: read runs-on: ubuntu-latest - needs: [sepolia-smoke-tests, optimism-sepolia-smoke-tests, arbitrum-sepolia-smoke-tests, base-goerli-smoke-tests, base-sepolia-smoke-tests, polygon-mumbai-smoke-tests, avalanche-fuji-smoke-tests, fantom-testnet-smoke-tests, celo-alfajores-smoke-tests, linea-goerli-smoke-tests] + needs: [sepolia-smoke-tests, optimism-sepolia-smoke-tests, arbitrum-sepolia-smoke-tests, base-sepolia-smoke-tests, polygon-mumbai-smoke-tests, avalanche-fuji-smoke-tests, fantom-testnet-smoke-tests, celo-alfajores-smoke-tests, linea-goerli-smoke-tests] steps: - name: Debug Result run: echo ${{ join(needs.*.result, ',') }} @@ -205,7 +176,7 @@ jobs: strategy: fail-fast: false matrix: - network: [Sepolia, Optimism Sepolia, Arbitrum Sepolia, Base Goerli, Base Sepolia, Polygon Mumbai, Avalanche Fuji, Fantom Testnet, Celo Alfajores, Linea Goerli] + network: [Sepolia, Optimism Sepolia, Arbitrum Sepolia, Base Sepolia, Polygon Mumbai, Avalanche Fuji, Fantom Testnet, Celo Alfajores, Linea Goerli] steps: - name: Checkout the repo uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 @@ -233,8 +204,6 @@ jobs: id-token: write contents: read needs: [build-chainlink, build-tests] - env: - SELECTED_NETWORKS: SEPOLIA strategy: max-parallel: 1 fail-fast: false @@ -249,16 +218,35 @@ jobs: name: Sepolia ${{ matrix.product }} Tests runs-on: ubuntu-latest steps: + - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + with: + fetch-depth: 0 + - name: Prepare Base64 TOML override + uses: ./.github/actions/setup-create-base64-config-live-testnets + with: + runId: ${{ github.run_id }} + testLogCollect: ${{ vars.TEST_LOG_COLLECT }} + chainlinkImage: ${{ env.CHAINLINK_IMAGE }} + chainlinkVersion: ${{ github.sha }} + pyroscopeServer: ${{ matrix.product.pyroscope_env == '' && '' || !startsWith(github.ref, 'refs/tags/') && '' || secrets.QA_PYROSCOPE_INSTANCE }} # Avoid sending blank envs https://github.com/orgs/community/discussions/25725 + pyroscopeEnvironment: ci-smoke-${{ matrix.product }}-sepolia + pyroscopeKey: ${{ secrets.QA_PYROSCOPE_KEY }} + lokiEndpoint: ${{ secrets.LOKI_URL }} + lokiTenantId: ${{ vars.LOKI_TENANT_ID }} + lokiBasicAuth: ${{ secrets.LOKI_BASIC_AUTH }} + logstreamLogTargets: ${{ vars.LOGSTREAM_LOG_TARGETS }} + grafanaUrl: ${{ vars.GRAFANA_URL }} + grafanaDashboardUrl: "/d/ddf75041-1e39-42af-aa46-361fe4c36e9e/ci-e2e-tests-logs" + network: "sepolia" + httpEndpoints: ${{ secrets.QA_SEPOLIA_HTTP_URLS }} + wsEndpoints: ${{ secrets.QA_SEPOLIA_URLS }} + fundingKeys: ${{ secrets.QA_EVM_KEYS }} - name: Download Tests Binary uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # v3.0.2 with: name: tests - name: Run Tests - uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/run-tests-binary@912bed7e07a1df4d06ea53a031e9773bb65dc7bd # v2.3.0 - env: - PYROSCOPE_SERVER: ${{ secrets.QA_PYROSCOPE_INSTANCE }} - PYROSCOPE_ENVIRONMENT: ci-smoke-${{ matrix.product }}-sepolia - PYROSCOPE_KEY: ${{ secrets.QA_PYROSCOPE_KEY }} + uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/run-tests-binary@ea889b3133bd7f16ab19ba4ba130de5d9162c669 # v2.3.4 with: test_command_to_run: ./tests -test.timeout 30m -test.count=1 -test.parallel=1 -test.run ${{ matrix.test }} binary_name: tests @@ -274,6 +262,9 @@ 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: Print failed test summary + if: always() + uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/show-test-summary@ea889b3133bd7f16ab19ba4ba130de5d9162c669 # v2.3.4 bsc-testnet-tests: # TODO: BSC RPCs are all in a bad state right now, so we're skipping these tests until they're fixed @@ -285,8 +276,6 @@ jobs: id-token: write contents: read needs: [build-chainlink, build-tests] - env: - SELECTED_NETWORKS: BSC_TESTNET strategy: max-parallel: 1 fail-fast: false @@ -301,16 +290,35 @@ jobs: name: BSC Testnet ${{ matrix.product }} Tests runs-on: ubuntu-latest steps: + - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + with: + fetch-depth: 0 + - name: Prepare Base64 TOML override + uses: ./.github/actions/setup-create-base64-config-live-testnets + with: + runId: ${{ github.run_id }} + testLogCollect: ${{ vars.TEST_LOG_COLLECT }} + chainlinkImage: ${{ env.CHAINLINK_IMAGE }} + chainlinkVersion: ${{ github.sha }} + pyroscopeServer: ${{ matrix.product.pyroscope_env == '' && '' || !startsWith(github.ref, 'refs/tags/') && '' || secrets.QA_PYROSCOPE_INSTANCE }} # Avoid sending blank envs https://github.com/orgs/community/discussions/25725 + pyroscopeEnvironment: ci-smoke-${{ matrix.product }}-bsc-testnet + pyroscopeKey: ${{ secrets.QA_PYROSCOPE_KEY }} + lokiEndpoint: ${{ secrets.LOKI_URL }} + lokiTenantId: ${{ vars.LOKI_TENANT_ID }} + lokiBasicAuth: ${{ secrets.LOKI_BASIC_AUTH }} + logstreamLogTargets: ${{ vars.LOGSTREAM_LOG_TARGETS }} + grafanaUrl: ${{ vars.GRAFANA_URL }} + grafanaDashboardUrl: "/d/ddf75041-1e39-42af-aa46-361fe4c36e9e/ci-e2e-tests-logs" + network: "bsc_testnet" + httpEndpoints: ${{ secrets.QA_BSC_TESTNET_HTTP_URLS }} + wsEndpoints: ${{ secrets.QA_BSC_TESTNET_URLS }} + fundingKeys: ${{ secrets.QA_EVM_KEYS }} - name: Download Tests Binary uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # v3.0.2 with: name: tests - name: Run Tests - uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/run-tests-binary@912bed7e07a1df4d06ea53a031e9773bb65dc7bd # v2.3.0 - env: - PYROSCOPE_SERVER: ${{ secrets.QA_PYROSCOPE_INSTANCE }} - PYROSCOPE_ENVIRONMENT: ci-smoke-${{ matrix.product }}-bsc-testnet - PYROSCOPE_KEY: ${{ secrets.QA_PYROSCOPE_KEY }} + uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/run-tests-binary@ea889b3133bd7f16ab19ba4ba130de5d9162c669 # v2.3.4 with: test_command_to_run: ./tests -test.timeout 30m -test.count=1 -test.parallel=1 -test.run ${{ matrix.test }} binary_name: tests @@ -326,6 +334,9 @@ 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: Print failed test summary + if: always() + uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/show-test-summary@ea889b3133bd7f16ab19ba4ba130de5d9162c669 # v2.3.4 optimism-sepolia-smoke-tests: environment: integration @@ -335,8 +346,6 @@ jobs: id-token: write contents: read needs: [build-chainlink, build-tests] - env: - SELECTED_NETWORKS: OPTIMISM_SEPOLIA strategy: max-parallel: 1 fail-fast: false @@ -351,16 +360,35 @@ jobs: name: Optimism Sepolia ${{ matrix.product }} Tests runs-on: ubuntu-latest steps: + - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + with: + fetch-depth: 0 + - name: Prepare Base64 TOML override + uses: ./.github/actions/setup-create-base64-config-live-testnets + with: + runId: ${{ github.run_id }} + testLogCollect: ${{ vars.TEST_LOG_COLLECT }} + chainlinkImage: ${{ env.CHAINLINK_IMAGE }} + chainlinkVersion: ${{ github.sha }} + pyroscopeServer: ${{ matrix.product.pyroscope_env == '' && '' || !startsWith(github.ref, 'refs/tags/') && '' || secrets.QA_PYROSCOPE_INSTANCE }} # Avoid sending blank envs https://github.com/orgs/community/discussions/25725 + pyroscopeEnvironment: ci-smoke-${{ matrix.product }}-optimism-sepolia + pyroscopeKey: ${{ secrets.QA_PYROSCOPE_KEY }} + lokiEndpoint: ${{ secrets.LOKI_URL }} + lokiTenantId: ${{ vars.LOKI_TENANT_ID }} + lokiBasicAuth: ${{ secrets.LOKI_BASIC_AUTH }} + logstreamLogTargets: ${{ vars.LOGSTREAM_LOG_TARGETS }} + grafanaUrl: ${{ vars.GRAFANA_URL }} + grafanaDashboardUrl: "/d/ddf75041-1e39-42af-aa46-361fe4c36e9e/ci-e2e-tests-logs" + network: "optimism_sepolia" + httpEndpoints: ${{ secrets.QA_OPTIMISM_SEPOLIA_HTTP_URLS }} + wsEndpoints: ${{ secrets.QA_OPTIMISM_SEPOLIA_URLS }} + fundingKeys: ${{ secrets.QA_EVM_KEYS }} - name: Download Tests Binary uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # v3.0.2 with: name: tests - name: Run Tests - uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/run-tests-binary@912bed7e07a1df4d06ea53a031e9773bb65dc7bd # v2.3.0 - env: - PYROSCOPE_SERVER: ${{ secrets.QA_PYROSCOPE_INSTANCE }} - PYROSCOPE_ENVIRONMENT: ci-smoke-${{ matrix.product }}-optimism-sepolia - PYROSCOPE_KEY: ${{ secrets.QA_PYROSCOPE_KEY }} + uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/run-tests-binary@ea889b3133bd7f16ab19ba4ba130de5d9162c669 # v2.3.4 with: test_command_to_run: ./tests -test.timeout 30m -test.count=1 -test.parallel=1 -test.run ${{ matrix.test }} binary_name: tests @@ -376,6 +404,9 @@ 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: Print failed test summary + if: always() + uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/show-test-summary@ea889b3133bd7f16ab19ba4ba130de5d9162c669 # v2.3.4 arbitrum-sepolia-smoke-tests: environment: integration @@ -385,8 +416,6 @@ jobs: id-token: write contents: read needs: [build-chainlink, build-tests] - env: - SELECTED_NETWORKS: ARBITRUM_SEPOLIA strategy: max-parallel: 1 fail-fast: false @@ -401,62 +430,35 @@ jobs: name: Arbitrum Sepolia ${{ matrix.product }} Tests runs-on: ubuntu-latest steps: + - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + with: + fetch-depth: 0 + - name: Prepare Base64 TOML override + uses: ./.github/actions/setup-create-base64-config-live-testnets + with: + runId: ${{ github.run_id }} + testLogCollect: ${{ vars.TEST_LOG_COLLECT }} + chainlinkImage: ${{ env.CHAINLINK_IMAGE }} + chainlinkVersion: ${{ github.sha }} + pyroscopeServer: ${{ matrix.product.pyroscope_env == '' && '' || !startsWith(github.ref, 'refs/tags/') && '' || secrets.QA_PYROSCOPE_INSTANCE }} # Avoid sending blank envs https://github.com/orgs/community/discussions/25725 + pyroscopeEnvironment: ci-smoke-${{ matrix.product }}-arbitrum-sepolia + pyroscopeKey: ${{ secrets.QA_PYROSCOPE_KEY }} + lokiEndpoint: ${{ secrets.LOKI_URL }} + lokiTenantId: ${{ vars.LOKI_TENANT_ID }} + lokiBasicAuth: ${{ secrets.LOKI_BASIC_AUTH }} + logstreamLogTargets: ${{ vars.LOGSTREAM_LOG_TARGETS }} + grafanaUrl: ${{ vars.GRAFANA_URL }} + grafanaDashboardUrl: "/d/ddf75041-1e39-42af-aa46-361fe4c36e9e/ci-e2e-tests-logs" + network: "arbitrum_sepolia" + httpEndpoints: ${{ secrets.QA_ARBITRUM_SEPOLIA_HTTP_URLS }} + wsEndpoints: ${{ secrets.QA_ARBITRUM_SEPOLIA_URLS }} + fundingKeys: ${{ secrets.QA_EVM_KEYS }} - name: Download Tests Binary uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # v3.0.2 with: name: tests - name: Run Tests - uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/run-tests-binary@912bed7e07a1df4d06ea53a031e9773bb65dc7bd # v2.3.0 - env: - PYROSCOPE_SERVER: ${{ secrets.QA_PYROSCOPE_INSTANCE }} - PYROSCOPE_ENVIRONMENT: ci-smoke-${{ matrix.product }}-arbitrum-sepolia - PYROSCOPE_KEY: ${{ secrets.QA_PYROSCOPE_KEY }} - with: - test_command_to_run: ./tests -test.timeout 30m -test.count=1 -test.parallel=1 -test.run ${{ matrix.test }} - binary_name: tests - cl_repo: ${{ env.CHAINLINK_IMAGE }} - cl_image_tag: ${{ github.sha }} - aws_registries: ${{ secrets.QA_AWS_ACCOUNT_NUMBER }} - dockerhub_username: ${{ secrets.DOCKERHUB_READONLY_USERNAME }} - dockerhub_password: ${{ secrets.DOCKERHUB_READONLY_PASSWORD }} - artifacts_location: ./logs - token: ${{ secrets.GITHUB_TOKEN }} - cache_key_id: core-e2e-${{ env.MOD_CACHE_VERSION }} - cache_restore_only: "true" - QA_AWS_REGION: ${{ secrets.QA_AWS_REGION }} - QA_AWS_ROLE_TO_ASSUME: ${{ secrets.QA_AWS_ROLE_TO_ASSUME }} - QA_KUBECONFIG: ${{ secrets.QA_KUBECONFIG }} - - base-goerli-smoke-tests: - environment: integration - permissions: - checks: write - pull-requests: write - id-token: write - contents: read - needs: [build-chainlink, build-tests] - env: - SELECTED_NETWORKS: BASE_GOERLI - strategy: - max-parallel: 1 - fail-fast: false - matrix: - include: # https://docs.github.com/en/actions/using-jobs/using-a-matrix-for-your-jobs#example-adding-configurations - - product: OCR - test: TestOCRBasic - name: Base Goerli ${{ matrix.product }} Tests - runs-on: ubuntu-latest - steps: - - name: Download Tests Binary - uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # v3.0.2 - with: - name: tests - - name: Run Tests - uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/run-tests-binary@912bed7e07a1df4d06ea53a031e9773bb65dc7bd # v2.3.0 - env: - PYROSCOPE_SERVER: ${{ secrets.QA_PYROSCOPE_INSTANCE }} - PYROSCOPE_ENVIRONMENT: ci-smoke-${{ matrix.product }}-base-goerli - PYROSCOPE_KEY: ${{ secrets.QA_PYROSCOPE_KEY }} + uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/run-tests-binary@ea889b3133bd7f16ab19ba4ba130de5d9162c669 # v2.3.4 with: test_command_to_run: ./tests -test.timeout 30m -test.count=1 -test.parallel=1 -test.run ${{ matrix.test }} binary_name: tests @@ -472,6 +474,9 @@ 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: Print failed test summary + if: always() + uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/show-test-summary@ea889b3133bd7f16ab19ba4ba130de5d9162c669 # v2.3.4 base-sepolia-smoke-tests: environment: integration @@ -481,8 +486,6 @@ jobs: id-token: write contents: read needs: [build-chainlink, build-tests] - env: - SELECTED_NETWORKS: BASE_SEPOLIA strategy: max-parallel: 1 fail-fast: false @@ -493,16 +496,35 @@ jobs: name: Base Sepolia ${{ matrix.product }} Tests runs-on: ubuntu-latest steps: + - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + with: + fetch-depth: 0 + - name: Prepare Base64 TOML override + uses: ./.github/actions/setup-create-base64-config-live-testnets + with: + runId: ${{ github.run_id }} + testLogCollect: ${{ vars.TEST_LOG_COLLECT }} + chainlinkImage: ${{ env.CHAINLINK_IMAGE }} + chainlinkVersion: ${{ github.sha }} + pyroscopeServer: ${{ matrix.product.pyroscope_env == '' && '' || !startsWith(github.ref, 'refs/tags/') && '' || secrets.QA_PYROSCOPE_INSTANCE }} # Avoid sending blank envs https://github.com/orgs/community/discussions/25725 + pyroscopeEnvironment: ci-smoke-${{ matrix.product }}-base-sepolia + pyroscopeKey: ${{ secrets.QA_PYROSCOPE_KEY }} + lokiEndpoint: ${{ secrets.LOKI_URL }} + lokiTenantId: ${{ vars.LOKI_TENANT_ID }} + lokiBasicAuth: ${{ secrets.LOKI_BASIC_AUTH }} + logstreamLogTargets: ${{ vars.LOGSTREAM_LOG_TARGETS }} + grafanaUrl: ${{ vars.GRAFANA_URL }} + grafanaDashboardUrl: "/d/ddf75041-1e39-42af-aa46-361fe4c36e9e/ci-e2e-tests-logs" + network: "base_sepolia" + httpEndpoints: ${{ secrets.QA_BASE_SEPOLIA_HTTP_URLS }} + wsEndpoints: ${{ secrets.QA_BASE_SEPOLIA_URLS }} + fundingKeys: ${{ secrets.QA_EVM_KEYS }} - name: Download Tests Binary uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # v3.0.2 with: name: tests - name: Run Tests - uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/run-tests-binary@912bed7e07a1df4d06ea53a031e9773bb65dc7bd # v2.3.0 - env: - PYROSCOPE_SERVER: ${{ secrets.QA_PYROSCOPE_INSTANCE }} - PYROSCOPE_ENVIRONMENT: ci-smoke-${{ matrix.product }}-base-sepolia - PYROSCOPE_KEY: ${{ secrets.QA_PYROSCOPE_KEY }} + uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/run-tests-binary@ea889b3133bd7f16ab19ba4ba130de5d9162c669 # v2.3.4 with: test_command_to_run: ./tests -test.timeout 30m -test.count=1 -test.parallel=1 -test.run ${{ matrix.test }} binary_name: tests @@ -518,7 +540,10 @@ 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: Print failed test summary + if: always() + uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/show-test-summary@ea889b3133bd7f16ab19ba4ba130de5d9162c669 # v2.3.4 + polygon-mumbai-smoke-tests: environment: integration permissions: @@ -527,8 +552,6 @@ jobs: id-token: write contents: read needs: [build-chainlink, build-tests] - env: - SELECTED_NETWORKS: POLYGON_MUMBAI strategy: max-parallel: 1 fail-fast: false @@ -543,16 +566,35 @@ jobs: name: Polygon Mumbai ${{ matrix.product }} Tests runs-on: ubuntu-latest steps: + - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + with: + fetch-depth: 0 + - name: Prepare Base64 TOML override + uses: ./.github/actions/setup-create-base64-config-live-testnets + with: + runId: ${{ github.run_id }} + testLogCollect: ${{ vars.TEST_LOG_COLLECT }} + chainlinkImage: ${{ env.CHAINLINK_IMAGE }} + chainlinkVersion: ${{ github.sha }} + pyroscopeServer: ${{ matrix.product.pyroscope_env == '' && '' || !startsWith(github.ref, 'refs/tags/') && '' || secrets.QA_PYROSCOPE_INSTANCE }} # Avoid sending blank envs https://github.com/orgs/community/discussions/25725 + pyroscopeEnvironment: ci-smoke-${{ matrix.product }}-polygon-mumbai + pyroscopeKey: ${{ secrets.QA_PYROSCOPE_KEY }} + lokiEndpoint: ${{ secrets.LOKI_URL }} + lokiTenantId: ${{ vars.LOKI_TENANT_ID }} + lokiBasicAuth: ${{ secrets.LOKI_BASIC_AUTH }} + logstreamLogTargets: ${{ vars.LOGSTREAM_LOG_TARGETS }} + grafanaUrl: ${{ vars.GRAFANA_URL }} + grafanaDashboardUrl: "/d/ddf75041-1e39-42af-aa46-361fe4c36e9e/ci-e2e-tests-logs" + network: "polygon_mumbai" + httpEndpoints: ${{ secrets.QA_POLYGON_MUMBAI_HTTP_URLS }} + wsEndpoints: ${{ secrets.QA_POLYGON_MUMBAI_URLS }} + fundingKeys: ${{ secrets.QA_EVM_KEYS }} - name: Download Tests Binary uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # v3.0.2 with: name: tests - name: Run Tests - uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/run-tests-binary@912bed7e07a1df4d06ea53a031e9773bb65dc7bd # v2.3.0 - env: - PYROSCOPE_SERVER: ${{ secrets.QA_PYROSCOPE_INSTANCE }} - PYROSCOPE_ENVIRONMENT: ci-smoke-${{ matrix.product }}-polygon-mumbai - PYROSCOPE_KEY: ${{ secrets.QA_PYROSCOPE_KEY }} + uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/run-tests-binary@ea889b3133bd7f16ab19ba4ba130de5d9162c669 # v2.3.4 with: test_command_to_run: ./tests -test.timeout 30m -test.count=1 -test.parallel=1 -test.run ${{ matrix.test }} binary_name: tests @@ -568,6 +610,9 @@ 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: Print failed test summary + if: always() + uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/show-test-summary@ea889b3133bd7f16ab19ba4ba130de5d9162c669 # v2.3.4 avalanche-fuji-smoke-tests: environment: integration @@ -577,8 +622,6 @@ jobs: id-token: write contents: read needs: [build-chainlink, build-tests] - env: - SELECTED_NETWORKS: AVALANCHE_FUJI strategy: max-parallel: 1 fail-fast: false @@ -593,16 +636,35 @@ jobs: name: Avalanche Fuji ${{ matrix.product }} Tests runs-on: ubuntu-latest steps: + - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + with: + fetch-depth: 0 + - name: Prepare Base64 TOML override + uses: ./.github/actions/setup-create-base64-config-live-testnets + with: + runId: ${{ github.run_id }} + testLogCollect: ${{ vars.TEST_LOG_COLLECT }} + chainlinkImage: ${{ env.CHAINLINK_IMAGE }} + chainlinkVersion: ${{ github.sha }} + pyroscopeServer: ${{ matrix.product.pyroscope_env == '' && '' || !startsWith(github.ref, 'refs/tags/') && '' || secrets.QA_PYROSCOPE_INSTANCE }} # Avoid sending blank envs https://github.com/orgs/community/discussions/25725 + pyroscopeEnvironment: ci-smoke-${{ matrix.product }}-avalanche-fuji + pyroscopeKey: ${{ secrets.QA_PYROSCOPE_KEY }} + lokiEndpoint: ${{ secrets.LOKI_URL }} + lokiTenantId: ${{ vars.LOKI_TENANT_ID }} + lokiBasicAuth: ${{ secrets.LOKI_BASIC_AUTH }} + logstreamLogTargets: ${{ vars.LOGSTREAM_LOG_TARGETS }} + grafanaUrl: ${{ vars.GRAFANA_URL }} + grafanaDashboardUrl: "/d/ddf75041-1e39-42af-aa46-361fe4c36e9e/ci-e2e-tests-logs" + network: "avalanche_fuji" + httpEndpoints: ${{ secrets.QA_AVALANCHE_FUJI_HTTP_URLS }} + wsEndpoints: ${{ secrets.QA_AVALANCHE_FUJI_URLS }} + fundingKeys: ${{ secrets.QA_EVM_KEYS }} - name: Download Tests Binary uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # v3.0.2 with: name: tests - name: Run Tests - uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/run-tests-binary@912bed7e07a1df4d06ea53a031e9773bb65dc7bd # v2.3.0 - env: - PYROSCOPE_SERVER: ${{ secrets.QA_PYROSCOPE_INSTANCE }} - PYROSCOPE_ENVIRONMENT: ci-smoke-${{ matrix.product }}-avalanche-fuji - PYROSCOPE_KEY: ${{ secrets.QA_PYROSCOPE_KEY }} + uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/run-tests-binary@ea889b3133bd7f16ab19ba4ba130de5d9162c669 # v2.3.4 with: test_command_to_run: ./tests -test.timeout 30m -test.count=1 -test.parallel=1 -test.run ${{ matrix.test }} binary_name: tests @@ -618,6 +680,9 @@ 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: Print failed test summary + if: always() + uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/show-test-summary@ea889b3133bd7f16ab19ba4ba130de5d9162c669 # v2.3.4 fantom-testnet-smoke-tests: environment: integration @@ -627,8 +692,6 @@ jobs: id-token: write contents: read needs: [build-chainlink, build-tests] - env: - SELECTED_NETWORKS: FANTOM_TESTNET strategy: max-parallel: 1 fail-fast: false @@ -643,16 +706,35 @@ jobs: name: Fantom Testnet ${{ matrix.product }} Tests runs-on: ubuntu-latest steps: + - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + with: + fetch-depth: 0 + - name: Prepare Base64 TOML override + uses: ./.github/actions/setup-create-base64-config-live-testnets + with: + runId: ${{ github.run_id }} + testLogCollect: ${{ vars.TEST_LOG_COLLECT }} + chainlinkImage: ${{ env.CHAINLINK_IMAGE }} + chainlinkVersion: ${{ github.sha }} + pyroscopeServer: ${{ matrix.product.pyroscope_env == '' && '' || !startsWith(github.ref, 'refs/tags/') && '' || secrets.QA_PYROSCOPE_INSTANCE }} # Avoid sending blank envs https://github.com/orgs/community/discussions/25725 + pyroscopeEnvironment: ci-smoke-${{ matrix.product }}-fantom-testnet + pyroscopeKey: ${{ secrets.QA_PYROSCOPE_KEY }} + lokiEndpoint: ${{ secrets.LOKI_URL }} + lokiTenantId: ${{ vars.LOKI_TENANT_ID }} + lokiBasicAuth: ${{ secrets.LOKI_BASIC_AUTH }} + logstreamLogTargets: ${{ vars.LOGSTREAM_LOG_TARGETS }} + grafanaUrl: ${{ vars.GRAFANA_URL }} + grafanaDashboardUrl: "/d/ddf75041-1e39-42af-aa46-361fe4c36e9e/ci-e2e-tests-logs" + network: "fantom_testnet" + httpEndpoints: ${{ secrets.QA_FANTOM_TESTNET_HTTP_URLS }} + wsEndpoints: ${{ secrets.QA_FANTOM_TESTNET_URLS }} + fundingKeys: ${{ secrets.QA_EVM_KEYS }} - name: Download Tests Binary uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # v3.0.2 with: name: tests - name: Run Tests - uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/run-tests-binary@912bed7e07a1df4d06ea53a031e9773bb65dc7bd # v2.3.0 - env: - PYROSCOPE_SERVER: ${{ secrets.QA_PYROSCOPE_INSTANCE }} - PYROSCOPE_ENVIRONMENT: ci-smoke-${{ matrix.product }}-fantom-testnet - PYROSCOPE_KEY: ${{ secrets.QA_PYROSCOPE_KEY }} + uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/run-tests-binary@ea889b3133bd7f16ab19ba4ba130de5d9162c669 # v2.3.4 with: test_command_to_run: ./tests -test.timeout 30m -test.count=1 -test.parallel=1 -test.run ${{ matrix.test }} binary_name: tests @@ -668,6 +750,9 @@ 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: Print failed test summary + if: always() + uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/show-test-summary@ea889b3133bd7f16ab19ba4ba130de5d9162c669 # v2.3.4 celo-alfajores-smoke-tests: environment: integration @@ -677,8 +762,6 @@ jobs: id-token: write contents: read needs: [build-chainlink, build-tests] - env: - SELECTED_NETWORKS: CELO_ALFAJORES strategy: max-parallel: 1 fail-fast: false @@ -689,16 +772,35 @@ jobs: name: Celo Alfajores ${{ matrix.product }} Tests runs-on: ubuntu-latest steps: + - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + with: + fetch-depth: 0 + - name: Prepare Base64 TOML override + uses: ./.github/actions/setup-create-base64-config-live-testnets + with: + runId: ${{ github.run_id }} + testLogCollect: ${{ vars.TEST_LOG_COLLECT }} + chainlinkImage: ${{ env.CHAINLINK_IMAGE }} + chainlinkVersion: ${{ github.sha }} + pyroscopeServer: ${{ matrix.product.pyroscope_env == '' && '' || !startsWith(github.ref, 'refs/tags/') && '' || secrets.QA_PYROSCOPE_INSTANCE }} # Avoid sending blank envs https://github.com/orgs/community/discussions/25725 + pyroscopeEnvironment: ci-smoke-${{ matrix.product }}-celo-alfajores + pyroscopeKey: ${{ secrets.QA_PYROSCOPE_KEY }} + lokiEndpoint: ${{ secrets.LOKI_URL }} + lokiTenantId: ${{ vars.LOKI_TENANT_ID }} + lokiBasicAuth: ${{ secrets.LOKI_BASIC_AUTH }} + logstreamLogTargets: ${{ vars.LOGSTREAM_LOG_TARGETS }} + grafanaUrl: ${{ vars.GRAFANA_URL }} + grafanaDashboardUrl: "/d/ddf75041-1e39-42af-aa46-361fe4c36e9e/ci-e2e-tests-logs" + network: "celo_alfajores" + httpEndpoints: ${{ secrets.QA_CELO_ALFAJORES_HTTP_URLS }} + wsEndpoints: ${{ secrets.QA_CELO_ALFAJORES_URLS }} + fundingKeys: ${{ secrets.QA_EVM_KEYS }} - name: Download Tests Binary uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # v3.0.2 with: name: tests - name: Run Tests - uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/run-tests-binary@912bed7e07a1df4d06ea53a031e9773bb65dc7bd # v2.3.0 - env: - PYROSCOPE_SERVER: ${{ secrets.QA_PYROSCOPE_INSTANCE }} - PYROSCOPE_ENVIRONMENT: ci-smoke-${{ matrix.product }}-celo-alfajores - PYROSCOPE_KEY: ${{ secrets.QA_PYROSCOPE_KEY }} + uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/run-tests-binary@ea889b3133bd7f16ab19ba4ba130de5d9162c669 # v2.3.4 with: test_command_to_run: ./tests -test.timeout 30m -test.count=1 -test.parallel=1 -test.run ${{ matrix.test }} binary_name: tests @@ -714,7 +816,10 @@ 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: Print failed test summary + if: always() + uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/show-test-summary@ea889b3133bd7f16ab19ba4ba130de5d9162c669 # v2.3.4 + scroll-sepolia-smoke-tests: # TODO: Disabled until bug TT-767 is fixed if: false @@ -725,8 +830,6 @@ jobs: id-token: write contents: read needs: [build-chainlink, build-tests] - env: - SELECTED_NETWORKS: SCROLL_SEPOLIA strategy: max-parallel: 1 fail-fast: false @@ -737,16 +840,35 @@ jobs: name: Scroll Sepolia ${{ matrix.product }} Tests runs-on: ubuntu-latest steps: + - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + with: + fetch-depth: 0 + - name: Prepare Base64 TOML override + uses: ./.github/actions/setup-create-base64-config-live-testnets + with: + runId: ${{ github.run_id }} + testLogCollect: ${{ vars.TEST_LOG_COLLECT }} + chainlinkImage: ${{ env.CHAINLINK_IMAGE }} + chainlinkVersion: ${{ github.sha }} + pyroscopeServer: ${{ matrix.product.pyroscope_env == '' && '' || !startsWith(github.ref, 'refs/tags/') && '' || secrets.QA_PYROSCOPE_INSTANCE }} # Avoid sending blank envs https://github.com/orgs/community/discussions/25725 + pyroscopeEnvironment: ci-smoke-${{ matrix.product }}-scroll-sepolia + pyroscopeKey: ${{ secrets.QA_PYROSCOPE_KEY }} + lokiEndpoint: ${{ secrets.LOKI_URL }} + lokiTenantId: ${{ vars.LOKI_TENANT_ID }} + lokiBasicAuth: ${{ secrets.LOKI_BASIC_AUTH }} + logstreamLogTargets: ${{ vars.LOGSTREAM_LOG_TARGETS }} + grafanaUrl: ${{ vars.GRAFANA_URL }} + grafanaDashboardUrl: "/d/ddf75041-1e39-42af-aa46-361fe4c36e9e/ci-e2e-tests-logs" + network: "scroll_sepolia" + httpEndpoints: ${{ secrets.QA_SCROLL_SEPOLIA_HTTP_URLS }} + wsEndpoints: ${{ secrets.QA_SCROLL_SEPOLIA_URLS }} + fundingKeys: ${{ secrets.QA_EVM_KEYS }} - name: Download Tests Binary uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # v3.0.2 with: name: tests - name: Run Tests - uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/run-tests-binary@912bed7e07a1df4d06ea53a031e9773bb65dc7bd # v2.3.0 - env: - PYROSCOPE_SERVER: ${{ secrets.QA_PYROSCOPE_INSTANCE }} - PYROSCOPE_ENVIRONMENT: ci-smoke-${{ matrix.product }}-scroll-sepolia - PYROSCOPE_KEY: ${{ secrets.QA_PYROSCOPE_KEY }} + uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/run-tests-binary@ea889b3133bd7f16ab19ba4ba130de5d9162c669 # v2.3.4 with: test_command_to_run: ./tests -test.timeout 30m -test.count=1 -test.parallel=1 -test.run ${{ matrix.test }} binary_name: tests @@ -762,6 +884,9 @@ 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: Print failed test summary + if: always() + uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/show-test-summary@ea889b3133bd7f16ab19ba4ba130de5d9162c669 # v2.3.4 linea-goerli-smoke-tests: environment: integration @@ -771,8 +896,6 @@ jobs: id-token: write contents: read needs: [build-chainlink, build-tests] - env: - SELECTED_NETWORKS: LINEA_GOERLI strategy: max-parallel: 1 fail-fast: false @@ -783,16 +906,35 @@ jobs: name: Linea Goerli ${{ matrix.product }} Tests runs-on: ubuntu-latest steps: + - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + with: + fetch-depth: 0 + - name: Prepare Base64 TOML override + uses: ./.github/actions/setup-create-base64-config-live-testnets + with: + runId: ${{ github.run_id }} + testLogCollect: ${{ vars.TEST_LOG_COLLECT }} + chainlinkImage: ${{ env.CHAINLINK_IMAGE }} + chainlinkVersion: ${{ github.sha }} + pyroscopeServer: ${{ matrix.product.pyroscope_env == '' && '' || !startsWith(github.ref, 'refs/tags/') && '' || secrets.QA_PYROSCOPE_INSTANCE }} # Avoid sending blank envs https://github.com/orgs/community/discussions/25725 + pyroscopeEnvironment: ci-smoke-${{ matrix.product }}-linea-goerli + pyroscopeKey: ${{ secrets.QA_PYROSCOPE_KEY }} + lokiEndpoint: ${{ secrets.LOKI_URL }} + lokiTenantId: ${{ vars.LOKI_TENANT_ID }} + lokiBasicAuth: ${{ secrets.LOKI_BASIC_AUTH }} + logstreamLogTargets: ${{ vars.LOGSTREAM_LOG_TARGETS }} + grafanaUrl: ${{ vars.GRAFANA_URL }} + grafanaDashboardUrl: "/d/ddf75041-1e39-42af-aa46-361fe4c36e9e/ci-e2e-tests-logs" + network: "linea_goerli" + httpEndpoints: ${{ secrets.QA_LINEA_GOERLI_HTTP_URLS }} + wsEndpoints: ${{ secrets.QA_LINEA_GOERLI_URLS }} + fundingKeys: ${{ secrets.QA_EVM_KEYS }} - name: Download Tests Binary uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # v3.0.2 with: name: tests - name: Run Tests - uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/run-tests-binary@912bed7e07a1df4d06ea53a031e9773bb65dc7bd # v2.3.0 - env: - PYROSCOPE_SERVER: ${{ secrets.QA_PYROSCOPE_INSTANCE }} - PYROSCOPE_ENVIRONMENT: ci-smoke-${{ matrix.product }}-linea-goerli - PYROSCOPE_KEY: ${{ secrets.QA_PYROSCOPE_KEY }} + uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/run-tests-binary@ea889b3133bd7f16ab19ba4ba130de5d9162c669 # v2.3.4 with: test_command_to_run: ./tests -test.timeout 30m -test.count=1 -test.parallel=1 -test.run ${{ matrix.test }} binary_name: tests @@ -807,4 +949,7 @@ jobs: cache_restore_only: "true" QA_AWS_REGION: ${{ secrets.QA_AWS_REGION }} QA_AWS_ROLE_TO_ASSUME: ${{ secrets.QA_AWS_ROLE_TO_ASSUME }} - QA_KUBECONFIG: ${{ secrets.QA_KUBECONFIG }} \ No newline at end of file + QA_KUBECONFIG: ${{ secrets.QA_KUBECONFIG }} + - name: Print failed test summary + if: always() + uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/show-test-summary@ea889b3133bd7f16ab19ba4ba130de5d9162c669 # v2.3.4 \ No newline at end of file diff --git a/.github/workflows/on-demand-log-poller.yml b/.github/workflows/on-demand-log-poller.yml index 4658e188ba..ad3617841d 100644 --- a/.github/workflows/on-demand-log-poller.yml +++ b/.github/workflows/on-demand-log-poller.yml @@ -2,79 +2,26 @@ name: On Demand Log Poller Consistency Test on: workflow_dispatch: inputs: - contracts: - description: Number of test contracts - default: "2" - required: true - eventsPerTx: - description: Number of events to emit per transaction - default: "10" - required: true - useFinalityTag: - description: Use finality tag - default: "false" - required: true - loadDuration: - description: Load duration (e.g. 10s, 10m, 1h) - default: "10m" - required: true - chainlinkImage: - description: Chainlink image to use - default: "public.ecr.aws/chainlink/chainlink" - required: true - chainlinkVersion: - description: Chainlink version to use - default: "2.7.0-beta1" - required: true - selectedNetworks: - type: choice - options: - - "SIMULATED" - - "SEPOLIA" - - "MUMBAI" - fundingPrivateKey: - description: Private funding key (Skip for Simulated) + base64Config: + description: base64-ed config required: true type: string - wsURL: - description: WS URL for the network (Skip for Simulated) - required: true - type: string - httpURL: - description: HTTP URL for the network (Skip for Simulated) - required: true - type: string jobs: test: env: - CONTRACTS: ${{ inputs.contracts }} - EVENTS_PER_TX: ${{ inputs.eventsPerTx }} - LOAD_DURATION: ${{ inputs.loadDuration }} - USE_FINALITY_TAG: ${{ inputs.useFinalityTag }} - CHAINLINK_IMAGE: ${{ inputs.chainlinkImage }} - CHAINLINK_VERSION: ${{ inputs.chainlinkVersion }} - SELECTED_NETWORKS: ${{ inputs.selectedNetworks }} REF_NAME: ${{ github.head_ref || github.ref_name }} runs-on: ubuntu20.04-8cores-32GB steps: - - name: Get Inputs + - name: Add masks and export base64 config 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 + BASE64_CONFIG_OVERRIDE=$(jq -r '.inputs.base64Config' $GITHUB_EVENT_PATH) + echo ::add-mask::$BASE64_CONFIG_OVERRIDE + echo "BASE64_CONFIG_OVERRIDE=$BASE64_CONFIG_OVERRIDE" >> $GITHUB_ENV - name: Checkout the repo - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 with: - ref: ${{ env.REF_NAME }} + ref: ${{ env.REF_NAME }} - name: Setup Go uses: actions/setup-go@0c52d547c9bc32b1aa3301fd7a9cb496313a4491 # v5.0.0 with: @@ -84,4 +31,4 @@ jobs: run: | cd integration-tests go mod download - go test -v -timeout 5h -v -count=1 -run ^TestLogPollerFromEnv$ ./reorg/log_poller_maybe_reorg_test.go + go test -v -timeout 5h -v -count=1 -run ^TestLogPollerFewFiltersFixedDepth$ ./smoke/log_poller_test.go diff --git a/.github/workflows/on-demand-ocr-soak-test.yml b/.github/workflows/on-demand-ocr-soak-test.yml index 32e080aafc..b02e44db11 100644 --- a/.github/workflows/on-demand-ocr-soak-test.yml +++ b/.github/workflows/on-demand-ocr-soak-test.yml @@ -2,74 +2,19 @@ name: On Demand OCR Soak Test on: workflow_dispatch: inputs: - network: - description: Network to run tests on - type: choice - options: - - "SIMULATED" - - "GOERLI" - - "OPTIMISM_GOERLI" - - "ARBITRUM_GOERLI" - - "ARBITRUM_SEPOLIA" - - "ARBITRUM_MAINNET" - - "CELO_ALFAJORES" - - "CELO_MAINNET" - - "BASE_GOERLI" - - "BASE_SEPOLIA" - - "BASE_MAINNET" - - "BSC_MAINNET" - - "BSC_TESTNET" - - "SCROLL_SEPOLIA" - - "SCROLL_MAINNET" - - "POLYGON_MUMBAI" - - "POLYGON_MAINNET" - - "LINEA_GOERLI" - - "LINEA_MAINNET" - - "FANTOM_TESTNET" - - "FANTOM_MAINNET" - - "KROMA_MAINNET" - - "KROMA_SEPOLIA" - - "WEMIX_TESTNET" - - "WEMIX_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 + base64Config: + description: base64-ed config + required: true + type: string slackMemberID: description: Slack Member ID (Not your @) required: true default: U01A2B2C3D4 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.7.0" - ocrVersion: - description: Version of OCR to Use - type: choice - options: - - 1 - - 2 - testInputs: - description: Duration;Funding;TimeBetweenRounds - required: false - default: "10m;.1;1m" jobs: ocr_soak_test: - name: ${{ inputs.network }} OCR Soak Test + name: OCR Soak Test environment: integration runs-on: ubuntu-latest permissions: @@ -78,12 +23,9 @@ jobs: id-token: write contents: read env: - CHAINLINK_COMMIT_SHA: ${{ inputs.chainlinkVersion }} CHAINLINK_ENV_USER: ${{ github.actor }} - SELECTED_NETWORKS: ${{ inputs.network }} SLACK_API_KEY: ${{ secrets.QA_SLACK_API_KEY }} SLACK_CHANNEL: ${{ secrets.QA_SLACK_CHANNEL }} - OCR_VERSION: ${{ inputs.ocrVersion }} TEST_LOG_LEVEL: debug REF_NAME: ${{ github.head_ref || github.ref_name }} ENV_JOB_IMAGE_BASE: ${{ secrets.QA_AWS_ACCOUNT_NUMBER }}.dkr.ecr.${{ secrets.QA_AWS_REGION }}.amazonaws.com/chainlink-tests @@ -96,54 +38,32 @@ jobs: hostname: ${{ secrets.GRAFANA_CLOUD_HOST }} this-job-name: ${{ inputs.network }} OCR Soak Test continue-on-error: true - - name: Get Inputs + - name: Checkout the repo + uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + with: + ref: ${{ env.REF_NAME }} + - name: Get Slack config and mask base64 config run: | - # Mask the sensitive inputs - 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) SLACK_USER=$(jq -r '.inputs.slackMemberID' $GITHUB_EVENT_PATH) - - echo ::add-mask::$EVM_URLS - echo ::add-mask::$EVM_HTTP_URLS - echo ::add-mask::$EVM_KEYS echo ::add-mask::$SLACK_USER - - echo EVM_URLS=$EVM_URLS >> $GITHUB_ENV - echo EVM_HTTP_URLS=$EVM_HTTP_URLS >> $GITHUB_ENV - echo EVM_KEYS=$EVM_KEYS >> $GITHUB_ENV echo SLACK_USER=$SLACK_USER >> $GITHUB_ENV - # Read in our test inputs - IFS=';' read -ra parts <<< "${{ inputs.testInputs }}" - index=0 - for part in "${parts[@]}"; do - # A little hacky, but good enough for this - if [ $index -eq 0 ]; then - echo "OCR_TEST_DURATION=$part" - echo "OCR_TEST_DURATION=$part" >> $GITHUB_ENV - elif [ $index -eq 1 ]; then - echo "OCR_CHAINLINK_NODE_FUNDING=$part" - echo "OCR_CHAINLINK_NODE_FUNDING=$part" >> $GITHUB_ENV - elif [ $index -eq 2 ]; then - echo "OCR_TIME_BETWEEN_ROUNDS=$part" - echo "OCR_TIME_BETWEEN_ROUNDS=$part" >> $GITHUB_ENV - else - echo "Additional Unregistered Input: $part" - fi - ((index+=1)) - done - - name: Checkout the repo - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + BASE64_CONFIG_OVERRIDE=$(jq -r '.inputs.base64Config' $GITHUB_EVENT_PATH) + echo ::add-mask::$BASE64_CONFIG_OVERRIDE + echo "BASE64_CONFIG_OVERRIDE=$BASE64_CONFIG_OVERRIDE" >> $GITHUB_ENV + - name: Parse base64 config + uses: ./.github/actions/setup-parse-base64-config with: - ref: ${{ env.REF_NAME }} + base64Config: ${{ env.BASE64_CONFIG_OVERRIDE }} - name: Setup Push Tag shell: bash run: | echo "### chainlink image used for this test run :link:" >>$GITHUB_STEP_SUMMARY - echo "\`${{ inputs.chainlinkVersion }}\`" >>$GITHUB_STEP_SUMMARY + echo "\`${{ env.CHAINLINK_IMAGE }}\`" >>$GITHUB_STEP_SUMMARY echo "### chainlink-tests image tag for this test run :ship:" >>$GITHUB_STEP_SUMMARY echo "\`${GITHUB_SHA}\`" >>$GITHUB_STEP_SUMMARY + echo "### Networks on which test was run" >>$GITHUB_STEP_SUMMARY + echo "\`${{ env.NETWORKS }}\`" >>$GITHUB_STEP_SUMMARY - name: Build Image uses: ./.github/actions/build-test-image with: @@ -163,8 +83,8 @@ jobs: with: test_command_to_run: cd ./integration-tests && go test -v -count=1 -run ^TestOCRSoak$ ./soak test_download_vendor_packages_command: make gomod - cl_repo: ${{ inputs.chainlinkImage }} - cl_image_tag: ${{ inputs.chainlinkVersion }} + cl_repo: ${{ env.CHAINLINK_IMAGE }} + cl_image_tag: ${{ env.CHAINLINK_VERSION }} token: ${{ secrets.GITHUB_TOKEN }} should_cleanup: false go_mod_path: ./integration-tests/go.mod diff --git a/.github/workflows/on-demand-vrfv2-eth2-clients-test.yml b/.github/workflows/on-demand-vrfv2-eth2-clients-test.yml index 3b27e4519c..de53b493a5 100644 --- a/.github/workflows/on-demand-vrfv2-eth2-clients-test.yml +++ b/.github/workflows/on-demand-vrfv2-eth2-clients-test.yml @@ -2,28 +2,14 @@ name: On Demand VRFV2 Smoke Test (Ethereum clients) on: workflow_dispatch: inputs: - client: - description: Execution client to use - type: choice - options: - - "geth" - - "nethermind" - - "besu" - - "erigon" - chainlinkImage: - description: Container image location for the Chainlink nodes + base64Config: + description: base64-ed config required: true - default: public.ecr.aws/chainlink/chainlink - chainlinkVersion: - description: Container image version for the Chainlink nodes - required: true - default: "2.6.0" - configBase64: - description: TOML config in base64 (Needed when overriding config or providing contract addresses for existing env) - required: false + type: string + jobs: vrfv2_smoke_test: - name: VRFV2 Smoke Test with ${{ inputs.client }} client + name: VRFV2 Smoke Test with custom EL client client environment: integration runs-on: ubuntu20.04-8cores-32GB permissions: @@ -32,31 +18,40 @@ jobs: id-token: write contents: read env: - SELECTED_NETWORKS: "SIMULATED" - CONFIG: ${{ inputs.configBase64 }} TEST_LOG_LEVEL: debug REF_NAME: ${{ github.head_ref || github.ref_name }} - CHAINLINK_IMAGE: ${{ inputs.chainlinkImage }} - CHAINLINK_VERSION: ${{ inputs.chainlinkVersion }} steps: - - name: Setup Push Tag + - name: Checkout code + uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + with: + fetch-depth: 0 + - name: Mask base64 config + run: | + BASE64_CONFIG_OVERRIDE=$(jq -r '.inputs.base64Config' $GITHUB_EVENT_PATH) + echo ::add-mask::$BASE64_CONFIG_OVERRIDE + echo "BASE64_CONFIG_OVERRIDE=$BASE64_CONFIG_OVERRIDE" >> $GITHUB_ENV + - name: Parse base64 config + uses: ./.github/actions/setup-parse-base64-config + with: + base64Config: ${{ env.BASE64_CONFIG_OVERRIDE }} + - name: Send details to Step Summary shell: bash run: | echo "### chainlink image used for this test run :link:" >>$GITHUB_STEP_SUMMARY - echo "\`${{ inputs.chainlinkVersion }}\`" >>$GITHUB_STEP_SUMMARY + echo "\`${{ env.CHAINLINK_IMAGE }}\`" >>$GITHUB_STEP_SUMMARY echo "### chainlink-tests image tag for this test run :ship:" >>$GITHUB_STEP_SUMMARY echo "\`${GITHUB_SHA}\`" >>$GITHUB_STEP_SUMMARY - - name: Checkout code - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - with: - fetch-depth: 0 + echo "### Networks on which test was run" >>$GITHUB_STEP_SUMMARY + echo "\`${{ env.NETWORKS }}\`" >>$GITHUB_STEP_SUMMARY + echo "### Execution client used" >>$GITHUB_STEP_SUMMARY + echo "\`${{ env.ETH2_EL_CLIENT }}\`" >>$GITHUB_STEP_SUMMARY - name: Run Tests uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/run-tests@7d541cbbca52d45b8a718257af86d9cf49774d1f # v2.2.15 with: test_command_to_run: cd ./integration-tests && go test -timeout 30m -count=1 -json -run TestVRFv2Basic ./smoke/vrfv2_test.go 2>&1 | tee /tmp/gotest.log | gotestfmt test_download_vendor_packages_command: cd ./integration-tests && go mod download - cl_repo: ${{ inputs.chainlinkImage }} - cl_image_tag: ${{ inputs.chainlinkVersion }} + cl_repo: ${{ env.CHAINLINK_IMAGE }} + cl_image_tag: ${{ env.CHAINLINK_VERSION }} aws_registries: ${{ secrets.QA_AWS_ACCOUNT_NUMBER }} artifacts_name: vrf-test-logs artifacts_location: ./integration-tests/smoke/logs/ @@ -66,5 +61,3 @@ jobs: QA_AWS_REGION: ${{ secrets.QA_AWS_REGION }} QA_AWS_ROLE_TO_ASSUME: ${{ secrets.QA_AWS_ROLE_TO_ASSUME }} QA_KUBECONFIG: "" - env: - ETH2_EL_CLIENT: ${{ inputs.client }} diff --git a/.github/workflows/on-demand-vrfv2-performance-test.yml b/.github/workflows/on-demand-vrfv2-performance-test.yml index 56a5c8eee8..7fd0d2b83b 100644 --- a/.github/workflows/on-demand-vrfv2-performance-test.yml +++ b/.github/workflows/on-demand-vrfv2-performance-test.yml @@ -2,44 +2,10 @@ name: On Demand VRFV2 Performance 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" - - "ARBITRUM_SEPOLIA" - - "BSC_MAINNET" - - "BSC_TESTNET" - - "POLYGON_MAINNET" - - "POLYGON_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 + base64Config: + description: base64-ed config required: true - default: public.ecr.aws/chainlink/chainlink - chainlinkVersion: - description: Container image version for the Chainlink nodes - required: true - default: "2.6.0" + type: string performanceTestType: description: Performance Test Type of test to run type: choice @@ -48,20 +14,9 @@ on: - "Load" - "Stress" - "Spike" - testDuration: - description: Duration of the test (time string) - required: true - default: 5m - 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: vrfv2_performance_test: - name: ${{ inputs.network }} VRFV2 Performance Test + name: VRFV2 Performance Test environment: integration runs-on: ubuntu20.04-8cores-32GB permissions: @@ -73,15 +28,9 @@ jobs: LOKI_URL: ${{ secrets.LOKI_URL }} LOKI_TENANT_ID: ${{ secrets.LOKI_TENANT_ID }} LOKI_BASIC_AUTH: ${{ secrets.LOKI_BASIC_AUTH }} - SELECTED_NETWORKS: ${{ inputs.network }} TEST_TYPE: ${{ inputs.performanceTestType }} - VRFV2_TEST_DURATION: ${{ inputs.testDuration }} - VRFV2_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 }} SLACK_API_KEY: ${{ secrets.QA_SLACK_API_KEY }} SLACK_CHANNEL: ${{ secrets.QA_VRF_SLACK_CHANNEL }} WASP_LOG_LEVEL: info @@ -94,38 +43,35 @@ jobs: hostname: ${{ secrets.GRAFANA_CLOUD_HOST }} this-job-name: ${{ inputs.network }} VRFV2 Performance Test continue-on-error: true - - name: Setup Push Tag + - name: Checkout code + uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + with: + fetch-depth: 0 + - name: Mask base64 config + run: | + BASE64_CONFIG_OVERRIDE=$(jq -r '.inputs.base64Config' $GITHUB_EVENT_PATH) + echo ::add-mask::$BASE64_CONFIG_OVERRIDE + echo "BASE64_CONFIG_OVERRIDE=$BASE64_CONFIG_OVERRIDE" >> $GITHUB_ENV + - name: Merge and export base64 config + uses: ./.github/actions/setup-merge-base64-config + with: + base64Config: ${{ env.BASE64_CONFIG_OVERRIDE }} + - name: Send details to Step Summary shell: bash run: | echo "### chainlink image used for this test run :link:" >>$GITHUB_STEP_SUMMARY - echo "\`${{ inputs.chainlinkVersion }}\`" >>$GITHUB_STEP_SUMMARY + echo "\`${{ env.CHAINLINK_IMAGE }}\`" >>$GITHUB_STEP_SUMMARY echo "### chainlink-tests image tag for this test run :ship:" >>$GITHUB_STEP_SUMMARY echo "\`${GITHUB_SHA}\`" >>$GITHUB_STEP_SUMMARY - - 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@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - with: - fetch-depth: 0 + echo "### Networks on which test was run" >>$GITHUB_STEP_SUMMARY + echo "\`${{ env.NETWORKS }}\`" >>$GITHUB_STEP_SUMMARY - name: Run Tests uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/run-tests@7d541cbbca52d45b8a718257af86d9cf49774d1f # v2.2.15 with: test_command_to_run: cd ./integration-tests && go test -v -count=1 -timeout 24h -run TestVRFV2Performance/vrfv2_performance_test ./load/vrfv2 test_download_vendor_packages_command: cd ./integration-tests && go mod download - cl_repo: ${{ inputs.chainlinkImage }} - cl_image_tag: ${{ inputs.chainlinkVersion }} + cl_repo: ${{ env.CHAINLINK_IMAGE }} + cl_image_tag: ${{ env.CHAINLINK_VERSION }} aws_registries: ${{ secrets.QA_AWS_ACCOUNT_NUMBER }} artifacts_name: vrf-test-logs artifacts_location: ./integration-tests/load/vrfv2/logs/ diff --git a/.github/workflows/on-demand-vrfv2plus-eth2-clients-test.yml b/.github/workflows/on-demand-vrfv2plus-eth2-clients-test.yml index 331c626ba9..1772730075 100644 --- a/.github/workflows/on-demand-vrfv2plus-eth2-clients-test.yml +++ b/.github/workflows/on-demand-vrfv2plus-eth2-clients-test.yml @@ -2,28 +2,14 @@ name: On Demand VRFV2Plus Smoke Test (Ethereum clients) on: workflow_dispatch: inputs: - client: - description: Execution client to use - type: choice - options: - - "geth" - - "nethermind" - - "besu" - - "erigon" - chainlinkImage: - description: Container image location for the Chainlink nodes + base64Config: + description: base64-ed config required: true - default: public.ecr.aws/chainlink/chainlink - chainlinkVersion: - description: Container image version for the Chainlink nodes - required: true - default: "2.6.0" - configBase64: - description: TOML config in base64 (Needed when overriding config or providing contract addresses for existing env) - required: false + type: string + jobs: vrfv2plus_smoke_test: - name: VRFV2Plus Smoke Test with ${{ inputs.client }} client + name: VRFV2Plus Smoke Test with custom EL client environment: integration runs-on: ubuntu20.04-8cores-32GB permissions: @@ -32,31 +18,40 @@ jobs: id-token: write contents: read env: - SELECTED_NETWORKS: "SIMULATED" - CONFIG: ${{ inputs.configBase64 }} TEST_LOG_LEVEL: debug REF_NAME: ${{ github.head_ref || github.ref_name }} - CHAINLINK_IMAGE: ${{ inputs.chainlinkImage }} - CHAINLINK_VERSION: ${{ inputs.chainlinkVersion }} - steps: - - name: Setup Push Tag + steps: + - name: Checkout code + uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + with: + fetch-depth: 0 + - name: Mask base64 config + run: | + BASE64_CONFIG_OVERRIDE=$(jq -r '.inputs.base64Config' $GITHUB_EVENT_PATH) + echo ::add-mask::$BASE64_CONFIG_OVERRIDE + echo "BASE64_CONFIG_OVERRIDE=$BASE64_CONFIG_OVERRIDE" >> $GITHUB_ENV + - name: Parse base64 config + uses: ./.github/actions/setup-parse-base64-config + with: + base64Config: ${{ env.BASE64_CONFIG_OVERRIDE }} + - name: Send details to Step Summary shell: bash run: | echo "### chainlink image used for this test run :link:" >>$GITHUB_STEP_SUMMARY - echo "\`${{ inputs.chainlinkVersion }}\`" >>$GITHUB_STEP_SUMMARY + echo "\`${{ env.CHAINLINK_IMAGE }}\`" >>$GITHUB_STEP_SUMMARY echo "### chainlink-tests image tag for this test run :ship:" >>$GITHUB_STEP_SUMMARY echo "\`${GITHUB_SHA}\`" >>$GITHUB_STEP_SUMMARY - - name: Checkout code - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - with: - fetch-depth: 0 + echo "### Networks on which test was run" >>$GITHUB_STEP_SUMMARY + echo "\`${{ env.NETWORKS }}\`" >>$GITHUB_STEP_SUMMARY + echo "### Execution client used" >>$GITHUB_STEP_SUMMARY + echo "\`${{ env.ETH2_EL_CLIENT }}\`" >>$GITHUB_STEP_SUMMARY - name: Run Tests uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/run-tests@7d541cbbca52d45b8a718257af86d9cf49774d1f # v2.2.15 with: test_command_to_run: cd ./integration-tests && go test -timeout 30m -count=1 -json -run ^TestVRFv2Plus$/^Link_Billing$ ./smoke/vrfv2plus_test.go 2>&1 | tee /tmp/gotest.log | gotestfmt test_download_vendor_packages_command: cd ./integration-tests && go mod download - cl_repo: ${{ inputs.chainlinkImage }} - cl_image_tag: ${{ inputs.chainlinkVersion }} + cl_repo: ${{ env.CHAINLINK_IMAGE }} + cl_image_tag: ${{ env.CHAINLINK_VERSION }} aws_registries: ${{ secrets.QA_AWS_ACCOUNT_NUMBER }} artifacts_name: vrfplus-test-logs artifacts_location: ./integration-tests/smoke/logs/ @@ -66,5 +61,3 @@ jobs: QA_AWS_REGION: ${{ secrets.QA_AWS_REGION }} QA_AWS_ROLE_TO_ASSUME: ${{ secrets.QA_AWS_ROLE_TO_ASSUME }} QA_KUBECONFIG: "" - env: - ETH2_EL_CLIENT: ${{ inputs.client }} diff --git a/.github/workflows/on-demand-vrfv2plus-performance-test.yml b/.github/workflows/on-demand-vrfv2plus-performance-test.yml index 238f40de88..858eecff76 100644 --- a/.github/workflows/on-demand-vrfv2plus-performance-test.yml +++ b/.github/workflows/on-demand-vrfv2plus-performance-test.yml @@ -2,44 +2,10 @@ name: On Demand VRFV2 Plus Performance 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" - - "ARBITRUM_SEPOLIA" - - "BSC_MAINNET" - - "BSC_TESTNET" - - "POLYGON_MAINNET" - - "POLYGON_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 + base64Config: + description: base64-ed config required: true - default: "2.6.0" + type: string performanceTestType: description: Performance Test Type of test to run type: choice @@ -47,21 +13,11 @@ on: - "Soak" - "Load" - "Stress" - - "Spike" - testDuration: - description: Duration of the test (time string) - required: true - default: 5m - 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 + - "Spike" + jobs: vrfv2plus_performance_test: - name: ${{ inputs.network }} VRFV2 Plus Performance Test + name: VRFV2 Plus Performance Test environment: integration runs-on: ubuntu20.04-8cores-32GB permissions: @@ -71,20 +27,15 @@ jobs: contents: read env: LOKI_URL: ${{ secrets.LOKI_URL }} - LOKI_TOKEN: ${{ secrets.LOKI_TOKEN }} - SELECTED_NETWORKS: ${{ inputs.network }} + LOKI_TENANT_ID: ${{ secrets.LOKI_TENANT_ID }} + LOKI_BASIC_AUTH: ${{ secrets.LOKI_BASIC_AUTH }} 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 }} SLACK_API_KEY: ${{ secrets.QA_SLACK_API_KEY }} SLACK_CHANNEL: ${{ secrets.QA_VRF_SLACK_CHANNEL }} WASP_LOG_LEVEL: info - steps: + steps: - name: Collect Metrics id: collect-gha-metrics uses: smartcontractkit/push-gha-metrics-action@d1618b772a97fd87e6505de97b872ee0b1f1729a # v2.0.2 @@ -93,38 +44,35 @@ jobs: hostname: ${{ secrets.GRAFANA_CLOUD_HOST }} this-job-name: ${{ inputs.network }} VRFV2 Plus Performance Test continue-on-error: true - - name: Setup Push Tag + - name: Checkout code + uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + with: + fetch-depth: 0 + - name: Mask base64 config + run: | + BASE64_CONFIG_OVERRIDE=$(jq -r '.inputs.base64Config' $GITHUB_EVENT_PATH) + echo ::add-mask::$BASE64_CONFIG_OVERRIDE + echo "BASE64_CONFIG_OVERRIDE=$BASE64_CONFIG_OVERRIDE" >> $GITHUB_ENV + - name: Merge and export base64 config + uses: ./.github/actions/setup-merge-base64-config + with: + base64Config: ${{ env.BASE64_CONFIG_OVERRIDE }} + - name: Send details to Step Summary shell: bash run: | echo "### chainlink image used for this test run :link:" >>$GITHUB_STEP_SUMMARY - echo "\`${{ inputs.chainlinkVersion }}\`" >>$GITHUB_STEP_SUMMARY + echo "\`${{ env.CHAINLINK_IMAGE }}\`" >>$GITHUB_STEP_SUMMARY echo "### chainlink-tests image tag for this test run :ship:" >>$GITHUB_STEP_SUMMARY echo "\`${GITHUB_SHA}\`" >>$GITHUB_STEP_SUMMARY - - 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@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - with: - fetch-depth: 0 + echo "### Networks on which test was run" >>$GITHUB_STEP_SUMMARY + echo "\`${{ env.NETWORKS }}\`" >>$GITHUB_STEP_SUMMARY - name: Run Tests uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/run-tests@e865e376b8c2d594028c8d645dd6c47169b72974 # v2.2.16 with: test_command_to_run: cd ./integration-tests && go test -v -count=1 -timeout 24h -run TestVRFV2PlusPerformance/vrfv2plus_performance_test ./load/vrfv2plus test_download_vendor_packages_command: cd ./integration-tests && go mod download - cl_repo: ${{ inputs.chainlinkImage }} - cl_image_tag: ${{ inputs.chainlinkVersion }} + cl_repo: ${{ env.CHAINLINK_IMAGE }} + cl_image_tag: ${{ env.CHAINLINK_VERSION }} aws_registries: ${{ secrets.QA_AWS_ACCOUNT_NUMBER }} artifacts_name: vrf-test-logs artifacts_location: ./integration-tests/load/vrfv2plus/logs/ diff --git a/.github/workflows/performance-tests.yml b/.github/workflows/performance-tests.yml deleted file mode 100644 index 7b9eef7fcc..0000000000 --- a/.github/workflows/performance-tests.yml +++ /dev/null @@ -1,87 +0,0 @@ -name: Performance Tests -on: - workflow_dispatch: - inputs: - focus: - description: cron|directrequest|flux|keeper|ocr|vrf|suite - required: true - default: suite - type: string - -jobs: - build-chainlink: - environment: integration - permissions: - id-token: write - contents: read - name: Build Chainlink Image - runs-on: ubuntu-latest - steps: - - name: Checkout the repo - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - - name: Configure AWS Credentials - uses: aws-actions/configure-aws-credentials@010d0da01d0b5a38af31e9c3470dbfdabdecca3a # v4.0.1 - with: - aws-region: ${{ secrets.QA_AWS_REGION }} - role-to-assume: ${{ secrets.QA_AWS_ROLE_TO_ASSUME }} - role-duration-seconds: 3600 - - name: Login to Amazon ECR - id: login-ecr - uses: aws-actions/amazon-ecr-login@062b18b96a7aff071d4dc91bc00c4c1a7945b076 # v2.0.1 - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@f95db51fddba0c2d1ec667646a06c2ce06100226 # v3.0.0 - - name: Build and Push - uses: docker/build-push-action@4a13e500e55cf31b7a5d59a38ab2040ab0f42f56 # v5.1.0 - with: - context: . - file: core/chainlink.Dockerfile - # comma separated like: KEY1=VAL1,KEY2=VAL2,... - build-args: COMMIT_SHA=${{ github.sha }} - tags: ${{ secrets.QA_AWS_ACCOUNT_NUMBER }}.dkr.ecr.${{ secrets.QA_AWS_REGION }}.amazonaws.com/chainlink:latest.${{ github.sha }} - push: true - - name: Collect Metrics - if: always() - id: collect-gha-metrics - uses: smartcontractkit/push-gha-metrics-action@d1618b772a97fd87e6505de97b872ee0b1f1729a # v2.0.2 - with: - basic-auth: ${{ secrets.GRAFANA_CLOUD_BASIC_AUTH }} - hostname: ${{ secrets.GRAFANA_CLOUD_HOST }} - this-job-name: Build Chainlink Image - continue-on-error: true - run_tests: - environment: integration - name: run core evm ${{ github.event.inputs.focus }} performance tests - runs-on: ubuntu-latest - needs: build-chainlink - steps: - - name: Checkout the repo - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - - name: Run Tests - uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/run-tests@e865e376b8c2d594028c8d645dd6c47169b72974 # v2.2.16 - with: - test_command_to_run: cd integration-tests && go test -timeout 1h -count=1 -json -test.parallel 10 ./performance 2>&1 | tee /tmp/gotest.log | gotestfmt - test_download_vendor_packages_command: make gomod - cl_repo: ${{ secrets.QA_AWS_ACCOUNT_NUMBER }}.dkr.ecr.${{ secrets.QA_AWS_REGION }}.amazonaws.com/chainlink - cl_image_tag: latest.${{ github.sha }} - artifacts_location: ./integration-tests/performance/logs - publish_report_paths: ./tests-perf-report.xml - publish_check_name: Core Performance Test Results - go_mod_path: ./integration-tests/go.mod - QA_AWS_REGION: ${{ secrets.QA_AWS_REGION }} - QA_AWS_ROLE_TO_ASSUME: ${{ secrets.QA_AWS_ROLE_TO_ASSUME }} - QA_KUBECONFIG: ${{ secrets.QA_KUBECONFIG }} - - name: Publish pprof artifacts - if: ${{ success() }} - uses: actions/upload-artifact@0b7f8abb1508181956e8e162db84b466c27e18ce # v3.1.2 - with: - name: pprof_results - path: ./integration-tests/performance/logs - - name: Collect Metrics - if: always() - id: collect-gha-metrics - uses: smartcontractkit/push-gha-metrics-action@d1618b772a97fd87e6505de97b872ee0b1f1729a # v2.0.2 - with: - basic-auth: ${{ secrets.GRAFANA_CLOUD_BASIC_AUTH }} - hostname: ${{ secrets.GRAFANA_CLOUD_HOST }} - this-job-name: run core evm ${{ github.event.inputs.focus }} performance tests - continue-on-error: true diff --git a/.github/workflows/solidity-foundry.yml b/.github/workflows/solidity-foundry.yml index ff61f46a9d..89b911c281 100644 --- a/.github/workflows/solidity-foundry.yml +++ b/.github/workflows/solidity-foundry.yml @@ -95,7 +95,7 @@ jobs: strategy: fail-fast: false matrix: - product: [vrf, automation, llo-feeds, functions, shared, ccip, rebalancer] + product: [vrf, automation, llo-feeds, l2ep, functions, shared, ccip, rebalancer] needs: [changes] name: Foundry Tests ${{ matrix.product }} # See https://github.com/foundry-rs/foundry/issues/3827 diff --git a/.github/workflows/solidity-hardhat.yml b/.github/workflows/solidity-hardhat.yml index a74357ec9c..e6495f87d3 100644 --- a/.github/workflows/solidity-hardhat.yml +++ b/.github/workflows/solidity-hardhat.yml @@ -65,7 +65,7 @@ jobs: fail-fast: false matrix: split: ${{ fromJson(needs.split-tests.outputs.splits) }} - runs-on: ubuntu20.04-4cores-16GB + runs-on: ubuntu-latest steps: - name: Checkout the repo uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 @@ -130,7 +130,7 @@ jobs: fail-fast: false matrix: split: ${{ fromJson(needs.split-tests.outputs.splits) }} - runs-on: ubuntu20.04-4cores-16GB + runs-on: ubuntu-latest steps: - name: Checkout the repo uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 diff --git a/.gitignore b/.gitignore index 1ebe66f092..9b448ea3db 100644 --- a/.gitignore +++ b/.gitignore @@ -101,5 +101,12 @@ go.work* # This sometimes shows up for some reason tools/flakeytests/coverage.txt +# Integration tests create these files .test_summary/ .run.id + +# Fuzz tests can create these files +**/testdata/fuzz/* + +# Runtime test configuration that might contain secrets +overrides.toml \ No newline at end of file diff --git a/charts/chainlink-cluster/devspace.yaml b/charts/chainlink-cluster/devspace.yaml index 902925b278..0157ce7451 100644 --- a/charts/chainlink-cluster/devspace.yaml +++ b/charts/chainlink-cluster/devspace.yaml @@ -21,8 +21,8 @@ pipelines: run_dependencies --all ensure_pull_secrets --all build_images ---var DOCKER_DEFAULT_PLATFORM=linux/amd64 --all -t $(git rev-parse --short HEAD) - kubectl annotate namespace ${DEVSPACE_NAMESPACE} janitor/ttl=${NS_TTL} - kubectl label namespace/${DEVSPACE_NAMESPACE} network=crib + kubectl annotate namespace ${DEVSPACE_NAMESPACE} janitor/ttl=${NS_TTL} || true + kubectl label namespace/${DEVSPACE_NAMESPACE} network=crib || true create_deployments --all echo "Namespace ${DEVSPACE_NAMESPACE} will be deleted in ${NS_TTL}" purge: diff --git a/charts/chainlink-cluster/templates/chainlink-db-deployment.yaml b/charts/chainlink-cluster/templates/chainlink-db-deployment.yaml index f335130ea9..91924ba500 100644 --- a/charts/chainlink-cluster/templates/chainlink-db-deployment.yaml +++ b/charts/chainlink-cluster/templates/chainlink-db-deployment.yaml @@ -24,12 +24,20 @@ spec: selector: matchLabels: app: {{ $.Release.Name }}-db + # Used for testing. + # havoc-component-group and havoc-network-group are used by "havoc" chaos testing tool + havoc-component-group: db + havoc-network-group: db instance: {{ $cfg.name }}-db release: {{ $.Release.Name }} template: metadata: labels: app: {{ $.Release.Name }}-db + # Used for testing. + # havoc-component-group and havoc-network-group are used by "havoc" chaos testing tool + havoc-component-group: db + havoc-network-group: db instance: {{ $cfg.name }}-db release: {{ $.Release.Name }} {{- range $key, $value := $.Values.labels }} diff --git a/charts/chainlink-cluster/templates/chainlink-db-networkpolicy.yaml b/charts/chainlink-cluster/templates/chainlink-db-networkpolicy.yaml new file mode 100644 index 0000000000..e5d029b786 --- /dev/null +++ b/charts/chainlink-cluster/templates/chainlink-db-networkpolicy.yaml @@ -0,0 +1,23 @@ +apiVersion: networking.k8s.io/v1 +kind: NetworkPolicy +metadata: + name: {{ $.Release.Name }}-db +spec: + podSelector: + matchLabels: + app: {{ $.Release.Name }}-db + policyTypes: + - Ingress + ingress: + - from: + # Allow all node pods to access the database pods. + - podSelector: + matchLabels: + app: {{ $.Release.Name }} + # Allow all runner pods to access the database pods. + - podSelector: + matchLabels: + app: runner + ports: + - protocol: TCP + port: 5432 diff --git a/charts/chainlink-cluster/templates/chainlink-node-deployment.yaml b/charts/chainlink-cluster/templates/chainlink-node-deployment.yaml index 16156ef4ff..0ce16fd475 100644 --- a/charts/chainlink-cluster/templates/chainlink-node-deployment.yaml +++ b/charts/chainlink-cluster/templates/chainlink-node-deployment.yaml @@ -1,8 +1,8 @@ -{{- range $cfg := .Values.chainlink.nodes }} +{{- range $index, $cfg := .Values.chainlink.nodes }} apiVersion: apps/v1 kind: Deployment metadata: - name: {{ $.Release.Name }}-{{ $cfg.name }} + name: {{ if eq $index 0 }}{{ $.Release.Name }}-{{ $cfg.name }}-bootstrap{{ else }}{{ $.Release.Name }}-{{ $cfg.name }}{{ end }} spec: strategy: # Need to recreate the pod to deal with lease lock held by old pod. @@ -10,12 +10,29 @@ spec: selector: matchLabels: app: {{ $.Release.Name }} + # Used for testing. + # havoc-component-group and havoc-network-group are used by "havoc" chaos testing tool + {{ if eq $index 0 }}{{ else }} + havoc-component-group: node + {{ end }} + {{ if eq $index 0 }}{{ else }} + havoc-network-group: {{ if gt $index 2 }}"1"{{ else }}"2"{{ end }} + {{ end }} instance: {{ $cfg.name }} release: {{ $.Release.Name }} template: metadata: labels: app: {{ $.Release.Name }} + # Used for testing. + # havoc-component-group and havoc-network-group are used by "havoc" chaos testing tool + {{ if eq $index 0 }}{{ else }} + havoc-component-group: node + {{ end }} + {{ if eq $index 0 }}{{ else }} + havoc-network-group: {{ if gt $index 2 }}"1"{{ else }}"2"{{ end }} + {{ end }} + instance: {{ $cfg.name }} release: {{ $.Release.Name }} {{- range $key, $value := $.Values.labels }} @@ -39,7 +56,7 @@ spec: {{- toYaml $.Values.chainlink.securityContext | nindent 12 }} image: {{ default "public.ecr.aws/chainlink/chainlink" $cfg.image }} imagePullPolicy: Always - command: ["bash", "-c", "while ! pg_isready -U postgres --host {{ $.Release.Name }}-db-{{ $cfg.name }} --port 5432; do echo \"waiting for database to start\"; sleep 1; done && 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"] + command: [ "bash", "-c", "while ! pg_isready -U postgres --host {{ $.Release.Name }}-db-{{ $cfg.name }} --port 5432; do echo \"waiting for database to start\"; sleep 1; done && 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" ] ports: - name: access containerPort: {{ $.Values.chainlink.web_port }} diff --git a/charts/chainlink-cluster/templates/chainlink-node-networkpolicy.yaml b/charts/chainlink-cluster/templates/chainlink-node-networkpolicy.yaml new file mode 100644 index 0000000000..321bc53162 --- /dev/null +++ b/charts/chainlink-cluster/templates/chainlink-node-networkpolicy.yaml @@ -0,0 +1,19 @@ +apiVersion: networking.k8s.io/v1 +kind: NetworkPolicy +metadata: + name: {{ $.Release.Name }}-node +spec: + podSelector: + matchLabels: + app: {{ $.Release.Name }} + policyTypes: + - Ingress + ingress: + # Allow all ingress traffic between the node pods and from runner pod. + - from: + - podSelector: + matchLabels: + app: {{ $.Release.Name }} + - podSelector: + matchLabels: + app: runner diff --git a/charts/chainlink-cluster/templates/geth-deployment.yaml b/charts/chainlink-cluster/templates/geth-deployment.yaml index 6948c4df28..abc7853d97 100644 --- a/charts/chainlink-cluster/templates/geth-deployment.yaml +++ b/charts/chainlink-cluster/templates/geth-deployment.yaml @@ -7,11 +7,19 @@ spec: selector: matchLabels: app: geth + # Used for testing. + # havoc-component-group and havoc-network-group are used by "havoc" chaos testing tool + havoc-component-group: "blockchain" + havoc-network-group: "blockchain" release: {{ .Release.Name }} template: metadata: labels: app: geth + # Used for testing. + # havoc-component-group and havoc-network-group are used by "havoc" chaos testing tool + havoc-component-group: "blockchain" + havoc-network-group: "blockchain" release: {{ .Release.Name }} annotations: {{- range $key, $value := .Values.podAnnotations }} @@ -65,6 +73,8 @@ spec: - '--miner.etherbase' - '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266' - '--ipcdisable' + - '--http.api' + - 'admin,debug,web3,eth,txpool,personal,miner,net' - '--http' - '--http.vhosts' - '*' diff --git a/charts/chainlink-cluster/templates/geth-networkpolicy.yaml b/charts/chainlink-cluster/templates/geth-networkpolicy.yaml new file mode 100644 index 0000000000..5be5913625 --- /dev/null +++ b/charts/chainlink-cluster/templates/geth-networkpolicy.yaml @@ -0,0 +1,25 @@ +apiVersion: networking.k8s.io/v1 +kind: NetworkPolicy +metadata: + name: {{ $.Release.Name }}-geth +spec: + podSelector: + matchLabels: + app: geth + policyTypes: + - Ingress + ingress: + - from: + # Allow http and websocket connections from the node pods. + - podSelector: + matchLabels: + app: {{ $.Release.Name }} + # Allow http and websocket connections from the runner pods. + - podSelector: + matchLabels: + app: runner + ports: + - protocol: TCP + port: 8544 + - protocol: TCP + port: 8546 diff --git a/charts/chainlink-cluster/templates/mockserver-networkpolicy.yaml b/charts/chainlink-cluster/templates/mockserver-networkpolicy.yaml new file mode 100644 index 0000000000..074b1ab089 --- /dev/null +++ b/charts/chainlink-cluster/templates/mockserver-networkpolicy.yaml @@ -0,0 +1,23 @@ +apiVersion: networking.k8s.io/v1 +kind: NetworkPolicy +metadata: + name: {{ $.Release.Name }}-mockserver +spec: + podSelector: + matchLabels: + app: mockserver + policyTypes: + - Ingress + ingress: + - from: + # Allow http traffic from the node pods. + - podSelector: + matchLabels: + app: {{ $.Release.Name }} + # Allow http traffic from the runner pods. + - podSelector: + matchLabels: + app: runner + ports: + - protocol: TCP + port: 1080 diff --git a/charts/chainlink-cluster/templates/networkpolicy-default.yaml b/charts/chainlink-cluster/templates/networkpolicy-default.yaml new file mode 100644 index 0000000000..f2d9416cf1 --- /dev/null +++ b/charts/chainlink-cluster/templates/networkpolicy-default.yaml @@ -0,0 +1,41 @@ +apiVersion: networking.k8s.io/v1 +kind: NetworkPolicy +metadata: + name: default +spec: + podSelector: + matchLabels: {} + policyTypes: + - Ingress + - Egress + ingress: + {{- if and .Values.networkPolicyDefault.ingress.allowCustomCidrs (not (empty .Values.networkPolicyDefault.ingress.customCidrs)) }} + # Using a comma separated list to make it easy to pass in with: + # `helm template ... --set networkPolicyDefault.ingress.customCidrs=...` + {{- $cidrs := splitList "," .Values.networkPolicyDefault.ingress.customCidrs }} + - from: + {{- range $cidr := $cidrs }} + - ipBlock: + cidr: {{ $cidr | quote }} + {{- end }} + {{- else }} + # Deny all ingress if no rules are specified. Rules can still be specified in other templates. + - {} + {{- end }} + egress: + - to: + - namespaceSelector: + matchLabels: + kubernetes.io/metadata.name: "{{ $.Release.Namespace }}" + - to: + - namespaceSelector: + matchLabels: + kubernetes.io/metadata.name: kube-system + podSelector: + matchLabels: + k8s-app: kube-dns + ports: + - protocol: TCP + port: 53 + - protocol: UDP + port: 53 diff --git a/charts/chainlink-cluster/templates/runner-networkpolicy.yaml b/charts/chainlink-cluster/templates/runner-networkpolicy.yaml new file mode 100644 index 0000000000..2bb6ac9862 --- /dev/null +++ b/charts/chainlink-cluster/templates/runner-networkpolicy.yaml @@ -0,0 +1,19 @@ +apiVersion: networking.k8s.io/v1 +kind: NetworkPolicy +metadata: + name: {{ $.Release.Name }}-runner +spec: + podSelector: + matchLabels: + app: runner + policyTypes: + - Ingress + ingress: + # Allow all ingress traffic between the node pods and from runner pod. + - from: + - podSelector: + matchLabels: + app: {{ $.Release.Name }} + - podSelector: + matchLabels: + app: runner diff --git a/charts/chainlink-cluster/values.yaml b/charts/chainlink-cluster/values.yaml index 9394bda121..24914a40a9 100644 --- a/charts/chainlink-cluster/values.yaml +++ b/charts/chainlink-cluster/values.yaml @@ -283,3 +283,12 @@ podAnnotations: nodeSelector: tolerations: affinity: + +# Configure the default network policy. +networkPolicyDefault: + ingress: + allowCustomCidrs: false + # String of comma separated CIDRs + customCidrs: null + # Example: + # customCidrs: "10.0.0.0/16,192.168.0.1/24" diff --git a/common/client/node_selector_priority_level_test.go b/common/client/node_selector_priority_level_test.go index ac84645e91..15a7a7ac60 100644 --- a/common/client/node_selector_priority_level_test.go +++ b/common/client/node_selector_priority_level_test.go @@ -17,72 +17,75 @@ func TestPriorityLevelNodeSelector(t *testing.T) { t.Parallel() type nodeClient NodeClient[types.ID, Head] - var nodes []Node[types.ID, Head, nodeClient] - n1 := newMockNode[types.ID, Head, nodeClient](t) - n1.On("State").Return(nodeStateAlive) - n1.On("Order").Return(int32(1)) - - n2 := newMockNode[types.ID, Head, nodeClient](t) - n2.On("State").Return(nodeStateAlive) - n2.On("Order").Return(int32(1)) - - n3 := newMockNode[types.ID, Head, nodeClient](t) - n3.On("State").Return(nodeStateAlive) - n3.On("Order").Return(int32(1)) - - nodes = append(nodes, n1, n2, n3) - selector := newNodeSelector(NodeSelectionModePriorityLevel, nodes) - assert.Same(t, nodes[0], selector.Select()) - assert.Same(t, nodes[1], selector.Select()) - assert.Same(t, nodes[2], selector.Select()) - assert.Same(t, nodes[0], selector.Select()) - assert.Same(t, nodes[1], selector.Select()) - assert.Same(t, nodes[2], selector.Select()) -} - -func TestPriorityLevelNodeSelector_None(t *testing.T) { - t.Parallel() - - type nodeClient NodeClient[types.ID, Head] - var nodes []Node[types.ID, Head, nodeClient] - - for i := 0; i < 3; i++ { - node := newMockNode[types.ID, Head, nodeClient](t) - if i == 0 { - // first node is out of sync - node.On("State").Return(nodeStateOutOfSync) - node.On("Order").Return(int32(1)) - } else { - // others are unreachable - node.On("State").Return(nodeStateUnreachable) - node.On("Order").Return(int32(1)) - } - nodes = append(nodes, node) + type testNode struct { + order int32 + state nodeState + } + type testCase struct { + name string + nodes []testNode + expect []int // indexes of the nodes expected to be returned by Select } - selector := newNodeSelector(NodeSelectionModePriorityLevel, nodes) - assert.Nil(t, selector.Select()) -} - -func TestPriorityLevelNodeSelector_DifferentOrder(t *testing.T) { - t.Parallel() - - type nodeClient NodeClient[types.ID, Head] - var nodes []Node[types.ID, Head, nodeClient] - n1 := newMockNode[types.ID, Head, nodeClient](t) - n1.On("State").Return(nodeStateAlive) - n1.On("Order").Return(int32(1)) - - n2 := newMockNode[types.ID, Head, nodeClient](t) - n2.On("State").Return(nodeStateAlive) - n2.On("Order").Return(int32(2)) - - n3 := newMockNode[types.ID, Head, nodeClient](t) - n3.On("State").Return(nodeStateAlive) - n3.On("Order").Return(int32(3)) + testCases := []testCase{ + { + name: "TwoNodesSameOrder: Highest Allowed Order", + nodes: []testNode{ + {order: 1, state: nodeStateAlive}, + {order: 1, state: nodeStateAlive}, + }, + expect: []int{0, 1, 0, 1, 0, 1}, + }, + { + name: "TwoNodesSameOrder: Lowest Allowed Order", + nodes: []testNode{ + {order: 100, state: nodeStateAlive}, + {order: 100, state: nodeStateAlive}, + }, + expect: []int{0, 1, 0, 1, 0, 1}, + }, + { + name: "NoneAvailable", + nodes: []testNode{ + {order: 1, state: nodeStateOutOfSync}, + {order: 1, state: nodeStateUnreachable}, + {order: 1, state: nodeStateUnreachable}, + }, + expect: []int{}, // no nodes should be selected + }, + { + name: "DifferentOrder", + nodes: []testNode{ + {order: 1, state: nodeStateAlive}, + {order: 2, state: nodeStateAlive}, + {order: 3, state: nodeStateAlive}, + }, + expect: []int{0, 0}, // only the highest order node should be selected + }, + } - nodes = append(nodes, n1, n2, n3) - selector := newNodeSelector(NodeSelectionModePriorityLevel, nodes) - assert.Same(t, nodes[0], selector.Select()) - assert.Same(t, nodes[0], selector.Select()) + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + var nodes []Node[types.ID, Head, nodeClient] + for _, tn := range tc.nodes { + node := newMockNode[types.ID, Head, nodeClient](t) + node.On("State").Return(tn.state) + node.On("Order").Return(tn.order) + nodes = append(nodes, node) + } + + selector := newNodeSelector(NodeSelectionModePriorityLevel, nodes) + for _, idx := range tc.expect { + if idx >= len(nodes) { + t.Fatalf("Invalid node index %d in test case '%s'", idx, tc.name) + } + assert.Same(t, nodes[idx], selector.Select()) + } + + // Check for nil selection if expected slice is empty + if len(tc.expect) == 0 { + assert.Nil(t, selector.Select()) + } + }) + } } diff --git a/common/config/chaintype.go b/common/config/chaintype.go index 21fb8cd297..9ef4864b86 100644 --- a/common/config/chaintype.go +++ b/common/config/chaintype.go @@ -18,16 +18,17 @@ const ( ChainWeMix ChainType = "wemix" ChainKroma ChainType = "kroma" ChainZkSync ChainType = "zksync" + ChainScroll ChainType = "scroll" ) var ErrInvalidChainType = fmt.Errorf("must be one of %s or omitted", strings.Join([]string{ string(ChainArbitrum), string(ChainMetis), string(ChainXDai), string(ChainOptimismBedrock), string(ChainCelo), - string(ChainKroma), string(ChainWeMix), string(ChainZkSync)}, ", ")) + string(ChainKroma), string(ChainWeMix), string(ChainZkSync), string(ChainScroll)}, ", ")) // IsValid returns true if the ChainType value is known or empty. func (c ChainType) IsValid() bool { switch c { - case "", ChainArbitrum, ChainMetis, ChainOptimismBedrock, ChainXDai, ChainCelo, ChainKroma, ChainWeMix, ChainZkSync: + case "", ChainArbitrum, ChainMetis, ChainOptimismBedrock, ChainXDai, ChainCelo, ChainKroma, ChainWeMix, ChainZkSync, ChainScroll: return true } return false diff --git a/common/txmgr/confirmer.go b/common/txmgr/confirmer.go index f10481fef5..d55f982c11 100644 --- a/common/txmgr/confirmer.go +++ b/common/txmgr/confirmer.go @@ -14,10 +14,11 @@ import ( "github.com/prometheus/client_golang/prometheus/promauto" "go.uber.org/multierr" + commonhex "github.com/smartcontractkit/chainlink-common/pkg/utils/hex" + "github.com/smartcontractkit/chainlink-common/pkg/chains/label" "github.com/smartcontractkit/chainlink-common/pkg/logger" "github.com/smartcontractkit/chainlink-common/pkg/services" - commonhex "github.com/smartcontractkit/chainlink-common/pkg/utils/hex" "github.com/smartcontractkit/chainlink-common/pkg/utils/mailbox" "github.com/smartcontractkit/chainlink/v2/common/client" diff --git a/common/txmgr/resender.go b/common/txmgr/resender.go index dded59f55d..384c0c7a2c 100644 --- a/common/txmgr/resender.go +++ b/common/txmgr/resender.go @@ -140,7 +140,8 @@ func (er *Resender[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) resendUnco return fmt.Errorf("Resender failed getting enabled keys for chain %s: %w", er.chainID.String(), err) } - resendAddresses = append(resendAddresses, er.tracker.GetAbandonedAddresses()...) + // Tracker currently disabled for BCI-2638; refactor required + // resendAddresses = append(resendAddresses, er.tracker.GetAbandonedAddresses()...) ageThreshold := er.txConfig.ResendAfterThreshold() maxInFlightTransactions := er.txConfig.MaxInFlight() diff --git a/common/txmgr/tracker.go b/common/txmgr/tracker.go index 3ef2fc0720..8b66668c41 100644 --- a/common/txmgr/tracker.go +++ b/common/txmgr/tracker.go @@ -92,19 +92,22 @@ func NewTracker[ } func (tr *Tracker[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) Start(_ context.Context) (err error) { - tr.lock.Lock() - defer tr.lock.Unlock() + tr.lggr.Info("Abandoned transaction tracking enabled") return tr.StartOnce("Tracker", func() error { return tr.startInternal() }) } func (tr *Tracker[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) startInternal() (err error) { + tr.lock.Lock() + defer tr.lock.Unlock() + tr.ctx, tr.ctxCancel = context.WithCancel(context.Background()) if err := tr.setEnabledAddresses(); err != nil { return fmt.Errorf("failed to set enabled addresses: %w", err) } + tr.lggr.Info("Enabled addresses set") if err := tr.trackAbandonedTxes(tr.ctx); err != nil { return fmt.Errorf("failed to track abandoned txes: %w", err) @@ -112,9 +115,11 @@ func (tr *Tracker[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) startIntern tr.isStarted = true if len(tr.txCache) == 0 { - tr.lggr.Infow("no abandoned txes found, skipping runLoop") + tr.lggr.Info("no abandoned txes found, skipping runLoop") return nil } + + tr.lggr.Infof("%d abandoned txes found, starting runLoop", len(tr.txCache)) tr.wg.Add(1) go tr.runLoop() return nil @@ -129,7 +134,7 @@ func (tr *Tracker[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) Close() err } func (tr *Tracker[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) closeInternal() error { - tr.lggr.Infow("stopping tracker") + tr.lggr.Info("stopping tracker") if !tr.isStarted { return fmt.Errorf("tracker not started") } @@ -159,7 +164,7 @@ func (tr *Tracker[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) runLoop() { } } case <-ttlExceeded.C: - tr.lggr.Infow("ttl exceeded") + tr.lggr.Info("ttl exceeded") tr.MarkAllTxesFatal(tr.ctx) return case <-tr.ctx.Done(): @@ -211,6 +216,7 @@ func (tr *Tracker[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) trackAbando return fmt.Errorf("tracker already started") } + tr.lggr.Info("Retrieving non fatal transactions from txStore") nonFatalTxes, err := tr.txStore.GetNonFatalTransactions(ctx, tr.chainID) if err != nil { return fmt.Errorf("failed to get non fatal txes from txStore: %w", err) @@ -239,6 +245,8 @@ func (tr *Tracker[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) HandleTxesB } func (tr *Tracker[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) handleTxesByState(ctx context.Context, blockHeight int64) error { + tr.lggr.Info("Handling transactions by state") + for id, atx := range tr.txCache { tx, err := tr.txStore.GetTxByID(ctx, atx.id) if err != nil { diff --git a/common/txmgr/txmgr.go b/common/txmgr/txmgr.go index 25c3b9beb3..c6676674fb 100644 --- a/common/txmgr/txmgr.go +++ b/common/txmgr/txmgr.go @@ -191,10 +191,14 @@ func (b *Txm[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) Start(ctx return fmt.Errorf("Txm: Estimator failed to start: %w", err) } + /* Tracker currently disabled for BCI-2638; refactor required + b.logger.Info("Txm starting tracker") if err := ms.Start(ctx, b.tracker); err != nil { return fmt.Errorf("Txm: Tracker failed to start: %w", err) } + */ + b.logger.Info("Txm starting runLoop") b.wg.Add(1) go b.runLoop() <-b.chSubbed @@ -272,9 +276,11 @@ func (b *Txm[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) Close() (m merr = errors.Join(merr, fmt.Errorf("Txm: failed to close TxAttemptBuilder: %w", err)) } + /* Tracker currently disabled for BCI-2638; refactor required if err := b.tracker.Close(); err != nil { merr = errors.Join(merr, fmt.Errorf("Txm: failed to close Tracker: %w", err)) } + */ return nil }) @@ -389,7 +395,8 @@ func (b *Txm[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) runLoop() b.broadcaster.Trigger(address) case head := <-b.chHeads: b.confirmer.mb.Deliver(head) - b.tracker.mb.Deliver(head.BlockNumber()) + // Tracker currently disabled for BCI-2638; refactor required + // b.tracker.mb.Deliver(head.BlockNumber()) case reset := <-b.reset: // This check prevents the weird edge-case where you can select // into this block after chStop has already been closed and the @@ -417,10 +424,12 @@ func (b *Txm[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) runLoop() if err != nil && (!errors.Is(err, services.ErrAlreadyStopped) || !errors.Is(err, services.ErrCannotStopUnstarted)) { b.logger.Errorw(fmt.Sprintf("Failed to Close Confirmer: %v", err), "err", err) } + /* Tracker currently disabled for BCI-2638; refactor required err = b.tracker.Close() if err != nil && (!errors.Is(err, services.ErrAlreadyStopped) || !errors.Is(err, services.ErrCannotStopUnstarted)) { b.logger.Errorw(fmt.Sprintf("Failed to Close Tracker: %v", err), "err", err) } + */ return case <-keysChanged: // This check prevents the weird edge-case where you can select diff --git a/contracts/.solhint.json b/contracts/.solhint.json index 6fc9442a2b..f3d2289f9c 100644 --- a/contracts/.solhint.json +++ b/contracts/.solhint.json @@ -9,6 +9,7 @@ "func-named-parameters": "off", "immutable-vars-naming": "off", "no-inline-assembly": "off", + "contract-name-camelcase": "off", "no-unused-import": "error", "func-visibility": [ "error", diff --git a/contracts/.solhintignore b/contracts/.solhintignore index 02c99f8695..0e1571c0bc 100644 --- a/contracts/.solhintignore +++ b/contracts/.solhintignore @@ -6,6 +6,21 @@ ./src/v0.8/automation/v1_3 ./src/v0.8/automation/v2_0 ./src/v0.8/automation/v2_1 +./src/v0.8/automation/interfaces/v2_1/ +./src/v0.8/automation/interfaces/MigratableKeeperRegistryInterface.sol +./src/v0.8/automation/upkeeps/UpkeepBalanceMonitor.sol +./src/v0.8/automation/upkeeps/LinkAvailableBalanceMonitor.sol +./src/v0.8/automation/upkeeps/EthBalanceMonitor.sol +./src/v0.8/automation/upkeeps/ERC20BalanceMonitor.sol +./src/v0.8/automation/upkeeps/CronUpkeepFactory.sol +./src/v0.8/automation/upkeeps/CronUpkeepDelegate.sol +./src/v0.8/automation/upkeeps/CronUpkeep.sol +./src/v0.8/automation/libraries/internal/Cron.sol +./src/v0.8/automation/AutomationForwarder.sol +./src/v0.8/automation/AutomationForwarderLogic.sol + + +# Ignore tests / test helpers (for now) ./src/v0.8/automation/mocks ./src/v0.8/automation/testhelpers @@ -23,4 +38,4 @@ # Always ignore vendor ./src/v0.8/vendor -./node_modules/ \ No newline at end of file +./node_modules/ diff --git a/contracts/GNUmakefile b/contracts/GNUmakefile index 58c47a5ae3..e88f3ace80 100644 --- a/contracts/GNUmakefile +++ b/contracts/GNUmakefile @@ -1,6 +1,6 @@ # ALL_FOUNDRY_PRODUCTS contains a list of all products that have a foundry # profile defined and use the Foundry snapshots. -ALL_FOUNDRY_PRODUCTS = llo-feeds functions shared ccip rebalancer +ALL_FOUNDRY_PRODUCTS = l2ep llo-feeds functions shared ccip rebalancer # To make a snapshot for a specific product, either set the `FOUNDRY_PROFILE` env var # or call the target with `FOUNDRY_PROFILE=product` diff --git a/contracts/gas-snapshots/functions.gas-snapshot b/contracts/gas-snapshots/functions.gas-snapshot index d0893969bf..39efc0d10e 100644 --- a/contracts/gas-snapshots/functions.gas-snapshot +++ b/contracts/gas-snapshots/functions.gas-snapshot @@ -1,12 +1,12 @@ -ChainSpecificUtil__getCurrentTxL1GasFees_Arbitrum:test__getCurrentTxL1GasFees_SuccessWhenArbitrumGoerli() (gas: 14579333) -ChainSpecificUtil__getCurrentTxL1GasFees_Arbitrum:test__getCurrentTxL1GasFees_SuccessWhenArbitrumMainnet() (gas: 14579311) -ChainSpecificUtil__getCurrentTxL1GasFees_Arbitrum:test__getCurrentTxL1GasFees_SuccessWhenArbitrumSepolia() (gas: 14579327) -ChainSpecificUtil__getCurrentTxL1GasFees_Base:test__getCurrentTxL1GasFees_SuccessWhenBaseGoerli() (gas: 14590747) -ChainSpecificUtil__getCurrentTxL1GasFees_Base:test__getCurrentTxL1GasFees_SuccessWhenBaseMainnet() (gas: 14590724) -ChainSpecificUtil__getCurrentTxL1GasFees_Base:test__getCurrentTxL1GasFees_SuccessWhenBaseSepolia() (gas: 14590696) -ChainSpecificUtil__getCurrentTxL1GasFees_Optimism:test__getCurrentTxL1GasFees_SuccessWhenOptimismGoerli() (gas: 14590647) -ChainSpecificUtil__getCurrentTxL1GasFees_Optimism:test__getCurrentTxL1GasFees_SuccessWhenOptimismMainnet() (gas: 14590636) -ChainSpecificUtil__getCurrentTxL1GasFees_Optimism:test__getCurrentTxL1GasFees_SuccessWhenOptimismSepolia() (gas: 14590680) +ChainSpecificUtil__getCurrentTxL1GasFees_Arbitrum:test__getCurrentTxL1GasFees_SuccessWhenArbitrumGoerli() (gas: 14805978) +ChainSpecificUtil__getCurrentTxL1GasFees_Arbitrum:test__getCurrentTxL1GasFees_SuccessWhenArbitrumMainnet() (gas: 14805956) +ChainSpecificUtil__getCurrentTxL1GasFees_Arbitrum:test__getCurrentTxL1GasFees_SuccessWhenArbitrumSepolia() (gas: 14805972) +ChainSpecificUtil__getCurrentTxL1GasFees_Base:test__getCurrentTxL1GasFees_SuccessWhenBaseGoerli() (gas: 14817392) +ChainSpecificUtil__getCurrentTxL1GasFees_Base:test__getCurrentTxL1GasFees_SuccessWhenBaseMainnet() (gas: 14817369) +ChainSpecificUtil__getCurrentTxL1GasFees_Base:test__getCurrentTxL1GasFees_SuccessWhenBaseSepolia() (gas: 14817341) +ChainSpecificUtil__getCurrentTxL1GasFees_Optimism:test__getCurrentTxL1GasFees_SuccessWhenOptimismGoerli() (gas: 14817292) +ChainSpecificUtil__getCurrentTxL1GasFees_Optimism:test__getCurrentTxL1GasFees_SuccessWhenOptimismMainnet() (gas: 14817281) +ChainSpecificUtil__getCurrentTxL1GasFees_Optimism:test__getCurrentTxL1GasFees_SuccessWhenOptimismSepolia() (gas: 14817325) FunctionsBilling_Constructor:test_Constructor_Success() (gas: 14812) FunctionsBilling_DeleteCommitment:test_DeleteCommitment_RevertIfNotRouter() (gas: 13282) FunctionsBilling_DeleteCommitment:test_DeleteCommitment_Success() (gas: 15897) @@ -28,7 +28,7 @@ FunctionsBilling_UpdateConfig:test_UpdateConfig_Success() (gas: 38251) FunctionsBilling__DisperseFeePool:test__DisperseFeePool_RevertIfNotSet() (gas: 8810) FunctionsBilling__FulfillAndBill:test__FulfillAndBill_RevertIfInvalidCommitment() (gas: 13302) FunctionsBilling__FulfillAndBill:test__FulfillAndBill_Success() (gas: 180763) -FunctionsBilling__StartBilling:test__FulfillAndBill_HasUniqueGlobalRequestId() (gas: 398312) +FunctionsBilling__StartBilling:test__FulfillAndBill_HasUniqueGlobalRequestId() (gas: 398400) FunctionsClient_Constructor:test_Constructor_Success() (gas: 7573) FunctionsClient_FulfillRequest:test_FulfillRequest_MaximumGas() (gas: 497786) FunctionsClient_FulfillRequest:test_FulfillRequest_MinimumGas() (gas: 198990) @@ -61,7 +61,7 @@ FunctionsRouter_Fulfill:test_Fulfill_RevertIfNotCommittedCoordinator() (gas: 280 FunctionsRouter_Fulfill:test_Fulfill_RevertIfPaused() (gas: 151496) FunctionsRouter_Fulfill:test_Fulfill_SuccessClientNoLongerExists() (gas: 321059) FunctionsRouter_Fulfill:test_Fulfill_SuccessFulfilled() (gas: 334680) -FunctionsRouter_Fulfill:test_Fulfill_SuccessUserCallbackReverts() (gas: 2509962) +FunctionsRouter_Fulfill:test_Fulfill_SuccessUserCallbackReverts() (gas: 2510006) FunctionsRouter_Fulfill:test_Fulfill_SuccessUserCallbackRunsOutOfGas() (gas: 540441) FunctionsRouter_GetAdminFee:test_GetAdminFee_Success() (gas: 17983) FunctionsRouter_GetAllowListId:test_GetAllowListId_Success() (gas: 12904) @@ -82,17 +82,17 @@ FunctionsRouter_ProposeContractsUpdate:test_ProposeContractsUpdate_RevertIfLengt FunctionsRouter_ProposeContractsUpdate:test_ProposeContractsUpdate_RevertIfNotNewContract() (gas: 19048) FunctionsRouter_ProposeContractsUpdate:test_ProposeContractsUpdate_RevertIfNotOwner() (gas: 23392) FunctionsRouter_ProposeContractsUpdate:test_ProposeContractsUpdate_Success() (gas: 118479) -FunctionsRouter_SendRequest:test_SendRequest_RevertIfConsumerNotAllowed() (gas: 59347) +FunctionsRouter_SendRequest:test_SendRequest_RevertIfConsumerNotAllowed() (gas: 59391) FunctionsRouter_SendRequest:test_SendRequest_RevertIfDuplicateRequestId() (gas: 193436) FunctionsRouter_SendRequest:test_SendRequest_RevertIfEmptyData() (gas: 29426) -FunctionsRouter_SendRequest:test_SendRequest_RevertIfIncorrectDonId() (gas: 57925) -FunctionsRouter_SendRequest:test_SendRequest_RevertIfInsufficientSubscriptionBalance() (gas: 186932) +FunctionsRouter_SendRequest:test_SendRequest_RevertIfIncorrectDonId() (gas: 57904) +FunctionsRouter_SendRequest:test_SendRequest_RevertIfInsufficientSubscriptionBalance() (gas: 187020) FunctionsRouter_SendRequest:test_SendRequest_RevertIfInvalidCallbackGasLimit() (gas: 50947) FunctionsRouter_SendRequest:test_SendRequest_RevertIfInvalidDonId() (gas: 25082) FunctionsRouter_SendRequest:test_SendRequest_RevertIfNoSubscription() (gas: 29132) FunctionsRouter_SendRequest:test_SendRequest_RevertIfPaused() (gas: 34291) FunctionsRouter_SendRequest:test_SendRequest_Success() (gas: 286243) -FunctionsRouter_SendRequestToProposed:test_SendRequestToProposed_RevertIfConsumerNotAllowed() (gas: 65843) +FunctionsRouter_SendRequestToProposed:test_SendRequestToProposed_RevertIfConsumerNotAllowed() (gas: 65887) FunctionsRouter_SendRequestToProposed:test_SendRequestToProposed_RevertIfEmptyData() (gas: 36012) FunctionsRouter_SendRequestToProposed:test_SendRequestToProposed_RevertIfIncorrectDonId() (gas: 29896) FunctionsRouter_SendRequestToProposed:test_SendRequestToProposed_RevertIfInvalidCallbackGasLimit() (gas: 57533) @@ -100,7 +100,7 @@ FunctionsRouter_SendRequestToProposed:test_SendRequestToProposed_RevertIfInvalid FunctionsRouter_SendRequestToProposed:test_SendRequestToProposed_RevertIfNoSubscription() (gas: 35717) FunctionsRouter_SendRequestToProposed:test_SendRequestToProposed_RevertIfPaused() (gas: 40810) FunctionsRouter_SendRequestToProposed:test_SendRequestToProposed_Success() (gas: 292812) -FunctionsRouter_SendRequestToProposed:test_SendRequest_RevertIfInsufficientSubscriptionBalance() (gas: 193424) +FunctionsRouter_SendRequestToProposed:test_SendRequest_RevertIfInsufficientSubscriptionBalance() (gas: 193512) FunctionsRouter_SetAllowListId:test_SetAllowListId_Success() (gas: 30688) FunctionsRouter_SetAllowListId:test_UpdateConfig_RevertIfNotOwner() (gas: 13403) FunctionsRouter_Unpause:test_Unpause_RevertIfNotOwner() (gas: 13293) @@ -109,30 +109,30 @@ FunctionsRouter_UpdateConfig:test_UpdateConfig_RevertIfNotOwner() (gas: 24437) FunctionsRouter_UpdateConfig:test_UpdateConfig_Success() (gas: 60676) FunctionsRouter_UpdateContracts:test_UpdateContracts_RevertIfNotOwner() (gas: 13336) FunctionsRouter_UpdateContracts:test_UpdateContracts_Success() (gas: 38732) -FunctionsSubscriptions_AcceptSubscriptionOwnerTransfer:test_AcceptSubscriptionOwnerTransfer_RevertIfNotAllowedSender() (gas: 60326) -FunctionsSubscriptions_AcceptSubscriptionOwnerTransfer:test_AcceptSubscriptionOwnerTransfer_RevertIfPaused() (gas: 60987) -FunctionsSubscriptions_AcceptSubscriptionOwnerTransfer:test_AcceptSubscriptionOwnerTransfer_RevertIfSenderBecomesBlocked() (gas: 94677) -FunctionsSubscriptions_AcceptSubscriptionOwnerTransfer:test_AcceptSubscriptionOwnerTransfer_RevertIfSenderIsNotNewOwner() (gas: 62693) -FunctionsSubscriptions_AcceptSubscriptionOwnerTransfer:test_AcceptSubscriptionOwnerTransfer_Success() (gas: 215197) -FunctionsSubscriptions_AddConsumer:test_AddConsumer_RevertIfMaximumConsumers() (gas: 137893) -FunctionsSubscriptions_AddConsumer:test_AddConsumer_RevertIfMaximumConsumersAfterConfigUpdate() (gas: 164837) +FunctionsSubscriptions_AcceptSubscriptionOwnerTransfer:test_AcceptSubscriptionOwnerTransfer_RevertIfNotAllowedSender() (gas: 60414) +FunctionsSubscriptions_AcceptSubscriptionOwnerTransfer:test_AcceptSubscriptionOwnerTransfer_RevertIfPaused() (gas: 61031) +FunctionsSubscriptions_AcceptSubscriptionOwnerTransfer:test_AcceptSubscriptionOwnerTransfer_RevertIfSenderBecomesBlocked() (gas: 139404) +FunctionsSubscriptions_AcceptSubscriptionOwnerTransfer:test_AcceptSubscriptionOwnerTransfer_RevertIfSenderIsNotNewOwner() (gas: 62781) +FunctionsSubscriptions_AcceptSubscriptionOwnerTransfer:test_AcceptSubscriptionOwnerTransfer_Success() (gas: 215285) +FunctionsSubscriptions_AddConsumer:test_AddConsumer_RevertIfMaximumConsumers() (gas: 138025) +FunctionsSubscriptions_AddConsumer:test_AddConsumer_RevertIfMaximumConsumersAfterConfigUpdate() (gas: 164969) FunctionsSubscriptions_AddConsumer:test_AddConsumer_RevertIfNoSubscription() (gas: 12946) -FunctionsSubscriptions_AddConsumer:test_AddConsumer_RevertIfNotAllowedSender() (gas: 57809) -FunctionsSubscriptions_AddConsumer:test_AddConsumer_RevertIfNotSubscriptionOwner() (gas: 87177) +FunctionsSubscriptions_AddConsumer:test_AddConsumer_RevertIfNotAllowedSender() (gas: 102448) +FunctionsSubscriptions_AddConsumer:test_AddConsumer_RevertIfNotSubscriptionOwner() (gas: 87199) FunctionsSubscriptions_AddConsumer:test_AddConsumer_RevertIfPaused() (gas: 18094) -FunctionsSubscriptions_AddConsumer:test_AddConsumer_Success() (gas: 95480) +FunctionsSubscriptions_AddConsumer:test_AddConsumer_Success() (gas: 95524) FunctionsSubscriptions_CancelSubscription:test_CancelSubscription_RevertIfNoSubscription() (gas: 15041) -FunctionsSubscriptions_CancelSubscription:test_CancelSubscription_RevertIfNotAllowedSender() (gas: 57885) -FunctionsSubscriptions_CancelSubscription:test_CancelSubscription_RevertIfNotSubscriptionOwner() (gas: 89287) +FunctionsSubscriptions_CancelSubscription:test_CancelSubscription_RevertIfNotAllowedSender() (gas: 102524) +FunctionsSubscriptions_CancelSubscription:test_CancelSubscription_RevertIfNotSubscriptionOwner() (gas: 89309) FunctionsSubscriptions_CancelSubscription:test_CancelSubscription_RevertIfPaused() (gas: 20148) -FunctionsSubscriptions_CancelSubscription:test_CancelSubscription_RevertIfPendingRequests() (gas: 194325) -FunctionsSubscriptions_CancelSubscription:test_CancelSubscription_SuccessForfeitAllBalanceAsDeposit() (gas: 114506) -FunctionsSubscriptions_CancelSubscription:test_CancelSubscription_SuccessForfeitSomeBalanceAsDeposit() (gas: 125832) -FunctionsSubscriptions_CancelSubscription_ReceiveDeposit:test_CancelSubscription_SuccessRecieveDeposit() (gas: 74973) +FunctionsSubscriptions_CancelSubscription:test_CancelSubscription_RevertIfPendingRequests() (gas: 194369) +FunctionsSubscriptions_CancelSubscription:test_CancelSubscription_SuccessForfeitAllBalanceAsDeposit() (gas: 114541) +FunctionsSubscriptions_CancelSubscription:test_CancelSubscription_SuccessForfeitSomeBalanceAsDeposit() (gas: 125867) +FunctionsSubscriptions_CancelSubscription_ReceiveDeposit:test_CancelSubscription_SuccessRecieveDeposit() (gas: 75017) FunctionsSubscriptions_Constructor:test_Constructor_Success() (gas: 7654) -FunctionsSubscriptions_CreateSubscriptionWithConsumer:test_CreateSubscriptionWithConsumer_RevertIfNotAllowedSender() (gas: 28660) +FunctionsSubscriptions_CreateSubscriptionWithConsumer:test_CreateSubscriptionWithConsumer_RevertIfNotAllowedSender() (gas: 28704) FunctionsSubscriptions_CreateSubscriptionWithConsumer:test_CreateSubscriptionWithConsumer_RevertIfPaused() (gas: 17994) -FunctionsSubscriptions_CreateSubscriptionWithConsumer:test_CreateSubscriptionWithConsumer_Success() (gas: 351726) +FunctionsSubscriptions_CreateSubscriptionWithConsumer:test_CreateSubscriptionWithConsumer_Success() (gas: 351858) FunctionsSubscriptions_GetConsumer:test_GetConsumer_Success() (gas: 16226) FunctionsSubscriptions_GetFlags:test_GetFlags_SuccessInvalidSubscription() (gas: 13101) FunctionsSubscriptions_GetFlags:test_GetFlags_SuccessValidSubscription() (gas: 40903) @@ -168,23 +168,23 @@ FunctionsSubscriptions_OwnerWithdraw:test_OwnerWithdraw_SuccessPaysRecipient() ( FunctionsSubscriptions_OwnerWithdraw:test_OwnerWithdraw_SuccessSetsBalanceToZero() (gas: 37790) FunctionsSubscriptions_PendingRequestExists:test_PendingRequestExists_SuccessFalseIfNoPendingRequests() (gas: 14981) FunctionsSubscriptions_PendingRequestExists:test_PendingRequestExists_SuccessTrueIfPendingRequests() (gas: 176494) -FunctionsSubscriptions_ProposeSubscriptionOwnerTransfer:test_ProposeSubscriptionOwnerTransfer_RevertIfEmptyNewOwner() (gas: 27611) -FunctionsSubscriptions_ProposeSubscriptionOwnerTransfer:test_ProposeSubscriptionOwnerTransfer_RevertIfInvalidNewOwner() (gas: 57709) +FunctionsSubscriptions_ProposeSubscriptionOwnerTransfer:test_ProposeSubscriptionOwnerTransfer_RevertIfEmptyNewOwner() (gas: 27655) +FunctionsSubscriptions_ProposeSubscriptionOwnerTransfer:test_ProposeSubscriptionOwnerTransfer_RevertIfInvalidNewOwner() (gas: 57797) FunctionsSubscriptions_ProposeSubscriptionOwnerTransfer:test_ProposeSubscriptionOwnerTransfer_RevertIfNoSubscription() (gas: 15001) -FunctionsSubscriptions_ProposeSubscriptionOwnerTransfer:test_ProposeSubscriptionOwnerTransfer_RevertIfNotAllowedSender() (gas: 75131) +FunctionsSubscriptions_ProposeSubscriptionOwnerTransfer:test_ProposeSubscriptionOwnerTransfer_RevertIfNotAllowedSender() (gas: 119770) FunctionsSubscriptions_ProposeSubscriptionOwnerTransfer:test_ProposeSubscriptionOwnerTransfer_RevertIfNotSubscriptionOwner() (gas: 17960) FunctionsSubscriptions_ProposeSubscriptionOwnerTransfer:test_ProposeSubscriptionOwnerTransfer_RevertIfPaused() (gas: 20128) -FunctionsSubscriptions_ProposeSubscriptionOwnerTransfer:test_ProposeSubscriptionOwnerTransfer_Success() (gas: 68196) -FunctionsSubscriptions_ProposeSubscriptionOwnerTransfer:test_ProposeSubscriptionOwnerTransfer_SuccessChangeProposedOwner() (gas: 82749) +FunctionsSubscriptions_ProposeSubscriptionOwnerTransfer:test_ProposeSubscriptionOwnerTransfer_Success() (gas: 68240) +FunctionsSubscriptions_ProposeSubscriptionOwnerTransfer:test_ProposeSubscriptionOwnerTransfer_SuccessChangeProposedOwner() (gas: 82837) FunctionsSubscriptions_RecoverFunds:test_OwnerCancelSubscription_RevertIfNotOwner() (gas: 15554) FunctionsSubscriptions_RecoverFunds:test_RecoverFunds_Success() (gas: 41111) -FunctionsSubscriptions_RemoveConsumer:test_RemoveConsumer_RevertIfInvalidConsumer() (gas: 30260) +FunctionsSubscriptions_RemoveConsumer:test_RemoveConsumer_RevertIfInvalidConsumer() (gas: 30304) FunctionsSubscriptions_RemoveConsumer:test_RemoveConsumer_RevertIfNoSubscription() (gas: 15019) -FunctionsSubscriptions_RemoveConsumer:test_RemoveConsumer_RevertIfNotAllowedSender() (gas: 57800) -FunctionsSubscriptions_RemoveConsumer:test_RemoveConsumer_RevertIfNotSubscriptionOwner() (gas: 87223) +FunctionsSubscriptions_RemoveConsumer:test_RemoveConsumer_RevertIfNotAllowedSender() (gas: 102439) +FunctionsSubscriptions_RemoveConsumer:test_RemoveConsumer_RevertIfNotSubscriptionOwner() (gas: 87245) FunctionsSubscriptions_RemoveConsumer:test_RemoveConsumer_RevertIfPaused() (gas: 18049) -FunctionsSubscriptions_RemoveConsumer:test_RemoveConsumer_RevertIfPendingRequests() (gas: 191858) -FunctionsSubscriptions_RemoveConsumer:test_RemoveConsumer_Success() (gas: 41979) +FunctionsSubscriptions_RemoveConsumer:test_RemoveConsumer_RevertIfPendingRequests() (gas: 191902) +FunctionsSubscriptions_RemoveConsumer:test_RemoveConsumer_Success() (gas: 42023) FunctionsSubscriptions_SetFlags:test_SetFlags_RevertIfNoSubscription() (gas: 12891) FunctionsSubscriptions_SetFlags:test_SetFlags_RevertIfNotOwner() (gas: 15684) FunctionsSubscriptions_SetFlags:test_SetFlags_Success() (gas: 35594) @@ -192,34 +192,44 @@ FunctionsSubscriptions_TimeoutRequests:test_TimeoutRequests_RevertIfPaused() (ga FunctionsSubscriptions_TimeoutRequests:test_TimeoutRequests_RevertIfTimeoutNotExceeded() (gas: 25261) FunctionsSubscriptions_TimeoutRequests:test_TimeoutRequests_RevertInvalidRequest() (gas: 28242) FunctionsSubscriptions_TimeoutRequests:test_TimeoutRequests_Success() (gas: 57754) -FunctionsSubscriptions_createSubscription:test_CreateSubscription_RevertIfNotAllowedSender() (gas: 26390) +FunctionsSubscriptions_createSubscription:test_CreateSubscription_RevertIfNotAllowedSender() (gas: 26434) FunctionsSubscriptions_createSubscription:test_CreateSubscription_RevertIfPaused() (gas: 15759) -FunctionsSubscriptions_createSubscription:test_CreateSubscription_Success() (gas: 152576) -FunctionsTermsOfServiceAllowList_AcceptTermsOfService:testAcceptTermsOfService_InvalidSigner_vuln() (gas: 94830) -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: 1866530) -FunctionsTermsOfServiceAllowList_AcceptTermsOfService:test_AcceptTermsOfService_RevertIfRecipientIsNotSender() (gas: 26003) -FunctionsTermsOfServiceAllowList_AcceptTermsOfService:test_AcceptTermsOfService_SuccessIfAcceptingForContract() (gas: 1946562) -FunctionsTermsOfServiceAllowList_AcceptTermsOfService:test_AcceptTermsOfService_SuccessIfAcceptingForSelf() (gas: 103411) -FunctionsTermsOfServiceAllowList_BlockSender:test_BlockSender_RevertIfNotOwner() (gas: 15469) -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) -FunctionsTermsOfServiceAllowList_GetMessage:test_GetMessage_Success() (gas: 11583) -FunctionsTermsOfServiceAllowList_HasAccess:test_HasAccess_FalseWhenEnabled() (gas: 15925) -FunctionsTermsOfServiceAllowList_HasAccess:test_HasAccess_TrueWhenDisabled() (gas: 23430) -FunctionsTermsOfServiceAllowList_IsBlockedSender:test_IsBlockedSender_SuccessFalse() (gas: 15354) -FunctionsTermsOfServiceAllowList_IsBlockedSender:test_IsBlockedSender_SuccessTrue() (gas: 41957) -FunctionsTermsOfServiceAllowList_UnblockSender:test_UnblockSender_RevertIfNotOwner() (gas: 13525) -FunctionsTermsOfServiceAllowList_UnblockSender:test_UnblockSender_Success() (gas: 95199) -FunctionsTermsOfServiceAllowList_UpdateConfig:test_UpdateConfig_RevertIfNotOwner() (gas: 13727) +FunctionsSubscriptions_createSubscription:test_CreateSubscription_Success() (gas: 152708) +FunctionsTermsOfServiceAllowList_AcceptTermsOfService:testAcceptTermsOfService_InvalidSigner_vuln() (gas: 94864) +FunctionsTermsOfServiceAllowList_AcceptTermsOfService:test_AcceptTermsOfService_RevertIfAcceptorIsNotSender() (gas: 25859) +FunctionsTermsOfServiceAllowList_AcceptTermsOfService:test_AcceptTermsOfService_RevertIfBlockedSender() (gas: 88990) +FunctionsTermsOfServiceAllowList_AcceptTermsOfService:test_AcceptTermsOfService_RevertIfInvalidSigner() (gas: 23619) +FunctionsTermsOfServiceAllowList_AcceptTermsOfService:test_AcceptTermsOfService_RevertIfRecipientContractIsNotSender() (gas: 1866552) +FunctionsTermsOfServiceAllowList_AcceptTermsOfService:test_AcceptTermsOfService_RevertIfRecipientIsNotSender() (gas: 26025) +FunctionsTermsOfServiceAllowList_AcceptTermsOfService:test_AcceptTermsOfService_SuccessIfAcceptingForContract() (gas: 1946628) +FunctionsTermsOfServiceAllowList_AcceptTermsOfService:test_AcceptTermsOfService_SuccessIfAcceptingForSelf() (gas: 103533) +FunctionsTermsOfServiceAllowList_BlockSender:test_BlockSender_RevertIfNotOwner() (gas: 15491) +FunctionsTermsOfServiceAllowList_BlockSender:test_BlockSender_Success() (gas: 96662) +FunctionsTermsOfServiceAllowList_Constructor:test_Constructor_Success() (gas: 12253) +FunctionsTermsOfServiceAllowList_GetAllAllowedSenders:test_GetAllAllowedSenders_Success() (gas: 19199) +FunctionsTermsOfServiceAllowList_GetAllowedSendersCount:test_GetAllowedSendersCount_Success() (gas: 12995) +FunctionsTermsOfServiceAllowList_GetAllowedSendersInRange:test_GetAllowedSendersInRange_RevertIfAllowedSendersIsEmpty() (gas: 12184656) +FunctionsTermsOfServiceAllowList_GetAllowedSendersInRange:test_GetAllowedSendersInRange_RevertIfEndIsAfterLastAllowedSender() (gas: 16571) +FunctionsTermsOfServiceAllowList_GetAllowedSendersInRange:test_GetAllowedSendersInRange_RevertIfStartIsAfterEnd() (gas: 13301) +FunctionsTermsOfServiceAllowList_GetAllowedSendersInRange:test_GetAllowedSendersInRange_Success() (gas: 20448) +FunctionsTermsOfServiceAllowList_GetBlockedSendersCount:test_GetBlockedSendersCount_Success() (gas: 12931) +FunctionsTermsOfServiceAllowList_GetBlockedSendersInRange:test_GetBlockedSendersInRange_RevertIfAllowedSendersIsEmpty() (gas: 12184660) +FunctionsTermsOfServiceAllowList_GetBlockedSendersInRange:test_GetBlockedSendersInRange_RevertIfEndIsAfterLastAllowedSender() (gas: 16549) +FunctionsTermsOfServiceAllowList_GetBlockedSendersInRange:test_GetBlockedSendersInRange_RevertIfStartIsAfterEnd() (gas: 13367) +FunctionsTermsOfServiceAllowList_GetBlockedSendersInRange:test_GetBlockedSendersInRange_Success() (gas: 18493) +FunctionsTermsOfServiceAllowList_GetConfig:test_GetConfig_Success() (gas: 15751) +FunctionsTermsOfServiceAllowList_GetMessage:test_GetMessage_Success() (gas: 11593) +FunctionsTermsOfServiceAllowList_HasAccess:test_HasAccess_FalseWhenEnabled() (gas: 15969) +FunctionsTermsOfServiceAllowList_HasAccess:test_HasAccess_TrueWhenDisabled() (gas: 23496) +FunctionsTermsOfServiceAllowList_IsBlockedSender:test_IsBlockedSender_SuccessFalse() (gas: 15445) +FunctionsTermsOfServiceAllowList_IsBlockedSender:test_IsBlockedSender_SuccessTrue() (gas: 86643) +FunctionsTermsOfServiceAllowList_UnblockSender:test_UnblockSender_RevertIfNotOwner() (gas: 13502) +FunctionsTermsOfServiceAllowList_UnblockSender:test_UnblockSender_Success() (gas: 96216) +FunctionsTermsOfServiceAllowList_UpdateConfig:test_UpdateConfig_RevertIfNotOwner() (gas: 13749) FunctionsTermsOfServiceAllowList_UpdateConfig:test_UpdateConfig_Success() (gas: 22073) -Gas_AcceptTermsOfService:test_AcceptTermsOfService_Gas() (gas: 84690) -Gas_AddConsumer:test_AddConsumer_Gas() (gas: 79087) -Gas_CreateSubscription:test_CreateSubscription_Gas() (gas: 73375) +Gas_AcceptTermsOfService:test_AcceptTermsOfService_Gas() (gas: 84702) +Gas_AddConsumer:test_AddConsumer_Gas() (gas: 79131) +Gas_CreateSubscription:test_CreateSubscription_Gas() (gas: 73419) Gas_FundSubscription:test_FundSubscription_Gas() (gas: 38546) Gas_SendRequest:test_SendRequest_MaximumGas() (gas: 979631) Gas_SendRequest:test_SendRequest_MinimumGas() (gas: 157578) \ No newline at end of file diff --git a/contracts/gas-snapshots/l2ep.gas-snapshot b/contracts/gas-snapshots/l2ep.gas-snapshot new file mode 100644 index 0000000000..1f229f7d1d --- /dev/null +++ b/contracts/gas-snapshots/l2ep.gas-snapshot @@ -0,0 +1,146 @@ +ArbitrumCrossDomainForwarder_AcceptL1Ownership:test_CallableByPendingL1Owner() (gas: 37312) +ArbitrumCrossDomainForwarder_AcceptL1Ownership:test_NotCallableByNonPendingOwners() (gas: 12963) +ArbitrumCrossDomainForwarder_Constructor:test_InitialState() (gas: 18431) +ArbitrumCrossDomainForwarder_Forward:test_Forward() (gas: 47601) +ArbitrumCrossDomainForwarder_Forward:test_ForwardRevert() (gas: 22151) +ArbitrumCrossDomainForwarder_Forward:test_NotCallableByUnknownAddress() (gas: 16048) +ArbitrumCrossDomainForwarder_TransferL1Ownership:test_CallableByL1Owner() (gas: 41408) +ArbitrumCrossDomainForwarder_TransferL1Ownership:test_CallableByL1OwnerOrZeroAddress() (gas: 19312) +ArbitrumCrossDomainForwarder_TransferL1Ownership:test_NotCallableByL2Owner() (gas: 18323) +ArbitrumCrossDomainForwarder_TransferL1Ownership:test_NotCallableByNonOwners() (gas: 13200) +ArbitrumCrossDomainGovernor_AcceptL1Ownership:test_CallableByPendingL1Owner() (gas: 37312) +ArbitrumCrossDomainGovernor_AcceptL1Ownership:test_NotCallableByNonPendingOwners() (gas: 12963) +ArbitrumCrossDomainGovernor_Constructor:test_InitialState() (gas: 18454) +ArbitrumCrossDomainGovernor_Forward:test_CallableByL2Owner() (gas: 49720) +ArbitrumCrossDomainGovernor_Forward:test_Forward() (gas: 47658) +ArbitrumCrossDomainGovernor_Forward:test_ForwardRevert() (gas: 24348) +ArbitrumCrossDomainGovernor_Forward:test_NotCallableByUnknownAddress() (gas: 18247) +ArbitrumCrossDomainGovernor_ForwardDelegate:test_BubbleUpRevert() (gas: 19386) +ArbitrumCrossDomainGovernor_ForwardDelegate:test_CallableByCrossDomainMessengerAddressOrL1Owner() (gas: 60617) +ArbitrumCrossDomainGovernor_ForwardDelegate:test_CallableByL2Owner() (gas: 62723) +ArbitrumCrossDomainGovernor_ForwardDelegate:test_NotCallableByUnknownAddress() (gas: 18237) +ArbitrumCrossDomainGovernor_ForwardDelegate:test_RevertsBatchWhenOneCallFails() (gas: 64110) +ArbitrumCrossDomainGovernor_TransferL1Ownership:test_CallableByL1Owner() (gas: 41408) +ArbitrumCrossDomainGovernor_TransferL1Ownership:test_CallableByL1OwnerOrZeroAddress() (gas: 19312) +ArbitrumCrossDomainGovernor_TransferL1Ownership:test_NotCallableByL2Owner() (gas: 18323) +ArbitrumCrossDomainGovernor_TransferL1Ownership:test_NotCallableByNonOwners() (gas: 13200) +ArbitrumSequencerUptimeFeed_AggregatorInterfaceGasCosts:test_GasUsageForGetAnswer() (gas: 92118) +ArbitrumSequencerUptimeFeed_AggregatorInterfaceGasCosts:test_GasUsageForGetRoundData() (gas: 92673) +ArbitrumSequencerUptimeFeed_AggregatorInterfaceGasCosts:test_GasUsageForGetTimestamp() (gas: 92039) +ArbitrumSequencerUptimeFeed_AggregatorInterfaceGasCosts:test_GasUsageForLatestAnswer() (gas: 89813) +ArbitrumSequencerUptimeFeed_AggregatorInterfaceGasCosts:test_GasUsageForLatestRound() (gas: 89705) +ArbitrumSequencerUptimeFeed_AggregatorInterfaceGasCosts:test_GasUsageForLatestRoundData() (gas: 90246) +ArbitrumSequencerUptimeFeed_AggregatorInterfaceGasCosts:test_GasUsageForLatestTimestamp() (gas: 89690) +ArbitrumSequencerUptimeFeed_AggregatorV3Interface:test_AggregatorV3Interface() (gas: 98825) +ArbitrumSequencerUptimeFeed_AggregatorV3Interface:test_Return0WhenRoundDoesNotExistYet() (gas: 18309) +ArbitrumSequencerUptimeFeed_Constants:test_InitialState() (gas: 5684) +ArbitrumSequencerUptimeFeed_GasCosts:test_GasCosts() (gas: 97495) +ArbitrumSequencerUptimeFeed_ProtectReadsOnAggregatorV2V3InterfaceFunctions:test_AggregatorV2V3InterfaceAllowReadsIfConsumingContractIsWhitelisted() (gas: 602711) +ArbitrumSequencerUptimeFeed_ProtectReadsOnAggregatorV2V3InterfaceFunctions:test_AggregatorV2V3InterfaceDisallowReadsIfConsumingContractIsNotWhitelisted() (gas: 573802) +ArbitrumSequencerUptimeFeed_UpdateStatus:test_IgnoreOutOfOrderUpdates() (gas: 98976) +ArbitrumSequencerUptimeFeed_UpdateStatus:test_RevertIfNotL2CrossDomainMessengerAddr() (gas: 15416) +ArbitrumSequencerUptimeFeed_UpdateStatus:test_UpdateStatusWhenStatusChangeAndNoTimeChange() (gas: 113269) +ArbitrumSequencerUptimeFeed_UpdateStatus:test_UpdateStatusWhenStatusChangeAndTimeChange() (gas: 113329) +ArbitrumValidator_Validate:test_PostSequencerOffline() (gas: 69068) +OptimismCrossDomainForwarder_AcceptL1Ownership:test_CallableByPendingL1Owner() (gas: 46888) +OptimismCrossDomainForwarder_AcceptL1Ownership:test_NotCallableByNonPendingOwners() (gas: 22155) +OptimismCrossDomainForwarder_Constructor:test_InitialState() (gas: 18266) +OptimismCrossDomainForwarder_Forward:test_Forward() (gas: 58025) +OptimismCrossDomainForwarder_Forward:test_ForwardRevert() (gas: 32546) +OptimismCrossDomainForwarder_Forward:test_NotCallableByUnknownAddress() (gas: 13859) +OptimismCrossDomainForwarder_TransferL1Ownership:test_CallableByL1Owner() (gas: 48886) +OptimismCrossDomainForwarder_TransferL1Ownership:test_CallableByL1OwnerOrZeroAddress() (gas: 28767) +OptimismCrossDomainForwarder_TransferL1Ownership:test_NotCallableByL2Owner() (gas: 16134) +OptimismCrossDomainForwarder_TransferL1Ownership:test_NotCallableByNonOwners() (gas: 11011) +OptimismCrossDomainGovernor_AcceptL1Ownership:test_CallableByPendingL1Owner() (gas: 46888) +OptimismCrossDomainGovernor_AcceptL1Ownership:test_NotCallableByNonPendingOwners() (gas: 22155) +OptimismCrossDomainGovernor_Constructor:test_InitialState() (gas: 18289) +OptimismCrossDomainGovernor_Forward:test_CallableByL2Owner() (gas: 47557) +OptimismCrossDomainGovernor_Forward:test_Forward() (gas: 58096) +OptimismCrossDomainGovernor_Forward:test_ForwardRevert() (gas: 32627) +OptimismCrossDomainGovernor_Forward:test_NotCallableByUnknownAddress() (gas: 16061) +OptimismCrossDomainGovernor_ForwardDelegate:test_BubbleUpRevert() (gas: 29181) +OptimismCrossDomainGovernor_ForwardDelegate:test_CallableByCrossDomainMessengerAddressOrL1Owner() (gas: 72695) +OptimismCrossDomainGovernor_ForwardDelegate:test_CallableByL2Owner() (gas: 72685) +OptimismCrossDomainGovernor_ForwardDelegate:test_NotCallableByUnknownAddress() (gas: 16051) +OptimismCrossDomainGovernor_ForwardDelegate:test_RevertsBatchWhenOneCallFails() (gas: 75908) +OptimismCrossDomainGovernor_TransferL1Ownership:test_CallableByL1Owner() (gas: 48886) +OptimismCrossDomainGovernor_TransferL1Ownership:test_CallableByL1OwnerOrZeroAddress() (gas: 28767) +OptimismCrossDomainGovernor_TransferL1Ownership:test_NotCallableByL2Owner() (gas: 16134) +OptimismCrossDomainGovernor_TransferL1Ownership:test_NotCallableByNonOwners() (gas: 11011) +OptimismSequencerUptimeFeed_AggregatorInterfaceGasCosts:test_GasUsageForGetAnswer() (gas: 59095) +OptimismSequencerUptimeFeed_AggregatorInterfaceGasCosts:test_GasUsageForGetRoundData() (gas: 59635) +OptimismSequencerUptimeFeed_AggregatorInterfaceGasCosts:test_GasUsageForGetTimestamp() (gas: 58950) +OptimismSequencerUptimeFeed_AggregatorInterfaceGasCosts:test_GasUsageForLatestAnswer() (gas: 56887) +OptimismSequencerUptimeFeed_AggregatorInterfaceGasCosts:test_GasUsageForLatestRound() (gas: 56773) +OptimismSequencerUptimeFeed_AggregatorInterfaceGasCosts:test_GasUsageForLatestRoundData() (gas: 57309) +OptimismSequencerUptimeFeed_AggregatorInterfaceGasCosts:test_GasUsageForLatestTimestamp() (gas: 56740) +OptimismSequencerUptimeFeed_AggregatorV3Interface:test_AggregatorV3Interface() (gas: 65617) +OptimismSequencerUptimeFeed_AggregatorV3Interface:test_RevertGetAnswerWhenRoundDoesNotExistYet() (gas: 17679) +OptimismSequencerUptimeFeed_AggregatorV3Interface:test_RevertGetRoundDataWhenRoundDoesNotExistYet() (gas: 17897) +OptimismSequencerUptimeFeed_AggregatorV3Interface:test_RevertGetTimestampWhenRoundDoesNotExistYet() (gas: 17603) +OptimismSequencerUptimeFeed_Constructor:test_InitialState() (gas: 21078) +OptimismSequencerUptimeFeed_GasCosts:test_GasCosts() (gas: 67197) +OptimismSequencerUptimeFeed_ProtectReadsOnAggregatorV2V3InterfaceFunctions:test_AggregatorV2V3InterfaceAllowReadsIfConsumingContractIsWhitelisted() (gas: 597640) +OptimismSequencerUptimeFeed_ProtectReadsOnAggregatorV2V3InterfaceFunctions:test_AggregatorV2V3InterfaceDisallowReadsIfConsumingContractIsNotWhitelisted() (gas: 573807) +OptimismSequencerUptimeFeed_UpdateStatus:test_IgnoreOutOfOrderUpdates() (gas: 66532) +OptimismSequencerUptimeFeed_UpdateStatus:test_RevertIfNotL2CrossDomainMessengerAddr() (gas: 13200) +OptimismSequencerUptimeFeed_UpdateStatus:test_RevertIfNotL2CrossDomainMessengerAddrAndNotL1SenderAddr() (gas: 23607) +OptimismSequencerUptimeFeed_UpdateStatus:test_UpdateStatusWhenNoChange() (gas: 74035) +OptimismSequencerUptimeFeed_UpdateStatus:test_UpdateStatusWhenStatusChangeAndNoTimeChange() (gas: 96155) +OptimismSequencerUptimeFeed_UpdateStatus:test_UpdateStatusWhenStatusChangeAndTimeChange() (gas: 96215) +OptimismValidator_SetGasLimit:test_CorrectlyUpdatesTheGasLimit() (gas: 15503) +OptimismValidator_Validate:test_PostSequencerOffline() (gas: 74813) +OptimismValidator_Validate:test_PostSequencerStatusWhenThereIsNotStatusChange() (gas: 74869) +OptimismValidator_Validate:test_RevertsIfCalledByAnAccountWithNoAccess() (gas: 15563) +ScrollCrossDomainForwarder_AcceptL1Ownership:test_CallableByPendingL1Owner() (gas: 46988) +ScrollCrossDomainForwarder_AcceptL1Ownership:test_NotCallableByNonPendingOwners() (gas: 22207) +ScrollCrossDomainForwarder_Constructor:test_InitialState() (gas: 17930) +ScrollCrossDomainForwarder_Forward:test_Forward() (gas: 58092) +ScrollCrossDomainForwarder_Forward:test_ForwardRevert() (gas: 32619) +ScrollCrossDomainForwarder_Forward:test_NotCallableByUnknownAddress() (gas: 13859) +ScrollCrossDomainForwarder_TransferL1Ownership:test_CallableByL1Owner() (gas: 48952) +ScrollCrossDomainForwarder_TransferL1Ownership:test_CallableByL1OwnerOrZeroAddress() (gas: 28833) +ScrollCrossDomainForwarder_TransferL1Ownership:test_NotCallableByL2Owner() (gas: 16134) +ScrollCrossDomainForwarder_TransferL1Ownership:test_NotCallableByNonOwners() (gas: 11011) +ScrollCrossDomainGovernor_AcceptL1Ownership:test_CallableByPendingL1Owner() (gas: 46988) +ScrollCrossDomainGovernor_AcceptL1Ownership:test_NotCallableByNonPendingOwners() (gas: 22207) +ScrollCrossDomainGovernor_Constructor:test_InitialState() (gas: 17953) +ScrollCrossDomainGovernor_Forward:test_CallableByL2Owner() (gas: 47552) +ScrollCrossDomainGovernor_Forward:test_Forward() (gas: 58158) +ScrollCrossDomainGovernor_Forward:test_ForwardRevert() (gas: 32697) +ScrollCrossDomainGovernor_Forward:test_NotCallableByUnknownAddress() (gas: 16058) +ScrollCrossDomainGovernor_ForwardDelegate:test_BubbleUpRevert() (gas: 29248) +ScrollCrossDomainGovernor_ForwardDelegate:test_CallableByCrossDomainMessengerAddressOrL1Owner() (gas: 72756) +ScrollCrossDomainGovernor_ForwardDelegate:test_CallableByL2Owner() (gas: 72746) +ScrollCrossDomainGovernor_ForwardDelegate:test_NotCallableByUnknownAddress() (gas: 16048) +ScrollCrossDomainGovernor_ForwardDelegate:test_RevertsBatchWhenOneCallFails() (gas: 75970) +ScrollCrossDomainGovernor_TransferL1Ownership:test_CallableByL1Owner() (gas: 48952) +ScrollCrossDomainGovernor_TransferL1Ownership:test_CallableByL1OwnerOrZeroAddress() (gas: 28833) +ScrollCrossDomainGovernor_TransferL1Ownership:test_NotCallableByL2Owner() (gas: 16134) +ScrollCrossDomainGovernor_TransferL1Ownership:test_NotCallableByNonOwners() (gas: 11011) +ScrollSequencerUptimeFeed_AggregatorInterfaceGasCosts:test_GasUsageForGetAnswer() (gas: 57250) +ScrollSequencerUptimeFeed_AggregatorInterfaceGasCosts:test_GasUsageForGetRoundData() (gas: 57780) +ScrollSequencerUptimeFeed_AggregatorInterfaceGasCosts:test_GasUsageForGetTimestamp() (gas: 57105) +ScrollSequencerUptimeFeed_AggregatorInterfaceGasCosts:test_GasUsageForLatestAnswer() (gas: 54888) +ScrollSequencerUptimeFeed_AggregatorInterfaceGasCosts:test_GasUsageForLatestRound() (gas: 54768) +ScrollSequencerUptimeFeed_AggregatorInterfaceGasCosts:test_GasUsageForLatestRoundData() (gas: 55473) +ScrollSequencerUptimeFeed_AggregatorInterfaceGasCosts:test_GasUsageForLatestTimestamp() (gas: 54758) +ScrollSequencerUptimeFeed_AggregatorV3Interface:test_AggregatorV3Interface() (gas: 63903) +ScrollSequencerUptimeFeed_AggregatorV3Interface:test_RevertGetAnswerWhenRoundDoesNotExistYet() (gas: 17675) +ScrollSequencerUptimeFeed_AggregatorV3Interface:test_RevertGetRoundDataWhenRoundDoesNotExistYet() (gas: 17893) +ScrollSequencerUptimeFeed_AggregatorV3Interface:test_RevertGetTimestampWhenRoundDoesNotExistYet() (gas: 17599) +ScrollSequencerUptimeFeed_Constructor:test_InitialState() (gas: 102485) +ScrollSequencerUptimeFeed_GasCosts:test_GasCosts() (gas: 64888) +ScrollSequencerUptimeFeed_ProtectReadsOnAggregatorV2V3InterfaceFunctions:test_AggregatorV2V3InterfaceAllowReadsIfConsumingContractIsWhitelisted() (gas: 597491) +ScrollSequencerUptimeFeed_ProtectReadsOnAggregatorV2V3InterfaceFunctions:test_AggregatorV2V3InterfaceDisallowReadsIfConsumingContractIsNotWhitelisted() (gas: 573807) +ScrollSequencerUptimeFeed_UpdateStatus:test_IgnoreOutOfOrderUpdates() (gas: 64417) +ScrollSequencerUptimeFeed_UpdateStatus:test_RevertIfNotL2CrossDomainMessengerAddr() (gas: 13200) +ScrollSequencerUptimeFeed_UpdateStatus:test_RevertIfNotL2CrossDomainMessengerAddrAndNotL1SenderAddr() (gas: 23607) +ScrollSequencerUptimeFeed_UpdateStatus:test_UpdateStatusWhenNoChange() (gas: 71618) +ScrollSequencerUptimeFeed_UpdateStatus:test_UpdateStatusWhenStatusChangeAndNoTimeChange() (gas: 92018) +ScrollSequencerUptimeFeed_UpdateStatus:test_UpdateStatusWhenStatusChangeAndTimeChange() (gas: 92078) +ScrollValidator_SetGasLimit:test_CorrectlyUpdatesTheGasLimit() (gas: 15503) +ScrollValidator_Validate:test_PostSequencerOffline() (gas: 75094) +ScrollValidator_Validate:test_PostSequencerStatusWhenThereIsNotStatusChange() (gas: 75156) +ScrollValidator_Validate:test_RevertsIfCalledByAnAccountWithNoAccess() (gas: 15563) \ No newline at end of file diff --git a/contracts/remappings.txt b/contracts/remappings.txt index d5215a8979..a314323752 100644 --- a/contracts/remappings.txt +++ b/contracts/remappings.txt @@ -1,7 +1,8 @@ -ds-test/=foundry-lib/forge-std/lib/ds-test/src -forge-std/=foundry-lib/forge-std/src +ds-test/=foundry-lib/forge-std/lib/ds-test/src/ +forge-std/=foundry-lib/forge-std/src/ @openzeppelin/=node_modules/@openzeppelin/ @arbitrum/=node_modules/@arbitrum/ hardhat/=node_modules/hardhat/ -@eth-optimism/=node_modules/@eth-optimism +@eth-optimism/=node_modules/@eth-optimism/ +@scroll-tech/=node_modules/@scroll-tech/ diff --git a/contracts/scripts/generate-automation-master-interface.ts b/contracts/scripts/generate-automation-master-interface.ts index de71c56806..78c09cf283 100644 --- a/contracts/scripts/generate-automation-master-interface.ts +++ b/contracts/scripts/generate-automation-master-interface.ts @@ -2,24 +2,20 @@ * @description this script generates a master interface for interacting with the automation registry * @notice run this script with pnpm ts-node ./scripts/generate-automation-master-interface.ts */ -import { KeeperRegistry2_1__factory as KeeperRegistry } from '../typechain/factories/KeeperRegistry2_1__factory' -import { KeeperRegistryLogicA2_1__factory as KeeperRegistryLogicA } from '../typechain/factories/KeeperRegistryLogicA2_1__factory' -import { KeeperRegistryLogicB2_1__factory as KeeperRegistryLogicB } from '../typechain/factories/KeeperRegistryLogicB2_1__factory' +import { AutomationRegistry2_2__factory as Registry } from '../typechain/factories/AutomationRegistry2_2__factory' +import { AutomationRegistryLogicA2_2__factory as RegistryLogicA } from '../typechain/factories/AutomationRegistryLogicA2_2__factory' +import { AutomationRegistryLogicB2_2__factory as RegistryLogicB } from '../typechain/factories/AutomationRegistryLogicB2_2__factory' import { utils } from 'ethers' import fs from 'fs' import { exec } from 'child_process' -const dest = 'src/v0.8/automation/interfaces/v2_1' -const srcDest = `${dest}/IKeeperRegistryMaster.sol` +const dest = 'src/v0.8/automation/dev/interfaces/v2_2' +const srcDest = `${dest}/IAutomationRegistryMaster.sol` const tmpDest = `${dest}/tmp.txt` const combinedABI = [] const abiSet = new Set() -const abis = [ - KeeperRegistry.abi, - KeeperRegistryLogicA.abi, - KeeperRegistryLogicB.abi, -] +const abis = [Registry.abi, RegistryLogicA.abi, RegistryLogicB.abi] for (const abi of abis) { for (const entry of abi) { @@ -44,7 +40,7 @@ const checksum = utils.id(abis.join('')) fs.writeFileSync(`${tmpDest}`, JSON.stringify(combinedABI)) const cmd = ` -cat ${tmpDest} | pnpm abi-to-sol --solidity-version ^0.8.4 --license MIT > ${srcDest} IKeeperRegistryMaster; +cat ${tmpDest} | pnpm abi-to-sol --solidity-version ^0.8.4 --license MIT > ${srcDest} IAutomationRegistryMaster; echo "// abi-checksum: ${checksum}" | cat - ${srcDest} > ${tmpDest} && mv ${tmpDest} ${srcDest}; pnpm prettier --write ${srcDest}; ` diff --git a/contracts/scripts/native_solc_compile_all_automation b/contracts/scripts/native_solc_compile_all_automation index ddf6c2c8bf..379b647ffe 100755 --- a/contracts/scripts/native_solc_compile_all_automation +++ b/contracts/scripts/native_solc_compile_all_automation @@ -57,10 +57,18 @@ compileContract automation/v2_1/AutomationRegistrar2_1.sol compileContract automation/v2_1/KeeperRegistry2_1.sol compileContract automation/v2_1/KeeperRegistryLogicA2_1.sol compileContract automation/v2_1/KeeperRegistryLogicB2_1.sol +compileContract automation/v2_1/AutomationUtils2_1.sol compileContract automation/interfaces/v2_1/IKeeperRegistryMaster.sol + +compileContract automation/dev/v2_2/AutomationRegistrar2_2.sol +compileContract automation/dev/v2_2/AutomationRegistry2_2.sol +compileContract automation/dev/v2_2/AutomationRegistryLogicA2_2.sol +compileContract automation/dev/v2_2/AutomationRegistryLogicB2_2.sol +compileContract automation/dev/v2_2/AutomationUtils2_2.sol +compileContract automation/dev/interfaces/v2_2/IAutomationRegistryMaster.sol + compileContract automation/interfaces/ILogAutomation.sol -compileContract automation/v2_1/AutomationUtils2_1.sol -compileContract automation/v2_1/AutomationForwarderLogic.sol +compileContract automation/AutomationForwarderLogic.sol compileContract automation/testhelpers/LogTriggeredStreamsLookup.sol compileContract automation/testhelpers/DummyProtocol.sol diff --git a/contracts/scripts/native_solc_compile_all_l2ep b/contracts/scripts/native_solc_compile_all_l2ep new file mode 100755 index 0000000000..1b9f5fb611 --- /dev/null +++ b/contracts/scripts/native_solc_compile_all_l2ep @@ -0,0 +1,70 @@ +#!/usr/bin/env bash + +########### +# Logging # +########### + +set -e + +echo " ┌──────────────────────────────────────────────┐" +echo " │ Compiling L2EP contracts... │" +echo " └──────────────────────────────────────────────┘" + +###################### +# Helper Variable(s) # +###################### + +export SOLC_VERSION="0.8.19" + +SCRIPTPATH="$( + cd "$(dirname "$0")" >/dev/null 2>&1 + pwd -P +)" + +ROOT="$( + cd "$(dirname "$0")" >/dev/null 2>&1 + cd ../ && pwd -P +)" + +###################### +# Helper Function(s) # +###################### + +compileContract() { + local optimize_runs=1000000 + local version="$1" + local srcpath="$2" + solc \ + @openzeppelin/=$ROOT/node_modules/@openzeppelin/ \ + @eth-optimism/=$ROOT/node_modules/@eth-optimism/ \ + @scroll-tech/=$ROOT/node_modules/@scroll-tech/ \ + --overwrite --optimize --optimize-runs $optimize_runs --metadata-hash none \ + -o $ROOT/solc/v$SOLC_VERSION/l2ep/"$version" \ + --abi --bin \ + --allow-paths $ROOT/src/v0.8,$ROOT/node_modules \ + $ROOT/src/v0.8/l2ep/"$srcpath" +} + +################# +# Version 1.0.0 # +################# + +python3 -m pip install --require-hashes -r $SCRIPTPATH/requirements.txt + +solc-select install $SOLC_VERSION +solc-select use $SOLC_VERSION + +compileContract v1_0_0 dev/arbitrum/ArbitrumValidator.sol +compileContract v1_0_0 dev/arbitrum/ArbitrumSequencerUptimeFeed.sol +compileContract v1_0_0 dev/arbitrum/ArbitrumCrossDomainForwarder.sol +compileContract v1_0_0 dev/arbitrum/ArbitrumCrossDomainGovernor.sol + +compileContract v1_0_0 dev/optimism/OptimismValidator.sol +compileContract v1_0_0 dev/optimism/OptimismSequencerUptimeFeed.sol +compileContract v1_0_0 dev/optimism/OptimismCrossDomainForwarder.sol +compileContract v1_0_0 dev/optimism/OptimismCrossDomainGovernor.sol + +compileContract v1_0_0 dev/scroll/ScrollValidator.sol +compileContract v1_0_0 dev/scroll/ScrollSequencerUptimeFeed.sol +compileContract v1_0_0 dev/scroll/ScrollCrossDomainForwarder.sol +compileContract v1_0_0 dev/scroll/ScrollCrossDomainGovernor.sol diff --git a/contracts/scripts/native_solc_compile_all_shared b/contracts/scripts/native_solc_compile_all_shared index 9178237b8a..eeaa990234 100755 --- a/contracts/scripts/native_solc_compile_all_shared +++ b/contracts/scripts/native_solc_compile_all_shared @@ -32,3 +32,4 @@ compileContract shared/token/ERC677/BurnMintERC677.sol compileContract shared/token/ERC677/LinkToken.sol compileContract shared/mocks/WERC20Mock.sol compileContract vendor/openzeppelin-solidity/v4.8.3/contracts/token/ERC20/ERC20.sol +compileContract shared/test/helpers/ChainReaderTestContract.sol diff --git a/contracts/scripts/native_solc_compile_all_vrf b/contracts/scripts/native_solc_compile_all_vrf index 828ba79051..3b6b96d2f5 100755 --- a/contracts/scripts/native_solc_compile_all_vrf +++ b/contracts/scripts/native_solc_compile_all_vrf @@ -101,6 +101,8 @@ compileContract vrf/testhelpers/VRFLoadTestOwnerlessConsumer.sol compileContract vrf/testhelpers/VRFLoadTestExternalSubOwner.sol compileContract vrf/testhelpers/VRFV2LoadTestWithMetrics.sol compileContract vrf/testhelpers/VRFV2OwnerTestConsumer.sol +compileContractAltOpts vrf/testhelpers/VRFCoordinatorTestV2.sol 10000 +compileContract vrf/testhelpers/VRFMockETHLINKAggregator.sol # Helper contracts compileContract vrf/interfaces/IAuthorizedReceiver.sol diff --git a/contracts/src/v0.8/automation/v2_1/AutomationForwarder.sol b/contracts/src/v0.8/automation/AutomationForwarder.sol similarity index 97% rename from contracts/src/v0.8/automation/v2_1/AutomationForwarder.sol rename to contracts/src/v0.8/automation/AutomationForwarder.sol index e5a80ce325..f4088ed07f 100644 --- a/contracts/src/v0.8/automation/v2_1/AutomationForwarder.sol +++ b/contracts/src/v0.8/automation/AutomationForwarder.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.16; -import {IAutomationRegistryConsumer} from "../interfaces/IAutomationRegistryConsumer.sol"; +import {IAutomationRegistryConsumer} from "./interfaces/IAutomationRegistryConsumer.sol"; uint256 constant PERFORM_GAS_CUSHION = 5_000; diff --git a/contracts/src/v0.8/automation/v2_1/AutomationForwarderLogic.sol b/contracts/src/v0.8/automation/AutomationForwarderLogic.sol similarity index 80% rename from contracts/src/v0.8/automation/v2_1/AutomationForwarderLogic.sol rename to contracts/src/v0.8/automation/AutomationForwarderLogic.sol index a7903c379d..76da5f68cb 100644 --- a/contracts/src/v0.8/automation/v2_1/AutomationForwarderLogic.sol +++ b/contracts/src/v0.8/automation/AutomationForwarderLogic.sol @@ -1,8 +1,8 @@ // SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.16; -import {IAutomationRegistryConsumer} from "../interfaces/IAutomationRegistryConsumer.sol"; -import {ITypeAndVersion} from "../../shared/interfaces/ITypeAndVersion.sol"; +import {IAutomationRegistryConsumer} from "./interfaces/IAutomationRegistryConsumer.sol"; +import {ITypeAndVersion} from "../shared/interfaces/ITypeAndVersion.sol"; contract AutomationForwarderLogic is ITypeAndVersion { IAutomationRegistryConsumer private s_registry; diff --git a/contracts/src/v0.8/automation/dev/interfaces/v2_2/IAutomationRegistryMaster.sol b/contracts/src/v0.8/automation/dev/interfaces/v2_2/IAutomationRegistryMaster.sol new file mode 100644 index 0000000000..a72177bef2 --- /dev/null +++ b/contracts/src/v0.8/automation/dev/interfaces/v2_2/IAutomationRegistryMaster.sol @@ -0,0 +1,316 @@ +// abi-checksum: 0x0ed34e4b36bd7b4a5447152c2d61491e6ba7ed944b11e4dfef4fea184708975e +// SPDX-License-Identifier: MIT +// !! THIS FILE WAS AUTOGENERATED BY abi-to-sol v0.6.6. SEE SOURCE BELOW. !! +pragma solidity ^0.8.4; + +interface IAutomationRegistryMaster { + error ArrayHasNoEntries(); + error CannotCancel(); + error CheckDataExceedsLimit(); + error ConfigDigestMismatch(); + error DuplicateEntry(); + error DuplicateSigners(); + error GasLimitCanOnlyIncrease(); + error GasLimitOutsideRange(); + error IncorrectNumberOfFaultyOracles(); + error IncorrectNumberOfSignatures(); + error IncorrectNumberOfSigners(); + error IndexOutOfRange(); + error InsufficientFunds(); + error InvalidDataLength(); + error InvalidPayee(); + error InvalidRecipient(); + error InvalidReport(); + error InvalidSigner(); + error InvalidTransmitter(); + error InvalidTrigger(); + error InvalidTriggerType(); + error MaxCheckDataSizeCanOnlyIncrease(); + error MaxPerformDataSizeCanOnlyIncrease(); + error MigrationNotPermitted(); + error NotAContract(); + error OnlyActiveSigners(); + error OnlyActiveTransmitters(); + error OnlyCallableByAdmin(); + error OnlyCallableByLINKToken(); + error OnlyCallableByOwnerOrAdmin(); + error OnlyCallableByOwnerOrRegistrar(); + error OnlyCallableByPayee(); + error OnlyCallableByProposedAdmin(); + error OnlyCallableByProposedPayee(); + error OnlyCallableByUpkeepPrivilegeManager(); + error OnlyPausedUpkeep(); + error OnlySimulatedBackend(); + error OnlyUnpausedUpkeep(); + error ParameterLengthError(); + error PaymentGreaterThanAllLINK(); + error ReentrantCall(); + error RegistryPaused(); + error RepeatedSigner(); + error RepeatedTransmitter(); + error TargetCheckReverted(bytes reason); + error TooManyOracles(); + error TranscoderNotSet(); + error UpkeepAlreadyExists(); + error UpkeepCancelled(); + error UpkeepNotCanceled(); + error UpkeepNotNeeded(); + error ValueNotChanged(); + event AdminPrivilegeConfigSet(address indexed admin, bytes privilegeConfig); + event CancelledUpkeepReport(uint256 indexed id, bytes trigger); + event ConfigSet( + uint32 previousConfigBlockNumber, + bytes32 configDigest, + uint64 configCount, + address[] signers, + address[] transmitters, + uint8 f, + bytes onchainConfig, + uint64 offchainConfigVersion, + bytes offchainConfig + ); + event DedupKeyAdded(bytes32 indexed dedupKey); + event FundsAdded(uint256 indexed id, address indexed from, uint96 amount); + event FundsWithdrawn(uint256 indexed id, uint256 amount, address to); + event InsufficientFundsUpkeepReport(uint256 indexed id, bytes trigger); + event OwnerFundsWithdrawn(uint96 amount); + event OwnershipTransferRequested(address indexed from, address indexed to); + event OwnershipTransferred(address indexed from, address indexed to); + event Paused(address account); + event PayeesUpdated(address[] transmitters, address[] payees); + event PayeeshipTransferRequested(address indexed transmitter, address indexed from, address indexed to); + event PayeeshipTransferred(address indexed transmitter, address indexed from, address indexed to); + event PaymentWithdrawn(address indexed transmitter, uint256 indexed amount, address indexed to, address payee); + event ReorgedUpkeepReport(uint256 indexed id, bytes trigger); + event StaleUpkeepReport(uint256 indexed id, bytes trigger); + event Transmitted(bytes32 configDigest, uint32 epoch); + event Unpaused(address account); + event UpkeepAdminTransferRequested(uint256 indexed id, address indexed from, address indexed to); + event UpkeepAdminTransferred(uint256 indexed id, address indexed from, address indexed to); + event UpkeepCanceled(uint256 indexed id, uint64 indexed atBlockHeight); + event UpkeepCheckDataSet(uint256 indexed id, bytes newCheckData); + event UpkeepGasLimitSet(uint256 indexed id, uint96 gasLimit); + event UpkeepMigrated(uint256 indexed id, uint256 remainingBalance, address destination); + event UpkeepOffchainConfigSet(uint256 indexed id, bytes offchainConfig); + event UpkeepPaused(uint256 indexed id); + event UpkeepPerformed( + uint256 indexed id, + bool indexed success, + uint96 totalPayment, + uint256 gasUsed, + uint256 gasOverhead, + bytes trigger + ); + event UpkeepPrivilegeConfigSet(uint256 indexed id, bytes privilegeConfig); + event UpkeepReceived(uint256 indexed id, uint256 startingBalance, address importedFrom); + event UpkeepRegistered(uint256 indexed id, uint32 performGas, address admin); + event UpkeepTriggerConfigSet(uint256 indexed id, bytes triggerConfig); + event UpkeepUnpaused(uint256 indexed id); + + fallback() external; + function acceptOwnership() external; + function fallbackTo() external view returns (address); + function latestConfigDetails() external view returns (uint32 configCount, uint32 blockNumber, bytes32 configDigest); + function latestConfigDigestAndEpoch() external view returns (bool scanLogs, bytes32 configDigest, uint32 epoch); + function onTokenTransfer(address sender, uint256 amount, bytes memory data) external; + function owner() external view returns (address); + function setConfig( + address[] memory signers, + address[] memory transmitters, + uint8 f, + bytes memory onchainConfigBytes, + uint64 offchainConfigVersion, + bytes memory offchainConfig + ) external; + function setConfigTypeSafe( + address[] memory signers, + address[] memory transmitters, + uint8 f, + AutomationRegistryBase2_2.OnchainConfig memory onchainConfig, + uint64 offchainConfigVersion, + bytes memory offchainConfig + ) external; + function simulatePerformUpkeep( + uint256 id, + bytes memory performData + ) external view returns (bool success, uint256 gasUsed); + function transferOwnership(address to) external; + function transmit( + bytes32[3] memory reportContext, + bytes memory rawReport, + bytes32[] memory rs, + bytes32[] memory ss, + bytes32 rawVs + ) external; + function typeAndVersion() external view returns (string memory); + + function addFunds(uint256 id, uint96 amount) external; + function cancelUpkeep(uint256 id) external; + function checkCallback( + uint256 id, + bytes[] memory values, + bytes memory extraData + ) 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, + uint8 upkeepFailureReason, + uint256 gasUsed, + uint256 gasLimit, + uint256 fastGasWei, + uint256 linkNative + ); + function checkUpkeep( + uint256 id + ) + external + view + returns ( + bool upkeepNeeded, + bytes memory performData, + uint8 upkeepFailureReason, + uint256 gasUsed, + uint256 gasLimit, + uint256 fastGasWei, + uint256 linkNative + ); + function executeCallback( + uint256 id, + bytes memory payload + ) external returns (bool upkeepNeeded, bytes memory performData, uint8 upkeepFailureReason, uint256 gasUsed); + function migrateUpkeeps(uint256[] memory ids, address destination) external; + function receiveUpkeeps(bytes memory encodedUpkeeps) external; + function registerUpkeep( + address target, + uint32 gasLimit, + address admin, + uint8 triggerType, + bytes memory checkData, + bytes memory triggerConfig, + bytes memory offchainConfig + ) external returns (uint256 id); + function registerUpkeep( + address target, + uint32 gasLimit, + address admin, + bytes memory checkData, + bytes memory offchainConfig + ) external returns (uint256 id); + function setUpkeepTriggerConfig(uint256 id, bytes memory triggerConfig) external; + + function acceptPayeeship(address transmitter) external; + function acceptUpkeepAdmin(uint256 id) external; + function getActiveUpkeepIDs(uint256 startIndex, uint256 maxCount) external view returns (uint256[] memory); + function getAdminPrivilegeConfig(address admin) external view returns (bytes memory); + function getAutomationForwarderLogic() external view returns (address); + function getBalance(uint256 id) external view returns (uint96 balance); + function getCancellationDelay() external pure returns (uint256); + function getConditionalGasOverhead() external pure returns (uint256); + function getFastGasFeedAddress() external view returns (address); + function getForwarder(uint256 upkeepID) external view returns (address); + function getLinkAddress() external view returns (address); + function getLinkNativeFeedAddress() external view returns (address); + function getLogGasOverhead() external pure returns (uint256); + function getMaxPaymentForGas(uint8 triggerType, uint32 gasLimit) external view returns (uint96 maxPayment); + function getMinBalance(uint256 id) external view returns (uint96); + function getMinBalanceForUpkeep(uint256 id) external view returns (uint96 minBalance); + function getMode() external view returns (uint8); + function getPeerRegistryMigrationPermission(address peer) external view returns (uint8); + function getPerPerformByteGasOverhead() external pure returns (uint256); + function getPerSignerGasOverhead() external pure returns (uint256); + function getSignerInfo(address query) external view returns (bool active, uint8 index); + function getState() + external + view + returns ( + AutomationRegistryBase2_2.State memory state, + AutomationRegistryBase2_2.OnchainConfig memory config, + address[] memory signers, + address[] memory transmitters, + uint8 f + ); + function getTransmitterInfo( + address query + ) external view returns (bool active, uint8 index, uint96 balance, uint96 lastCollected, address payee); + function getTriggerType(uint256 upkeepId) external pure returns (uint8); + function getUpkeep(uint256 id) external view returns (AutomationRegistryBase2_2.UpkeepInfo memory upkeepInfo); + function getUpkeepPrivilegeConfig(uint256 upkeepId) external view returns (bytes memory); + function getUpkeepTriggerConfig(uint256 upkeepId) external view returns (bytes memory); + function hasDedupKey(bytes32 dedupKey) external view returns (bool); + function pause() external; + function pauseUpkeep(uint256 id) external; + function recoverFunds() external; + function setAdminPrivilegeConfig(address admin, bytes memory newPrivilegeConfig) external; + function setPayees(address[] memory payees) external; + function setPeerRegistryMigrationPermission(address peer, uint8 permission) external; + function setUpkeepCheckData(uint256 id, bytes memory newCheckData) external; + function setUpkeepGasLimit(uint256 id, uint32 gasLimit) external; + function setUpkeepOffchainConfig(uint256 id, bytes memory config) external; + function setUpkeepPrivilegeConfig(uint256 upkeepId, bytes memory newPrivilegeConfig) external; + function transferPayeeship(address transmitter, address proposed) external; + function transferUpkeepAdmin(uint256 id, address proposed) external; + function unpause() external; + function unpauseUpkeep(uint256 id) external; + function upkeepTranscoderVersion() external pure returns (uint8); + function upkeepVersion() external pure returns (uint8); + function withdrawFunds(uint256 id, address to) external; + function withdrawOwnerFunds() external; + function withdrawPayment(address from, address to) external; +} + +interface AutomationRegistryBase2_2 { + struct OnchainConfig { + uint32 paymentPremiumPPB; + uint32 flatFeeMicroLink; + uint32 checkGasLimit; + uint24 stalenessSeconds; + uint16 gasCeilingMultiplier; + uint96 minUpkeepSpend; + uint32 maxPerformGas; + uint32 maxCheckDataSize; + uint32 maxPerformDataSize; + uint32 maxRevertDataSize; + uint256 fallbackGasPrice; + uint256 fallbackLinkPrice; + address transcoder; + address[] registrars; + address upkeepPrivilegeManager; + } + + struct State { + uint32 nonce; + uint96 ownerLinkBalance; + uint256 expectedLinkBalance; + uint96 totalPremium; + uint256 numUpkeeps; + uint32 configCount; + uint32 latestConfigBlockNumber; + bytes32 latestConfigDigest; + uint32 latestEpoch; + bool paused; + } + + struct UpkeepInfo { + address target; + uint32 performGas; + bytes checkData; + uint96 balance; + address admin; + uint64 maxValidBlocknumber; + uint32 lastPerformedBlockNumber; + uint96 amountSpent; + bool paused; + bytes offchainConfig; + } +} + +// THIS FILE WAS AUTOGENERATED FROM THE FOLLOWING ABI JSON: +/* +[{"inputs":[{"internalType":"contract AutomationRegistryLogicB2_2","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 AutomationRegistryBase2_2.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 AutomationRegistryLogicB2_2","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 AutomationRegistryBase2_2.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 AutomationRegistryBase2_2.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 AutomationRegistryBase2_2.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 AutomationRegistryBase2_2.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 AutomationRegistryBase2_2.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 AutomationRegistryBase2_2.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 AutomationRegistryBase2_2.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 AutomationRegistryBase2_2.Mode","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"peer","type":"address"}],"name":"getPeerRegistryMigrationPermission","outputs":[{"internalType":"enum AutomationRegistryBase2_2.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 AutomationRegistryBase2_2.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 AutomationRegistryBase2_2.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 AutomationRegistryBase2_2.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 AutomationRegistryBase2_2.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 AutomationRegistryBase2_2.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/dev/v2_2/AutomationRegistrar2_2.sol b/contracts/src/v0.8/automation/dev/v2_2/AutomationRegistrar2_2.sol new file mode 100644 index 0000000000..1fa1feeb57 --- /dev/null +++ b/contracts/src/v0.8/automation/dev/v2_2/AutomationRegistrar2_2.sol @@ -0,0 +1,535 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity 0.8.16; + +import {LinkTokenInterface} from "../../../shared/interfaces/LinkTokenInterface.sol"; +import {IAutomationRegistryMaster} from "../interfaces/v2_2/IAutomationRegistryMaster.sol"; +import {TypeAndVersionInterface} from "../../../interfaces/TypeAndVersionInterface.sol"; +import {ConfirmedOwner} from "../../../shared/access/ConfirmedOwner.sol"; +import {IERC677Receiver} from "../../../shared/interfaces/IERC677Receiver.sol"; + +/** + * @notice Contract to accept requests for upkeep registrations + * @dev There are 2 registration workflows in this contract + * Flow 1. auto approve OFF / manual registration - UI calls `register` function on this contract, this contract owner at a later time then manually + * calls `approve` to register upkeep and emit events to inform UI and others interested. + * Flow 2. auto approve ON / real time registration - UI calls `register` function as before, which calls the `registerUpkeep` function directly on + * keeper registry and then emits approved event to finish the flow automatically without manual intervention. + * The idea is to have same interface(functions,events) for UI or anyone using this contract irrespective of auto approve being enabled or not. + * they can just listen to `RegistrationRequested` & `RegistrationApproved` events and know the status on registrations. + */ +contract AutomationRegistrar2_2 is TypeAndVersionInterface, ConfirmedOwner, IERC677Receiver { + /** + * DISABLED: No auto approvals, all new upkeeps should be approved manually. + * ENABLED_SENDER_ALLOWLIST: Auto approvals for allowed senders subject to max allowed. Manual for rest. + * ENABLED_ALL: Auto approvals for all new upkeeps subject to max allowed. + */ + enum AutoApproveType { + DISABLED, + ENABLED_SENDER_ALLOWLIST, + ENABLED_ALL + } + + bytes4 private constant REGISTER_REQUEST_SELECTOR = this.register.selector; + + mapping(bytes32 => PendingRequest) private s_pendingRequests; + mapping(uint8 => TriggerRegistrationStorage) private s_triggerRegistrations; + + LinkTokenInterface public immutable LINK; + + /** + * @notice versions: + * - KeeperRegistrar 2.1.0: Update for compatability with registry 2.1.0 + * Add auto approval levels by type + * - KeeperRegistrar 2.0.0: Remove source from register + * Breaks our example of "Register an Upkeep using your own deployed contract" + * - KeeperRegistrar 1.1.0: Add functionality for sender allowlist in auto approve + * : Remove rate limit and add max allowed for auto approve + * - KeeperRegistrar 1.0.0: initial release + */ + string public constant override typeAndVersion = "AutomationRegistrar 2.1.0"; + + /** + * @notice TriggerRegistrationStorage stores the auto-approval levels for upkeeps by type + * @member autoApproveType the auto approval setting (see enum) + * @member autoApproveMaxAllowed the max number of upkeeps that can be auto approved of this type + * @member approvedCount the count of upkeeps auto approved of this type + */ + struct TriggerRegistrationStorage { + AutoApproveType autoApproveType; + uint32 autoApproveMaxAllowed; + uint32 approvedCount; + } + + /** + * @notice InitialTriggerConfig configures the auto-approval levels for upkeeps by trigger type + * @dev this struct is only used in the constructor to set the initial values for various trigger configs + * @member triggerType the upkeep type to configure + * @member autoApproveType the auto approval setting (see enum) + * @member autoApproveMaxAllowed the max number of upkeeps that can be auto approved of this type + */ + struct InitialTriggerConfig { + uint8 triggerType; + AutoApproveType autoApproveType; + uint32 autoApproveMaxAllowed; + } + + struct RegistrarConfig { + IAutomationRegistryMaster AutomationRegistry; + uint96 minLINKJuels; + } + + struct PendingRequest { + address admin; + uint96 balance; + } + + struct RegistrationParams { + string name; + bytes encryptedEmail; + address upkeepContract; + uint32 gasLimit; + address adminAddress; + uint8 triggerType; + bytes checkData; + bytes triggerConfig; + bytes offchainConfig; + uint96 amount; + } + + RegistrarConfig private s_config; + // Only applicable if s_config.configType is ENABLED_SENDER_ALLOWLIST + mapping(address => bool) private s_autoApproveAllowedSenders; + + event RegistrationRequested( + bytes32 indexed hash, + string name, + bytes encryptedEmail, + address indexed upkeepContract, + uint32 gasLimit, + address adminAddress, + uint8 triggerType, + bytes triggerConfig, + bytes offchainConfig, + bytes checkData, + uint96 amount + ); + + event RegistrationApproved(bytes32 indexed hash, string displayName, uint256 indexed upkeepId); + + event RegistrationRejected(bytes32 indexed hash); + + event AutoApproveAllowedSenderSet(address indexed senderAddress, bool allowed); + + event ConfigChanged(address AutomationRegistry, uint96 minLINKJuels); + + event TriggerConfigSet(uint8 triggerType, AutoApproveType autoApproveType, uint32 autoApproveMaxAllowed); + + error InvalidAdminAddress(); + error RequestNotFound(); + error HashMismatch(); + error OnlyAdminOrOwner(); + error InsufficientPayment(); + error RegistrationRequestFailed(); + error OnlyLink(); + error AmountMismatch(); + error SenderMismatch(); + error FunctionNotPermitted(); + error LinkTransferFailed(address to); + error InvalidDataLength(); + + /** + * @param LINKAddress Address of Link token + * @param AutomationRegistry keeper registry address + * @param minLINKJuels minimum LINK that new registrations should fund their upkeep with + * @param triggerConfigs the initial config for individual triggers + */ + constructor( + address LINKAddress, + address AutomationRegistry, + uint96 minLINKJuels, + InitialTriggerConfig[] memory triggerConfigs + ) ConfirmedOwner(msg.sender) { + LINK = LinkTokenInterface(LINKAddress); + setConfig(AutomationRegistry, minLINKJuels); + for (uint256 idx = 0; idx < triggerConfigs.length; idx++) { + setTriggerConfig( + triggerConfigs[idx].triggerType, + triggerConfigs[idx].autoApproveType, + triggerConfigs[idx].autoApproveMaxAllowed + ); + } + } + + //EXTERNAL + + /** + * @notice register can only be called through transferAndCall on LINK contract + * @param name string of the upkeep to be registered + * @param encryptedEmail email address of upkeep contact + * @param upkeepContract address to perform upkeep on + * @param gasLimit amount of gas to provide the target contract when performing upkeep + * @param adminAddress address to cancel upkeep and withdraw remaining funds + * @param triggerType the type of trigger for the upkeep + * @param checkData data passed to the contract when checking for upkeep + * @param triggerConfig the config for the trigger + * @param offchainConfig offchainConfig for upkeep in bytes + * @param amount quantity of LINK upkeep is funded with (specified in Juels) + * @param sender address of the sender making the request + */ + function register( + string memory name, + bytes calldata encryptedEmail, + address upkeepContract, + uint32 gasLimit, + address adminAddress, + uint8 triggerType, + bytes memory checkData, + bytes memory triggerConfig, + bytes memory offchainConfig, + uint96 amount, + address sender + ) external onlyLINK { + _register( + RegistrationParams({ + name: name, + encryptedEmail: encryptedEmail, + upkeepContract: upkeepContract, + gasLimit: gasLimit, + adminAddress: adminAddress, + triggerType: triggerType, + checkData: checkData, + triggerConfig: triggerConfig, + offchainConfig: offchainConfig, + amount: amount + }), + sender + ); + } + + /** + * @notice Allows external users to register upkeeps; assumes amount is approved for transfer by the contract + * @param requestParams struct of all possible registration parameters + */ + function registerUpkeep(RegistrationParams calldata requestParams) external returns (uint256) { + if (requestParams.amount < s_config.minLINKJuels) { + revert InsufficientPayment(); + } + + LINK.transferFrom(msg.sender, address(this), requestParams.amount); + + return _register(requestParams, msg.sender); + } + + /** + * @dev register upkeep on AutomationRegistry contract and emit RegistrationApproved event + */ + function approve( + string memory name, + address upkeepContract, + uint32 gasLimit, + address adminAddress, + uint8 triggerType, + bytes calldata checkData, + bytes memory triggerConfig, + bytes calldata offchainConfig, + bytes32 hash + ) external onlyOwner { + PendingRequest memory request = s_pendingRequests[hash]; + if (request.admin == address(0)) { + revert RequestNotFound(); + } + bytes32 expectedHash = keccak256( + abi.encode(upkeepContract, gasLimit, adminAddress, triggerType, checkData, triggerConfig, offchainConfig) + ); + if (hash != expectedHash) { + revert HashMismatch(); + } + delete s_pendingRequests[hash]; + _approve( + RegistrationParams({ + name: name, + encryptedEmail: "", + upkeepContract: upkeepContract, + gasLimit: gasLimit, + adminAddress: adminAddress, + triggerType: triggerType, + checkData: checkData, + triggerConfig: triggerConfig, + offchainConfig: offchainConfig, + amount: request.balance + }), + expectedHash + ); + } + + /** + * @notice cancel will remove a registration request and return the refunds to the request.admin + * @param hash the request hash + */ + function cancel(bytes32 hash) external { + PendingRequest memory request = s_pendingRequests[hash]; + if (!(msg.sender == request.admin || msg.sender == owner())) { + revert OnlyAdminOrOwner(); + } + if (request.admin == address(0)) { + revert RequestNotFound(); + } + delete s_pendingRequests[hash]; + bool success = LINK.transfer(request.admin, request.balance); + if (!success) { + revert LinkTransferFailed(request.admin); + } + emit RegistrationRejected(hash); + } + + /** + * @notice owner calls this function to set contract config + * @param AutomationRegistry new keeper registry address + * @param minLINKJuels minimum LINK that new registrations should fund their upkeep with + */ + function setConfig(address AutomationRegistry, uint96 minLINKJuels) public onlyOwner { + s_config = RegistrarConfig({ + minLINKJuels: minLINKJuels, + AutomationRegistry: IAutomationRegistryMaster(AutomationRegistry) + }); + emit ConfigChanged(AutomationRegistry, minLINKJuels); + } + + /** + * @notice owner calls to set the config for this upkeep type + * @param triggerType the upkeep type to configure + * @param autoApproveType the auto approval setting (see enum) + * @param autoApproveMaxAllowed the max number of upkeeps that can be auto approved of this type + */ + function setTriggerConfig( + uint8 triggerType, + AutoApproveType autoApproveType, + uint32 autoApproveMaxAllowed + ) public onlyOwner { + s_triggerRegistrations[triggerType].autoApproveType = autoApproveType; + s_triggerRegistrations[triggerType].autoApproveMaxAllowed = autoApproveMaxAllowed; + emit TriggerConfigSet(triggerType, autoApproveType, autoApproveMaxAllowed); + } + + /** + * @notice owner calls this function to set allowlist status for senderAddress + * @param senderAddress senderAddress to set the allowlist status for + * @param allowed true if senderAddress needs to be added to allowlist, false if needs to be removed + */ + function setAutoApproveAllowedSender(address senderAddress, bool allowed) external onlyOwner { + s_autoApproveAllowedSenders[senderAddress] = allowed; + + emit AutoApproveAllowedSenderSet(senderAddress, allowed); + } + + /** + * @notice read the allowlist status of senderAddress + * @param senderAddress address to read the allowlist status for + */ + function getAutoApproveAllowedSender(address senderAddress) external view returns (bool) { + return s_autoApproveAllowedSenders[senderAddress]; + } + + /** + * @notice read the current registration configuration + */ + function getConfig() external view returns (address AutomationRegistry, uint256 minLINKJuels) { + RegistrarConfig memory config = s_config; + return (address(config.AutomationRegistry), config.minLINKJuels); + } + + /** + * @notice read the config for this upkeep type + * @param triggerType upkeep type to read config for + */ + function getTriggerRegistrationDetails(uint8 triggerType) external view returns (TriggerRegistrationStorage memory) { + return s_triggerRegistrations[triggerType]; + } + + /** + * @notice gets the admin address and the current balance of a registration request + */ + function getPendingRequest(bytes32 hash) external view returns (address, uint96) { + PendingRequest memory request = s_pendingRequests[hash]; + return (request.admin, request.balance); + } + + /** + * @notice Called when LINK is sent to the contract via `transferAndCall` + * @param sender Address of the sender transfering LINK + * @param amount Amount of LINK sent (specified in Juels) + * @param data Payload of the transaction + */ + function onTokenTransfer( + address sender, + uint256 amount, + bytes calldata data + ) + external + override + onlyLINK + permittedFunctionsForLINK(data) + isActualAmount(amount, data) + isActualSender(sender, data) + { + if (amount < s_config.minLINKJuels) { + revert InsufficientPayment(); + } + (bool success, ) = address(this).delegatecall(data); + // calls register + if (!success) { + revert RegistrationRequestFailed(); + } + } + + // ================================================================ + // | PRIVATE | + // ================================================================ + + /** + * @dev verify registration request and emit RegistrationRequested event + */ + function _register(RegistrationParams memory params, address sender) private returns (uint256) { + if (params.adminAddress == address(0)) { + revert InvalidAdminAddress(); + } + bytes32 hash = keccak256( + abi.encode( + params.upkeepContract, + params.gasLimit, + params.adminAddress, + params.triggerType, + params.checkData, + params.triggerConfig, + params.offchainConfig + ) + ); + + emit RegistrationRequested( + hash, + params.name, + params.encryptedEmail, + params.upkeepContract, + params.gasLimit, + params.adminAddress, + params.triggerType, + params.triggerConfig, + params.offchainConfig, + params.checkData, + params.amount + ); + + uint256 upkeepId; + if (_shouldAutoApprove(s_triggerRegistrations[params.triggerType], sender)) { + s_triggerRegistrations[params.triggerType].approvedCount++; + upkeepId = _approve(params, hash); + } else { + uint96 newBalance = s_pendingRequests[hash].balance + params.amount; + s_pendingRequests[hash] = PendingRequest({admin: params.adminAddress, balance: newBalance}); + } + + return upkeepId; + } + + /** + * @dev register upkeep on AutomationRegistry contract and emit RegistrationApproved event + */ + function _approve(RegistrationParams memory params, bytes32 hash) private returns (uint256) { + IAutomationRegistryMaster AutomationRegistry = s_config.AutomationRegistry; + uint256 upkeepId = AutomationRegistry.registerUpkeep( + params.upkeepContract, + params.gasLimit, + params.adminAddress, + params.triggerType, + params.checkData, + params.triggerConfig, + params.offchainConfig + ); + bool success = LINK.transferAndCall(address(AutomationRegistry), params.amount, abi.encode(upkeepId)); + if (!success) { + revert LinkTransferFailed(address(AutomationRegistry)); + } + emit RegistrationApproved(hash, params.name, upkeepId); + return upkeepId; + } + + /** + * @dev verify sender allowlist if needed and check max limit + */ + function _shouldAutoApprove(TriggerRegistrationStorage memory config, address sender) private view returns (bool) { + if (config.autoApproveType == AutoApproveType.DISABLED) { + return false; + } + if (config.autoApproveType == AutoApproveType.ENABLED_SENDER_ALLOWLIST && (!s_autoApproveAllowedSenders[sender])) { + return false; + } + if (config.approvedCount < config.autoApproveMaxAllowed) { + return true; + } + return false; + } + + // ================================================================ + // | MODIFIERS | + // ================================================================ + + /** + * @dev Reverts if not sent from the LINK token + */ + modifier onlyLINK() { + if (msg.sender != address(LINK)) { + revert OnlyLink(); + } + _; + } + + /** + * @dev Reverts if the given data does not begin with the `register` 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)) // First 32 bytes contain length of data + } + if (funcSelector != REGISTER_REQUEST_SELECTOR) { + revert FunctionNotPermitted(); + } + _; + } + + /** + * @dev Reverts if the actual amount passed does not match the expected amount + * @param expected amount that should match the actual amount + * @param data bytes + */ + modifier isActualAmount(uint256 expected, bytes calldata data) { + // decode register function arguments to get actual amount + (, , , , , , , , , uint96 amount, ) = abi.decode( + data[4:], + (string, bytes, address, uint32, address, uint8, bytes, bytes, bytes, uint96, address) + ); + if (expected != amount) { + revert AmountMismatch(); + } + _; + } + + /** + * @dev Reverts if the actual sender address does not match the expected sender address + * @param expected address that should match the actual sender address + * @param data bytes + */ + modifier isActualSender(address expected, bytes calldata data) { + // decode register function arguments to get actual sender + (, , , , , , , , , , address sender) = abi.decode( + data[4:], + (string, bytes, address, uint32, address, uint8, bytes, bytes, bytes, uint96, address) + ); + if (expected != sender) { + revert SenderMismatch(); + } + _; + } +} diff --git a/contracts/src/v0.8/automation/dev/v2_2/AutomationRegistry2_2.sol b/contracts/src/v0.8/automation/dev/v2_2/AutomationRegistry2_2.sol new file mode 100644 index 0000000000..e21387936e --- /dev/null +++ b/contracts/src/v0.8/automation/dev/v2_2/AutomationRegistry2_2.sol @@ -0,0 +1,397 @@ +// SPDX-License-Identifier: BUSL-1.1 +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 {AutomationRegistryBase2_2} from "./AutomationRegistryBase2_2.sol"; +import {AutomationRegistryLogicB2_2} from "./AutomationRegistryLogicB2_2.sol"; +import {Chainable} from "../../Chainable.sol"; +import {IERC677Receiver} from "../../../shared/interfaces/IERC677Receiver.sol"; +import {OCR2Abstract} from "../../../shared/ocr2/OCR2Abstract.sol"; + +/** + * @notice Registry for adding work for Chainlink nodes to perform on client + * contracts. Clients must support the AutomationCompatibleInterface interface. + */ +contract AutomationRegistry2_2 is AutomationRegistryBase2_2, OCR2Abstract, Chainable, IERC677Receiver { + using Address for address; + using EnumerableSet for EnumerableSet.UintSet; + using EnumerableSet for EnumerableSet.AddressSet; + + /** + * @notice versions: + * AutomationRegistry 2.2.0: moves chain-spicific integration code into a separate module + * KeeperRegistry 2.1.0: introduces support for log triggers + * removes the need for "wrapped perform data" + * KeeperRegistry 2.0.2: pass revert bytes as performData when target contract reverts + * fixes issue with arbitrum block number + * does an early return in case of stale report instead of revert + * KeeperRegistry 2.0.1: implements workaround for buggy migrate function in 1.X + * KeeperRegistry 2.0.0: implement OCR interface + * KeeperRegistry 1.3.0: split contract into Proxy and Logic + * account for Arbitrum and Optimism L1 gas fee + * allow users to configure upkeeps + * KeeperRegistry 1.2.0: allow funding within performUpkeep + * allow configurable registry maxPerformGas + * add function to let admin change upkeep gas limit + * add minUpkeepSpend requirement + * upgrade to solidity v0.8 + * KeeperRegistry 1.1.0: added flatFeeMicroLink + * KeeperRegistry 1.0.0: initial release + */ + string public constant override typeAndVersion = "AutomationRegistry 2.2.0"; + + /** + * @param logicA the address of the first logic contract, but cast as logicB in order to call logicB functions + */ + constructor( + AutomationRegistryLogicB2_2 logicA + ) + AutomationRegistryBase2_2( + logicA.getMode(), + logicA.getLinkAddress(), + logicA.getLinkNativeFeedAddress(), + logicA.getFastGasFeedAddress(), + logicA.getAutomationForwarderLogic() + ) + Chainable(address(logicA)) + {} + + // ================================================================ + // | ACTIONS | + // ================================================================ + + /** + * @inheritdoc OCR2Abstract + */ + function transmit( + bytes32[3] calldata reportContext, + bytes calldata rawReport, + bytes32[] calldata rs, + bytes32[] calldata ss, + bytes32 rawVs + ) external override { + uint256 gasOverhead = gasleft(); + HotVars memory hotVars = s_hotVars; + + if (hotVars.paused) revert RegistryPaused(); + if (!s_transmitters[msg.sender].active) revert OnlyActiveTransmitters(); + + // Verify signatures + if (s_latestConfigDigest != reportContext[0]) revert ConfigDigestMismatch(); + if (rs.length != hotVars.f + 1 || rs.length != ss.length) revert IncorrectNumberOfSignatures(); + _verifyReportSignature(reportContext, rawReport, rs, ss, rawVs); + + Report memory report = _decodeReport(rawReport); + UpkeepTransmitInfo[] memory upkeepTransmitInfo = new UpkeepTransmitInfo[](report.upkeepIds.length); + uint16 numUpkeepsPassedChecks; + + for (uint256 i = 0; i < report.upkeepIds.length; i++) { + upkeepTransmitInfo[i].upkeep = s_upkeep[report.upkeepIds[i]]; + upkeepTransmitInfo[i].triggerType = _getTriggerType(report.upkeepIds[i]); + upkeepTransmitInfo[i].maxLinkPayment = _getMaxLinkPayment( + hotVars, + upkeepTransmitInfo[i].triggerType, + uint32(report.gasLimits[i]), + uint32(report.performDatas[i].length), + report.fastGasWei, + report.linkNative, + true + ); + (upkeepTransmitInfo[i].earlyChecksPassed, upkeepTransmitInfo[i].dedupID) = _prePerformChecks( + report.upkeepIds[i], + report.triggers[i], + upkeepTransmitInfo[i] + ); + + if (upkeepTransmitInfo[i].earlyChecksPassed) { + numUpkeepsPassedChecks += 1; + } else { + continue; + } + + // Actually perform the target upkeep + (upkeepTransmitInfo[i].performSuccess, upkeepTransmitInfo[i].gasUsed) = _performUpkeep( + upkeepTransmitInfo[i].upkeep.forwarder, + report.gasLimits[i], + report.performDatas[i] + ); + + // Deduct that gasUsed by upkeep from our running counter + gasOverhead -= upkeepTransmitInfo[i].gasUsed; + + // Store last perform block number / deduping key for upkeep + _updateTriggerMarker(report.upkeepIds[i], upkeepTransmitInfo[i]); + } + // No upkeeps to be performed in this report + if (numUpkeepsPassedChecks == 0) { + return; + } + + // This is the overall gas overhead that will be split across performed upkeeps + // Take upper bound of 16 gas per callData bytes, which is approximated to be reportLength + // Rest of msg.data is accounted for in accounting overheads + gasOverhead = + (gasOverhead - gasleft() + 16 * rawReport.length) + + ACCOUNTING_FIXED_GAS_OVERHEAD + + (ACCOUNTING_PER_SIGNER_GAS_OVERHEAD * (hotVars.f + 1)); + gasOverhead = gasOverhead / numUpkeepsPassedChecks + ACCOUNTING_PER_UPKEEP_GAS_OVERHEAD; + + uint96 totalReimbursement; + uint96 totalPremium; + { + uint96 reimbursement; + uint96 premium; + for (uint256 i = 0; i < report.upkeepIds.length; i++) { + if (upkeepTransmitInfo[i].earlyChecksPassed) { + upkeepTransmitInfo[i].gasOverhead = _getCappedGasOverhead( + gasOverhead, + upkeepTransmitInfo[i].triggerType, + uint32(report.performDatas[i].length), + hotVars.f + ); + + (reimbursement, premium) = _postPerformPayment( + hotVars, + report.upkeepIds[i], + upkeepTransmitInfo[i], + report.fastGasWei, + report.linkNative, + numUpkeepsPassedChecks + ); + totalPremium += premium; + totalReimbursement += reimbursement; + + emit UpkeepPerformed( + report.upkeepIds[i], + upkeepTransmitInfo[i].performSuccess, + reimbursement + premium, + upkeepTransmitInfo[i].gasUsed, + upkeepTransmitInfo[i].gasOverhead, + report.triggers[i] + ); + } + } + } + // record payments + s_transmitters[msg.sender].balance += totalReimbursement; + s_hotVars.totalPremium += totalPremium; + + uint40 epochAndRound = uint40(uint256(reportContext[1])); + uint32 epoch = uint32(epochAndRound >> 8); + if (epoch > hotVars.latestEpoch) { + s_hotVars.latestEpoch = epoch; + } + } + + /** + * @notice simulates the upkeep with the perform data returned from checkUpkeep + * @param id identifier of the upkeep to execute the data with. + * @param performData calldata parameter to be passed to the target upkeep. + * @return success whether the call reverted or not + * @return gasUsed the amount of gas the target contract consumed + */ + function simulatePerformUpkeep( + uint256 id, + bytes calldata performData + ) external cannotExecute returns (bool success, uint256 gasUsed) { + if (s_hotVars.paused) revert RegistryPaused(); + Upkeep memory upkeep = s_upkeep[id]; + (success, gasUsed) = _performUpkeep(upkeep.forwarder, upkeep.performGas, performData); + return (success, gasUsed); + } + + /** + * @notice uses LINK's transferAndCall to LINK and add funding to an upkeep + * @dev safe to cast uint256 to uint96 as total LINK supply is under UINT96MAX + * @param sender the account which transferred the funds + * @param amount number of LINK transfer + */ + function onTokenTransfer(address sender, uint256 amount, bytes calldata data) external override { + if (msg.sender != address(i_link)) revert OnlyCallableByLINKToken(); + if (data.length != 32) revert InvalidDataLength(); + uint256 id = abi.decode(data, (uint256)); + if (s_upkeep[id].maxValidBlocknumber != UINT32_MAX) revert UpkeepCancelled(); + s_upkeep[id].balance = s_upkeep[id].balance + uint96(amount); + s_expectedLinkBalance = s_expectedLinkBalance + amount; + emit FundsAdded(id, sender, uint96(amount)); + } + + // ================================================================ + // | SETTERS | + // ================================================================ + + /** + * @inheritdoc OCR2Abstract + * @dev prefer the type-safe version of setConfig (below) whenever possible + */ + function setConfig( + address[] memory signers, + address[] memory transmitters, + uint8 f, + bytes memory onchainConfigBytes, + uint64 offchainConfigVersion, + bytes memory offchainConfig + ) external override { + setConfigTypeSafe( + signers, + transmitters, + f, + abi.decode(onchainConfigBytes, (OnchainConfig)), + offchainConfigVersion, + offchainConfig + ); + } + + function setConfigTypeSafe( + address[] memory signers, + address[] memory transmitters, + uint8 f, + OnchainConfig memory onchainConfig, + uint64 offchainConfigVersion, + bytes memory offchainConfig + ) public onlyOwner { + if (signers.length > MAX_NUM_ORACLES) revert TooManyOracles(); + if (f == 0) revert IncorrectNumberOfFaultyOracles(); + if (signers.length != transmitters.length || signers.length <= 3 * f) revert IncorrectNumberOfSigners(); + + // move all pooled payments out of the pool to each transmitter's balance + uint96 totalPremium = s_hotVars.totalPremium; + uint96 oldLength = uint96(s_transmittersList.length); + for (uint256 i = 0; i < oldLength; i++) { + _updateTransmitterBalanceFromPool(s_transmittersList[i], totalPremium, oldLength); + } + + // remove any old signer/transmitter addresses + address signerAddress; + address transmitterAddress; + for (uint256 i = 0; i < oldLength; i++) { + signerAddress = s_signersList[i]; + transmitterAddress = s_transmittersList[i]; + delete s_signers[signerAddress]; + // Do not delete the whole transmitter struct as it has balance information stored + s_transmitters[transmitterAddress].active = false; + } + delete s_signersList; + delete s_transmittersList; + + // add new signer/transmitter addresses + { + Transmitter memory transmitter; + address temp; + for (uint256 i = 0; i < signers.length; i++) { + if (s_signers[signers[i]].active) revert RepeatedSigner(); + if (signers[i] == ZERO_ADDRESS) revert InvalidSigner(); + s_signers[signers[i]] = Signer({active: true, index: uint8(i)}); + + temp = transmitters[i]; + if (temp == ZERO_ADDRESS) revert InvalidTransmitter(); + transmitter = s_transmitters[temp]; + if (transmitter.active) revert RepeatedTransmitter(); + transmitter.active = true; + transmitter.index = uint8(i); + // new transmitters start afresh from current totalPremium + // some spare change of premium from previous pool will be forfeited + transmitter.lastCollected = totalPremium; + s_transmitters[temp] = transmitter; + } + } + s_signersList = signers; + s_transmittersList = transmitters; + + s_hotVars = HotVars({ + f: f, + paymentPremiumPPB: onchainConfig.paymentPremiumPPB, + flatFeeMicroLink: onchainConfig.flatFeeMicroLink, + stalenessSeconds: onchainConfig.stalenessSeconds, + gasCeilingMultiplier: onchainConfig.gasCeilingMultiplier, + paused: s_hotVars.paused, + reentrancyGuard: s_hotVars.reentrancyGuard, + totalPremium: totalPremium, + latestEpoch: 0 // DON restarts epoch + }); + + s_storage = Storage({ + checkGasLimit: onchainConfig.checkGasLimit, + minUpkeepSpend: onchainConfig.minUpkeepSpend, + maxPerformGas: onchainConfig.maxPerformGas, + transcoder: onchainConfig.transcoder, + maxCheckDataSize: onchainConfig.maxCheckDataSize, + maxPerformDataSize: onchainConfig.maxPerformDataSize, + maxRevertDataSize: onchainConfig.maxRevertDataSize, + upkeepPrivilegeManager: onchainConfig.upkeepPrivilegeManager, + nonce: s_storage.nonce, + configCount: s_storage.configCount, + latestConfigBlockNumber: s_storage.latestConfigBlockNumber, + ownerLinkBalance: s_storage.ownerLinkBalance + }); + s_fallbackGasPrice = onchainConfig.fallbackGasPrice; + s_fallbackLinkPrice = onchainConfig.fallbackLinkPrice; + + uint32 previousConfigBlockNumber = s_storage.latestConfigBlockNumber; + s_storage.latestConfigBlockNumber = uint32(_blockNum()); + s_storage.configCount += 1; + + bytes memory onchainConfigBytes = abi.encode(onchainConfig); + + s_latestConfigDigest = _configDigestFromConfigData( + block.chainid, + address(this), + s_storage.configCount, + signers, + transmitters, + f, + onchainConfigBytes, + offchainConfigVersion, + offchainConfig + ); + + for (uint256 idx = 0; idx < s_registrars.length(); idx++) { + s_registrars.remove(s_registrars.at(idx)); + } + + for (uint256 idx = 0; idx < onchainConfig.registrars.length; idx++) { + s_registrars.add(onchainConfig.registrars[idx]); + } + + emit ConfigSet( + previousConfigBlockNumber, + s_latestConfigDigest, + s_storage.configCount, + signers, + transmitters, + f, + onchainConfigBytes, + offchainConfigVersion, + offchainConfig + ); + } + + // ================================================================ + // | GETTERS | + // ================================================================ + + /** + * @inheritdoc OCR2Abstract + */ + function latestConfigDetails() + external + view + override + returns (uint32 configCount, uint32 blockNumber, bytes32 configDigest) + { + return (s_storage.configCount, s_storage.latestConfigBlockNumber, s_latestConfigDigest); + } + + /** + * @inheritdoc OCR2Abstract + */ + function latestConfigDigestAndEpoch() + external + view + override + returns (bool scanLogs, bytes32 configDigest, uint32 epoch) + { + return (false, s_latestConfigDigest, s_hotVars.latestEpoch); + } +} diff --git a/contracts/src/v0.8/automation/dev/v2_2/AutomationRegistryBase2_2.sol b/contracts/src/v0.8/automation/dev/v2_2/AutomationRegistryBase2_2.sol new file mode 100644 index 0000000000..e4b6e61d6f --- /dev/null +++ b/contracts/src/v0.8/automation/dev/v2_2/AutomationRegistryBase2_2.sol @@ -0,0 +1,955 @@ +// SPDX-License-Identifier: BUSL-1.1 +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 {ArbGasInfo} from "../../../vendor/@arbitrum/nitro-contracts/src/precompiles/ArbGasInfo.sol"; +import {OVM_GasPriceOracle} from "../../../vendor/@eth-optimism/contracts/v0.8.9/contracts/L2/predeploys/OVM_GasPriceOracle.sol"; +import {ExecutionPrevention} from "../../ExecutionPrevention.sol"; +import {ArbSys} from "../../../vendor/@arbitrum/nitro-contracts/src/precompiles/ArbSys.sol"; +import {StreamsLookupCompatibleInterface} from "../../interfaces/StreamsLookupCompatibleInterface.sol"; +import {ILogAutomation, Log} from "../../interfaces/ILogAutomation.sol"; +import {IAutomationForwarder} from "../../interfaces/IAutomationForwarder.sol"; +import {ConfirmedOwner} from "../../../shared/access/ConfirmedOwner.sol"; +import {AggregatorV3Interface} from "../../../shared/interfaces/AggregatorV3Interface.sol"; +import {LinkTokenInterface} from "../../../shared/interfaces/LinkTokenInterface.sol"; +import {KeeperCompatibleInterface} from "../../interfaces/KeeperCompatibleInterface.sol"; +import {UpkeepFormat} from "../../interfaces/UpkeepTranscoderInterface.sol"; + +/** + * @notice Base Keeper Registry contract, contains shared logic between + * AutomationRegistry and AutomationRegistryLogic + * @dev all errors, events, and internal functions should live here + */ +abstract contract AutomationRegistryBase2_2 is ConfirmedOwner, ExecutionPrevention { + using Address for address; + using EnumerableSet for EnumerableSet.UintSet; + using EnumerableSet for EnumerableSet.AddressSet; + + address internal constant ZERO_ADDRESS = address(0); + address internal constant IGNORE_ADDRESS = 0xFFfFfFffFFfffFFfFFfFFFFFffFFFffffFfFFFfF; + bytes4 internal constant CHECK_SELECTOR = KeeperCompatibleInterface.checkUpkeep.selector; + bytes4 internal constant PERFORM_SELECTOR = KeeperCompatibleInterface.performUpkeep.selector; + bytes4 internal constant CHECK_CALLBACK_SELECTOR = StreamsLookupCompatibleInterface.checkCallback.selector; + bytes4 internal constant CHECK_LOG_SELECTOR = ILogAutomation.checkLog.selector; + uint256 internal constant PERFORM_GAS_MIN = 2_300; + uint256 internal constant CANCELLATION_DELAY = 50; + uint256 internal constant PERFORM_GAS_CUSHION = 5_000; + uint256 internal constant PPB_BASE = 1_000_000_000; + uint32 internal constant UINT32_MAX = type(uint32).max; + uint96 internal constant LINK_TOTAL_SUPPLY = 1e27; + // The first byte of the mask can be 0, because we only ever have 31 oracles + uint256 internal constant ORACLE_MASK = 0x0001010101010101010101010101010101010101010101010101010101010101; + /** + * @dev UPKEEP_TRANSCODER_VERSION_BASE is temporary necessity for backwards compatibility with + * MigratableAutomationRegistryInterfaceV1 - it should be removed in future versions in favor of + * UPKEEP_VERSION_BASE and MigratableAutomationRegistryInterfaceV2 + */ + UpkeepFormat internal constant UPKEEP_TRANSCODER_VERSION_BASE = UpkeepFormat.V1; + uint8 internal constant UPKEEP_VERSION_BASE = 3; + // L1_FEE_DATA_PADDING includes 35 bytes for L1 data padding for Optimism + bytes internal constant L1_FEE_DATA_PADDING = + "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"; + + uint256 internal constant REGISTRY_CONDITIONAL_OVERHEAD = 90_000; // Used in maxPayment estimation, and in capping overheads during actual payment + uint256 internal constant REGISTRY_LOG_OVERHEAD = 110_000; // Used only in maxPayment estimation, and in capping overheads during actual payment. + uint256 internal constant REGISTRY_PER_PERFORM_BYTE_GAS_OVERHEAD = 20; // Used only in maxPayment estimation, and in capping overheads during actual payment. Value scales with performData length. + uint256 internal constant REGISTRY_PER_SIGNER_GAS_OVERHEAD = 7_500; // Used only in maxPayment estimation, and in capping overheads during actual payment. Value scales with f. + + uint256 internal constant ACCOUNTING_FIXED_GAS_OVERHEAD = 27_500; // Used in actual payment. Fixed overhead per tx + uint256 internal constant ACCOUNTING_PER_SIGNER_GAS_OVERHEAD = 1_100; // Used in actual payment. overhead per signer + uint256 internal constant ACCOUNTING_PER_UPKEEP_GAS_OVERHEAD = 7_000; // Used in actual payment. overhead per upkeep performed + + OVM_GasPriceOracle internal constant OPTIMISM_ORACLE = OVM_GasPriceOracle(0x420000000000000000000000000000000000000F); + ArbGasInfo internal constant ARB_NITRO_ORACLE = ArbGasInfo(0x000000000000000000000000000000000000006C); + ArbSys internal constant ARB_SYS = ArbSys(0x0000000000000000000000000000000000000064); + + LinkTokenInterface internal immutable i_link; + AggregatorV3Interface internal immutable i_linkNativeFeed; + AggregatorV3Interface internal immutable i_fastGasFeed; + Mode internal immutable i_mode; + address internal immutable i_automationForwarderLogic; + + /** + * @dev - The storage is gas optimised for one and only one function - transmit. All the storage accessed in transmit + * is stored compactly. Rest of the storage layout is not of much concern as transmit is the only hot path + */ + + // Upkeep storage + EnumerableSet.UintSet internal s_upkeepIDs; + mapping(uint256 => Upkeep) internal s_upkeep; // accessed during transmit + mapping(uint256 => address) internal s_upkeepAdmin; + mapping(uint256 => address) internal s_proposedAdmin; + mapping(uint256 => bytes) internal s_checkData; + mapping(bytes32 => bool) internal s_dedupKeys; + // Registry config and state + EnumerableSet.AddressSet internal s_registrars; + mapping(address => Transmitter) internal s_transmitters; + mapping(address => Signer) internal s_signers; + address[] internal s_signersList; // s_signersList contains the signing address of each oracle + address[] internal s_transmittersList; // s_transmittersList contains the transmission address of each oracle + mapping(address => address) internal s_transmitterPayees; // s_payees contains the mapping from transmitter to payee. + mapping(address => address) internal s_proposedPayee; // proposed payee for a transmitter + bytes32 internal s_latestConfigDigest; // Read on transmit path in case of signature verification + HotVars internal s_hotVars; // Mixture of config and state, used in transmit + Storage internal s_storage; // Mixture of config and state, not used in transmit + uint256 internal s_fallbackGasPrice; + uint256 internal s_fallbackLinkPrice; + uint256 internal s_expectedLinkBalance; // Used in case of erroneous LINK transfers to contract + mapping(address => MigrationPermission) internal s_peerRegistryMigrationPermission; // Permissions for migration to and fro + mapping(uint256 => bytes) internal s_upkeepTriggerConfig; // upkeep triggers + mapping(uint256 => bytes) internal s_upkeepOffchainConfig; // general config set by users for each upkeep + mapping(uint256 => bytes) internal s_upkeepPrivilegeConfig; // general config set by an administrative role for an upkeep + mapping(address => bytes) internal s_adminPrivilegeConfig; // general config set by an administrative role for an admin + + error ArrayHasNoEntries(); + error CannotCancel(); + error CheckDataExceedsLimit(); + error ConfigDigestMismatch(); + error DuplicateEntry(); + error DuplicateSigners(); + error GasLimitCanOnlyIncrease(); + error GasLimitOutsideRange(); + error IncorrectNumberOfFaultyOracles(); + error IncorrectNumberOfSignatures(); + error IncorrectNumberOfSigners(); + error IndexOutOfRange(); + error InsufficientFunds(); + error InvalidDataLength(); + error InvalidTrigger(); + error InvalidPayee(); + error InvalidRecipient(); + error InvalidReport(); + error InvalidSigner(); + error InvalidTransmitter(); + error InvalidTriggerType(); + error MaxCheckDataSizeCanOnlyIncrease(); + error MaxPerformDataSizeCanOnlyIncrease(); + error MigrationNotPermitted(); + error NotAContract(); + error OnlyActiveSigners(); + error OnlyActiveTransmitters(); + error OnlyCallableByAdmin(); + error OnlyCallableByLINKToken(); + error OnlyCallableByOwnerOrAdmin(); + error OnlyCallableByOwnerOrRegistrar(); + error OnlyCallableByPayee(); + error OnlyCallableByProposedAdmin(); + error OnlyCallableByProposedPayee(); + error OnlyCallableByUpkeepPrivilegeManager(); + error OnlyPausedUpkeep(); + error OnlyUnpausedUpkeep(); + error ParameterLengthError(); + error PaymentGreaterThanAllLINK(); + error ReentrantCall(); + error RegistryPaused(); + error RepeatedSigner(); + error RepeatedTransmitter(); + error TargetCheckReverted(bytes reason); + error TooManyOracles(); + error TranscoderNotSet(); + error UpkeepAlreadyExists(); + error UpkeepCancelled(); + error UpkeepNotCanceled(); + error UpkeepNotNeeded(); + error ValueNotChanged(); + + enum MigrationPermission { + NONE, + OUTGOING, + INCOMING, + BIDIRECTIONAL + } + + enum Mode { + DEFAULT, + ARBITRUM, + OPTIMISM + } + + enum Trigger { + CONDITION, + LOG + } + + enum UpkeepFailureReason { + NONE, + UPKEEP_CANCELLED, + UPKEEP_PAUSED, + TARGET_CHECK_REVERTED, + UPKEEP_NOT_NEEDED, + PERFORM_DATA_EXCEEDS_LIMIT, + INSUFFICIENT_BALANCE, + CALLBACK_REVERTED, + REVERT_DATA_EXCEEDS_LIMIT, + REGISTRY_PAUSED + } + + /** + * @notice OnchainConfig of the registry + * @dev only used in params and return values + * @member paymentPremiumPPB payment premium rate oracles receive on top of + * being reimbursed for gas, measured in parts per billion + * @member flatFeeMicroLink flat fee paid to oracles for performing upkeeps, + * priced in MicroLink; can be used in conjunction with or independently of + * paymentPremiumPPB + * @member checkGasLimit gas limit when checking for upkeep + * @member stalenessSeconds number of seconds that is allowed for feed data to + * be stale before switching to the fallback pricing + * @member gasCeilingMultiplier multiplier to apply to the fast gas feed price + * when calculating the payment ceiling for keepers + * @member minUpkeepSpend minimum LINK that an upkeep must spend before cancelling + * @member maxPerformGas max performGas allowed for an upkeep on this registry + * @member maxCheckDataSize max length of checkData bytes + * @member maxPerformDataSize max length of performData bytes + * @member maxRevertDataSize max length of revertData bytes + * @member fallbackGasPrice gas price used if the gas price feed is stale + * @member fallbackLinkPrice LINK price used if the LINK price feed is stale + * @member transcoder address of the transcoder contract + * @member registrars addresses of the registrar contracts + * @member upkeepPrivilegeManager address which can set privilege for upkeeps + */ + struct OnchainConfig { + uint32 paymentPremiumPPB; + uint32 flatFeeMicroLink; // min 0.000001 LINK, max 4294 LINK + uint32 checkGasLimit; + uint24 stalenessSeconds; + uint16 gasCeilingMultiplier; + uint96 minUpkeepSpend; + uint32 maxPerformGas; + uint32 maxCheckDataSize; + uint32 maxPerformDataSize; + uint32 maxRevertDataSize; + uint256 fallbackGasPrice; + uint256 fallbackLinkPrice; + address transcoder; + address[] registrars; + address upkeepPrivilegeManager; + } + + /** + * @notice state of the registry + * @dev only used in params and return values + * @dev this will likely be deprecated in a future version of the registry in favor of individual getters + * @member nonce used for ID generation + * @member ownerLinkBalance withdrawable balance of LINK by contract owner + * @member expectedLinkBalance the expected balance of LINK of the registry + * @member totalPremium the total premium collected on registry so far + * @member numUpkeeps total number of upkeeps on the registry + * @member configCount ordinal number of current config, out of all configs applied to this contract so far + * @member latestConfigBlockNumber last block at which this config was set + * @member latestConfigDigest domain-separation tag for current config + * @member latestEpoch for which a report was transmitted + * @member paused freeze on execution scoped to the entire registry + */ + struct State { + uint32 nonce; + uint96 ownerLinkBalance; + uint256 expectedLinkBalance; + uint96 totalPremium; + uint256 numUpkeeps; + uint32 configCount; + uint32 latestConfigBlockNumber; + bytes32 latestConfigDigest; + uint32 latestEpoch; + bool paused; + } + + /** + * @notice relevant state of an upkeep which is used in transmit function + * @member paused if this upkeep has been paused + * @member performGas the gas limit of upkeep execution + * @member maxValidBlocknumber until which block this upkeep is valid + * @member forwarder the forwarder contract to use for this upkeep + * @member amountSpent the amount this upkeep has spent + * @member balance the balance of this upkeep + * @member lastPerformedBlockNumber the last block number when this upkeep was performed + */ + struct Upkeep { + bool paused; + uint32 performGas; + uint32 maxValidBlocknumber; + IAutomationForwarder forwarder; + // 0 bytes left in 1st EVM word - not written to in transmit + uint96 amountSpent; + uint96 balance; + uint32 lastPerformedBlockNumber; + // 2 bytes left in 2nd EVM word - written in transmit path + } + + /** + * @notice all information about an upkeep + * @dev only used in return values + * @dev this will likely be deprecated in a future version of the registry + * @member target the contract which needs to be serviced + * @member performGas the gas limit of upkeep execution + * @member checkData the checkData bytes for this upkeep + * @member balance the balance of this upkeep + * @member admin for this upkeep + * @member maxValidBlocknumber until which block this upkeep is valid + * @member lastPerformedBlockNumber the last block number when this upkeep was performed + * @member amountSpent the amount this upkeep has spent + * @member paused if this upkeep has been paused + * @member offchainConfig the off-chain config of this upkeep + */ + struct UpkeepInfo { + address target; + uint32 performGas; + bytes checkData; + uint96 balance; + address admin; + uint64 maxValidBlocknumber; + uint32 lastPerformedBlockNumber; + uint96 amountSpent; + bool paused; + bytes offchainConfig; + } + + /// @dev Config + State storage struct which is on hot transmit path + struct HotVars { + uint8 f; // maximum number of faulty oracles + uint32 paymentPremiumPPB; // premium percentage charged to user over tx cost + uint32 flatFeeMicroLink; // flat fee charged to user for every perform + uint24 stalenessSeconds; // Staleness tolerance for feeds + uint16 gasCeilingMultiplier; // multiplier on top of fast gas feed for upper bound + bool paused; // pause switch for all upkeeps in the registry + bool reentrancyGuard; // guard against reentrancy + uint96 totalPremium; // total historical payment to oracles for premium + uint32 latestEpoch; // latest epoch for which a report was transmitted + // 1 EVM word full + } + + /// @dev Config + State storage struct which is not on hot transmit path + struct Storage { + uint96 minUpkeepSpend; // Minimum amount an upkeep must spend + address transcoder; // Address of transcoder contract used in migrations + // 1 EVM word full + uint96 ownerLinkBalance; // Balance of owner, accumulates minUpkeepSpend in case it is not spent + uint32 checkGasLimit; // Gas limit allowed in checkUpkeep + uint32 maxPerformGas; // Max gas an upkeep can use on this registry + uint32 nonce; // Nonce for each upkeep created + uint32 configCount; // incremented each time a new config is posted, The count + // is incorporated into the config digest to prevent replay attacks. + uint32 latestConfigBlockNumber; // makes it easier for offchain systems to extract config from logs + // 2 EVM word full + uint32 maxCheckDataSize; // max length of checkData bytes + uint32 maxPerformDataSize; // max length of performData bytes + uint32 maxRevertDataSize; // max length of revertData bytes + address upkeepPrivilegeManager; // address which can set privilege for upkeeps + // 3 EVM word full + } + + /// @dev Report transmitted by OCR to transmit function + struct Report { + uint256 fastGasWei; + uint256 linkNative; + uint256[] upkeepIds; + uint256[] gasLimits; + bytes[] triggers; + bytes[] performDatas; + } + + /** + * @dev This struct is used to maintain run time information about an upkeep in transmit function + * @member upkeep the upkeep struct + * @member earlyChecksPassed whether the upkeep passed early checks before perform + * @member maxLinkPayment the max amount this upkeep could pay for work + * @member performSuccess whether the perform was successful + * @member triggerType the type of trigger + * @member gasUsed gasUsed by this upkeep in perform + * @member gasOverhead gasOverhead for this upkeep + * @member dedupID unique ID used to dedup an upkeep/trigger combo + */ + struct UpkeepTransmitInfo { + Upkeep upkeep; + bool earlyChecksPassed; + uint96 maxLinkPayment; + bool performSuccess; + Trigger triggerType; + uint256 gasUsed; + uint256 gasOverhead; + bytes32 dedupID; + } + + struct Transmitter { + bool active; + uint8 index; // Index of oracle in s_signersList/s_transmittersList + uint96 balance; + uint96 lastCollected; + } + + struct Signer { + bool active; + // Index of oracle in s_signersList/s_transmittersList + uint8 index; + } + + /** + * @notice the trigger structure conditional trigger type + */ + struct ConditionalTrigger { + uint32 blockNum; + bytes32 blockHash; + } + + /** + * @notice the trigger structure of log upkeeps + * @dev NOTE that blockNum / blockHash describe the block used for the callback, + * not necessarily the block number that the log was emitted in!!!! + */ + struct LogTrigger { + bytes32 logBlockHash; + bytes32 txHash; + uint32 logIndex; + uint32 blockNum; + bytes32 blockHash; + } + + event AdminPrivilegeConfigSet(address indexed admin, bytes privilegeConfig); + event CancelledUpkeepReport(uint256 indexed id, bytes trigger); + event DedupKeyAdded(bytes32 indexed dedupKey); + event FundsAdded(uint256 indexed id, address indexed from, uint96 amount); + event FundsWithdrawn(uint256 indexed id, uint256 amount, address to); + event InsufficientFundsUpkeepReport(uint256 indexed id, bytes trigger); + event OwnerFundsWithdrawn(uint96 amount); + event Paused(address account); + event PayeesUpdated(address[] transmitters, address[] payees); + event PayeeshipTransferRequested(address indexed transmitter, address indexed from, address indexed to); + event PayeeshipTransferred(address indexed transmitter, address indexed from, address indexed to); + event PaymentWithdrawn(address indexed transmitter, uint256 indexed amount, address indexed to, address payee); + event ReorgedUpkeepReport(uint256 indexed id, bytes trigger); + event StaleUpkeepReport(uint256 indexed id, bytes trigger); + event UpkeepAdminTransferred(uint256 indexed id, address indexed from, address indexed to); + event UpkeepAdminTransferRequested(uint256 indexed id, address indexed from, address indexed to); + event UpkeepCanceled(uint256 indexed id, uint64 indexed atBlockHeight); + event UpkeepCheckDataSet(uint256 indexed id, bytes newCheckData); + event UpkeepGasLimitSet(uint256 indexed id, uint96 gasLimit); + event UpkeepMigrated(uint256 indexed id, uint256 remainingBalance, address destination); + event UpkeepOffchainConfigSet(uint256 indexed id, bytes offchainConfig); + event UpkeepPaused(uint256 indexed id); + event UpkeepPerformed( + uint256 indexed id, + bool indexed success, + uint96 totalPayment, + uint256 gasUsed, + uint256 gasOverhead, + bytes trigger + ); + event UpkeepPrivilegeConfigSet(uint256 indexed id, bytes privilegeConfig); + event UpkeepReceived(uint256 indexed id, uint256 startingBalance, address importedFrom); + event UpkeepRegistered(uint256 indexed id, uint32 performGas, address admin); + event UpkeepTriggerConfigSet(uint256 indexed id, bytes triggerConfig); + event UpkeepUnpaused(uint256 indexed id); + event Unpaused(address account); + + /** + * @param mode the contract mode of default, Arbitrum, or Optimism + * @param link address of the LINK Token + * @param linkNativeFeed address of the LINK/Native price feed + * @param fastGasFeed address of the Fast Gas price feed + */ + constructor( + Mode mode, + address link, + address linkNativeFeed, + address fastGasFeed, + address automationForwarderLogic + ) ConfirmedOwner(msg.sender) { + i_mode = mode; + i_link = LinkTokenInterface(link); + i_linkNativeFeed = AggregatorV3Interface(linkNativeFeed); + i_fastGasFeed = AggregatorV3Interface(fastGasFeed); + i_automationForwarderLogic = automationForwarderLogic; + } + + // ================================================================ + // | INTERNAL FUNCTIONS ONLY | + // ================================================================ + + /** + * @dev creates a new upkeep with the given fields + * @param id the id of the upkeep + * @param upkeep the upkeep to create + * @param admin address to cancel upkeep and withdraw remaining funds + * @param checkData data which is passed to user's checkUpkeep + * @param triggerConfig the trigger config for this upkeep + * @param offchainConfig the off-chain config of this upkeep + */ + function _createUpkeep( + uint256 id, + Upkeep memory upkeep, + address admin, + bytes memory checkData, + bytes memory triggerConfig, + bytes memory offchainConfig + ) internal { + if (s_hotVars.paused) revert RegistryPaused(); + if (checkData.length > s_storage.maxCheckDataSize) revert CheckDataExceedsLimit(); + if (upkeep.performGas < PERFORM_GAS_MIN || upkeep.performGas > s_storage.maxPerformGas) + revert GasLimitOutsideRange(); + if (address(s_upkeep[id].forwarder) != address(0)) revert UpkeepAlreadyExists(); + s_upkeep[id] = upkeep; + s_upkeepAdmin[id] = admin; + s_checkData[id] = checkData; + s_expectedLinkBalance = s_expectedLinkBalance + upkeep.balance; + s_upkeepTriggerConfig[id] = triggerConfig; + s_upkeepOffchainConfig[id] = offchainConfig; + s_upkeepIDs.add(id); + } + + /** + * @dev creates an ID for the upkeep based on the upkeep's type + * @dev the format of the ID looks like this: + * ****00000000000X**************** + * 4 bytes of entropy + * 11 bytes of zeros + * 1 identifying byte for the trigger type + * 16 bytes of entropy + * @dev this maintains the same level of entropy as eth addresses, so IDs will still be unique + * @dev we add the "identifying" part in the middle so that it is mostly hidden from users who usually only + * see the first 4 and last 4 hex values ex 0x1234...ABCD + */ + function _createID(Trigger triggerType) internal view returns (uint256) { + bytes1 empty; + bytes memory idBytes = abi.encodePacked( + keccak256(abi.encode(_blockHash(_blockNum() - 1), address(this), s_storage.nonce)) + ); + for (uint256 idx = 4; idx < 15; idx++) { + idBytes[idx] = empty; + } + idBytes[15] = bytes1(uint8(triggerType)); + return uint256(bytes32(idBytes)); + } + + /** + * @dev retrieves feed data for fast gas/native and link/native prices. if the feed + * data is stale it uses the configured fallback price. Once a price is picked + * for gas it takes the min of gas price in the transaction or the fast gas + * price in order to reduce costs for the upkeep clients. + */ + function _getFeedData(HotVars memory hotVars) internal view returns (uint256 gasWei, uint256 linkNative) { + uint32 stalenessSeconds = hotVars.stalenessSeconds; + bool staleFallback = stalenessSeconds > 0; + uint256 timestamp; + int256 feedValue; + (, feedValue, , timestamp, ) = i_fastGasFeed.latestRoundData(); + if ( + feedValue <= 0 || block.timestamp < timestamp || (staleFallback && stalenessSeconds < block.timestamp - timestamp) + ) { + gasWei = s_fallbackGasPrice; + } else { + gasWei = uint256(feedValue); + } + (, feedValue, , timestamp, ) = i_linkNativeFeed.latestRoundData(); + if ( + feedValue <= 0 || block.timestamp < timestamp || (staleFallback && stalenessSeconds < block.timestamp - timestamp) + ) { + linkNative = s_fallbackLinkPrice; + } else { + linkNative = uint256(feedValue); + } + return (gasWei, linkNative); + } + + /** + * @dev calculates LINK paid for gas spent plus a configure premium percentage + * @param gasLimit the amount of gas used + * @param gasOverhead the amount of gas overhead + * @param fastGasWei the fast gas price + * @param linkNative the exchange ratio between LINK and Native token + * @param numBatchedUpkeeps the number of upkeeps in this batch. Used to divide the L1 cost + * @param isExecution if this is triggered by a perform upkeep function + */ + function _calculatePaymentAmount( + HotVars memory hotVars, + uint256 gasLimit, + uint256 gasOverhead, + uint256 fastGasWei, + uint256 linkNative, + uint16 numBatchedUpkeeps, + bool isExecution + ) internal view returns (uint96, uint96) { + uint256 gasWei = fastGasWei * hotVars.gasCeilingMultiplier; + // in case it's actual execution use actual gas price, capped by fastGasWei * gasCeilingMultiplier + if (isExecution && tx.gasprice < gasWei) { + gasWei = tx.gasprice; + } + + uint256 l1CostWei = 0; + if (i_mode == Mode.OPTIMISM) { + bytes memory txCallData = new bytes(0); + if (isExecution) { + txCallData = bytes.concat(msg.data, L1_FEE_DATA_PADDING); + } else { + // fee is 4 per 0 byte, 16 per non-zero byte. Worst case we can have + // s_storage.maxPerformDataSize non zero-bytes. Instead of setting bytes to non-zero + // we initialize 'new bytes' of length 4*maxPerformDataSize to cover for zero bytes. + txCallData = new bytes(4 * s_storage.maxPerformDataSize); + } + l1CostWei = OPTIMISM_ORACLE.getL1Fee(txCallData); + } else if (i_mode == Mode.ARBITRUM) { + if (isExecution) { + l1CostWei = ARB_NITRO_ORACLE.getCurrentTxL1GasFees(); + } else { + // fee is 4 per 0 byte, 16 per non-zero byte - we assume all non-zero and + // max data size to calculate max payment + (, uint256 perL1CalldataUnit, , , , ) = ARB_NITRO_ORACLE.getPricesInWei(); + l1CostWei = perL1CalldataUnit * s_storage.maxPerformDataSize * 16; + } + } + // if it's not performing upkeeps, use gas ceiling multiplier to estimate the upper bound + if (!isExecution) { + l1CostWei = hotVars.gasCeilingMultiplier * l1CostWei; + } + // Divide l1CostWei among all batched upkeeps. Spare change from division is not charged + l1CostWei = l1CostWei / numBatchedUpkeeps; + + uint256 gasPayment = ((gasWei * (gasLimit + gasOverhead) + l1CostWei) * 1e18) / linkNative; + uint256 premium = (((gasWei * gasLimit) + l1CostWei) * 1e9 * hotVars.paymentPremiumPPB) / + linkNative + + uint256(hotVars.flatFeeMicroLink) * + 1e12; + // LINK_TOTAL_SUPPLY < UINT96_MAX + if (gasPayment + premium > LINK_TOTAL_SUPPLY) revert PaymentGreaterThanAllLINK(); + return (uint96(gasPayment), uint96(premium)); + } + + /** + * @dev calculates the max LINK payment for an upkeep + */ + function _getMaxLinkPayment( + HotVars memory hotVars, + Trigger triggerType, + uint32 performGas, + uint32 performDataLength, + uint256 fastGasWei, + uint256 linkNative, + bool isExecution // Whether this is an actual perform execution or just a simulation + ) internal view returns (uint96) { + uint256 gasOverhead = _getMaxGasOverhead(triggerType, performDataLength, hotVars.f); + (uint96 reimbursement, uint96 premium) = _calculatePaymentAmount( + hotVars, + performGas, + gasOverhead, + fastGasWei, + linkNative, + 1, // Consider only 1 upkeep in batch to get maxPayment + isExecution + ); + + return reimbursement + premium; + } + + /** + * @dev returns the max gas overhead that can be charged for an upkeep + */ + function _getMaxGasOverhead(Trigger triggerType, uint32 performDataLength, uint8 f) internal pure returns (uint256) { + // performData causes additional overhead in report length and memory operations + uint256 baseOverhead; + if (triggerType == Trigger.CONDITION) { + baseOverhead = REGISTRY_CONDITIONAL_OVERHEAD; + } else if (triggerType == Trigger.LOG) { + baseOverhead = REGISTRY_LOG_OVERHEAD; + } else { + revert InvalidTriggerType(); + } + return + baseOverhead + + (REGISTRY_PER_SIGNER_GAS_OVERHEAD * (f + 1)) + + (REGISTRY_PER_PERFORM_BYTE_GAS_OVERHEAD * performDataLength); + } + + /** + * @dev move a transmitter's balance from total pool to withdrawable balance + */ + function _updateTransmitterBalanceFromPool( + address transmitterAddress, + uint96 totalPremium, + uint96 payeeCount + ) internal returns (uint96) { + Transmitter memory transmitter = s_transmitters[transmitterAddress]; + + if (transmitter.active) { + uint96 uncollected = totalPremium - transmitter.lastCollected; + uint96 due = uncollected / payeeCount; + transmitter.balance += due; + transmitter.lastCollected += due * payeeCount; + s_transmitters[transmitterAddress] = transmitter; + } + + return transmitter.balance; + } + + /** + * @dev gets the trigger type from an upkeepID (trigger type is encoded in the middle of the ID) + */ + function _getTriggerType(uint256 upkeepId) internal pure returns (Trigger) { + bytes32 rawID = bytes32(upkeepId); + bytes1 empty = bytes1(0); + for (uint256 idx = 4; idx < 15; idx++) { + if (rawID[idx] != empty) { + // old IDs that were created before this standard and migrated to this registry + return Trigger.CONDITION; + } + } + return Trigger(uint8(rawID[15])); + } + + function _checkPayload( + uint256 upkeepId, + Trigger triggerType, + bytes memory triggerData + ) internal view returns (bytes memory) { + if (triggerType == Trigger.CONDITION) { + return abi.encodeWithSelector(CHECK_SELECTOR, s_checkData[upkeepId]); + } else if (triggerType == Trigger.LOG) { + Log memory log = abi.decode(triggerData, (Log)); + return abi.encodeWithSelector(CHECK_LOG_SELECTOR, log, s_checkData[upkeepId]); + } + revert InvalidTriggerType(); + } + + /** + * @dev _decodeReport decodes a serialized report into a Report struct + */ + function _decodeReport(bytes calldata rawReport) internal pure returns (Report memory) { + Report memory report = abi.decode(rawReport, (Report)); + uint256 expectedLength = report.upkeepIds.length; + if ( + report.gasLimits.length != expectedLength || + report.triggers.length != expectedLength || + report.performDatas.length != expectedLength + ) { + revert InvalidReport(); + } + return report; + } + + /** + * @dev Does some early sanity checks before actually performing an upkeep + * @return bool whether the upkeep should be performed + * @return bytes32 dedupID for preventing duplicate performances of this trigger + */ + function _prePerformChecks( + uint256 upkeepId, + bytes memory rawTrigger, + UpkeepTransmitInfo memory transmitInfo + ) internal returns (bool, bytes32) { + bytes32 dedupID; + if (transmitInfo.triggerType == Trigger.CONDITION) { + if (!_validateConditionalTrigger(upkeepId, rawTrigger, transmitInfo)) return (false, dedupID); + } else if (transmitInfo.triggerType == Trigger.LOG) { + bool valid; + (valid, dedupID) = _validateLogTrigger(upkeepId, rawTrigger); + if (!valid) return (false, dedupID); + } else { + revert InvalidTriggerType(); + } + if (transmitInfo.upkeep.maxValidBlocknumber <= _blockNum()) { + // Can happen when an upkeep got cancelled after report was generated. + // However we have a CANCELLATION_DELAY of 50 blocks so shouldn't happen in practice + emit CancelledUpkeepReport(upkeepId, rawTrigger); + return (false, dedupID); + } + if (transmitInfo.upkeep.balance < transmitInfo.maxLinkPayment) { + // Can happen due to fluctuations in gas / link prices + emit InsufficientFundsUpkeepReport(upkeepId, rawTrigger); + return (false, dedupID); + } + return (true, dedupID); + } + + /** + * @dev Does some early sanity checks before actually performing an upkeep + */ + function _validateConditionalTrigger( + uint256 upkeepId, + bytes memory rawTrigger, + UpkeepTransmitInfo memory transmitInfo + ) internal returns (bool) { + ConditionalTrigger memory trigger = abi.decode(rawTrigger, (ConditionalTrigger)); + if (trigger.blockNum < transmitInfo.upkeep.lastPerformedBlockNumber) { + // Can happen when another report performed this upkeep after this report was generated + emit StaleUpkeepReport(upkeepId, rawTrigger); + return false; + } + if ( + (trigger.blockHash != bytes32("") && _blockHash(trigger.blockNum) != trigger.blockHash) || + trigger.blockNum >= _blockNum() + ) { + // There are two cases of reorged report + // 1. trigger block number is in future: this is an edge case during extreme deep reorgs of chain + // which is always protected against + // 2. blockHash at trigger block number was same as trigger time. This is an optional check which is + // applied if DON sends non empty trigger.blockHash. Note: It only works for last 256 blocks on chain + // when it is sent + emit ReorgedUpkeepReport(upkeepId, rawTrigger); + return false; + } + return true; + } + + function _validateLogTrigger(uint256 upkeepId, bytes memory rawTrigger) internal returns (bool, bytes32) { + LogTrigger memory trigger = abi.decode(rawTrigger, (LogTrigger)); + bytes32 dedupID = keccak256(abi.encodePacked(upkeepId, trigger.logBlockHash, trigger.txHash, trigger.logIndex)); + if ( + (trigger.blockHash != bytes32("") && _blockHash(trigger.blockNum) != trigger.blockHash) || + trigger.blockNum >= _blockNum() + ) { + // Reorg protection is same as conditional trigger upkeeps + emit ReorgedUpkeepReport(upkeepId, rawTrigger); + return (false, dedupID); + } + if (s_dedupKeys[dedupID]) { + emit StaleUpkeepReport(upkeepId, rawTrigger); + return (false, dedupID); + } + return (true, dedupID); + } + + /** + * @dev Verify signatures attached to report + */ + function _verifyReportSignature( + bytes32[3] calldata reportContext, + bytes calldata report, + bytes32[] calldata rs, + bytes32[] calldata ss, + bytes32 rawVs + ) internal view { + bytes32 h = keccak256(abi.encode(keccak256(report), reportContext)); + // i-th byte counts number of sigs made by i-th signer + uint256 signedCount = 0; + + Signer memory signer; + address signerAddress; + for (uint256 i = 0; i < rs.length; i++) { + signerAddress = ecrecover(h, uint8(rawVs[i]) + 27, rs[i], ss[i]); + signer = s_signers[signerAddress]; + if (!signer.active) revert OnlyActiveSigners(); + unchecked { + signedCount += 1 << (8 * signer.index); + } + } + + if (signedCount & ORACLE_MASK != signedCount) revert DuplicateSigners(); + } + + /** + * @dev updates a storage marker for this upkeep to prevent duplicate and out of order performances + * @dev for conditional triggers we set the latest block number, for log triggers we store a dedupID + */ + function _updateTriggerMarker(uint256 upkeepID, UpkeepTransmitInfo memory upkeepTransmitInfo) internal { + if (upkeepTransmitInfo.triggerType == Trigger.CONDITION) { + s_upkeep[upkeepID].lastPerformedBlockNumber = uint32(_blockNum()); + } else if (upkeepTransmitInfo.triggerType == Trigger.LOG) { + s_dedupKeys[upkeepTransmitInfo.dedupID] = true; + emit DedupKeyAdded(upkeepTransmitInfo.dedupID); + } + } + + /** + * @dev calls the Upkeep target with the performData param passed in by the + * transmitter and the exact gas required by the Upkeep + */ + function _performUpkeep( + IAutomationForwarder forwarder, + uint256 performGas, + bytes memory performData + ) internal nonReentrant returns (bool success, uint256 gasUsed) { + performData = abi.encodeWithSelector(PERFORM_SELECTOR, performData); + return forwarder.forward(performGas, performData); + } + + /** + * @dev does postPerform payment processing for an upkeep. Deducts upkeep's balance and increases + * amount spent. + */ + function _postPerformPayment( + HotVars memory hotVars, + uint256 upkeepId, + UpkeepTransmitInfo memory upkeepTransmitInfo, + uint256 fastGasWei, + uint256 linkNative, + uint16 numBatchedUpkeeps + ) internal returns (uint96 gasReimbursement, uint96 premium) { + (gasReimbursement, premium) = _calculatePaymentAmount( + hotVars, + upkeepTransmitInfo.gasUsed, + upkeepTransmitInfo.gasOverhead, + fastGasWei, + linkNative, + numBatchedUpkeeps, + true + ); + + uint96 payment = gasReimbursement + premium; + s_upkeep[upkeepId].balance -= payment; + s_upkeep[upkeepId].amountSpent += payment; + + return (gasReimbursement, premium); + } + + /** + * @dev Caps the gas overhead by the constant overhead used within initial payment checks in order to + * prevent a revert in payment processing. + */ + function _getCappedGasOverhead( + uint256 calculatedGasOverhead, + Trigger triggerType, + uint32 performDataLength, + uint8 f + ) internal pure returns (uint256 cappedGasOverhead) { + cappedGasOverhead = _getMaxGasOverhead(triggerType, performDataLength, f); + if (calculatedGasOverhead < cappedGasOverhead) { + return calculatedGasOverhead; + } + return cappedGasOverhead; + } + + /** + * @dev ensures the upkeep is not cancelled and the caller is the upkeep admin + */ + function _requireAdminAndNotCancelled(uint256 upkeepId) internal view { + if (msg.sender != s_upkeepAdmin[upkeepId]) revert OnlyCallableByAdmin(); + if (s_upkeep[upkeepId].maxValidBlocknumber != UINT32_MAX) revert UpkeepCancelled(); + } + + /** + * @dev returns the current block number in a chain agnostic manner + */ + function _blockNum() internal view returns (uint256) { + if (i_mode == Mode.ARBITRUM) { + return ARB_SYS.arbBlockNumber(); + } else { + return block.number; + } + } + + /** + * @dev returns the blockhash of the provided block number in a chain agnostic manner + * @param n the blocknumber to retrieve the blockhash for + * @return blockhash the blockhash of block number n, or 0 if n is out queryable of range + */ + function _blockHash(uint256 n) internal view returns (bytes32) { + if (i_mode == Mode.ARBITRUM) { + uint256 blockNum = ARB_SYS.arbBlockNumber(); + if (n >= blockNum || blockNum - n > 256) { + return ""; + } + return ARB_SYS.arbBlockHash(n); + } else { + return blockhash(n); + } + } + + /** + * @dev replicates Open Zeppelin's ReentrancyGuard but optimized to fit our storage + */ + modifier nonReentrant() { + if (s_hotVars.reentrancyGuard) revert ReentrantCall(); + s_hotVars.reentrancyGuard = true; + _; + s_hotVars.reentrancyGuard = false; + } +} diff --git a/contracts/src/v0.8/automation/dev/v2_2/AutomationRegistryLogicA2_2.sol b/contracts/src/v0.8/automation/dev/v2_2/AutomationRegistryLogicA2_2.sol new file mode 100644 index 0000000000..8c2183c4e2 --- /dev/null +++ b/contracts/src/v0.8/automation/dev/v2_2/AutomationRegistryLogicA2_2.sol @@ -0,0 +1,438 @@ +// SPDX-License-Identifier: BUSL-1.1 +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 {AutomationRegistryBase2_2} from "./AutomationRegistryBase2_2.sol"; +import {AutomationRegistryLogicB2_2} from "./AutomationRegistryLogicB2_2.sol"; +import {Chainable} from "../../Chainable.sol"; +import {AutomationForwarder} from "../../AutomationForwarder.sol"; +import {IAutomationForwarder} from "../../interfaces/IAutomationForwarder.sol"; +import {UpkeepTranscoderInterfaceV2} from "../../interfaces/UpkeepTranscoderInterfaceV2.sol"; +import {MigratableKeeperRegistryInterfaceV2} from "../../interfaces/MigratableKeeperRegistryInterfaceV2.sol"; + +/** + * @notice Logic contract, works in tandem with AutomationRegistry as a proxy + */ +contract AutomationRegistryLogicA2_2 is AutomationRegistryBase2_2, Chainable { + using Address for address; + using EnumerableSet for EnumerableSet.UintSet; + using EnumerableSet for EnumerableSet.AddressSet; + + /** + * @param logicB the address of the second logic contract + */ + constructor( + AutomationRegistryLogicB2_2 logicB + ) + AutomationRegistryBase2_2( + logicB.getMode(), + logicB.getLinkAddress(), + logicB.getLinkNativeFeedAddress(), + logicB.getFastGasFeedAddress(), + logicB.getAutomationForwarderLogic() + ) + Chainable(address(logicB)) + {} + + /** + * @notice called by the automation DON to check if work is needed + * @param id the upkeep ID to check for work needed + * @param triggerData extra contextual data about the trigger (not used in all code paths) + * @dev this one of the core functions called in the hot path + * @dev there is a 2nd checkUpkeep function (below) that is being maintained for backwards compatibility + * @dev there is an incongruency on what gets returned during failure modes + * ex sometimes we include price data, sometimes we omit it depending on the failure + */ + function checkUpkeep( + uint256 id, + bytes memory triggerData + ) + public + cannotExecute + returns ( + bool upkeepNeeded, + bytes memory performData, + UpkeepFailureReason upkeepFailureReason, + uint256 gasUsed, + uint256 gasLimit, + uint256 fastGasWei, + uint256 linkNative + ) + { + Trigger triggerType = _getTriggerType(id); + HotVars memory hotVars = s_hotVars; + Upkeep memory upkeep = s_upkeep[id]; + + if (hotVars.paused) return (false, bytes(""), UpkeepFailureReason.REGISTRY_PAUSED, 0, upkeep.performGas, 0, 0); + if (upkeep.maxValidBlocknumber != UINT32_MAX) + return (false, bytes(""), UpkeepFailureReason.UPKEEP_CANCELLED, 0, upkeep.performGas, 0, 0); + if (upkeep.paused) return (false, bytes(""), UpkeepFailureReason.UPKEEP_PAUSED, 0, upkeep.performGas, 0, 0); + + (fastGasWei, linkNative) = _getFeedData(hotVars); + uint96 maxLinkPayment = _getMaxLinkPayment( + hotVars, + triggerType, + upkeep.performGas, + s_storage.maxPerformDataSize, + fastGasWei, + linkNative, + false + ); + if (upkeep.balance < maxLinkPayment) { + return (false, bytes(""), UpkeepFailureReason.INSUFFICIENT_BALANCE, 0, upkeep.performGas, 0, 0); + } + + bytes memory callData = _checkPayload(id, triggerType, triggerData); + + gasUsed = gasleft(); + (bool success, bytes memory result) = upkeep.forwarder.getTarget().call{gas: s_storage.checkGasLimit}(callData); + gasUsed = gasUsed - gasleft(); + + if (!success) { + // User's target check reverted. We capture the revert data here and pass it within performData + if (result.length > s_storage.maxRevertDataSize) { + return ( + false, + bytes(""), + UpkeepFailureReason.REVERT_DATA_EXCEEDS_LIMIT, + gasUsed, + upkeep.performGas, + fastGasWei, + linkNative + ); + } + return ( + upkeepNeeded, + result, + UpkeepFailureReason.TARGET_CHECK_REVERTED, + gasUsed, + upkeep.performGas, + fastGasWei, + linkNative + ); + } + + (upkeepNeeded, performData) = abi.decode(result, (bool, bytes)); + if (!upkeepNeeded) + return ( + false, + bytes(""), + UpkeepFailureReason.UPKEEP_NOT_NEEDED, + gasUsed, + upkeep.performGas, + fastGasWei, + linkNative + ); + + if (performData.length > s_storage.maxPerformDataSize) + return ( + false, + bytes(""), + UpkeepFailureReason.PERFORM_DATA_EXCEEDS_LIMIT, + gasUsed, + upkeep.performGas, + fastGasWei, + linkNative + ); + + return (upkeepNeeded, performData, upkeepFailureReason, gasUsed, upkeep.performGas, fastGasWei, linkNative); + } + + /** + * @notice see other checkUpkeep function for description + * @dev this function may be deprecated in a future version of chainlink automation + */ + function checkUpkeep( + uint256 id + ) + external + returns ( + bool upkeepNeeded, + bytes memory performData, + UpkeepFailureReason upkeepFailureReason, + uint256 gasUsed, + uint256 gasLimit, + uint256 fastGasWei, + uint256 linkNative + ) + { + return checkUpkeep(id, bytes("")); + } + + /** + * @dev checkCallback is used specifically for automation data streams lookups (see StreamsLookupCompatibleInterface.sol) + * @param id the upkeepID to execute a callback for + * @param values the values returned from the data streams lookup + * @param extraData the user-provided extra context data + */ + function checkCallback( + uint256 id, + bytes[] memory values, + bytes calldata extraData + ) + external + cannotExecute + returns (bool upkeepNeeded, bytes memory performData, UpkeepFailureReason upkeepFailureReason, uint256 gasUsed) + { + bytes memory payload = abi.encodeWithSelector(CHECK_CALLBACK_SELECTOR, values, extraData); + return executeCallback(id, payload); + } + + /** + * @notice this is a generic callback executor that forwards a call to a user's contract with the configured + * gas limit + * @param id the upkeepID to execute a callback for + * @param payload the data (including function selector) to call on the upkeep target contract + */ + function executeCallback( + uint256 id, + bytes memory payload + ) + public + cannotExecute + returns (bool upkeepNeeded, bytes memory performData, UpkeepFailureReason upkeepFailureReason, uint256 gasUsed) + { + Upkeep memory upkeep = s_upkeep[id]; + gasUsed = gasleft(); + (bool success, bytes memory result) = upkeep.forwarder.getTarget().call{gas: s_storage.checkGasLimit}(payload); + gasUsed = gasUsed - gasleft(); + if (!success) { + return (false, bytes(""), UpkeepFailureReason.CALLBACK_REVERTED, gasUsed); + } + (upkeepNeeded, performData) = abi.decode(result, (bool, bytes)); + if (!upkeepNeeded) { + return (false, bytes(""), UpkeepFailureReason.UPKEEP_NOT_NEEDED, gasUsed); + } + if (performData.length > s_storage.maxPerformDataSize) { + return (false, bytes(""), UpkeepFailureReason.PERFORM_DATA_EXCEEDS_LIMIT, gasUsed); + } + return (upkeepNeeded, performData, upkeepFailureReason, gasUsed); + } + + /** + * @notice adds a new upkeep + * @param target address to perform upkeep on + * @param gasLimit amount of gas to provide the target contract when + * performing upkeep + * @param admin address to cancel upkeep and withdraw remaining funds + * @param triggerType the trigger for the upkeep + * @param checkData data passed to the contract when checking for upkeep + * @param triggerConfig the config for the trigger + * @param offchainConfig arbitrary offchain config for the upkeep + */ + function registerUpkeep( + address target, + uint32 gasLimit, + address admin, + Trigger triggerType, + bytes calldata checkData, + bytes memory triggerConfig, + bytes memory offchainConfig + ) public returns (uint256 id) { + if (msg.sender != owner() && !s_registrars.contains(msg.sender)) revert OnlyCallableByOwnerOrRegistrar(); + if (!target.isContract()) revert NotAContract(); + id = _createID(triggerType); + IAutomationForwarder forwarder = IAutomationForwarder( + address(new AutomationForwarder(target, address(this), i_automationForwarderLogic)) + ); + _createUpkeep( + id, + Upkeep({ + performGas: gasLimit, + balance: 0, + maxValidBlocknumber: UINT32_MAX, + lastPerformedBlockNumber: 0, + amountSpent: 0, + paused: false, + forwarder: forwarder + }), + admin, + checkData, + triggerConfig, + offchainConfig + ); + s_storage.nonce++; + emit UpkeepRegistered(id, gasLimit, admin); + emit UpkeepCheckDataSet(id, checkData); + emit UpkeepTriggerConfigSet(id, triggerConfig); + emit UpkeepOffchainConfigSet(id, offchainConfig); + return (id); + } + + /** + * @notice this function registers a conditional upkeep, using a backwards compatible function signature + * @dev this function is backwards compatible with versions <=2.0, but may be removed in a future version + */ + function registerUpkeep( + address target, + uint32 gasLimit, + address admin, + bytes calldata checkData, + bytes calldata offchainConfig + ) external returns (uint256 id) { + return registerUpkeep(target, gasLimit, admin, Trigger.CONDITION, checkData, bytes(""), offchainConfig); + } + + /** + * @notice cancels an upkeep + * @param id the upkeepID to cancel + * @dev if a user cancels an upkeep, their funds are locked for CANCELLATION_DELAY blocks to + * allow any pending performUpkeep txs time to get confirmed + */ + function cancelUpkeep(uint256 id) external { + Upkeep memory upkeep = s_upkeep[id]; + bool canceled = upkeep.maxValidBlocknumber != UINT32_MAX; + bool isOwner = msg.sender == owner(); + + if (canceled && !(isOwner && upkeep.maxValidBlocknumber > _blockNum())) revert CannotCancel(); + if (!isOwner && msg.sender != s_upkeepAdmin[id]) revert OnlyCallableByOwnerOrAdmin(); + + uint256 height = _blockNum(); + if (!isOwner) { + height = height + CANCELLATION_DELAY; + } + s_upkeep[id].maxValidBlocknumber = uint32(height); + s_upkeepIDs.remove(id); + + // charge the cancellation fee if the minUpkeepSpend is not met + uint96 minUpkeepSpend = s_storage.minUpkeepSpend; + uint96 cancellationFee = 0; + // cancellationFee is supposed to be min(max(minUpkeepSpend - amountSpent,0), amountLeft) + if (upkeep.amountSpent < minUpkeepSpend) { + cancellationFee = minUpkeepSpend - upkeep.amountSpent; + if (cancellationFee > upkeep.balance) { + cancellationFee = upkeep.balance; + } + } + s_upkeep[id].balance = upkeep.balance - cancellationFee; + s_storage.ownerLinkBalance = s_storage.ownerLinkBalance + cancellationFee; + + emit UpkeepCanceled(id, uint64(height)); + } + + /** + * @notice adds fund to an upkeep + * @param id the upkeepID + * @param amount the amount of LINK to fund, in jules (jules = "wei" of LINK) + */ + function addFunds(uint256 id, uint96 amount) external { + Upkeep memory upkeep = s_upkeep[id]; + if (upkeep.maxValidBlocknumber != UINT32_MAX) revert UpkeepCancelled(); + s_upkeep[id].balance = upkeep.balance + amount; + s_expectedLinkBalance = s_expectedLinkBalance + amount; + i_link.transferFrom(msg.sender, address(this), amount); + emit FundsAdded(id, msg.sender, amount); + } + + /** + * @notice migrates upkeeps from one registry to another + * @param ids the upkeepIDs to migrate + * @param destination the destination registry address + * @dev a transcoder must be set in order to enable migration + * @dev migration permissions must be set on *both* sending and receiving registries + * @dev only an upkeep admin can migrate their upkeeps + */ + function migrateUpkeeps(uint256[] calldata ids, address destination) external { + if ( + s_peerRegistryMigrationPermission[destination] != MigrationPermission.OUTGOING && + s_peerRegistryMigrationPermission[destination] != MigrationPermission.BIDIRECTIONAL + ) revert MigrationNotPermitted(); + if (s_storage.transcoder == ZERO_ADDRESS) revert TranscoderNotSet(); + if (ids.length == 0) revert ArrayHasNoEntries(); + uint256 id; + Upkeep memory upkeep; + uint256 totalBalanceRemaining; + address[] memory admins = new address[](ids.length); + Upkeep[] memory upkeeps = new Upkeep[](ids.length); + bytes[] memory checkDatas = new bytes[](ids.length); + bytes[] memory triggerConfigs = new bytes[](ids.length); + bytes[] memory offchainConfigs = new bytes[](ids.length); + for (uint256 idx = 0; idx < ids.length; idx++) { + id = ids[idx]; + upkeep = s_upkeep[id]; + _requireAdminAndNotCancelled(id); + upkeep.forwarder.updateRegistry(destination); + upkeeps[idx] = upkeep; + admins[idx] = s_upkeepAdmin[id]; + checkDatas[idx] = s_checkData[id]; + triggerConfigs[idx] = s_upkeepTriggerConfig[id]; + offchainConfigs[idx] = s_upkeepOffchainConfig[id]; + totalBalanceRemaining = totalBalanceRemaining + upkeep.balance; + delete s_upkeep[id]; + delete s_checkData[id]; + delete s_upkeepTriggerConfig[id]; + delete s_upkeepOffchainConfig[id]; + // nullify existing proposed admin change if an upkeep is being migrated + delete s_proposedAdmin[id]; + s_upkeepIDs.remove(id); + emit UpkeepMigrated(id, upkeep.balance, destination); + } + s_expectedLinkBalance = s_expectedLinkBalance - totalBalanceRemaining; + bytes memory encodedUpkeeps = abi.encode( + ids, + upkeeps, + new address[](ids.length), + admins, + checkDatas, + triggerConfigs, + offchainConfigs + ); + MigratableKeeperRegistryInterfaceV2(destination).receiveUpkeeps( + UpkeepTranscoderInterfaceV2(s_storage.transcoder).transcodeUpkeeps( + UPKEEP_VERSION_BASE, + MigratableKeeperRegistryInterfaceV2(destination).upkeepVersion(), + encodedUpkeeps + ) + ); + i_link.transfer(destination, totalBalanceRemaining); + } + + /** + * @notice received upkeeps migrated from another registry + * @param encodedUpkeeps the raw upkeep data to import + * @dev this function is never called directly, it is only called by another registry's migrate function + */ + function receiveUpkeeps(bytes calldata encodedUpkeeps) external { + if ( + s_peerRegistryMigrationPermission[msg.sender] != MigrationPermission.INCOMING && + s_peerRegistryMigrationPermission[msg.sender] != MigrationPermission.BIDIRECTIONAL + ) revert MigrationNotPermitted(); + ( + uint256[] memory ids, + Upkeep[] memory upkeeps, + address[] memory targets, + address[] memory upkeepAdmins, + bytes[] memory checkDatas, + bytes[] memory triggerConfigs, + bytes[] memory offchainConfigs + ) = abi.decode(encodedUpkeeps, (uint256[], Upkeep[], address[], address[], bytes[], bytes[], bytes[])); + for (uint256 idx = 0; idx < ids.length; idx++) { + if (address(upkeeps[idx].forwarder) == ZERO_ADDRESS) { + upkeeps[idx].forwarder = IAutomationForwarder( + address(new AutomationForwarder(targets[idx], address(this), i_automationForwarderLogic)) + ); + } + _createUpkeep( + ids[idx], + upkeeps[idx], + upkeepAdmins[idx], + checkDatas[idx], + triggerConfigs[idx], + offchainConfigs[idx] + ); + emit UpkeepReceived(ids[idx], upkeeps[idx].balance, msg.sender); + } + } + + /** + * @notice sets the upkeep trigger config + * @param id the upkeepID to change the trigger for + * @param triggerConfig the new trigger config + */ + function setUpkeepTriggerConfig(uint256 id, bytes calldata triggerConfig) external { + _requireAdminAndNotCancelled(id); + s_upkeepTriggerConfig[id] = triggerConfig; + emit UpkeepTriggerConfigSet(id, triggerConfig); + } +} diff --git a/contracts/src/v0.8/automation/dev/v2_2/AutomationRegistryLogicB2_2.sol b/contracts/src/v0.8/automation/dev/v2_2/AutomationRegistryLogicB2_2.sol new file mode 100644 index 0000000000..0724fbd53f --- /dev/null +++ b/contracts/src/v0.8/automation/dev/v2_2/AutomationRegistryLogicB2_2.sol @@ -0,0 +1,516 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity 0.8.16; + +import {AutomationRegistryBase2_2} from "./AutomationRegistryBase2_2.sol"; +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 {UpkeepFormat} from "../../interfaces/UpkeepTranscoderInterface.sol"; +import {IAutomationForwarder} from "../../interfaces/IAutomationForwarder.sol"; + +contract AutomationRegistryLogicB2_2 is AutomationRegistryBase2_2 { + using Address for address; + using EnumerableSet for EnumerableSet.UintSet; + using EnumerableSet for EnumerableSet.AddressSet; + + /** + * @dev see AutomationRegistry master contract for constructor description + */ + constructor( + Mode mode, + address link, + address linkNativeFeed, + address fastGasFeed, + address automationForwarderLogic + ) AutomationRegistryBase2_2(mode, link, linkNativeFeed, fastGasFeed, automationForwarderLogic) {} + + // ================================================================ + // | UPKEEP MANAGEMENT | + // ================================================================ + + /** + * @notice transfers the address of an admin for an upkeep + */ + function transferUpkeepAdmin(uint256 id, address proposed) external { + _requireAdminAndNotCancelled(id); + if (proposed == msg.sender) revert ValueNotChanged(); + + if (s_proposedAdmin[id] != proposed) { + s_proposedAdmin[id] = proposed; + emit UpkeepAdminTransferRequested(id, msg.sender, proposed); + } + } + + /** + * @notice accepts the transfer of an upkeep admin + */ + function acceptUpkeepAdmin(uint256 id) external { + Upkeep memory upkeep = s_upkeep[id]; + if (upkeep.maxValidBlocknumber != UINT32_MAX) revert UpkeepCancelled(); + if (s_proposedAdmin[id] != msg.sender) revert OnlyCallableByProposedAdmin(); + address past = s_upkeepAdmin[id]; + s_upkeepAdmin[id] = msg.sender; + s_proposedAdmin[id] = ZERO_ADDRESS; + + emit UpkeepAdminTransferred(id, past, msg.sender); + } + + /** + * @notice pauses an upkeep - an upkeep will be neither checked nor performed while paused + */ + function pauseUpkeep(uint256 id) external { + _requireAdminAndNotCancelled(id); + Upkeep memory upkeep = s_upkeep[id]; + if (upkeep.paused) revert OnlyUnpausedUpkeep(); + s_upkeep[id].paused = true; + s_upkeepIDs.remove(id); + emit UpkeepPaused(id); + } + + /** + * @notice unpauses an upkeep + */ + function unpauseUpkeep(uint256 id) external { + _requireAdminAndNotCancelled(id); + Upkeep memory upkeep = s_upkeep[id]; + if (!upkeep.paused) revert OnlyPausedUpkeep(); + s_upkeep[id].paused = false; + s_upkeepIDs.add(id); + emit UpkeepUnpaused(id); + } + + /** + * @notice updates the checkData for an upkeep + */ + function setUpkeepCheckData(uint256 id, bytes calldata newCheckData) external { + _requireAdminAndNotCancelled(id); + if (newCheckData.length > s_storage.maxCheckDataSize) revert CheckDataExceedsLimit(); + s_checkData[id] = newCheckData; + emit UpkeepCheckDataSet(id, newCheckData); + } + + /** + * @notice updates the gas limit for an upkeep + */ + function setUpkeepGasLimit(uint256 id, uint32 gasLimit) external { + if (gasLimit < PERFORM_GAS_MIN || gasLimit > s_storage.maxPerformGas) revert GasLimitOutsideRange(); + _requireAdminAndNotCancelled(id); + s_upkeep[id].performGas = gasLimit; + + emit UpkeepGasLimitSet(id, gasLimit); + } + + /** + * @notice updates the offchain config for an upkeep + */ + function setUpkeepOffchainConfig(uint256 id, bytes calldata config) external { + _requireAdminAndNotCancelled(id); + s_upkeepOffchainConfig[id] = config; + emit UpkeepOffchainConfigSet(id, config); + } + + /** + * @notice withdraws LINK funds from an upkeep + * @dev note that an upkeep must be cancelled first!! + */ + function withdrawFunds(uint256 id, address to) external nonReentrant { + if (to == ZERO_ADDRESS) revert InvalidRecipient(); + Upkeep memory upkeep = s_upkeep[id]; + if (s_upkeepAdmin[id] != msg.sender) revert OnlyCallableByAdmin(); + if (upkeep.maxValidBlocknumber > _blockNum()) revert UpkeepNotCanceled(); + uint96 amountToWithdraw = s_upkeep[id].balance; + s_expectedLinkBalance = s_expectedLinkBalance - amountToWithdraw; + s_upkeep[id].balance = 0; + i_link.transfer(to, amountToWithdraw); + emit FundsWithdrawn(id, amountToWithdraw, to); + } + + // ================================================================ + // | NODE MANAGEMENT | + // ================================================================ + + /** + * @notice transfers the address of payee for a transmitter + */ + function transferPayeeship(address transmitter, address proposed) external { + if (s_transmitterPayees[transmitter] != msg.sender) revert OnlyCallableByPayee(); + if (proposed == msg.sender) revert ValueNotChanged(); + + if (s_proposedPayee[transmitter] != proposed) { + s_proposedPayee[transmitter] = proposed; + emit PayeeshipTransferRequested(transmitter, msg.sender, proposed); + } + } + + /** + * @notice accepts the transfer of the payee + */ + function acceptPayeeship(address transmitter) external { + if (s_proposedPayee[transmitter] != msg.sender) revert OnlyCallableByProposedPayee(); + address past = s_transmitterPayees[transmitter]; + s_transmitterPayees[transmitter] = msg.sender; + s_proposedPayee[transmitter] = ZERO_ADDRESS; + + emit PayeeshipTransferred(transmitter, past, msg.sender); + } + + /** + * @notice withdraws LINK received as payment for work performed + */ + function withdrawPayment(address from, address to) external { + if (to == ZERO_ADDRESS) revert InvalidRecipient(); + if (s_transmitterPayees[from] != msg.sender) revert OnlyCallableByPayee(); + uint96 balance = _updateTransmitterBalanceFromPool(from, s_hotVars.totalPremium, uint96(s_transmittersList.length)); + s_transmitters[from].balance = 0; + s_expectedLinkBalance = s_expectedLinkBalance - balance; + i_link.transfer(to, balance); + emit PaymentWithdrawn(from, balance, to, msg.sender); + } + + // ================================================================ + // | OWNER / MANAGER ACTIONS | + // ================================================================ + + /** + * @notice sets the privilege config for an upkeep + */ + function setUpkeepPrivilegeConfig(uint256 upkeepId, bytes calldata newPrivilegeConfig) external { + if (msg.sender != s_storage.upkeepPrivilegeManager) { + revert OnlyCallableByUpkeepPrivilegeManager(); + } + s_upkeepPrivilegeConfig[upkeepId] = newPrivilegeConfig; + emit UpkeepPrivilegeConfigSet(upkeepId, newPrivilegeConfig); + } + + /** + * @notice withdraws the owner's LINK balance + */ + function withdrawOwnerFunds() external onlyOwner { + uint96 amount = s_storage.ownerLinkBalance; + s_expectedLinkBalance = s_expectedLinkBalance - amount; + s_storage.ownerLinkBalance = 0; + emit OwnerFundsWithdrawn(amount); + i_link.transfer(msg.sender, amount); + } + + /** + * @notice allows the owner to withdraw any LINK accidentally sent to the contract + */ + function recoverFunds() external onlyOwner { + uint256 total = i_link.balanceOf(address(this)); + i_link.transfer(msg.sender, total - s_expectedLinkBalance); + } + + /** + * @notice sets the payees for the transmitters + */ + function setPayees(address[] calldata payees) external onlyOwner { + if (s_transmittersList.length != payees.length) revert ParameterLengthError(); + for (uint256 i = 0; i < s_transmittersList.length; i++) { + address transmitter = s_transmittersList[i]; + address oldPayee = s_transmitterPayees[transmitter]; + address newPayee = payees[i]; + if ( + (newPayee == ZERO_ADDRESS) || (oldPayee != ZERO_ADDRESS && oldPayee != newPayee && newPayee != IGNORE_ADDRESS) + ) revert InvalidPayee(); + if (newPayee != IGNORE_ADDRESS) { + s_transmitterPayees[transmitter] = newPayee; + } + } + emit PayeesUpdated(s_transmittersList, payees); + } + + /** + * @notice sets the migration permission for a peer registry + * @dev this must be done before upkeeps can be migrated to/from another registry + */ + function setPeerRegistryMigrationPermission(address peer, MigrationPermission permission) external onlyOwner { + s_peerRegistryMigrationPermission[peer] = permission; + } + + /** + * @notice pauses the entire registry + */ + function pause() external onlyOwner { + s_hotVars.paused = true; + emit Paused(msg.sender); + } + + /** + * @notice unpauses the entire registry + */ + function unpause() external onlyOwner { + s_hotVars.paused = false; + emit Unpaused(msg.sender); + } + + /** + * @notice sets a generic bytes field used to indicate the privilege that this admin address had + * @param admin the address to set privilege for + * @param newPrivilegeConfig the privileges that this admin has + */ + function setAdminPrivilegeConfig(address admin, bytes calldata newPrivilegeConfig) external { + if (msg.sender != s_storage.upkeepPrivilegeManager) { + revert OnlyCallableByUpkeepPrivilegeManager(); + } + s_adminPrivilegeConfig[admin] = newPrivilegeConfig; + emit AdminPrivilegeConfigSet(admin, newPrivilegeConfig); + } + + // ================================================================ + // | GETTERS | + // ================================================================ + + function getConditionalGasOverhead() external pure returns (uint256) { + return REGISTRY_CONDITIONAL_OVERHEAD; + } + + function getLogGasOverhead() external pure returns (uint256) { + return REGISTRY_LOG_OVERHEAD; + } + + function getPerPerformByteGasOverhead() external pure returns (uint256) { + return REGISTRY_PER_PERFORM_BYTE_GAS_OVERHEAD; + } + + function getPerSignerGasOverhead() external pure returns (uint256) { + return REGISTRY_PER_SIGNER_GAS_OVERHEAD; + } + + function getCancellationDelay() external pure returns (uint256) { + return CANCELLATION_DELAY; + } + + function getMode() external view returns (Mode) { + return i_mode; + } + + function getLinkAddress() external view returns (address) { + return address(i_link); + } + + function getLinkNativeFeedAddress() external view returns (address) { + return address(i_linkNativeFeed); + } + + function getFastGasFeedAddress() external view returns (address) { + return address(i_fastGasFeed); + } + + function getAutomationForwarderLogic() external view returns (address) { + return i_automationForwarderLogic; + } + + function upkeepTranscoderVersion() public pure returns (UpkeepFormat) { + return UPKEEP_TRANSCODER_VERSION_BASE; + } + + function upkeepVersion() public pure returns (uint8) { + return UPKEEP_VERSION_BASE; + } + + /** + * @notice read all of the details about an upkeep + * @dev this function may be deprecated in a future version of automation in favor of individual + * getters for each field + */ + function getUpkeep(uint256 id) external view returns (UpkeepInfo memory upkeepInfo) { + Upkeep memory reg = s_upkeep[id]; + address target = address(reg.forwarder) == address(0) ? address(0) : reg.forwarder.getTarget(); + upkeepInfo = UpkeepInfo({ + target: target, + performGas: reg.performGas, + checkData: s_checkData[id], + balance: reg.balance, + admin: s_upkeepAdmin[id], + maxValidBlocknumber: reg.maxValidBlocknumber, + lastPerformedBlockNumber: reg.lastPerformedBlockNumber, + amountSpent: reg.amountSpent, + paused: reg.paused, + offchainConfig: s_upkeepOffchainConfig[id] + }); + return upkeepInfo; + } + + /** + * @notice retrieve active upkeep IDs. Active upkeep is defined as an upkeep which is not paused and not canceled. + * @param startIndex starting index in list + * @param maxCount max count to retrieve (0 = unlimited) + * @dev the order of IDs in the list is **not guaranteed**, therefore, if making successive calls, one + * should consider keeping the blockheight constant to ensure a holistic picture of the contract state + */ + function getActiveUpkeepIDs(uint256 startIndex, uint256 maxCount) external view returns (uint256[] memory) { + uint256 numUpkeeps = s_upkeepIDs.length(); + if (startIndex >= numUpkeeps) revert IndexOutOfRange(); + uint256 endIndex = startIndex + maxCount; + endIndex = endIndex > numUpkeeps || maxCount == 0 ? numUpkeeps : endIndex; + uint256[] memory ids = new uint256[](endIndex - startIndex); + for (uint256 idx = 0; idx < ids.length; idx++) { + ids[idx] = s_upkeepIDs.at(idx + startIndex); + } + return ids; + } + + /** + * @notice returns the upkeep's trigger type + */ + function getTriggerType(uint256 upkeepId) external pure returns (Trigger) { + return _getTriggerType(upkeepId); + } + + /** + * @notice returns the trigger config for an upkeeep + */ + function getUpkeepTriggerConfig(uint256 upkeepId) public view returns (bytes memory) { + return s_upkeepTriggerConfig[upkeepId]; + } + + /** + * @notice read the current info about any transmitter address + */ + function getTransmitterInfo( + address query + ) external view returns (bool active, uint8 index, uint96 balance, uint96 lastCollected, address payee) { + Transmitter memory transmitter = s_transmitters[query]; + + uint96 pooledShare = 0; + if (transmitter.active) { + uint96 totalDifference = s_hotVars.totalPremium - transmitter.lastCollected; + pooledShare = totalDifference / uint96(s_transmittersList.length); + } + + return ( + transmitter.active, + transmitter.index, + (transmitter.balance + pooledShare), + transmitter.lastCollected, + s_transmitterPayees[query] + ); + } + + /** + * @notice read the current info about any signer address + */ + function getSignerInfo(address query) external view returns (bool active, uint8 index) { + Signer memory signer = s_signers[query]; + return (signer.active, signer.index); + } + + /** + * @notice read the current state of the registry + */ + function getState() + external + view + returns ( + State memory state, + OnchainConfig memory config, + address[] memory signers, + address[] memory transmitters, + uint8 f + ) + { + state = State({ + nonce: s_storage.nonce, + ownerLinkBalance: s_storage.ownerLinkBalance, + expectedLinkBalance: s_expectedLinkBalance, + totalPremium: s_hotVars.totalPremium, + numUpkeeps: s_upkeepIDs.length(), + configCount: s_storage.configCount, + latestConfigBlockNumber: s_storage.latestConfigBlockNumber, + latestConfigDigest: s_latestConfigDigest, + latestEpoch: s_hotVars.latestEpoch, + paused: s_hotVars.paused + }); + + config = OnchainConfig({ + paymentPremiumPPB: s_hotVars.paymentPremiumPPB, + flatFeeMicroLink: s_hotVars.flatFeeMicroLink, + checkGasLimit: s_storage.checkGasLimit, + stalenessSeconds: s_hotVars.stalenessSeconds, + gasCeilingMultiplier: s_hotVars.gasCeilingMultiplier, + minUpkeepSpend: s_storage.minUpkeepSpend, + maxPerformGas: s_storage.maxPerformGas, + maxCheckDataSize: s_storage.maxCheckDataSize, + maxPerformDataSize: s_storage.maxPerformDataSize, + maxRevertDataSize: s_storage.maxRevertDataSize, + fallbackGasPrice: s_fallbackGasPrice, + fallbackLinkPrice: s_fallbackLinkPrice, + transcoder: s_storage.transcoder, + registrars: s_registrars.values(), + upkeepPrivilegeManager: s_storage.upkeepPrivilegeManager + }); + + return (state, config, s_signersList, s_transmittersList, s_hotVars.f); + } + + /** + * @notice calculates the minimum balance required for an upkeep to remain eligible + * @param id the upkeep id to calculate minimum balance for + */ + function getBalance(uint256 id) external view returns (uint96 balance) { + return s_upkeep[id].balance; + } + + /** + * @notice calculates the minimum balance required for an upkeep to remain eligible + * @param id the upkeep id to calculate minimum balance for + */ + function getMinBalance(uint256 id) external view returns (uint96) { + return getMinBalanceForUpkeep(id); + } + + /** + * @notice calculates the minimum balance required for an upkeep to remain eligible + * @param id the upkeep id to calculate minimum balance for + * @dev this will be deprecated in a future version in favor of getMinBalance + */ + function getMinBalanceForUpkeep(uint256 id) public view returns (uint96 minBalance) { + return getMaxPaymentForGas(_getTriggerType(id), s_upkeep[id].performGas); + } + + /** + * @notice calculates the maximum payment for a given gas limit + * @param gasLimit the gas to calculate payment for + */ + function getMaxPaymentForGas(Trigger triggerType, uint32 gasLimit) public view returns (uint96 maxPayment) { + HotVars memory hotVars = s_hotVars; + (uint256 fastGasWei, uint256 linkNative) = _getFeedData(hotVars); + return + _getMaxLinkPayment(hotVars, triggerType, gasLimit, s_storage.maxPerformDataSize, fastGasWei, linkNative, false); + } + + /** + * @notice retrieves the migration permission for a peer registry + */ + function getPeerRegistryMigrationPermission(address peer) external view returns (MigrationPermission) { + return s_peerRegistryMigrationPermission[peer]; + } + + /** + * @notice returns the upkeep privilege config + */ + function getUpkeepPrivilegeConfig(uint256 upkeepId) external view returns (bytes memory) { + return s_upkeepPrivilegeConfig[upkeepId]; + } + + /** + * @notice returns the upkeep privilege config + */ + function getAdminPrivilegeConfig(address admin) external view returns (bytes memory) { + return s_adminPrivilegeConfig[admin]; + } + + /** + * @notice returns the upkeep's forwarder contract + */ + function getForwarder(uint256 upkeepID) external view returns (IAutomationForwarder) { + return s_upkeep[upkeepID].forwarder; + } + + /** + * @notice returns the upkeep's forwarder contract + */ + function hasDedupKey(bytes32 dedupKey) external view returns (bool) { + return s_dedupKeys[dedupKey]; + } +} diff --git a/contracts/src/v0.8/automation/dev/v2_2/AutomationUtils2_2.sol b/contracts/src/v0.8/automation/dev/v2_2/AutomationUtils2_2.sol new file mode 100644 index 0000000000..2b8fd8df6a --- /dev/null +++ b/contracts/src/v0.8/automation/dev/v2_2/AutomationUtils2_2.sol @@ -0,0 +1,40 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity 0.8.16; + +import {AutomationRegistryBase2_2} from "./AutomationRegistryBase2_2.sol"; +import {Log} from "../../interfaces/ILogAutomation.sol"; + +/** + * @notice this file exposes structs that are otherwise internal to the automation registry + * doing this allows those structs to be encoded and decoded with type safety in offchain code + * and tests because generated wrappers are made available + */ + +/** + * @notice structure of trigger for log triggers + */ +struct LogTriggerConfig { + address contractAddress; + uint8 filterSelector; // denotes which topics apply to filter ex 000, 101, 111...only last 3 bits apply + bytes32 topic0; + bytes32 topic1; + bytes32 topic2; + bytes32 topic3; +} + +contract AutomationUtils2_2 { + /** + * @dev this can be removed as OnchainConfig is now exposed directly from the registry + */ + function _onChainConfig(AutomationRegistryBase2_2.OnchainConfig memory) external {} // 0x2ff92a81 + + function _report(AutomationRegistryBase2_2.Report memory) external {} // 0xe65d6546 + + function _logTriggerConfig(LogTriggerConfig memory) external {} // 0x21f373d7 + + function _logTrigger(AutomationRegistryBase2_2.LogTrigger memory) external {} // 0x1c8d8260 + + function _conditionalTrigger(AutomationRegistryBase2_2.ConditionalTrigger memory) external {} // 0x4b6df294 + + function _log(Log memory) external {} // 0xe9720a49 +} diff --git a/contracts/src/v0.8/automation/dev/v2_2/LICENSE b/contracts/src/v0.8/automation/dev/v2_2/LICENSE new file mode 100644 index 0000000000..9230d392a9 --- /dev/null +++ b/contracts/src/v0.8/automation/dev/v2_2/LICENSE @@ -0,0 +1,57 @@ +Business Source License 1.1 + +License text copyright (c) 2017 MariaDB Corporation Ab, All Rights Reserved. +"Business Source License" is a trademark of MariaDB Corporation Ab. + +--- + +Parameters + +Licensor: SmartContract Chainlink Limited SEZC + +Licensed Work: Automation v2.2 +The Licensed Work is (c) 2024 SmartContract Chainlink Limited SEZC + +Additional Use Grant(s): +You may make use of Automation v2.1, v2.2 (which is available subject to the license here the “Licensed Work”) solely for purposes listed below: +https://github.com/smartcontractkit/chainlink-automation/tree/main/Automation_Grants.md + +Change Date: January 22, 2028 + +Change License: MIT + +--- + +Terms + +The Licensor hereby grants you the right to copy, modify, create derivative works, redistribute, and make non-production use of the Licensed Work. The Licensor may make an Additional Use Grant, above, permitting limited production use. + +Effective on the Change Date, or the fourth anniversary of the first publicly available distribution of a specific version of the Licensed Work under this License, whichever comes first, the Licensor hereby grants you rights under the terms of the Change License, and the rights granted in the paragraph above terminate. + +If your use of the Licensed Work does not comply with the requirements currently in effect as described in this License, you must purchase a commercial license from the Licensor, its affiliated entities, or authorized resellers, or you must refrain from using the Licensed Work. + +All copies of the original and modified Licensed Work, and derivative works of the Licensed Work, are subject to this License. This License applies separately for each version of the Licensed Work and the Change Date may vary for each version of the Licensed Work released by Licensor. + +You must conspicuously display this License on each original or modified copy of the Licensed Work. If you receive the Licensed Work in original or modified form from a third party, the terms and conditions set forth in this License apply to your use of that work. + +Any use of the Licensed Work in violation of this License will automatically terminate your rights under this License for the current and all other versions of the Licensed Work. + +This License does not grant you any right in any trademark or logo of Licensor or its affiliates (provided that you may use a trademark or logo of Licensor as expressly required by this License). + +TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON AN "AS IS" BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND TITLE. + +MariaDB hereby grants you permission to use this License’s text to license your works, and to refer to it using the trademark "Business Source License", as long as you comply with the Covenants of Licensor below. + +--- + +Covenants of Licensor + +In consideration of the right to use this License’s text and the "Business Source License" name and trademark, Licensor covenants to MariaDB, and to all other recipients of the licensed work to be provided by Licensor: + +1. To specify as the Change License the GPL Version 2.0 or any later version, or a license that is compatible with GPL Version 2.0 or a later version, where "compatible" means that software provided under the Change License can be included in a program with software provided under GPL Version 2.0 or a later version. Licensor may specify additional Change Licenses without limitation. + +2. To either: (a) specify an additional grant of rights to use that does not impose any additional restriction on the right granted in this License, as the Additional Use Grant; or (b) insert the text "None". + +3. To specify a Change Date. + +4. Not to modify this License in any other way. diff --git a/contracts/src/v0.8/automation/dev/v2_2/README.md b/contracts/src/v0.8/automation/dev/v2_2/README.md new file mode 100644 index 0000000000..abd3eb0ca8 --- /dev/null +++ b/contracts/src/v0.8/automation/dev/v2_2/README.md @@ -0,0 +1,40 @@ +# Automation Contract Structure + +The on-chain component of Chainlink automation is too large to fit into the [size requirements][size-limit-eip] of a single contract. It is also too large to fit into 2 contracts, a solution that works for most large projects. Therefore, we included this explanation of how the pieces fit together and various tradeoffs incurred. + +### Glossary + +**Master Contract** - also known as the “storage” contract. This is the contract whose state we care about. It is the entry-point into the chain of delegatecalls. (We avoid the term "proxy" because it is commonly associated with upgradability, and this system _is not upgradable_ even though it relies on some of the same mechanics.) + +**Logic Contract** - this a contract whose sole purpose is to hold code. We use the code at this address and execute it in the context of the master contract in order to increase our total capacity for on-chain code. + +### Overview + +We chain multiple logic contracts together using [fallback functions][fallback] and [delegatecall][delegatecall]. If a function definition is not found on one contract, we fall back to the next, always executing the function in the scope of the master contract. The actual implementation of this is based off of [OZ's Proxy contract][oz-proxy]. + +### Diagram + +```mermaid +graph LR + Master -- delegatecall --> la[Logic A] + la -- delegatecall --> lb[Logic B] + lb -. delegatecall .-> lx[Logic X] +``` + +### Special Considerations + +- functions on the master contract have the least gas overhead, therefore, our most price-sensitive functions live there +- functions on the master contract have first-class support from tools like etherscan and tenderly - functions that we (or users) call often to debug should live there +- etherscan supports executing logic contract functions that are once removed from the master - therefore we give secondary preference to the first logic contract for user and debugging functions +- functions on logic A through logic X (as of writing) have no support on etherscan and will essentially be "invisible" to everyone but advanced users - we will try to reserve this space for uncommon interactions that are mostly done progamatically +- We use Logic A, B, C... to avoid confusion with the version ex `AutomationRegistryLogicA2_2.sol` --> Logic Contract A verion 2.1 +- Storage locations for logic contract addresses MUST BE BYTECODE (this is done by marking them as "immutable") otherwise the chaining mechanism will break + +### Master Interface + +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. + +[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 +[oz-proxy]: https://docs.openzeppelin.com/contracts/4.x/api/proxy#Proxy diff --git a/contracts/src/v0.8/automation/v2_1/test/AutomationForwarder.t.sol b/contracts/src/v0.8/automation/test/AutomationForwarder.t.sol similarity index 88% rename from contracts/src/v0.8/automation/v2_1/test/AutomationForwarder.t.sol rename to contracts/src/v0.8/automation/test/AutomationForwarder.t.sol index 078d22d6c9..aee2fcfbd2 100644 --- a/contracts/src/v0.8/automation/v2_1/test/AutomationForwarder.t.sol +++ b/contracts/src/v0.8/automation/test/AutomationForwarder.t.sol @@ -1,16 +1,16 @@ // SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.16; -import {IAutomationRegistryConsumer} from "../../interfaces/IAutomationRegistryConsumer.sol"; -import {IAutomationForwarder} from "../../interfaces/IAutomationForwarder.sol"; +import {IAutomationRegistryConsumer} from "../interfaces/IAutomationRegistryConsumer.sol"; +import {IAutomationForwarder} from "../interfaces/IAutomationForwarder.sol"; import {AutomationForwarder} from "../AutomationForwarder.sol"; import {AutomationForwarderLogic} from "../AutomationForwarderLogic.sol"; -import {MockKeeperRegistry2_1} from "../../mocks/MockKeeperRegistry2_1.sol"; -import {UpkeepCounter} from "../../testhelpers/UpkeepCounter.sol"; +import {MockKeeperRegistry2_1} from "../mocks/MockKeeperRegistry2_1.sol"; +import {UpkeepCounter} from "../testhelpers/UpkeepCounter.sol"; import {BaseTest} from "./BaseTest.t.sol"; // in contracts directory, run -// forge test --match-path src/v0.8/automation/v2_1/test/AutomationForwarder.t.sol +// forge test --match-path src/v0.8/automation/test/AutomationForwarder.t.sol contract AutomationForwarderSetUp is BaseTest { IAutomationForwarder internal forwarder; diff --git a/contracts/src/v0.8/automation/test/BaseTest.t.sol b/contracts/src/v0.8/automation/test/BaseTest.t.sol index bcde8a1148..ecba6521c6 100644 --- a/contracts/src/v0.8/automation/test/BaseTest.t.sol +++ b/contracts/src/v0.8/automation/test/BaseTest.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity 0.8.6; +pragma solidity ^0.8.0; import "forge-std/Test.sol"; diff --git a/contracts/src/v0.8/automation/v2_1/test/StructFactory.sol b/contracts/src/v0.8/automation/test/StructFactory.sol similarity index 85% rename from contracts/src/v0.8/automation/v2_1/test/StructFactory.sol rename to contracts/src/v0.8/automation/test/StructFactory.sol index 83bb9e8905..9317244a31 100644 --- a/contracts/src/v0.8/automation/v2_1/test/StructFactory.sol +++ b/contracts/src/v0.8/automation/test/StructFactory.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity 0.8.16; +pragma solidity ^0.8.0; contract StructFactory { address internal OWNER; diff --git a/contracts/src/v0.8/automation/v2_1/KeeperRegistryLogicA2_1.sol b/contracts/src/v0.8/automation/v2_1/KeeperRegistryLogicA2_1.sol index e3845ce63b..517d14d8c9 100644 --- a/contracts/src/v0.8/automation/v2_1/KeeperRegistryLogicA2_1.sol +++ b/contracts/src/v0.8/automation/v2_1/KeeperRegistryLogicA2_1.sol @@ -6,7 +6,7 @@ import {Address} from "../../vendor/openzeppelin-solidity/v4.7.3/contracts/utils import {KeeperRegistryBase2_1} from "./KeeperRegistryBase2_1.sol"; import {KeeperRegistryLogicB2_1} from "./KeeperRegistryLogicB2_1.sol"; import {Chainable} from "../Chainable.sol"; -import {AutomationForwarder} from "./AutomationForwarder.sol"; +import {AutomationForwarder} from "../AutomationForwarder.sol"; import {IAutomationForwarder} from "../interfaces/IAutomationForwarder.sol"; import {UpkeepTranscoderInterfaceV2} from "../interfaces/UpkeepTranscoderInterfaceV2.sol"; import {MigratableKeeperRegistryInterfaceV2} from "../interfaces/MigratableKeeperRegistryInterfaceV2.sol"; diff --git a/contracts/src/v0.8/automation/v2_1/LICENSE b/contracts/src/v0.8/automation/v2_1/LICENSE index 7d09d647f5..f60ab65717 100644 --- a/contracts/src/v0.8/automation/v2_1/LICENSE +++ b/contracts/src/v0.8/automation/v2_1/LICENSE @@ -12,7 +12,8 @@ Licensor: SmartContract Chainlink Limited SEZC Licensed Work: Automation v2.1 The Licensed Work is (c) 2023 SmartContract Chainlink Limited SEZC -Additional Use Grant: Any uses listed and defined at https://github.com/smartcontractkit/chainlink-automation/tree/main/pkg/v3/Automation_v2.1_Grants.md +Additional Use Grant: Any uses listed and defined at https://github.com/smartcontractkit/chainlink-automation/tree/main/Automation_Grants.md + Change Date: September 12, 2027 diff --git a/contracts/src/v0.8/automation/v2_1/test/BaseTest.t.sol b/contracts/src/v0.8/automation/v2_1/test/BaseTest.t.sol deleted file mode 100644 index f5bc74286a..0000000000 --- a/contracts/src/v0.8/automation/v2_1/test/BaseTest.t.sol +++ /dev/null @@ -1,12 +0,0 @@ -// SPDX-License-Identifier: BUSL-1.1 -pragma solidity 0.8.16; - -import {StructFactory} from "./StructFactory.sol"; -import "forge-std/Test.sol"; - -contract BaseTest is Test, StructFactory { - function setUp() public virtual { - vm.startPrank(OWNER); - deal(OWNER, 1e20); - } -} diff --git a/contracts/src/v0.8/functions/dev/v1_X/accessControl/TermsOfServiceAllowList.sol b/contracts/src/v0.8/functions/dev/v1_X/accessControl/TermsOfServiceAllowList.sol index 3bb7c7b04c..3d93a3fef0 100644 --- a/contracts/src/v0.8/functions/dev/v1_X/accessControl/TermsOfServiceAllowList.sol +++ b/contracts/src/v0.8/functions/dev/v1_X/accessControl/TermsOfServiceAllowList.sol @@ -20,7 +20,7 @@ contract TermsOfServiceAllowList is ITermsOfServiceAllowList, IAccessController, string public constant override typeAndVersion = "Functions Terms of Service Allow List v1.1.0"; EnumerableSet.AddressSet private s_allowedSenders; - mapping(address => bool) private s_blockedSenders; + EnumerableSet.AddressSet private s_blockedSenders; event AddedAccess(address user); event BlockedAccess(address user); @@ -29,6 +29,7 @@ contract TermsOfServiceAllowList is ITermsOfServiceAllowList, IAccessController, error InvalidSignature(); error InvalidUsage(); error RecipientIsBlocked(); + error InvalidCalldata(); TermsOfServiceAllowListConfig private s_config; @@ -70,7 +71,7 @@ contract TermsOfServiceAllowList is ITermsOfServiceAllowList, IAccessController, /// @inheritdoc ITermsOfServiceAllowList function acceptTermsOfService(address acceptor, address recipient, bytes32 r, bytes32 s, uint8 v) external override { - if (s_blockedSenders[recipient]) { + if (s_blockedSenders.contains(recipient)) { revert RecipientIsBlocked(); } @@ -101,6 +102,32 @@ contract TermsOfServiceAllowList is ITermsOfServiceAllowList, IAccessController, return s_allowedSenders.values(); } + /// @inheritdoc ITermsOfServiceAllowList + function getAllowedSendersCount() external view override returns (uint64) { + return uint64(s_allowedSenders.length()); + } + + /// @inheritdoc ITermsOfServiceAllowList + function getAllowedSendersInRange( + uint64 allowedSenderIdxStart, + uint64 allowedSenderIdxEnd + ) external view override returns (address[] memory allowedSenders) { + if ( + allowedSenderIdxStart > allowedSenderIdxEnd || + allowedSenderIdxEnd >= s_allowedSenders.length() || + s_allowedSenders.length() == 0 + ) { + revert InvalidCalldata(); + } + + allowedSenders = new address[]((allowedSenderIdxEnd - allowedSenderIdxStart) + 1); + for (uint256 i = 0; i <= allowedSenderIdxEnd - allowedSenderIdxStart; ++i) { + allowedSenders[i] = s_allowedSenders.at(uint256(allowedSenderIdxStart + i)); + } + + return allowedSenders; + } + /// @inheritdoc IAccessController function hasAccess(address user, bytes calldata /* data */) external view override returns (bool) { if (!s_config.enabled) { @@ -118,19 +145,45 @@ contract TermsOfServiceAllowList is ITermsOfServiceAllowList, IAccessController, if (!s_config.enabled) { return false; } - return s_blockedSenders[sender]; + return s_blockedSenders.contains(sender); } /// @inheritdoc ITermsOfServiceAllowList function blockSender(address sender) external override onlyOwner { s_allowedSenders.remove(sender); - s_blockedSenders[sender] = true; + s_blockedSenders.add(sender); emit BlockedAccess(sender); } /// @inheritdoc ITermsOfServiceAllowList function unblockSender(address sender) external override onlyOwner { - s_blockedSenders[sender] = false; + s_blockedSenders.remove(sender); emit UnblockedAccess(sender); } + + /// @inheritdoc ITermsOfServiceAllowList + function getBlockedSendersCount() external view override returns (uint64) { + return uint64(s_blockedSenders.length()); + } + + /// @inheritdoc ITermsOfServiceAllowList + function getBlockedSendersInRange( + uint64 blockedSenderIdxStart, + uint64 blockedSenderIdxEnd + ) external view override returns (address[] memory blockedSenders) { + if ( + blockedSenderIdxStart > blockedSenderIdxEnd || + blockedSenderIdxEnd >= s_blockedSenders.length() || + s_blockedSenders.length() == 0 + ) { + revert InvalidCalldata(); + } + + blockedSenders = new address[]((blockedSenderIdxEnd - blockedSenderIdxStart) + 1); + for (uint256 i = 0; i <= blockedSenderIdxEnd - blockedSenderIdxStart; ++i) { + blockedSenders[i] = s_blockedSenders.at(uint256(blockedSenderIdxStart + i)); + } + + return blockedSenders; + } } diff --git a/contracts/src/v0.8/functions/dev/v1_X/accessControl/interfaces/ITermsOfServiceAllowList.sol b/contracts/src/v0.8/functions/dev/v1_X/accessControl/interfaces/ITermsOfServiceAllowList.sol index 209d25c0ab..65db9c42b6 100644 --- a/contracts/src/v0.8/functions/dev/v1_X/accessControl/interfaces/ITermsOfServiceAllowList.sol +++ b/contracts/src/v0.8/functions/dev/v1_X/accessControl/interfaces/ITermsOfServiceAllowList.sol @@ -22,6 +22,22 @@ interface ITermsOfServiceAllowList { /// @return addresses - all allowed addresses function getAllAllowedSenders() external view returns (address[] memory); + /// @notice Get details about the total number of allowed senders + /// @return count - total number of allowed senders in the system + function getAllowedSendersCount() external view returns (uint64); + + /// @notice Retrieve a list of allowed senders using an inclusive range + /// @dev WARNING: getAllowedSendersInRange uses EnumerableSet .length() and .at() methods to iterate over the list + /// without the need for an extra mapping. These method can not guarantee the ordering when new elements are added. + /// Evaluate if eventual consistency will satisfy your usecase before using it. + /// @param allowedSenderIdxStart - index of the allowed sender to start the range at + /// @param allowedSenderIdxEnd - index of the allowed sender to end the range at + /// @return allowedSenders - allowed addresses in the range provided + function getAllowedSendersInRange( + uint64 allowedSenderIdxStart, + uint64 allowedSenderIdxEnd + ) external view returns (address[] memory allowedSenders); + /// @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 @@ -37,6 +53,22 @@ interface ITermsOfServiceAllowList { /// @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; + + /// @notice Get details about the total number of blocked senders + /// @return count - total number of blocked senders in the system + function getBlockedSendersCount() external view returns (uint64); + + /// @notice Retrieve a list of blocked senders using an inclusive range + /// @dev WARNING: getBlockedSendersInRange uses EnumerableSet .length() and .at() methods to iterate over the list + /// without the need for an extra mapping. These method can not guarantee the ordering when new elements are added. + /// Evaluate if eventual consistency will satisfy your usecase before using it. + /// @param blockedSenderIdxStart - index of the blocked sender to start the range at + /// @param blockedSenderIdxEnd - index of the blocked sender to end the range at + /// @return blockedSenders - blocked addresses in the range provided + function getBlockedSendersInRange( + uint64 blockedSenderIdxStart, + uint64 blockedSenderIdxEnd + ) external view returns (address[] memory blockedSenders); } // ================================================================ diff --git a/contracts/src/v0.8/functions/tests/v1_X/FunctionsTermsOfServiceAllowList.t.sol b/contracts/src/v0.8/functions/tests/v1_X/FunctionsTermsOfServiceAllowList.t.sol index 08c981dd4f..e121f7b881 100644 --- a/contracts/src/v0.8/functions/tests/v1_X/FunctionsTermsOfServiceAllowList.t.sol +++ b/contracts/src/v0.8/functions/tests/v1_X/FunctionsTermsOfServiceAllowList.t.sol @@ -247,6 +247,69 @@ contract FunctionsTermsOfServiceAllowList_GetAllAllowedSenders is FunctionsOwner } } +/// @notice #getAllowedSendersCount +contract FunctionsTermsOfServiceAllowList_GetAllowedSendersCount is FunctionsOwnerAcceptTermsOfServiceSetup { + function test_GetAllowedSendersCount_Success() public { + // Send as stranger + vm.stopPrank(); + vm.startPrank(STRANGER_ADDRESS); + + uint96 allowedSendersCount = s_termsOfServiceAllowList.getAllowedSendersCount(); + // One allowed sender was made during setup + assertEq(allowedSendersCount, 1); + } +} + +/// @notice #getAllowedSendersInRange +contract FunctionsTermsOfServiceAllowList_GetAllowedSendersInRange is FunctionsOwnerAcceptTermsOfServiceSetup { + function test_GetAllowedSendersInRange_Success() public { + // Send as stranger + vm.stopPrank(); + vm.startPrank(STRANGER_ADDRESS); + + address[] memory expectedSenders = new address[](1); + expectedSenders[0] = OWNER_ADDRESS; + + assertEq(s_termsOfServiceAllowList.getAllowedSendersInRange(0, 0), expectedSenders); + } + + function test_GetAllowedSendersInRange_RevertIfAllowedSendersIsEmpty() public { + // setup a new empty s_termsOfServiceAllowList + FunctionsRoutesSetup.setUp(); + + // Send as stranger + vm.stopPrank(); + vm.startPrank(STRANGER_ADDRESS); + + uint64 AllowedSendersCount = s_termsOfServiceAllowList.getAllowedSendersCount(); + uint64 expected = 0; + assertEq(AllowedSendersCount, expected); + + vm.expectRevert(TermsOfServiceAllowList.InvalidCalldata.selector); + s_termsOfServiceAllowList.getAllowedSendersInRange(0, 0); + } + + function test_GetAllowedSendersInRange_RevertIfStartIsAfterEnd() public { + // Send as stranger + vm.stopPrank(); + vm.startPrank(STRANGER_ADDRESS); + + vm.expectRevert(TermsOfServiceAllowList.InvalidCalldata.selector); + + s_termsOfServiceAllowList.getAllowedSendersInRange(1, 0); + } + + function test_GetAllowedSendersInRange_RevertIfEndIsAfterLastAllowedSender() public { + // Send as stranger + vm.stopPrank(); + vm.startPrank(STRANGER_ADDRESS); + + uint64 AllowedSendersCount = s_termsOfServiceAllowList.getAllowedSendersCount(); + vm.expectRevert(TermsOfServiceAllowList.InvalidCalldata.selector); + s_termsOfServiceAllowList.getAllowedSendersInRange(1, AllowedSendersCount + 1); + } +} + /// @notice #hasAccess contract FunctionsTermsOfServiceAllowList_HasAccess is FunctionsRoutesSetup { function test_HasAccess_FalseWhenEnabled() public { @@ -373,3 +436,78 @@ contract FunctionsTermsOfServiceAllowList_UnblockSender is FunctionsRoutesSetup s_termsOfServiceAllowList.acceptTermsOfService(STRANGER_ADDRESS, STRANGER_ADDRESS, r, s, v); } } + +/// @notice #getBlockedSendersCount +contract FunctionsTermsOfServiceAllowList_GetBlockedSendersCount is FunctionsRoutesSetup { + function setUp() public virtual override { + FunctionsRoutesSetup.setUp(); + + s_termsOfServiceAllowList.blockSender(STRANGER_ADDRESS); + } + + function test_GetBlockedSendersCount_Success() public { + // Send as stranger + vm.stopPrank(); + vm.startPrank(STRANGER_ADDRESS); + + uint96 blockedSendersCount = s_termsOfServiceAllowList.getBlockedSendersCount(); + // One blocked sender was made during setup + assertEq(blockedSendersCount, 1); + } +} + +/// @notice #getBlockedSendersInRange +contract FunctionsTermsOfServiceAllowList_GetBlockedSendersInRange is FunctionsRoutesSetup { + function setUp() public virtual override { + FunctionsRoutesSetup.setUp(); + + s_termsOfServiceAllowList.blockSender(STRANGER_ADDRESS); + } + + function test_GetBlockedSendersInRange_Success() public { + // Send as stranger + vm.stopPrank(); + vm.startPrank(STRANGER_ADDRESS); + + address[] memory expectedBlockedSenders = new address[](1); + expectedBlockedSenders[0] = STRANGER_ADDRESS; + + assertEq(s_termsOfServiceAllowList.getBlockedSendersInRange(0, 0), expectedBlockedSenders); + } + + function test_GetBlockedSendersInRange_RevertIfAllowedSendersIsEmpty() public { + // setup a new empty s_termsOfServiceBlockList + FunctionsRoutesSetup.setUp(); + + // Send as stranger + vm.stopPrank(); + vm.startPrank(STRANGER_ADDRESS); + + uint64 BlockedSendersCount = s_termsOfServiceAllowList.getBlockedSendersCount(); + uint64 expected = 0; + assertEq(BlockedSendersCount, expected); + + vm.expectRevert(TermsOfServiceAllowList.InvalidCalldata.selector); + s_termsOfServiceAllowList.getBlockedSendersInRange(0, 0); + } + + function test_GetBlockedSendersInRange_RevertIfStartIsAfterEnd() public { + // Send as stranger + vm.stopPrank(); + vm.startPrank(STRANGER_ADDRESS); + + vm.expectRevert(TermsOfServiceAllowList.InvalidCalldata.selector); + + s_termsOfServiceAllowList.getBlockedSendersInRange(1, 0); + } + + function test_GetBlockedSendersInRange_RevertIfEndIsAfterLastAllowedSender() public { + // Send as stranger + vm.stopPrank(); + vm.startPrank(STRANGER_ADDRESS); + + uint64 BlockedSendersCount = s_termsOfServiceAllowList.getBlockedSendersCount(); + vm.expectRevert(TermsOfServiceAllowList.InvalidCalldata.selector); + s_termsOfServiceAllowList.getBlockedSendersInRange(1, BlockedSendersCount + 1); + } +} diff --git a/contracts/src/v0.8/l2ep/README.md b/contracts/src/v0.8/l2ep/README.md new file mode 100644 index 0000000000..21a537c4fe --- /dev/null +++ b/contracts/src/v0.8/l2ep/README.md @@ -0,0 +1,148 @@ +# Overview + +This folder contains the source code and tests for the Layer 2 +Emergency Protocol (L2EP) contracts. It is organized as follows: + +```text +. +├─/dev (stores the latest source code for L2EP) +├─/test (stores the Foundry tests for L2EP) +``` + +## The `/dev` Folder + +The `/dev` folder contains subfolders for each chain that +has an L2EP solution implemented for it (e.g. `/scroll`, `/arbitrum`, +`/optimism`). It also contains a subfolder named `/interfaces`, +which stores shared interface types between all the supported +contracts. The top-level contracts (e.g. `CrossDomainOwnable.sol`) +serve as either abstract or parent contracts that are meant +to be reused for each indiviudal chain. + +## The `/test` Folder + +This folder is arranged as follows: + +- `/mocks`: used for both Foundry test cases and Hardhat test cases (NOTE: +Hardhat test cases should be considered deprecated at this point) + +- `/[version]`: test cases for a specific version of the L2EP contracts + +### Testing Conventions and Methodology + +By convention, each testing file should end in `.t.sol` (this is a standard +that other projects have also adopted). Each testing file in this folder +follows a similar structure. + +```text +TestFile.t.sol + | + |--- Base Contract (inherits L2EPTest contract) + | + |--- Child Contract 1 (inherits base contract) + | | + | |--- Test Function + | | + | |--- ... + | + | + |--- Child Contract 2 (inherits base contract) + | | + | |--- Test Function + | | + | |--- ... + | + | + ... +``` + +All test files contain a base contract defined at the top of the file. This +base contract inherits from a contract called `L2EPTest`. The `L2EPTest` +contract and base contracts have no test cases. Instead, the `L2EPTest` +contract is meant to store data/functions that will be reused among all +the base contracts. Similarly, the base contract is meant to store data +and/or functions that will be reused by any contracts that inherit it. +As such, each test file will define separate child contracts, and each +will inherit from the base contract + define its own set of tests. + +The base contract defines a `setUp` function which is automatically called +exactly once before ***each*** of the tests are run in an inheriting contract. +The `setUp` function typically deploys a fresh set of test contracts so that +tests can run independently of each other. Alongside the `setUp` function, +the base contract can also define variables, constants, events, etc. that +are meant to be reused per test. + +The name of the base contract follows the following convention: + +```text +Test +``` + +The child contract names follow a similar convention: + +```text +_ +``` + +Each test function within the child contract complies +with the following naming pattern: + +```text +test_ +``` + +### Running Foundry Tests + +#### Usage + +First make sure you are in the contracts directory: + +```sh +# Assuming you are currently in the /chainlink directory +cd ./contracts +``` + +If you already have foundry installed, you can use the following command +to run all L2EP tests: + +```sh +FOUNDRY_PROFILE=l2ep forge test -vvv +``` + +To run a specific L2EP test, you can use a variation of the following command: + +```sh +FOUNDRY_PROFILE=l2ep forge test -vvv --match-path ./src/v0.8/l2ep/test/v1_0_0/scroll/ScrollSequencerUptimeFeed.t.sol +``` + +Or alternatively: + +```sh +FOUNDRY_PROFILE=l2ep forge test -vvv --match-contract ScrollSequencerUptimeFeed +``` + +If you prefer, you can also export `FOUNDRY_PROFILE` so that it doesn't need +to be provided before every command: + +```sh +# Export foundry profile +export FOUNDRY_PROFILE=l2ep + +# Run all tests +forge test -vvv + +# Run all tests and generate a gas snapshot +make snapshot +``` + +A full list of flags for `forge test` can be found [here](https://book.getfoundry.sh/reference/forge/forge-test). + +#### Coverage + +First ensure that the correct files are being evaluated. For example, if only +v1 contracts are, being evaluated then temporarily change the L2EP profile in +`./foundry.toml`. + +```sh +forge coverage +``` diff --git a/contracts/src/v0.8/l2ep/dev/arbitrum/ArbitrumSequencerUptimeFeed.sol b/contracts/src/v0.8/l2ep/dev/arbitrum/ArbitrumSequencerUptimeFeed.sol index e6a875ddf6..63952ab7ba 100644 --- a/contracts/src/v0.8/l2ep/dev/arbitrum/ArbitrumSequencerUptimeFeed.sol +++ b/contracts/src/v0.8/l2ep/dev/arbitrum/ArbitrumSequencerUptimeFeed.sol @@ -51,7 +51,7 @@ contract ArbitrumSequencerUptimeFeed is /// @dev Follows: https://eips.ethereum.org/EIPS/eip-1967 address public constant FLAG_L2_SEQ_OFFLINE = - address(bytes20(bytes32(uint256(keccak256("chainlink.flags.l2-seq-offline")) - 1))); + 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; diff --git a/contracts/src/v0.8/l2ep/dev/scroll/ScrollSequencerUptimeFeed.sol b/contracts/src/v0.8/l2ep/dev/scroll/ScrollSequencerUptimeFeed.sol index 22b5ed1e2b..9df2b61238 100644 --- a/contracts/src/v0.8/l2ep/dev/scroll/ScrollSequencerUptimeFeed.sol +++ b/contracts/src/v0.8/l2ep/dev/scroll/ScrollSequencerUptimeFeed.sol @@ -41,6 +41,8 @@ contract ScrollSequencerUptimeFeed is error InvalidSender(); /// @notice Replacement for AggregatorV3Interface "No data present" error NoDataPresent(); + /// @notice Address must not be the zero address + error ZeroAddress(); event L1SenderTransferred(address indexed from, address indexed to); /// @dev Emitted when an `updateStatus` call is ignored due to unchanged status or stale timestamp @@ -68,6 +70,10 @@ contract ScrollSequencerUptimeFeed is /// @param l2CrossDomainMessengerAddr Address of the L2CrossDomainMessenger contract /// @param initialStatus The initial status of the feed constructor(address l1SenderAddress, address l2CrossDomainMessengerAddr, bool initialStatus) { + if (l2CrossDomainMessengerAddr == address(0)) { + revert ZeroAddress(); + } + _setL1Sender(l1SenderAddress); s_l2CrossDomainMessenger = IL2ScrollMessenger(l2CrossDomainMessengerAddr); diff --git a/contracts/src/v0.8/l2ep/test/mocks/MockAggregatorV2V3.sol b/contracts/src/v0.8/l2ep/test/mocks/MockAggregatorV2V3.sol new file mode 100644 index 0000000000..c4e2f71030 --- /dev/null +++ b/contracts/src/v0.8/l2ep/test/mocks/MockAggregatorV2V3.sol @@ -0,0 +1,56 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.9; + +import {AggregatorV2V3Interface} from "../../../shared/interfaces/AggregatorV2V3Interface.sol"; + +contract MockAggregatorV2V3 is AggregatorV2V3Interface { + function latestAnswer() external pure returns (int256) { + return 0; + } + + function latestTimestamp() external pure returns (uint256) { + return 0; + } + + function latestRound() external pure returns (uint256) { + return 0; + } + + function getAnswer(uint256) external pure returns (int256) { + return 0; + } + + function getTimestamp(uint256 roundId) external pure returns (uint256) { + return roundId; + } + + function decimals() external pure returns (uint8) { + return 0; + } + + function description() external pure returns (string memory) { + return ""; + } + + function version() external pure returns (uint256) { + return 0; + } + + function getRoundData( + uint80 + ) + external + pure + returns (uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound) + { + return (0, 0, 0, 0, 0); + } + + function latestRoundData() + external + pure + returns (uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound) + { + return (73786976294838220258, 96800000000, 163826896, 1638268960, 73786976294838220258); + } +} diff --git a/contracts/src/v0.8/l2ep/test/mocks/optimism/MockOVMCrossDomainMessenger.sol b/contracts/src/v0.8/l2ep/test/mocks/optimism/MockOVMCrossDomainMessenger.sol new file mode 100644 index 0000000000..3a45cba347 --- /dev/null +++ b/contracts/src/v0.8/l2ep/test/mocks/optimism/MockOVMCrossDomainMessenger.sol @@ -0,0 +1,32 @@ +// SPDX-License-Identifier: MIT + +pragma solidity >=0.7.6 <0.9.0; + +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.8.3/contracts/utils/Address.sol"; + +contract MockOVMCrossDomainMessenger is iOVM_CrossDomainMessenger { + address internal s_mockMessageSender; + + constructor(address sender) { + s_mockMessageSender = sender; + } + + function xDomainMessageSender() external view override returns (address) { + return s_mockMessageSender; + } + + function _setMockMessageSender(address sender) external { + s_mockMessageSender = sender; + } + + /** + * Sends a cross domain message to the target messenger. + * @param _target Target contract address. + * @param _message Message to send to the target. + */ + function sendMessage(address _target, bytes calldata _message, uint32) external override { + Address.functionCall(_target, _message, "sendMessage reverted"); + } +} diff --git a/contracts/src/v0.8/l2ep/test/mocks/scroll/MockScrollCrossDomainMessenger.sol b/contracts/src/v0.8/l2ep/test/mocks/scroll/MockScrollCrossDomainMessenger.sol new file mode 100644 index 0000000000..37244910b8 --- /dev/null +++ b/contracts/src/v0.8/l2ep/test/mocks/scroll/MockScrollCrossDomainMessenger.sol @@ -0,0 +1,36 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.16; + +import {IScrollMessenger} from "@scroll-tech/contracts/libraries/IScrollMessenger.sol"; + +import {Address} from "../../../../vendor/openzeppelin-solidity/v4.8.3/contracts/utils/Address.sol"; + +contract MockScrollCrossDomainMessenger is IScrollMessenger { + address internal s_mockMessageSender; + + constructor(address sender) { + s_mockMessageSender = sender; + } + + function xDomainMessageSender() external view override returns (address) { + return s_mockMessageSender; + } + + function _setMockMessageSender(address sender) external { + s_mockMessageSender = sender; + } + + /// @notice Send cross chain message from L1 to L2 or L2 to L1. + /// @param _target The address of account who receive the message. + /// @param _message The content of the message. + function sendMessage(address _target, uint256, bytes calldata _message, uint256) external payable override { + Address.functionCall(_target, _message, "sendMessage reverted"); + } + + /// @notice Send cross chain message from L1 to L2 or L2 to L1. + /// @param _target The address of account who receive the message. + /// @param _message The content of the message. + function sendMessage(address _target, uint256, bytes calldata _message, uint256, address) external payable override { + Address.functionCall(_target, _message, "sendMessage reverted"); + } +} diff --git a/contracts/src/v0.8/l2ep/test/mocks/MockScrollL1CrossDomainMessenger.sol b/contracts/src/v0.8/l2ep/test/mocks/scroll/MockScrollL1CrossDomainMessenger.sol similarity index 100% rename from contracts/src/v0.8/l2ep/test/mocks/MockScrollL1CrossDomainMessenger.sol rename to contracts/src/v0.8/l2ep/test/mocks/scroll/MockScrollL1CrossDomainMessenger.sol diff --git a/contracts/src/v0.8/l2ep/test/mocks/MockScrollL2CrossDomainMessenger.sol b/contracts/src/v0.8/l2ep/test/mocks/scroll/MockScrollL2CrossDomainMessenger.sol similarity index 90% rename from contracts/src/v0.8/l2ep/test/mocks/MockScrollL2CrossDomainMessenger.sol rename to contracts/src/v0.8/l2ep/test/mocks/scroll/MockScrollL2CrossDomainMessenger.sol index f63faa3517..66400b7d30 100644 --- a/contracts/src/v0.8/l2ep/test/mocks/MockScrollL2CrossDomainMessenger.sol +++ b/contracts/src/v0.8/l2ep/test/mocks/scroll/MockScrollL2CrossDomainMessenger.sol @@ -40,11 +40,11 @@ contract MockScrollL2CrossDomainMessenger is IL2ScrollMessenger { bytes calldata message ) external override {} - /// Needed for testing + /// Needed for backwards compatibility in Hardhat tests function setSender(address newSender) external { s_sender = newSender; } - /// Needed for testing + /// Needed for backwards compatibility in Hardhat tests receive() external payable {} } diff --git a/contracts/src/v0.8/l2ep/test/v1_0_0/L2EPTest.t.sol b/contracts/src/v0.8/l2ep/test/v1_0_0/L2EPTest.t.sol new file mode 100644 index 0000000000..561e32be1a --- /dev/null +++ b/contracts/src/v0.8/l2ep/test/v1_0_0/L2EPTest.t.sol @@ -0,0 +1,82 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.19; + +import {Greeter} from "../../../tests/Greeter.sol"; + +import {MultiSend} from "../../../vendor/MultiSend.sol"; +import {Test} from "forge-std/Test.sol"; + +contract L2EPTest is Test { + /// Helper variable(s) + address internal s_strangerAddr = vm.addr(0x1); + address internal s_l1OwnerAddr = vm.addr(0x2); + address internal s_eoaValidator = vm.addr(0x3); + address internal s_deployerAddr = vm.addr(0x4); + + /// @param expectedGasUsage - the expected gas usage + /// @param startGasUsage - the gas usage before the code of interest is run + /// @param finalGasUsage - the gas usage after the code of interest is run + /// @param deviation - the amount of gas that the actual usage is allowed to deviate by (e.g. (expectedGas - deviation) <= actualGasUsage <= (expectedGas + deviation)) + function assertGasUsageIsCloseTo( + uint256 expectedGasUsage, + uint256 startGasUsage, + uint256 finalGasUsage, + uint256 deviation + ) public { + uint256 gasUsed = (startGasUsage - finalGasUsage) * tx.gasprice; + assertLe(gasUsed, expectedGasUsage + deviation); + assertGe(gasUsed, expectedGasUsage - deviation); + } + + /// @param selector - the function selector + /// @param greeterAddr - the address of the Greeter contract + /// @param message - the new greeting message, which will be passed as an argument to Greeter#setGreeting + /// @return a 2-layer encoding such that decoding the first layer provides the CrossDomainForwarder#forward + /// function selector and the corresponding arguments to the forward function, and decoding the + /// second layer provides the Greeter#setGreeting function selector and the corresponding + /// arguments to the set greeting function (which in this case is the input message) + function encodeCrossDomainSetGreetingMsg( + bytes4 selector, + address greeterAddr, + string memory message + ) public pure returns (bytes memory) { + return abi.encodeWithSelector(selector, greeterAddr, abi.encodeWithSelector(Greeter.setGreeting.selector, message)); + } + + /// @param selector - the function selector + /// @param multiSendAddr - the address of the MultiSend contract + /// @param encodedTxs - an encoded list of transactions (e.g. abi.encodePacked(encodeMultiSendTx("some data"), ...)) + /// @return a 2-layer encoding such that decoding the first layer provides the CrossDomainGoverner#forwardDelegate + /// function selector and the corresponding arguments to the forwardDelegate function, and decoding the + /// second layer provides the MultiSend#multiSend function selector and the corresponding + /// arguments to the multiSend function (which in this case is the input encodedTxs) + function encodeCrossDomainMultiSendMsg( + bytes4 selector, + address multiSendAddr, + bytes memory encodedTxs + ) public pure returns (bytes memory) { + return + abi.encodeWithSelector(selector, multiSendAddr, abi.encodeWithSelector(MultiSend.multiSend.selector, encodedTxs)); + } + + /// @param greeterAddr - the address of the greeter contract + /// @param data - the transaction data string + /// @return an encoded transaction structured as specified in the MultiSend#multiSend comments + function encodeMultiSendTx(address greeterAddr, bytes memory data) public pure returns (bytes memory) { + bytes memory txData = abi.encodeWithSelector(Greeter.setGreeting.selector, data); + return + abi.encodePacked( + uint8(0), // operation + greeterAddr, // to + uint256(0), // value + uint256(txData.length), // data length + txData // data as bytes + ); + } + + /// @param l1Address - Address on L1 + /// @return an Arbitrum L2 address + function toArbitrumL2AliasAddress(address l1Address) public pure returns (address) { + return address(uint160(l1Address) + uint160(0x1111000000000000000000000000000000001111)); + } +} diff --git a/contracts/src/v0.8/l2ep/test/v1_0_0/arbitrum/ArbitrumCrossDomainForwarder.t.sol b/contracts/src/v0.8/l2ep/test/v1_0_0/arbitrum/ArbitrumCrossDomainForwarder.t.sol new file mode 100644 index 0000000000..be3851c5b5 --- /dev/null +++ b/contracts/src/v0.8/l2ep/test/v1_0_0/arbitrum/ArbitrumCrossDomainForwarder.t.sol @@ -0,0 +1,159 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.19; + +import {ArbitrumCrossDomainForwarder} from "../../../dev/arbitrum/ArbitrumCrossDomainForwarder.sol"; +import {Greeter} from "../../../../tests/Greeter.sol"; +import {L2EPTest} from "../L2EPTest.t.sol"; + +contract ArbitrumCrossDomainForwarderTest is L2EPTest { + /// Helper variable(s) + address internal s_crossDomainMessengerAddr = toArbitrumL2AliasAddress(s_l1OwnerAddr); + address internal s_newOwnerCrossDomainMessengerAddr = toArbitrumL2AliasAddress(s_strangerAddr); + + /// Contracts + ArbitrumCrossDomainForwarder internal s_arbitrumCrossDomainForwarder; + Greeter internal s_greeter; + + /// Events + event L1OwnershipTransferRequested(address indexed from, address indexed to); + event L1OwnershipTransferred(address indexed from, address indexed to); + + /// Setup + function setUp() public { + // Deploys contracts + vm.startPrank(s_l1OwnerAddr); + s_arbitrumCrossDomainForwarder = new ArbitrumCrossDomainForwarder(s_l1OwnerAddr); + s_greeter = new Greeter(address(s_arbitrumCrossDomainForwarder)); + vm.stopPrank(); + } +} + +contract ArbitrumCrossDomainForwarder_Constructor is ArbitrumCrossDomainForwarderTest { + /// @notice it should have been deployed with the correct initial state + function test_InitialState() public { + // it should set the owner correctly + assertEq(s_arbitrumCrossDomainForwarder.owner(), s_l1OwnerAddr); + + // it should set the l1Owner correctly + assertEq(s_arbitrumCrossDomainForwarder.l1Owner(), s_l1OwnerAddr); + + // it should set the crossdomain messenger correctly + assertEq(s_arbitrumCrossDomainForwarder.crossDomainMessenger(), s_crossDomainMessengerAddr); + + // it should set the typeAndVersion correctly + assertEq(s_arbitrumCrossDomainForwarder.typeAndVersion(), "ArbitrumCrossDomainForwarder 1.0.0"); + } +} + +contract ArbitrumCrossDomainForwarder_Forward is ArbitrumCrossDomainForwarderTest { + /// @notice it should not be callable by unknown address + function test_NotCallableByUnknownAddress() public { + vm.startPrank(s_strangerAddr); + vm.expectRevert("Sender is not the L2 messenger"); + s_arbitrumCrossDomainForwarder.forward(address(s_greeter), abi.encode("")); + } + + /// @notice it should be callable by crossdomain messenger address / L1 owner + function test_Forward() public { + // Sets msg.sender and tx.origin + vm.startPrank(s_crossDomainMessengerAddr); + + // Defines the cross domain message to send + string memory greeting = "hello"; + + // Sends the message + s_arbitrumCrossDomainForwarder.forward( + address(s_greeter), + abi.encodeWithSelector(s_greeter.setGreeting.selector, greeting) + ); + + // Checks that the greeter got the message + assertEq(s_greeter.greeting(), greeting); + } + + /// @notice it should revert when contract call reverts + function test_ForwardRevert() public { + // Sets msg.sender and tx.origin + vm.startPrank(s_crossDomainMessengerAddr); + + // Sends an invalid message + vm.expectRevert("Invalid greeting length"); + s_arbitrumCrossDomainForwarder.forward( + address(s_greeter), + abi.encodeWithSelector(s_greeter.setGreeting.selector, "") + ); + } +} + +contract ArbitrumCrossDomainForwarder_TransferL1Ownership is ArbitrumCrossDomainForwarderTest { + /// @notice it should not be callable by non-owners + function test_NotCallableByNonOwners() public { + vm.startPrank(s_strangerAddr); + vm.expectRevert("Sender is not the L2 messenger"); + s_arbitrumCrossDomainForwarder.transferL1Ownership(s_strangerAddr); + } + + /// @notice it should not be callable by L2 owner + function test_NotCallableByL2Owner() public { + vm.startPrank(s_l1OwnerAddr); + assertEq(s_arbitrumCrossDomainForwarder.owner(), s_l1OwnerAddr); + vm.expectRevert("Sender is not the L2 messenger"); + s_arbitrumCrossDomainForwarder.transferL1Ownership(s_strangerAddr); + } + + /// @notice it should be callable by current L1 owner + function test_CallableByL1Owner() public { + // Sets msg.sender and tx.origin + vm.startPrank(s_crossDomainMessengerAddr); + + // Defines the cross domain message to send + vm.expectEmit(); + emit L1OwnershipTransferRequested(s_arbitrumCrossDomainForwarder.l1Owner(), s_strangerAddr); + + // Sends the message + s_arbitrumCrossDomainForwarder.transferL1Ownership(s_strangerAddr); + } + + /// @notice it should be callable by current L1 owner to zero address + function test_CallableByL1OwnerOrZeroAddress() public { + // Sets msg.sender and tx.origin + vm.startPrank(s_crossDomainMessengerAddr); + + // Defines the cross domain message to send + vm.expectEmit(); + emit L1OwnershipTransferRequested(s_arbitrumCrossDomainForwarder.l1Owner(), address(0)); + + // Sends the message + s_arbitrumCrossDomainForwarder.transferL1Ownership(address(0)); + } +} + +contract ArbitrumCrossDomainForwarder_AcceptL1Ownership is ArbitrumCrossDomainForwarderTest { + /// @notice it should not be callable by non pending-owners + function test_NotCallableByNonPendingOwners() public { + // Sets msg.sender and tx.origin + vm.startPrank(s_crossDomainMessengerAddr); + + // Sends the message + vm.expectRevert("Must be proposed L1 owner"); + s_arbitrumCrossDomainForwarder.acceptL1Ownership(); + } + + /// @notice it should be callable by pending L1 owner + function test_CallableByPendingL1Owner() public { + // Request ownership transfer + vm.startPrank(s_crossDomainMessengerAddr); + s_arbitrumCrossDomainForwarder.transferL1Ownership(s_strangerAddr); + + // Prepares expected event payload + vm.expectEmit(); + emit L1OwnershipTransferred(s_l1OwnerAddr, s_strangerAddr); + + // Accepts ownership transfer request + vm.startPrank(s_newOwnerCrossDomainMessengerAddr); + s_arbitrumCrossDomainForwarder.acceptL1Ownership(); + + // Asserts that the ownership was actually transferred + assertEq(s_arbitrumCrossDomainForwarder.l1Owner(), s_strangerAddr); + } +} diff --git a/contracts/src/v0.8/l2ep/test/v1_0_0/arbitrum/ArbitrumCrossDomainGovernor.t.sol b/contracts/src/v0.8/l2ep/test/v1_0_0/arbitrum/ArbitrumCrossDomainGovernor.t.sol new file mode 100644 index 0000000000..c5b8adaf7d --- /dev/null +++ b/contracts/src/v0.8/l2ep/test/v1_0_0/arbitrum/ArbitrumCrossDomainGovernor.t.sol @@ -0,0 +1,258 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.19; + +import {ArbitrumCrossDomainGovernor} from "../../../dev/arbitrum/ArbitrumCrossDomainGovernor.sol"; +import {Greeter} from "../../../../tests/Greeter.sol"; +import {L2EPTest} from "../L2EPTest.t.sol"; + +import {MultiSend} from "../../../../vendor/MultiSend.sol"; + +contract ArbitrumCrossDomainGovernorTest is L2EPTest { + /// Helper variable(s) + address internal s_crossDomainMessengerAddr = toArbitrumL2AliasAddress(s_l1OwnerAddr); + address internal s_newOwnerCrossDomainMessengerAddr = toArbitrumL2AliasAddress(s_strangerAddr); + + /// Contracts + ArbitrumCrossDomainGovernor internal s_arbitrumCrossDomainGovernor; + MultiSend internal s_multiSend; + Greeter internal s_greeter; + + /// Events + event L1OwnershipTransferRequested(address indexed from, address indexed to); + event L1OwnershipTransferred(address indexed from, address indexed to); + + /// Setup + function setUp() public { + // Deploys contracts + vm.startPrank(s_l1OwnerAddr); + s_arbitrumCrossDomainGovernor = new ArbitrumCrossDomainGovernor(s_l1OwnerAddr); + s_greeter = new Greeter(address(s_arbitrumCrossDomainGovernor)); + s_multiSend = new MultiSend(); + vm.stopPrank(); + } +} + +contract ArbitrumCrossDomainGovernor_Constructor is ArbitrumCrossDomainGovernorTest { + /// @notice it should have been deployed with the correct initial state + function test_InitialState() public { + // it should set the owner correctly + assertEq(s_arbitrumCrossDomainGovernor.owner(), s_l1OwnerAddr); + + // it should set the l1Owner correctly + assertEq(s_arbitrumCrossDomainGovernor.l1Owner(), s_l1OwnerAddr); + + // it should set the crossdomain messenger correctly + assertEq(s_arbitrumCrossDomainGovernor.crossDomainMessenger(), s_crossDomainMessengerAddr); + + // it should set the typeAndVersion correctly + assertEq(s_arbitrumCrossDomainGovernor.typeAndVersion(), "ArbitrumCrossDomainGovernor 1.0.0"); + } +} + +contract ArbitrumCrossDomainGovernor_Forward is ArbitrumCrossDomainGovernorTest { + /// @notice it should not be callable by unknown address + function test_NotCallableByUnknownAddress() public { + vm.startPrank(s_strangerAddr); + vm.expectRevert("Sender is not the L2 messenger or owner"); + s_arbitrumCrossDomainGovernor.forward(address(s_greeter), abi.encode("")); + } + + /// @notice it should be callable by crossdomain messenger address / L1 owner + function test_Forward() public { + // Sets msg.sender and tx.origin + vm.startPrank(s_crossDomainMessengerAddr); + + // Defines the cross domain message to send + string memory greeting = "hello"; + + // Sends the message + s_arbitrumCrossDomainGovernor.forward( + address(s_greeter), + abi.encodeWithSelector(s_greeter.setGreeting.selector, greeting) + ); + + // Checks that the greeter got the message + assertEq(s_greeter.greeting(), greeting); + } + + /// @notice it should be callable by L2 owner + function test_CallableByL2Owner() public { + // Sets msg.sender and tx.origin + vm.startPrank(s_l1OwnerAddr); + + // Defines the cross domain message to send + string memory greeting = "hello"; + + // Sends the message + s_arbitrumCrossDomainGovernor.forward( + address(s_greeter), + abi.encodeWithSelector(s_greeter.setGreeting.selector, greeting) + ); + + // Checks that the greeter message was updated + assertEq(s_greeter.greeting(), greeting); + } + + /// @notice it should revert when contract call reverts + function test_ForwardRevert() public { + // Sets msg.sender and tx.origin + vm.startPrank(s_l1OwnerAddr); + + // Sends an invalid message + vm.expectRevert("Invalid greeting length"); + s_arbitrumCrossDomainGovernor.forward( + address(s_greeter), + abi.encodeWithSelector(s_greeter.setGreeting.selector, "") + ); + } +} + +contract ArbitrumCrossDomainGovernor_ForwardDelegate is ArbitrumCrossDomainGovernorTest { + /// @notice it should not be callable by unknown address + function test_NotCallableByUnknownAddress() public { + vm.startPrank(s_strangerAddr); + vm.expectRevert("Sender is not the L2 messenger or owner"); + s_arbitrumCrossDomainGovernor.forwardDelegate(address(s_multiSend), abi.encode("")); + } + + /// @notice it should be callable by crossdomain messenger address / L1 owner + function test_CallableByCrossDomainMessengerAddressOrL1Owner() public { + // Sets msg.sender and tx.origin + vm.startPrank(s_crossDomainMessengerAddr); + + // Sends the message + s_arbitrumCrossDomainGovernor.forwardDelegate( + address(s_multiSend), + abi.encodeWithSelector( + MultiSend.multiSend.selector, + abi.encodePacked(encodeMultiSendTx(address(s_greeter), "foo"), encodeMultiSendTx(address(s_greeter), "bar")) + ) + ); + + // Checks that the greeter message was updated + assertEq(s_greeter.greeting(), "bar"); + } + + /// @notice it should be callable by L2 owner + function test_CallableByL2Owner() public { + // Sets msg.sender and tx.origin + vm.startPrank(s_l1OwnerAddr); + + // Sends the message + s_arbitrumCrossDomainGovernor.forwardDelegate( + address(s_multiSend), + abi.encodeWithSelector( + MultiSend.multiSend.selector, + abi.encodePacked(encodeMultiSendTx(address(s_greeter), "foo"), encodeMultiSendTx(address(s_greeter), "bar")) + ) + ); + + // Checks that the greeter message was updated + assertEq(s_greeter.greeting(), "bar"); + } + + /// @notice it should revert batch when one call fails + function test_RevertsBatchWhenOneCallFails() public { + // Sets msg.sender and tx.origin + vm.startPrank(s_crossDomainMessengerAddr); + + // Sends an invalid message (empty transaction data is not allowed) + vm.expectRevert("Governor delegatecall reverted"); + s_arbitrumCrossDomainGovernor.forwardDelegate( + address(s_multiSend), + abi.encodeWithSelector( + MultiSend.multiSend.selector, + abi.encodePacked(encodeMultiSendTx(address(s_greeter), "foo"), encodeMultiSendTx(address(s_greeter), "")) + ) + ); + + // Checks that the greeter message is unchanged + assertEq(s_greeter.greeting(), ""); + } + + /// @notice it should bubble up revert when contract call reverts + function test_BubbleUpRevert() public { + // Sets msg.sender and tx.origin + vm.startPrank(s_crossDomainMessengerAddr); + + // Sends an invalid message (empty transaction data is not allowed) + vm.expectRevert("Greeter: revert triggered"); + s_arbitrumCrossDomainGovernor.forwardDelegate( + address(s_greeter), + abi.encodeWithSelector(Greeter.triggerRevert.selector) + ); + } +} + +contract ArbitrumCrossDomainGovernor_TransferL1Ownership is ArbitrumCrossDomainGovernorTest { + /// @notice it should not be callable by non-owners + function test_NotCallableByNonOwners() public { + vm.startPrank(s_strangerAddr); + vm.expectRevert("Sender is not the L2 messenger"); + s_arbitrumCrossDomainGovernor.transferL1Ownership(s_strangerAddr); + } + + /// @notice it should not be callable by L2 owner + function test_NotCallableByL2Owner() public { + vm.startPrank(s_l1OwnerAddr); + assertEq(s_arbitrumCrossDomainGovernor.owner(), s_l1OwnerAddr); + vm.expectRevert("Sender is not the L2 messenger"); + s_arbitrumCrossDomainGovernor.transferL1Ownership(s_strangerAddr); + } + + /// @notice it should be callable by current L1 owner + function test_CallableByL1Owner() public { + // Sets msg.sender and tx.origin + vm.startPrank(s_crossDomainMessengerAddr); + + // Defines the cross domain message to send + vm.expectEmit(); + emit L1OwnershipTransferRequested(s_arbitrumCrossDomainGovernor.l1Owner(), s_strangerAddr); + + // Sends the message + s_arbitrumCrossDomainGovernor.transferL1Ownership(s_strangerAddr); + } + + /// @notice it should be callable by current L1 owner to zero address + function test_CallableByL1OwnerOrZeroAddress() public { + // Sets msg.sender and tx.origin + vm.startPrank(s_crossDomainMessengerAddr); + + // Defines the cross domain message to send + vm.expectEmit(); + emit L1OwnershipTransferRequested(s_arbitrumCrossDomainGovernor.l1Owner(), address(0)); + + // Sends the message + s_arbitrumCrossDomainGovernor.transferL1Ownership(address(0)); + } +} + +contract ArbitrumCrossDomainGovernor_AcceptL1Ownership is ArbitrumCrossDomainGovernorTest { + /// @notice it should not be callable by non pending-owners + function test_NotCallableByNonPendingOwners() public { + // Sets msg.sender and tx.origin + vm.startPrank(s_crossDomainMessengerAddr); + + // Sends the message + vm.expectRevert("Must be proposed L1 owner"); + s_arbitrumCrossDomainGovernor.acceptL1Ownership(); + } + + /// @notice it should be callable by pending L1 owner + function test_CallableByPendingL1Owner() public { + // Request ownership transfer + vm.startPrank(s_crossDomainMessengerAddr); + s_arbitrumCrossDomainGovernor.transferL1Ownership(s_strangerAddr); + + // Prepares expected event payload + vm.expectEmit(); + emit L1OwnershipTransferred(s_l1OwnerAddr, s_strangerAddr); + + // Accepts ownership transfer request + vm.startPrank(s_newOwnerCrossDomainMessengerAddr); + s_arbitrumCrossDomainGovernor.acceptL1Ownership(); + + // Asserts that the ownership was actually transferred + assertEq(s_arbitrumCrossDomainGovernor.l1Owner(), s_strangerAddr); + } +} diff --git a/contracts/src/v0.8/l2ep/test/v1_0_0/arbitrum/ArbitrumSequencerUptimeFeed.t.sol b/contracts/src/v0.8/l2ep/test/v1_0_0/arbitrum/ArbitrumSequencerUptimeFeed.t.sol new file mode 100644 index 0000000000..3b9df3bf91 --- /dev/null +++ b/contracts/src/v0.8/l2ep/test/v1_0_0/arbitrum/ArbitrumSequencerUptimeFeed.t.sol @@ -0,0 +1,444 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.19; + +import {SimpleWriteAccessController} from "../../../../shared/access/SimpleWriteAccessController.sol"; +import {ArbitrumSequencerUptimeFeed} from "../../../dev/arbitrum/ArbitrumSequencerUptimeFeed.sol"; +import {MockAggregatorV2V3} from "../../mocks/MockAggregatorV2V3.sol"; +import {FeedConsumer} from "../../../../tests/FeedConsumer.sol"; +import {Flags} from "../../../dev/Flags.sol"; +import {L2EPTest} from "../L2EPTest.t.sol"; + +contract ArbitrumSequencerUptimeFeedTest is L2EPTest { + /// Constants + uint256 internal constant GAS_USED_DEVIATION = 100; + + /// Helper variable(s) + address internal s_l2MessengerAddr = toArbitrumL2AliasAddress(s_l1OwnerAddr); + + /// L2EP contracts + ArbitrumSequencerUptimeFeed internal s_arbitrumSequencerUptimeFeed; + SimpleWriteAccessController internal s_accessController; + MockAggregatorV2V3 internal s_l1GasFeed; + Flags internal s_flags; + + /// Events + event UpdateIgnored(bool latestStatus, uint64 latestTimestamp, bool incomingStatus, uint64 incomingTimestamp); + event AnswerUpdated(int256 indexed current, uint256 indexed roundId, uint256 updatedAt); + event RoundUpdated(int256 status, uint64 updatedAt); + event Initialized(); + + /// Setup + function setUp() public { + vm.startPrank(s_deployerAddr, s_deployerAddr); + + s_accessController = new SimpleWriteAccessController(); + s_flags = new Flags(address(s_accessController), address(s_accessController)); + s_arbitrumSequencerUptimeFeed = new ArbitrumSequencerUptimeFeed(address(s_flags), s_l1OwnerAddr); + + s_accessController.addAccess(address(s_arbitrumSequencerUptimeFeed)); + s_accessController.addAccess(address(s_flags)); + s_accessController.addAccess(s_deployerAddr); + s_flags.addAccess(address(s_arbitrumSequencerUptimeFeed)); + + vm.expectEmit(); + emit Initialized(); + s_arbitrumSequencerUptimeFeed.initialize(); + + vm.stopPrank(); + } +} + +contract ArbitrumSequencerUptimeFeed_Constants is ArbitrumSequencerUptimeFeedTest { + /// @notice it should have the correct value for FLAG_L2_SEQ_OFFLINE' + function test_InitialState() public { + assertEq(s_arbitrumSequencerUptimeFeed.FLAG_L2_SEQ_OFFLINE(), 0xa438451D6458044c3c8CD2f6f31c91ac882A6d91); + } +} + +contract ArbitrumSequencerUptimeFeed_UpdateStatus is ArbitrumSequencerUptimeFeedTest { + /// @notice it should revert if called by an address that is not the L2 Cross Domain Messenger + function test_RevertIfNotL2CrossDomainMessengerAddr() public { + // Sets msg.sender and tx.origin to an unauthorized address + vm.startPrank(s_strangerAddr, s_strangerAddr); + + // Tries to update the status from an unauthorized account + vm.expectRevert(ArbitrumSequencerUptimeFeed.InvalidSender.selector); + s_arbitrumSequencerUptimeFeed.updateStatus(true, uint64(1)); + } + + /// @notice it should update status when status has changed and incoming timestamp is newer than the latest + function test_UpdateStatusWhenStatusChangeAndTimeChange() public { + // Sets msg.sender and tx.origin to a valid address + vm.startPrank(s_l2MessengerAddr, s_l2MessengerAddr); + + // Submits a status update + uint256 timestamp = s_arbitrumSequencerUptimeFeed.latestTimestamp(); + vm.expectEmit(); + emit AnswerUpdated(1, 2, timestamp); + s_arbitrumSequencerUptimeFeed.updateStatus(true, uint64(timestamp)); + assertEq(s_arbitrumSequencerUptimeFeed.latestAnswer(), 1); + assertEq(s_arbitrumSequencerUptimeFeed.latestTimestamp(), uint64(timestamp)); + + // Submit another status update, different status, newer timestamp should update + timestamp = timestamp + 200; + vm.expectEmit(); + emit AnswerUpdated(0, 3, timestamp); + s_arbitrumSequencerUptimeFeed.updateStatus(false, uint64(timestamp)); + assertEq(s_arbitrumSequencerUptimeFeed.latestAnswer(), 0); + assertEq(s_arbitrumSequencerUptimeFeed.latestTimestamp(), uint64(timestamp)); + } + + /// @notice it should update status when status has changed and incoming timestamp is the same as latest + function test_UpdateStatusWhenStatusChangeAndNoTimeChange() public { + // Sets msg.sender and tx.origin to a valid address + vm.startPrank(s_l2MessengerAddr, s_l2MessengerAddr); + + // Fetches the latest timestamp + uint256 timestamp = s_arbitrumSequencerUptimeFeed.latestTimestamp(); + + // Submits a status update + vm.expectEmit(); + emit AnswerUpdated(1, 2, timestamp); + s_arbitrumSequencerUptimeFeed.updateStatus(true, uint64(timestamp)); + assertEq(s_arbitrumSequencerUptimeFeed.latestAnswer(), 1); + assertEq(s_arbitrumSequencerUptimeFeed.latestTimestamp(), uint64(timestamp)); + + // Submit another status update, different status, same timestamp should update + vm.expectEmit(); + emit AnswerUpdated(0, 3, timestamp); + s_arbitrumSequencerUptimeFeed.updateStatus(false, uint64(timestamp)); + assertEq(s_arbitrumSequencerUptimeFeed.latestAnswer(), 0); + assertEq(s_arbitrumSequencerUptimeFeed.latestTimestamp(), uint64(timestamp)); + } + + /// @notice it should ignore out-of-order updates + function test_IgnoreOutOfOrderUpdates() public { + // Sets msg.sender and tx.origin to a valid address + vm.startPrank(s_l2MessengerAddr, s_l2MessengerAddr); + + // Submits a status update + uint256 timestamp = s_arbitrumSequencerUptimeFeed.latestTimestamp() + 10000; + vm.expectEmit(); + emit AnswerUpdated(1, 2, timestamp); + s_arbitrumSequencerUptimeFeed.updateStatus(true, uint64(timestamp)); + assertEq(s_arbitrumSequencerUptimeFeed.latestAnswer(), 1); + assertEq(s_arbitrumSequencerUptimeFeed.latestTimestamp(), uint64(timestamp)); + + // Update with different status, but stale timestamp, should be ignored + timestamp = timestamp - 1000; + vm.expectEmit(false, false, false, false); + emit UpdateIgnored(true, 0, true, 0); // arguments are dummy values + // TODO: how can we check that an AnswerUpdated event was NOT emitted + s_arbitrumSequencerUptimeFeed.updateStatus(false, uint64(timestamp)); + } +} + +contract ArbitrumSequencerUptimeFeed_AggregatorV3Interface is ArbitrumSequencerUptimeFeedTest { + /// @notice it should return valid answer from getRoundData and latestRoundData + function test_AggregatorV3Interface() public { + // Sets msg.sender and tx.origin to a valid address + vm.startPrank(s_l2MessengerAddr, s_l2MessengerAddr); + + // Defines helper variables + uint80 roundId; + int256 answer; + uint256 startedAt; + uint256 updatedAt; + uint80 answeredInRound; + + // Checks initial state + (roundId, answer, startedAt, updatedAt, answeredInRound) = s_arbitrumSequencerUptimeFeed.latestRoundData(); + assertEq(roundId, 1); + assertEq(answer, 0); + assertEq(answeredInRound, roundId); + assertEq(startedAt, updatedAt); + + // Submits status update with different status and newer timestamp, should update + uint256 timestamp = startedAt + 1000; + s_arbitrumSequencerUptimeFeed.updateStatus(true, uint64(timestamp)); + (roundId, answer, startedAt, updatedAt, answeredInRound) = s_arbitrumSequencerUptimeFeed.getRoundData(2); + assertEq(roundId, 2); + assertEq(answer, 1); + assertEq(answeredInRound, roundId); + assertEq(startedAt, timestamp); + assertLe(updatedAt, startedAt); + + // Saves round 2 data + uint80 roundId2 = roundId; + int256 answer2 = answer; + uint256 startedAt2 = startedAt; + uint256 updatedAt2 = updatedAt; + uint80 answeredInRound2 = answeredInRound; + + // Checks that last round is still returning the correct data + (roundId, answer, startedAt, updatedAt, answeredInRound) = s_arbitrumSequencerUptimeFeed.getRoundData(1); + assertEq(roundId, 1); + assertEq(answer, 0); + assertEq(answeredInRound, roundId); + assertEq(startedAt, updatedAt); + + // Assert latestRoundData corresponds to latest round id + (roundId, answer, startedAt, updatedAt, answeredInRound) = s_arbitrumSequencerUptimeFeed.latestRoundData(); + assertEq(roundId2, roundId); + assertEq(answer2, answer); + assertEq(startedAt2, startedAt); + assertEq(updatedAt2, updatedAt); + assertEq(answeredInRound2, answeredInRound); + } + + /// @notice it should revert from #getRoundData when round does not yet exist (future roundId) + function test_Return0WhenRoundDoesNotExistYet() public { + // Sets msg.sender and tx.origin to a valid address + vm.startPrank(s_l1OwnerAddr, s_l1OwnerAddr); + + // Gets data from a round that has not happened yet + ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) = s_arbitrumSequencerUptimeFeed.getRoundData(2); + + // Validates round data + assertEq(roundId, 2); + assertEq(answer, 0); + assertEq(startedAt, 0); + assertEq(updatedAt, 0); + assertEq(answeredInRound, 2); + } +} + +contract ArbitrumSequencerUptimeFeed_ProtectReadsOnAggregatorV2V3InterfaceFunctions is ArbitrumSequencerUptimeFeedTest { + /// @notice it should disallow reads on AggregatorV2V3Interface functions when consuming contract is not whitelisted + function test_AggregatorV2V3InterfaceDisallowReadsIfConsumingContractIsNotWhitelisted() public { + // Deploys a FeedConsumer contract + FeedConsumer feedConsumer = new FeedConsumer(address(s_arbitrumSequencerUptimeFeed)); + + // Sanity - consumer is not whitelisted + assertEq(s_arbitrumSequencerUptimeFeed.checkEnabled(), true); + assertEq(s_arbitrumSequencerUptimeFeed.hasAccess(address(feedConsumer), abi.encode("")), false); + + // Asserts reads are not possible from consuming contract + vm.expectRevert("No access"); + feedConsumer.latestAnswer(); + vm.expectRevert("No access"); + feedConsumer.latestRoundData(); + } + + /// @notice it should allow reads on AggregatorV2V3Interface functions when consuming contract is whitelisted + function test_AggregatorV2V3InterfaceAllowReadsIfConsumingContractIsWhitelisted() public { + // Deploys a FeedConsumer contract + FeedConsumer feedConsumer = new FeedConsumer(address(s_arbitrumSequencerUptimeFeed)); + + // Whitelist consumer + vm.startPrank(s_deployerAddr, s_deployerAddr); + s_arbitrumSequencerUptimeFeed.addAccess(address(feedConsumer)); + + // Sanity - consumer is whitelisted + assertEq(s_arbitrumSequencerUptimeFeed.checkEnabled(), true); + assertEq(s_arbitrumSequencerUptimeFeed.hasAccess(address(feedConsumer), abi.encode("")), true); + + // Asserts reads are possible from consuming contract + (uint80 roundId, int256 answer, , , ) = feedConsumer.latestRoundData(); + assertEq(feedConsumer.latestAnswer(), 0); + assertEq(roundId, 1); + assertEq(answer, 0); + } +} + +contract ArbitrumSequencerUptimeFeed_GasCosts is ArbitrumSequencerUptimeFeedTest { + /// @notice it should consume a known amount of gas for updates + function test_GasCosts() public { + // Sets msg.sender and tx.origin to a valid address + vm.startPrank(s_l2MessengerAddr, s_l2MessengerAddr); + + // Assert initial conditions + uint256 timestamp = s_arbitrumSequencerUptimeFeed.latestTimestamp(); + assertEq(s_arbitrumSequencerUptimeFeed.latestAnswer(), 0); + + // Defines helper variables for measuring gas usage + uint256 expectedGasUsed; + uint256 gasStart; + uint256 gasFinal; + + // measures gas used for no update + expectedGasUsed = 5507; // NOTE: used to be 28300 in hardhat tests + gasStart = gasleft(); + s_arbitrumSequencerUptimeFeed.updateStatus(false, uint64(timestamp + 1000)); + gasFinal = gasleft(); + assertEq(s_arbitrumSequencerUptimeFeed.latestAnswer(), 0); + assertGasUsageIsCloseTo(expectedGasUsed, gasStart, gasFinal, GAS_USED_DEVIATION); + + // measures gas used for update + expectedGasUsed = 68198; // NOTE: used to be 93015 in hardhat tests + gasStart = gasleft(); + s_arbitrumSequencerUptimeFeed.updateStatus(true, uint64(timestamp + 1000)); + gasFinal = gasleft(); + assertEq(s_arbitrumSequencerUptimeFeed.latestAnswer(), 1); + assertGasUsageIsCloseTo(expectedGasUsed, gasStart, gasFinal, GAS_USED_DEVIATION); + } +} + +contract ArbitrumSequencerUptimeFeed_AggregatorInterfaceGasCosts is ArbitrumSequencerUptimeFeedTest { + /// @notice it should consume a known amount of gas for getRoundData(uint80) + function test_GasUsageForGetRoundData() public { + // Sets msg.sender and tx.origin to a valid address + vm.startPrank(s_l2MessengerAddr, s_l2MessengerAddr); + + // Defines helper variables for measuring gas usage + uint256 expectedGasUsed = 4658; // NOTE: used to be 31157 in hardhat tests + uint256 gasStart; + uint256 gasFinal; + + // Initializes a round + uint256 timestamp = s_arbitrumSequencerUptimeFeed.latestTimestamp() + 1000; + s_arbitrumSequencerUptimeFeed.updateStatus(true, uint64(timestamp)); + + // Measures gas usage + gasStart = gasleft(); + s_arbitrumSequencerUptimeFeed.getRoundData(1); + gasFinal = gasleft(); + + // Checks that gas usage is within expected range + assertGasUsageIsCloseTo(expectedGasUsed, gasStart, gasFinal, GAS_USED_DEVIATION); + } + + /// @notice it should consume a known amount of gas for latestRoundData() + function test_GasUsageForLatestRoundData() public { + // Sets msg.sender and tx.origin to a valid address + vm.startPrank(s_l2MessengerAddr, s_l2MessengerAddr); + + // Defines helper variables for measuring gas usage + uint256 expectedGasUsed = 2154; // NOTE: used to be 28523 in hardhat tests + uint256 gasStart; + uint256 gasFinal; + + // Initializes a round + uint256 timestamp = s_arbitrumSequencerUptimeFeed.latestTimestamp() + 1000; + s_arbitrumSequencerUptimeFeed.updateStatus(true, uint64(timestamp)); + + // Measures gas usage + gasStart = gasleft(); + s_arbitrumSequencerUptimeFeed.latestRoundData(); + gasFinal = gasleft(); + + // Checks that gas usage is within expected range + assertGasUsageIsCloseTo(expectedGasUsed, gasStart, gasFinal, GAS_USED_DEVIATION); + } + + /// @notice it should consume a known amount of gas for latestAnswer() + function test_GasUsageForLatestAnswer() public { + // Sets msg.sender and tx.origin to a valid address + vm.startPrank(s_l2MessengerAddr, s_l2MessengerAddr); + + // Defines helper variables for measuring gas usage + uint256 expectedGasUsed = 1722; // NOTE: used to be 28329 in hardhat tests + uint256 gasStart; + uint256 gasFinal; + + // Initializes a round + uint256 timestamp = s_arbitrumSequencerUptimeFeed.latestTimestamp() + 1000; + s_arbitrumSequencerUptimeFeed.updateStatus(true, uint64(timestamp)); + + // Measures gas usage + gasStart = gasleft(); + s_arbitrumSequencerUptimeFeed.latestAnswer(); + gasFinal = gasleft(); + + // Checks that gas usage is within expected range + assertGasUsageIsCloseTo(expectedGasUsed, gasStart, gasFinal, GAS_USED_DEVIATION); + } + + /// @notice it should consume a known amount of gas for latestTimestamp() + function test_GasUsageForLatestTimestamp() public { + // Sets msg.sender and tx.origin to a valid address + vm.startPrank(s_l2MessengerAddr, s_l2MessengerAddr); + + // Defines helper variables for measuring gas usage + uint256 expectedGasUsed = 1652; // NOTE: used to be 28229 in hardhat tests + uint256 gasStart; + uint256 gasFinal; + + // Initializes a round + uint256 timestamp = s_arbitrumSequencerUptimeFeed.latestTimestamp() + 1000; + s_arbitrumSequencerUptimeFeed.updateStatus(true, uint64(timestamp)); + + // Measures gas usage + gasStart = gasleft(); + s_arbitrumSequencerUptimeFeed.latestTimestamp(); + gasFinal = gasleft(); + + // Checks that gas usage is within expected range + assertGasUsageIsCloseTo(expectedGasUsed, gasStart, gasFinal, GAS_USED_DEVIATION); + } + + /// @notice it should consume a known amount of gas for latestRound() + function test_GasUsageForLatestRound() public { + // Sets msg.sender and tx.origin to a valid address + vm.startPrank(s_l2MessengerAddr, s_l2MessengerAddr); + + // Defines helper variables for measuring gas usage + uint256 expectedGasUsed = 1632; // NOTE: used to be 28245 in hardhat tests + uint256 gasStart; + uint256 gasFinal; + + // Initializes a round + uint256 timestamp = s_arbitrumSequencerUptimeFeed.latestTimestamp() + 1000; + s_arbitrumSequencerUptimeFeed.updateStatus(true, uint64(timestamp)); + + // Measures gas usage + gasStart = gasleft(); + s_arbitrumSequencerUptimeFeed.latestRound(); + gasFinal = gasleft(); + + // Checks that gas usage is within expected range + assertGasUsageIsCloseTo(expectedGasUsed, gasStart, gasFinal, GAS_USED_DEVIATION); + } + + /// @notice it should consume a known amount of gas for getAnswer() + function test_GasUsageForGetAnswer() public { + // Sets msg.sender and tx.origin to a valid address + vm.startPrank(s_l2MessengerAddr, s_l2MessengerAddr); + + // Defines helper variables for measuring gas usage + uint256 expectedGasUsed = 4059; // NOTE: used to be 30799 in hardhat tests + uint256 gasStart; + uint256 gasFinal; + + // Initializes a round + uint256 timestamp = s_arbitrumSequencerUptimeFeed.latestTimestamp() + 1000; + s_arbitrumSequencerUptimeFeed.updateStatus(true, uint64(timestamp)); + + // Measures gas usage + gasStart = gasleft(); + s_arbitrumSequencerUptimeFeed.getAnswer(1); + gasFinal = gasleft(); + + // Checks that gas usage is within expected range + assertGasUsageIsCloseTo(expectedGasUsed, gasStart, gasFinal, GAS_USED_DEVIATION); + } + + /// @notice it should consume a known amount of gas for getTimestamp() + function test_GasUsageForGetTimestamp() public { + // Sets msg.sender and tx.origin to a valid address + vm.startPrank(s_l2MessengerAddr, s_l2MessengerAddr); + + // Defines helper variables for measuring gas usage + uint256 expectedGasUsed = 4024; // NOTE: used to be 30753 in hardhat tests + uint256 gasStart; + uint256 gasFinal; + + // Initializes a round + uint256 timestamp = s_arbitrumSequencerUptimeFeed.latestTimestamp() + 1000; + s_arbitrumSequencerUptimeFeed.updateStatus(true, uint64(timestamp)); + + // Measures gas usage + gasStart = gasleft(); + s_arbitrumSequencerUptimeFeed.getTimestamp(1); + gasFinal = gasleft(); + + // Checks that gas usage is within expected range + assertGasUsageIsCloseTo(expectedGasUsed, gasStart, gasFinal, GAS_USED_DEVIATION); + } +} diff --git a/contracts/src/v0.8/l2ep/test/v1_0_0/arbitrum/ArbitrumValidator.t.sol b/contracts/src/v0.8/l2ep/test/v1_0_0/arbitrum/ArbitrumValidator.t.sol new file mode 100644 index 0000000000..504635540c --- /dev/null +++ b/contracts/src/v0.8/l2ep/test/v1_0_0/arbitrum/ArbitrumValidator.t.sol @@ -0,0 +1,87 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.19; + +import {AccessControllerInterface} from "../../../../shared/interfaces/AccessControllerInterface.sol"; + +import {SimpleWriteAccessController} from "../../../../shared/access/SimpleWriteAccessController.sol"; +import {ArbitrumSequencerUptimeFeed} from "../../../dev/arbitrum/ArbitrumSequencerUptimeFeed.sol"; +import {ArbitrumValidator} from "../../../dev/arbitrum/ArbitrumValidator.sol"; +import {MockArbitrumInbox} from "../../../../tests/MockArbitrumInbox.sol"; +import {MockAggregatorV2V3} from "../../mocks/MockAggregatorV2V3.sol"; +import {L2EPTest} from "../L2EPTest.t.sol"; + +contract ArbitrumValidatorTest is L2EPTest { + /// Helper constants + address internal constant L2_SEQ_STATUS_RECORDER_ADDRESS = 0x491B1dDA0A8fa069bbC1125133A975BF4e85a91b; + uint256 internal constant GAS_PRICE_BID = 1000000; + uint256 internal constant BASE_FEE = 14000000000; + uint256 internal constant MAX_GAS = 1000000; + + /// L2EP contracts + AccessControllerInterface internal s_accessController; + MockArbitrumInbox internal s_mockArbitrumInbox; + ArbitrumValidator internal s_arbitrumValidator; + MockAggregatorV2V3 internal s_l1GasFeed; + + /// Events + event RetryableTicketNoRefundAliasRewriteCreated( + address destAddr, + uint256 arbTxCallValue, + uint256 maxSubmissionCost, + address submissionRefundAddress, + address valueRefundAddress, + uint256 maxGas, + uint256 gasPriceBid, + bytes data + ); + + /// Setup + function setUp() public { + s_accessController = new SimpleWriteAccessController(); + s_mockArbitrumInbox = new MockArbitrumInbox(); + s_l1GasFeed = new MockAggregatorV2V3(); + s_arbitrumValidator = new ArbitrumValidator( + address(s_mockArbitrumInbox), + L2_SEQ_STATUS_RECORDER_ADDRESS, + address(s_accessController), + MAX_GAS, + GAS_PRICE_BID, + BASE_FEE, + address(s_l1GasFeed), + ArbitrumValidator.PaymentStrategy.L1 + ); + } +} + +contract ArbitrumValidator_Validate is ArbitrumValidatorTest { + /// @notice it post sequencer offline + function test_PostSequencerOffline() public { + // Gives access to the s_eoaValidator + s_arbitrumValidator.addAccess(s_eoaValidator); + + // Gets the ArbitrumValidator L2 address + address arbitrumValidatorL2Addr = toArbitrumL2AliasAddress(address(s_arbitrumValidator)); + + // Sets block.timestamp to a later date, funds the ArbitrumValidator contract, and sets msg.sender and tx.origin + uint256 futureTimestampInSeconds = block.timestamp + 5000; + vm.warp(futureTimestampInSeconds); + vm.deal(address(s_arbitrumValidator), 1 ether); + vm.startPrank(s_eoaValidator); + + // Sets up the expected event data + vm.expectEmit(); + emit RetryableTicketNoRefundAliasRewriteCreated( + L2_SEQ_STATUS_RECORDER_ADDRESS, // destAddr + 0, // arbTxCallValue + 25312000000000, // maxSubmissionCost + arbitrumValidatorL2Addr, // submissionRefundAddress + arbitrumValidatorL2Addr, // valueRefundAddress + MAX_GAS, // maxGas + GAS_PRICE_BID, // gasPriceBid + abi.encodeWithSelector(ArbitrumSequencerUptimeFeed.updateStatus.selector, true, futureTimestampInSeconds) // data + ); + + // Runs the function (which produces the event to test) + s_arbitrumValidator.validate(0, 0, 1, 1); + } +} diff --git a/contracts/src/v0.8/l2ep/test/v1_0_0/optimism/OptimismCrossDomainForwarder.t.sol b/contracts/src/v0.8/l2ep/test/v1_0_0/optimism/OptimismCrossDomainForwarder.t.sol new file mode 100644 index 0000000000..d5c482dce9 --- /dev/null +++ b/contracts/src/v0.8/l2ep/test/v1_0_0/optimism/OptimismCrossDomainForwarder.t.sol @@ -0,0 +1,187 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.19; + +import {OptimismCrossDomainForwarder} from "../../../dev/optimism/OptimismCrossDomainForwarder.sol"; +import {MockOVMCrossDomainMessenger} from "../../mocks/optimism/MockOVMCrossDomainMessenger.sol"; +import {Greeter} from "../../../../tests/Greeter.sol"; +import {L2EPTest} from "../L2EPTest.t.sol"; + +contract OptimismCrossDomainForwarderTest is L2EPTest { + /// Contracts + MockOVMCrossDomainMessenger internal s_mockOptimismCrossDomainMessenger; + OptimismCrossDomainForwarder internal s_optimismCrossDomainForwarder; + Greeter internal s_greeter; + + /// Events + event L1OwnershipTransferRequested(address indexed from, address indexed to); + event L1OwnershipTransferred(address indexed from, address indexed to); + + /// Setup + function setUp() public { + // Deploys contracts + vm.startPrank(s_l1OwnerAddr); + s_mockOptimismCrossDomainMessenger = new MockOVMCrossDomainMessenger(s_l1OwnerAddr); + s_optimismCrossDomainForwarder = new OptimismCrossDomainForwarder( + s_mockOptimismCrossDomainMessenger, + s_l1OwnerAddr + ); + s_greeter = new Greeter(address(s_optimismCrossDomainForwarder)); + vm.stopPrank(); + } +} + +contract OptimismCrossDomainForwarder_Constructor is OptimismCrossDomainForwarderTest { + /// @notice it should have been deployed with the correct initial state + function test_InitialState() public { + // it should set the owner correctly + assertEq(s_optimismCrossDomainForwarder.owner(), s_l1OwnerAddr); + + // it should set the l1Owner correctly + assertEq(s_optimismCrossDomainForwarder.l1Owner(), s_l1OwnerAddr); + + // it should set the crossdomain messenger correctly + assertEq(s_optimismCrossDomainForwarder.crossDomainMessenger(), address(s_mockOptimismCrossDomainMessenger)); + + // it should set the typeAndVersion correctly + assertEq(s_optimismCrossDomainForwarder.typeAndVersion(), "OptimismCrossDomainForwarder 1.0.0"); + } +} + +contract OptimismCrossDomainForwarder_Forward is OptimismCrossDomainForwarderTest { + /// @notice it should not be callable by unknown address + function test_NotCallableByUnknownAddress() public { + vm.startPrank(s_strangerAddr); + vm.expectRevert("Sender is not the L2 messenger"); + s_optimismCrossDomainForwarder.forward(address(s_greeter), abi.encode("")); + } + + /// @notice it should be callable by crossdomain messenger address / L1 owner + function test_Forward() public { + // Sets msg.sender and tx.origin + vm.startPrank(s_strangerAddr); + + // Defines the cross domain message to send + string memory greeting = "hello"; + + // Sends the message + s_mockOptimismCrossDomainMessenger.sendMessage( + address(s_optimismCrossDomainForwarder), // target + encodeCrossDomainSetGreetingMsg(s_optimismCrossDomainForwarder.forward.selector, address(s_greeter), greeting), // message + 0 // gas limit + ); + + // Checks that the greeter got the message + assertEq(s_greeter.greeting(), greeting); + } + + /// @notice it should revert when contract call reverts + function test_ForwardRevert() public { + // Sets msg.sender and tx.origin + vm.startPrank(s_strangerAddr); + + // Sends an invalid message + vm.expectRevert("Invalid greeting length"); + s_mockOptimismCrossDomainMessenger.sendMessage( + address(s_optimismCrossDomainForwarder), // target + encodeCrossDomainSetGreetingMsg(s_optimismCrossDomainForwarder.forward.selector, address(s_greeter), ""), // message + 0 // gas limit + ); + } +} + +contract OptimismCrossDomainForwarder_TransferL1Ownership is OptimismCrossDomainForwarderTest { + /// @notice it should not be callable by non-owners + function test_NotCallableByNonOwners() public { + vm.startPrank(s_strangerAddr); + vm.expectRevert("Sender is not the L2 messenger"); + s_optimismCrossDomainForwarder.transferL1Ownership(s_strangerAddr); + } + + /// @notice it should not be callable by L2 owner + function test_NotCallableByL2Owner() public { + vm.startPrank(s_l1OwnerAddr); + assertEq(s_optimismCrossDomainForwarder.owner(), s_l1OwnerAddr); + vm.expectRevert("Sender is not the L2 messenger"); + s_optimismCrossDomainForwarder.transferL1Ownership(s_strangerAddr); + } + + /// @notice it should be callable by current L1 owner + function test_CallableByL1Owner() public { + // Sets msg.sender and tx.origin + vm.startPrank(s_strangerAddr); + + // Defines the cross domain message to send + vm.expectEmit(); + emit L1OwnershipTransferRequested(s_optimismCrossDomainForwarder.l1Owner(), s_strangerAddr); + + // Sends the message + s_mockOptimismCrossDomainMessenger.sendMessage( + address(s_optimismCrossDomainForwarder), // target + abi.encodeWithSelector(s_optimismCrossDomainForwarder.transferL1Ownership.selector, s_strangerAddr), // message + 0 // gas limit + ); + } + + /// @notice it should be callable by current L1 owner to zero address + function test_CallableByL1OwnerOrZeroAddress() public { + // Sets msg.sender and tx.origin + vm.startPrank(s_strangerAddr); + + // Defines the cross domain message to send + vm.expectEmit(); + emit L1OwnershipTransferRequested(s_optimismCrossDomainForwarder.l1Owner(), address(0)); + + // Sends the message + s_mockOptimismCrossDomainMessenger.sendMessage( + address(s_optimismCrossDomainForwarder), // target + abi.encodeWithSelector(s_optimismCrossDomainForwarder.transferL1Ownership.selector, address(0)), // message + 0 // gas limit + ); + } +} + +contract OptimismCrossDomainForwarder_AcceptL1Ownership is OptimismCrossDomainForwarderTest { + /// @notice it should not be callable by non pending-owners + function test_NotCallableByNonPendingOwners() public { + // Sets msg.sender and tx.origin + vm.startPrank(s_strangerAddr); + + // Sends the message + vm.expectRevert("Must be proposed L1 owner"); + s_mockOptimismCrossDomainMessenger.sendMessage( + address(s_optimismCrossDomainForwarder), // target + abi.encodeWithSelector(s_optimismCrossDomainForwarder.acceptL1Ownership.selector), // message + 0 // gas limit + ); + } + + /// @notice it should be callable by pending L1 owner + function test_CallableByPendingL1Owner() public { + // Sets msg.sender and tx.origin + vm.startPrank(s_strangerAddr); + + // Request ownership transfer + s_mockOptimismCrossDomainMessenger.sendMessage( + address(s_optimismCrossDomainForwarder), // target + abi.encodeWithSelector(s_optimismCrossDomainForwarder.transferL1Ownership.selector, s_strangerAddr), // message + 0 // gas limit + ); + + // Sets a mock message sender + s_mockOptimismCrossDomainMessenger._setMockMessageSender(s_strangerAddr); + + // Prepares expected event payload + vm.expectEmit(); + emit L1OwnershipTransferred(s_l1OwnerAddr, s_strangerAddr); + + // Accepts ownership transfer request + s_mockOptimismCrossDomainMessenger.sendMessage( + address(s_optimismCrossDomainForwarder), // target + abi.encodeWithSelector(s_optimismCrossDomainForwarder.acceptL1Ownership.selector, s_strangerAddr), // message + 0 // gas limit + ); + + // Asserts that the ownership was actually transferred + assertEq(s_optimismCrossDomainForwarder.l1Owner(), s_strangerAddr); + } +} diff --git a/contracts/src/v0.8/l2ep/test/v1_0_0/optimism/OptimismCrossDomainGovernor.t.sol b/contracts/src/v0.8/l2ep/test/v1_0_0/optimism/OptimismCrossDomainGovernor.t.sol new file mode 100644 index 0000000000..e1a5aef95a --- /dev/null +++ b/contracts/src/v0.8/l2ep/test/v1_0_0/optimism/OptimismCrossDomainGovernor.t.sol @@ -0,0 +1,294 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.19; + +import {OptimismCrossDomainGovernor} from "../../../dev/optimism/OptimismCrossDomainGovernor.sol"; +import {MockOVMCrossDomainMessenger} from "../../mocks/optimism/MockOVMCrossDomainMessenger.sol"; +import {Greeter} from "../../../../tests/Greeter.sol"; +import {L2EPTest} from "../L2EPTest.t.sol"; + +import {MultiSend} from "../../../../vendor/MultiSend.sol"; + +contract OptimismCrossDomainGovernorTest is L2EPTest { + /// Contracts + MockOVMCrossDomainMessenger internal s_mockOptimismCrossDomainMessenger; + OptimismCrossDomainGovernor internal s_optimismCrossDomainGovernor; + MultiSend internal s_multiSend; + Greeter internal s_greeter; + + /// Events + event L1OwnershipTransferRequested(address indexed from, address indexed to); + event L1OwnershipTransferred(address indexed from, address indexed to); + + /// Setup + function setUp() public { + // Deploys contracts + vm.startPrank(s_l1OwnerAddr); + s_mockOptimismCrossDomainMessenger = new MockOVMCrossDomainMessenger(s_l1OwnerAddr); + s_optimismCrossDomainGovernor = new OptimismCrossDomainGovernor(s_mockOptimismCrossDomainMessenger, s_l1OwnerAddr); + s_greeter = new Greeter(address(s_optimismCrossDomainGovernor)); + s_multiSend = new MultiSend(); + vm.stopPrank(); + } +} + +contract OptimismCrossDomainGovernor_Constructor is OptimismCrossDomainGovernorTest { + /// @notice it should have been deployed with the correct initial state + function test_InitialState() public { + // it should set the owner correctly + assertEq(s_optimismCrossDomainGovernor.owner(), s_l1OwnerAddr); + + // it should set the l1Owner correctly + assertEq(s_optimismCrossDomainGovernor.l1Owner(), s_l1OwnerAddr); + + // it should set the crossdomain messenger correctly + assertEq(s_optimismCrossDomainGovernor.crossDomainMessenger(), address(s_mockOptimismCrossDomainMessenger)); + + // it should set the typeAndVersion correctly + assertEq(s_optimismCrossDomainGovernor.typeAndVersion(), "OptimismCrossDomainGovernor 1.0.0"); + } +} + +contract OptimismCrossDomainGovernor_Forward is OptimismCrossDomainGovernorTest { + /// @notice it should not be callable by unknown address + function test_NotCallableByUnknownAddress() public { + vm.startPrank(s_strangerAddr); + vm.expectRevert("Sender is not the L2 messenger or owner"); + s_optimismCrossDomainGovernor.forward(address(s_greeter), abi.encode("")); + } + + /// @notice it should be callable by crossdomain messenger address / L1 owner + function test_Forward() public { + // Sets msg.sender and tx.origin + vm.startPrank(s_strangerAddr); + + // Defines the cross domain message to send + string memory greeting = "hello"; + + // Sends the message + s_mockOptimismCrossDomainMessenger.sendMessage( + address(s_optimismCrossDomainGovernor), // target + encodeCrossDomainSetGreetingMsg(s_optimismCrossDomainGovernor.forward.selector, address(s_greeter), greeting), // message + 0 // gas limit + ); + + // Checks that the greeter got the message + assertEq(s_greeter.greeting(), greeting); + } + + /// @notice it should revert when contract call reverts + function test_ForwardRevert() public { + // Sets msg.sender and tx.origin + vm.startPrank(s_strangerAddr); + + // Sends an invalid message + vm.expectRevert("Invalid greeting length"); + s_mockOptimismCrossDomainMessenger.sendMessage( + address(s_optimismCrossDomainGovernor), // target + encodeCrossDomainSetGreetingMsg(s_optimismCrossDomainGovernor.forward.selector, address(s_greeter), ""), // message + 0 // gas limit + ); + } + + /// @notice it should be callable by L2 owner + function test_CallableByL2Owner() public { + // Sets msg.sender and tx.origin + vm.startPrank(s_l1OwnerAddr); + + // Defines the cross domain message to send + string memory greeting = "hello"; + + // Sends the message + s_optimismCrossDomainGovernor.forward( + address(s_greeter), + abi.encodeWithSelector(s_greeter.setGreeting.selector, greeting) + ); + + // Checks that the greeter message was updated + assertEq(s_greeter.greeting(), greeting); + } +} + +contract OptimismCrossDomainGovernor_ForwardDelegate is OptimismCrossDomainGovernorTest { + /// @notice it should not be callable by unknown address + function test_NotCallableByUnknownAddress() public { + vm.startPrank(s_strangerAddr); + vm.expectRevert("Sender is not the L2 messenger or owner"); + s_optimismCrossDomainGovernor.forwardDelegate(address(s_greeter), abi.encode("")); + } + + /// @notice it should be callable by crossdomain messenger address / L1 owner + function test_CallableByCrossDomainMessengerAddressOrL1Owner() public { + // Sets msg.sender and tx.origin + vm.startPrank(s_strangerAddr); + + // Sends the message + s_mockOptimismCrossDomainMessenger.sendMessage( + address(s_optimismCrossDomainGovernor), // target + encodeCrossDomainMultiSendMsg( + s_optimismCrossDomainGovernor.forwardDelegate.selector, + address(s_multiSend), + abi.encodePacked(encodeMultiSendTx(address(s_greeter), "foo"), encodeMultiSendTx(address(s_greeter), "bar")) + ), // message + 0 // gas limit + ); + + // Checks that the greeter message was updated + assertEq(s_greeter.greeting(), "bar"); + } + + /// @notice it should be callable by L2 owner + function test_CallableByL2Owner() public { + // Sets msg.sender and tx.origin + vm.startPrank(s_l1OwnerAddr); + + // Sends the message + s_mockOptimismCrossDomainMessenger.sendMessage( + address(s_optimismCrossDomainGovernor), // target + encodeCrossDomainMultiSendMsg( + s_optimismCrossDomainGovernor.forwardDelegate.selector, + address(s_multiSend), + abi.encodePacked(encodeMultiSendTx(address(s_greeter), "foo"), encodeMultiSendTx(address(s_greeter), "bar")) + ), // message + 0 // gas limit + ); + + // Checks that the greeter message was updated + assertEq(s_greeter.greeting(), "bar"); + } + + /// @notice it should revert batch when one call fails + function test_RevertsBatchWhenOneCallFails() public { + // Sets msg.sender and tx.origin + vm.startPrank(s_strangerAddr); + + // Sends an invalid message (empty transaction data is not allowed) + vm.expectRevert("Governor delegatecall reverted"); + s_mockOptimismCrossDomainMessenger.sendMessage( + address(s_optimismCrossDomainGovernor), // target + encodeCrossDomainMultiSendMsg( + s_optimismCrossDomainGovernor.forwardDelegate.selector, + address(s_multiSend), + abi.encodePacked(encodeMultiSendTx(address(s_greeter), "foo"), encodeMultiSendTx(address(s_greeter), "")) + ), // message + 0 // gas limit + ); + + // Checks that the greeter message is unchanged + assertEq(s_greeter.greeting(), ""); + } + + /// @notice it should bubble up revert when contract call reverts + function test_BubbleUpRevert() public { + // Sets msg.sender and tx.origin + vm.startPrank(s_strangerAddr); + + // Sends an invalid message (empty transaction data is not allowed) + vm.expectRevert("Greeter: revert triggered"); + s_mockOptimismCrossDomainMessenger.sendMessage( + address(s_optimismCrossDomainGovernor), // target + abi.encodeWithSelector( + OptimismCrossDomainGovernor.forwardDelegate.selector, + address(s_greeter), + abi.encodeWithSelector(Greeter.triggerRevert.selector) + ), // message + 0 // gas limit + ); + } +} + +contract OptimismCrossDomainGovernor_TransferL1Ownership is OptimismCrossDomainGovernorTest { + /// @notice it should not be callable by non-owners + function test_NotCallableByNonOwners() public { + vm.startPrank(s_strangerAddr); + vm.expectRevert("Sender is not the L2 messenger"); + s_optimismCrossDomainGovernor.transferL1Ownership(s_strangerAddr); + } + + /// @notice it should not be callable by L2 owner + function test_NotCallableByL2Owner() public { + vm.startPrank(s_l1OwnerAddr); + assertEq(s_optimismCrossDomainGovernor.owner(), s_l1OwnerAddr); + vm.expectRevert("Sender is not the L2 messenger"); + s_optimismCrossDomainGovernor.transferL1Ownership(s_strangerAddr); + } + + /// @notice it should be callable by current L1 owner + function test_CallableByL1Owner() public { + // Sets msg.sender and tx.origin + vm.startPrank(s_strangerAddr); + + // Defines the cross domain message to send + vm.expectEmit(); + emit L1OwnershipTransferRequested(s_optimismCrossDomainGovernor.l1Owner(), s_strangerAddr); + + // Sends the message + s_mockOptimismCrossDomainMessenger.sendMessage( + address(s_optimismCrossDomainGovernor), // target + abi.encodeWithSelector(s_optimismCrossDomainGovernor.transferL1Ownership.selector, s_strangerAddr), // message + 0 // gas limit + ); + } + + /// @notice it should be callable by current L1 owner to zero address + function test_CallableByL1OwnerOrZeroAddress() public { + // Sets msg.sender and tx.origin + vm.startPrank(s_strangerAddr); + + // Defines the cross domain message to send + vm.expectEmit(); + emit L1OwnershipTransferRequested(s_optimismCrossDomainGovernor.l1Owner(), address(0)); + + // Sends the message + s_mockOptimismCrossDomainMessenger.sendMessage( + address(s_optimismCrossDomainGovernor), // target + abi.encodeWithSelector(s_optimismCrossDomainGovernor.transferL1Ownership.selector, address(0)), // message + 0 // gas limit + ); + } +} + +contract OptimismCrossDomainGovernor_AcceptL1Ownership is OptimismCrossDomainGovernorTest { + /// @notice it should not be callable by non pending-owners + function test_NotCallableByNonPendingOwners() public { + // Sets msg.sender and tx.origin + vm.startPrank(s_strangerAddr); + + // Sends the message + vm.expectRevert("Must be proposed L1 owner"); + s_mockOptimismCrossDomainMessenger.sendMessage( + address(s_optimismCrossDomainGovernor), // target + abi.encodeWithSelector(s_optimismCrossDomainGovernor.acceptL1Ownership.selector), // message + 0 // gas limit + ); + } + + /// @notice it should be callable by pending L1 owner + function test_CallableByPendingL1Owner() public { + // Sets msg.sender and tx.origin + vm.startPrank(s_strangerAddr); + + // Request ownership transfer + s_mockOptimismCrossDomainMessenger.sendMessage( + address(s_optimismCrossDomainGovernor), // target + abi.encodeWithSelector(s_optimismCrossDomainGovernor.transferL1Ownership.selector, s_strangerAddr), // message + 0 // gas limit + ); + + // Sets a mock message sender + s_mockOptimismCrossDomainMessenger._setMockMessageSender(s_strangerAddr); + + // Prepares expected event payload + vm.expectEmit(); + emit L1OwnershipTransferred(s_l1OwnerAddr, s_strangerAddr); + + // Accepts ownership transfer request + s_mockOptimismCrossDomainMessenger.sendMessage( + address(s_optimismCrossDomainGovernor), // target + abi.encodeWithSelector(s_optimismCrossDomainGovernor.acceptL1Ownership.selector, s_strangerAddr), // message + 0 // gas limit + ); + + // Asserts that the ownership was actually transferred + assertEq(s_optimismCrossDomainGovernor.l1Owner(), s_strangerAddr); + } +} diff --git a/contracts/src/v0.8/l2ep/test/v1_0_0/optimism/OptimismSequencerUptimeFeed.t.sol b/contracts/src/v0.8/l2ep/test/v1_0_0/optimism/OptimismSequencerUptimeFeed.t.sol new file mode 100644 index 0000000000..60598b9f95 --- /dev/null +++ b/contracts/src/v0.8/l2ep/test/v1_0_0/optimism/OptimismSequencerUptimeFeed.t.sol @@ -0,0 +1,524 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.19; + +import {MockOptimismL1CrossDomainMessenger} from "../../../../tests/MockOptimismL1CrossDomainMessenger.sol"; +import {MockOptimismL2CrossDomainMessenger} from "../../../../tests/MockOptimismL2CrossDomainMessenger.sol"; +import {OptimismSequencerUptimeFeed} from "../../../dev/optimism/OptimismSequencerUptimeFeed.sol"; +import {FeedConsumer} from "../../../../tests/FeedConsumer.sol"; +import {L2EPTest} from "../L2EPTest.t.sol"; + +contract OptimismSequencerUptimeFeedTest is L2EPTest { + /// Constants + uint256 internal constant GAS_USED_DEVIATION = 100; + + /// L2EP contracts + MockOptimismL1CrossDomainMessenger internal s_mockOptimismL1CrossDomainMessenger; + MockOptimismL2CrossDomainMessenger internal s_mockOptimismL2CrossDomainMessenger; + OptimismSequencerUptimeFeed internal s_optimismSequencerUptimeFeed; + + /// Events + event UpdateIgnored(bool latestStatus, uint64 latestTimestamp, bool incomingStatus, uint64 incomingTimestamp); + event AnswerUpdated(int256 indexed current, uint256 indexed roundId, uint256 updatedAt); + event RoundUpdated(int256 status, uint64 updatedAt); + + /// Setup + function setUp() public { + // Deploys contracts + s_mockOptimismL1CrossDomainMessenger = new MockOptimismL1CrossDomainMessenger(); + s_mockOptimismL2CrossDomainMessenger = new MockOptimismL2CrossDomainMessenger(); + s_optimismSequencerUptimeFeed = new OptimismSequencerUptimeFeed( + s_l1OwnerAddr, + address(s_mockOptimismL2CrossDomainMessenger), + false + ); + + // Sets mock sender in mock L2 messenger contract + s_mockOptimismL2CrossDomainMessenger.setSender(s_l1OwnerAddr); + } +} + +contract OptimismSequencerUptimeFeed_Constructor is OptimismSequencerUptimeFeedTest { + /// @notice it should have been deployed with the correct initial state + function test_InitialState() public { + // Sets msg.sender and tx.origin to a valid address + vm.startPrank(s_l1OwnerAddr, s_l1OwnerAddr); + + // Checks L1 sender + address actualL1Addr = s_optimismSequencerUptimeFeed.l1Sender(); + assertEq(actualL1Addr, s_l1OwnerAddr); + + // Checks latest round data + (uint80 roundId, int256 answer, , , ) = s_optimismSequencerUptimeFeed.latestRoundData(); + assertEq(roundId, 1); + assertEq(answer, 0); + } +} + +contract OptimismSequencerUptimeFeed_UpdateStatus is OptimismSequencerUptimeFeedTest { + /// @notice it should revert if called by an address that is not the L2 Cross Domain Messenger + function test_RevertIfNotL2CrossDomainMessengerAddr() public { + // Sets msg.sender and tx.origin to an unauthorized address + vm.startPrank(s_strangerAddr, s_strangerAddr); + + // Tries to update the status from an unauthorized account + vm.expectRevert(OptimismSequencerUptimeFeed.InvalidSender.selector); + s_optimismSequencerUptimeFeed.updateStatus(true, uint64(1)); + } + + /// @notice it should revert if called by an address that is not the L2 Cross Domain Messenger and is not the L1 sender + function test_RevertIfNotL2CrossDomainMessengerAddrAndNotL1SenderAddr() public { + // Sets msg.sender and tx.origin to an unauthorized address + vm.startPrank(s_strangerAddr, s_strangerAddr); + + // Sets mock sender in mock L2 messenger contract + s_mockOptimismL2CrossDomainMessenger.setSender(s_strangerAddr); + + // Tries to update the status from an unauthorized account + vm.expectRevert(OptimismSequencerUptimeFeed.InvalidSender.selector); + s_optimismSequencerUptimeFeed.updateStatus(true, uint64(1)); + } + + /// @notice it should update status when status has not changed and incoming timestamp is the same as latest + function test_UpdateStatusWhenNoChange() public { + // Sets msg.sender and tx.origin to a valid address + address l2MessengerAddr = address(s_mockOptimismL2CrossDomainMessenger); + vm.startPrank(l2MessengerAddr, l2MessengerAddr); + + // Fetches the latest timestamp + uint256 timestamp = s_optimismSequencerUptimeFeed.latestTimestamp(); + + // Submits a status update + vm.expectEmit(); + emit AnswerUpdated(1, 2, timestamp); + s_optimismSequencerUptimeFeed.updateStatus(true, uint64(timestamp)); + assertEq(s_optimismSequencerUptimeFeed.latestAnswer(), 1); + assertEq(s_optimismSequencerUptimeFeed.latestTimestamp(), uint64(timestamp)); + + // Stores the current round data before updating it + ( + uint80 roundIdBeforeUpdate, + int256 answerBeforeUpdate, + uint256 startedAtBeforeUpdate, + , + uint80 answeredInRoundBeforeUpdate + ) = s_optimismSequencerUptimeFeed.latestRoundData(); + + // Submit another status update with the same status + vm.expectEmit(); + emit RoundUpdated(1, uint64(block.timestamp)); + s_optimismSequencerUptimeFeed.updateStatus(true, uint64(timestamp + 200)); + assertEq(s_optimismSequencerUptimeFeed.latestAnswer(), 1); + assertEq(s_optimismSequencerUptimeFeed.latestTimestamp(), uint64(timestamp)); + + // Stores the current round data after updating it + ( + uint80 roundIdAfterUpdate, + int256 answerAfterUpdate, + uint256 startedAtAfterUpdate, + uint256 updatedAtAfterUpdate, + uint80 answeredInRoundAfterUpdate + ) = s_optimismSequencerUptimeFeed.latestRoundData(); + + // Verifies the latest round data has been properly updated + assertEq(roundIdAfterUpdate, roundIdBeforeUpdate); + assertEq(answerAfterUpdate, answerBeforeUpdate); + assertEq(startedAtAfterUpdate, startedAtBeforeUpdate); + assertEq(answeredInRoundAfterUpdate, answeredInRoundBeforeUpdate); + assertEq(updatedAtAfterUpdate, block.timestamp); + } + + /// @notice it should update status when status has changed and incoming timestamp is newer than the latest + function test_UpdateStatusWhenStatusChangeAndTimeChange() public { + // Sets msg.sender and tx.origin to a valid address + address l2MessengerAddr = address(s_mockOptimismL2CrossDomainMessenger); + vm.startPrank(l2MessengerAddr, l2MessengerAddr); + + // Submits a status update + uint256 timestamp = s_optimismSequencerUptimeFeed.latestTimestamp(); + vm.expectEmit(); + emit AnswerUpdated(1, 2, timestamp); + s_optimismSequencerUptimeFeed.updateStatus(true, uint64(timestamp)); + assertEq(s_optimismSequencerUptimeFeed.latestAnswer(), 1); + assertEq(s_optimismSequencerUptimeFeed.latestTimestamp(), uint64(timestamp)); + + // Submit another status update, different status, newer timestamp should update + timestamp = timestamp + 200; + vm.expectEmit(); + emit AnswerUpdated(0, 3, timestamp); + s_optimismSequencerUptimeFeed.updateStatus(false, uint64(timestamp)); + assertEq(s_optimismSequencerUptimeFeed.latestAnswer(), 0); + assertEq(s_optimismSequencerUptimeFeed.latestTimestamp(), uint64(timestamp)); + } + + /// @notice it should update status when status has changed and incoming timestamp is the same as latest + function test_UpdateStatusWhenStatusChangeAndNoTimeChange() public { + // Sets msg.sender and tx.origin to a valid address + address l2MessengerAddr = address(s_mockOptimismL2CrossDomainMessenger); + vm.startPrank(l2MessengerAddr, l2MessengerAddr); + + // Fetches the latest timestamp + uint256 timestamp = s_optimismSequencerUptimeFeed.latestTimestamp(); + + // Submits a status update + vm.expectEmit(); + emit AnswerUpdated(1, 2, timestamp); + s_optimismSequencerUptimeFeed.updateStatus(true, uint64(timestamp)); + assertEq(s_optimismSequencerUptimeFeed.latestAnswer(), 1); + assertEq(s_optimismSequencerUptimeFeed.latestTimestamp(), uint64(timestamp)); + + // Submit another status update, different status, same timestamp should update + vm.expectEmit(); + emit AnswerUpdated(0, 3, timestamp); + s_optimismSequencerUptimeFeed.updateStatus(false, uint64(timestamp)); + assertEq(s_optimismSequencerUptimeFeed.latestAnswer(), 0); + assertEq(s_optimismSequencerUptimeFeed.latestTimestamp(), uint64(timestamp)); + } + + /// @notice it should ignore out-of-order updates + function test_IgnoreOutOfOrderUpdates() public { + // Sets msg.sender and tx.origin to a valid address + address l2MessengerAddr = address(s_mockOptimismL2CrossDomainMessenger); + vm.startPrank(l2MessengerAddr, l2MessengerAddr); + + // Submits a status update + uint256 timestamp = s_optimismSequencerUptimeFeed.latestTimestamp() + 10000; + vm.expectEmit(); + emit AnswerUpdated(1, 2, timestamp); + s_optimismSequencerUptimeFeed.updateStatus(true, uint64(timestamp)); + assertEq(s_optimismSequencerUptimeFeed.latestAnswer(), 1); + assertEq(s_optimismSequencerUptimeFeed.latestTimestamp(), uint64(timestamp)); + + // Update with different status, but stale timestamp, should be ignored + timestamp = timestamp - 1000; + vm.expectEmit(false, false, false, false); + emit UpdateIgnored(true, 0, true, 0); // arguments are dummy values + // TODO: how can we check that an AnswerUpdated event was NOT emitted + s_optimismSequencerUptimeFeed.updateStatus(false, uint64(timestamp)); + } +} + +contract OptimismSequencerUptimeFeed_AggregatorV3Interface is OptimismSequencerUptimeFeedTest { + /// @notice it should return valid answer from getRoundData and latestRoundData + function test_AggregatorV3Interface() public { + // Sets msg.sender and tx.origin to a valid address + address l2MessengerAddr = address(s_mockOptimismL2CrossDomainMessenger); + vm.startPrank(l2MessengerAddr, l2MessengerAddr); + + // Defines helper variables + uint80 roundId; + int256 answer; + uint256 startedAt; + uint256 updatedAt; + uint80 answeredInRound; + + // Checks initial state + (roundId, answer, startedAt, updatedAt, answeredInRound) = s_optimismSequencerUptimeFeed.latestRoundData(); + assertEq(roundId, 1); + assertEq(answer, 0); + assertEq(answeredInRound, roundId); + assertEq(startedAt, updatedAt); + + // Submits status update with different status and newer timestamp, should update + uint256 timestamp = startedAt + 1000; + s_optimismSequencerUptimeFeed.updateStatus(true, uint64(timestamp)); + (roundId, answer, startedAt, updatedAt, answeredInRound) = s_optimismSequencerUptimeFeed.getRoundData(2); + assertEq(roundId, 2); + assertEq(answer, 1); + assertEq(answeredInRound, roundId); + assertEq(startedAt, timestamp); + assertLe(updatedAt, startedAt); + + // Saves round 2 data + uint80 roundId2 = roundId; + int256 answer2 = answer; + uint256 startedAt2 = startedAt; + uint256 updatedAt2 = updatedAt; + uint80 answeredInRound2 = answeredInRound; + + // Checks that last round is still returning the correct data + (roundId, answer, startedAt, updatedAt, answeredInRound) = s_optimismSequencerUptimeFeed.getRoundData(1); + assertEq(roundId, 1); + assertEq(answer, 0); + assertEq(answeredInRound, roundId); + assertEq(startedAt, updatedAt); + + // Assert latestRoundData corresponds to latest round id + (roundId, answer, startedAt, updatedAt, answeredInRound) = s_optimismSequencerUptimeFeed.latestRoundData(); + assertEq(roundId2, roundId); + assertEq(answer2, answer); + assertEq(startedAt2, startedAt); + assertEq(updatedAt2, updatedAt); + assertEq(answeredInRound2, answeredInRound); + } + + /// @notice it should revert from #getRoundData when round does not yet exist (future roundId) + function test_RevertGetRoundDataWhenRoundDoesNotExistYet() public { + // Sets msg.sender and tx.origin to a valid address + vm.startPrank(s_l1OwnerAddr, s_l1OwnerAddr); + + // Gets data from a round that has not happened yet + vm.expectRevert(OptimismSequencerUptimeFeed.NoDataPresent.selector); + s_optimismSequencerUptimeFeed.getRoundData(2); + } + + /// @notice it should revert from #getAnswer when round does not yet exist (future roundId) + function test_RevertGetAnswerWhenRoundDoesNotExistYet() public { + // Sets msg.sender and tx.origin to a valid address + vm.startPrank(s_l1OwnerAddr, s_l1OwnerAddr); + + // Gets data from a round that has not happened yet + vm.expectRevert(OptimismSequencerUptimeFeed.NoDataPresent.selector); + s_optimismSequencerUptimeFeed.getAnswer(2); + } + + /// @notice it should revert from #getTimestamp when round does not yet exist (future roundId) + function test_RevertGetTimestampWhenRoundDoesNotExistYet() public { + // Sets msg.sender and tx.origin to a valid address + vm.startPrank(s_l1OwnerAddr, s_l1OwnerAddr); + + // Gets data from a round that has not happened yet + vm.expectRevert(OptimismSequencerUptimeFeed.NoDataPresent.selector); + s_optimismSequencerUptimeFeed.getTimestamp(2); + } +} + +contract OptimismSequencerUptimeFeed_ProtectReadsOnAggregatorV2V3InterfaceFunctions is OptimismSequencerUptimeFeedTest { + /// @notice it should disallow reads on AggregatorV2V3Interface functions when consuming contract is not whitelisted + function test_AggregatorV2V3InterfaceDisallowReadsIfConsumingContractIsNotWhitelisted() public { + // Deploys a FeedConsumer contract + FeedConsumer feedConsumer = new FeedConsumer(address(s_optimismSequencerUptimeFeed)); + + // Sanity - consumer is not whitelisted + assertEq(s_optimismSequencerUptimeFeed.checkEnabled(), true); + assertEq(s_optimismSequencerUptimeFeed.hasAccess(address(feedConsumer), abi.encode("")), false); + + // Asserts reads are not possible from consuming contract + vm.expectRevert("No access"); + feedConsumer.latestAnswer(); + vm.expectRevert("No access"); + feedConsumer.latestRoundData(); + } + + /// @notice it should allow reads on AggregatorV2V3Interface functions when consuming contract is whitelisted + function test_AggregatorV2V3InterfaceAllowReadsIfConsumingContractIsWhitelisted() public { + // Deploys a FeedConsumer contract + FeedConsumer feedConsumer = new FeedConsumer(address(s_optimismSequencerUptimeFeed)); + + // Whitelist consumer + s_optimismSequencerUptimeFeed.addAccess(address(feedConsumer)); + + // Sanity - consumer is whitelisted + assertEq(s_optimismSequencerUptimeFeed.checkEnabled(), true); + assertEq(s_optimismSequencerUptimeFeed.hasAccess(address(feedConsumer), abi.encode("")), true); + + // Asserts reads are possible from consuming contract + (uint80 roundId, int256 answer, , , ) = feedConsumer.latestRoundData(); + assertEq(feedConsumer.latestAnswer(), 0); + assertEq(roundId, 1); + assertEq(answer, 0); + } +} + +contract OptimismSequencerUptimeFeed_GasCosts is OptimismSequencerUptimeFeedTest { + /// @notice it should consume a known amount of gas for updates + function test_GasCosts() public { + // Sets msg.sender and tx.origin to a valid address + address l2MessengerAddr = address(s_mockOptimismL2CrossDomainMessenger); + vm.startPrank(l2MessengerAddr, l2MessengerAddr); + + // Assert initial conditions + uint256 timestamp = s_optimismSequencerUptimeFeed.latestTimestamp(); + assertEq(s_optimismSequencerUptimeFeed.latestAnswer(), 0); + + // Defines helper variables for measuring gas usage + uint256 expectedGasUsed; + uint256 gasStart; + uint256 gasFinal; + + // measures gas used for no update + expectedGasUsed = 10197; // NOTE: used to be 38594 in hardhat tests + gasStart = gasleft(); + s_optimismSequencerUptimeFeed.updateStatus(false, uint64(timestamp + 1000)); + gasFinal = gasleft(); + assertEq(s_optimismSequencerUptimeFeed.latestAnswer(), 0); + assertGasUsageIsCloseTo(expectedGasUsed, gasStart, gasFinal, GAS_USED_DEVIATION); + + // measures gas used for update + expectedGasUsed = 33348; // NOTE: used to be 60170 in hardhat tests + gasStart = gasleft(); + s_optimismSequencerUptimeFeed.updateStatus(true, uint64(timestamp + 1000)); + gasFinal = gasleft(); + assertEq(s_optimismSequencerUptimeFeed.latestAnswer(), 1); + assertGasUsageIsCloseTo(expectedGasUsed, gasStart, gasFinal, GAS_USED_DEVIATION); + } +} + +contract OptimismSequencerUptimeFeed_AggregatorInterfaceGasCosts is OptimismSequencerUptimeFeedTest { + /// @notice it should consume a known amount of gas for getRoundData(uint80) + function test_GasUsageForGetRoundData() public { + // Sets msg.sender and tx.origin to a valid address + address l2MessengerAddr = address(s_mockOptimismL2CrossDomainMessenger); + vm.startPrank(l2MessengerAddr, l2MessengerAddr); + + // Defines helper variables for measuring gas usage + uint256 expectedGasUsed = 4504; // NOTE: used to be 30952 in hardhat tests + uint256 gasStart; + uint256 gasFinal; + + // Initializes a round + uint256 timestamp = s_optimismSequencerUptimeFeed.latestTimestamp() + 1000; + s_optimismSequencerUptimeFeed.updateStatus(true, uint64(timestamp)); + + // Measures gas usage + gasStart = gasleft(); + s_optimismSequencerUptimeFeed.getRoundData(1); + gasFinal = gasleft(); + + // Checks that gas usage is within expected range + assertGasUsageIsCloseTo(expectedGasUsed, gasStart, gasFinal, GAS_USED_DEVIATION); + } + + /// @notice it should consume a known amount of gas for latestRoundData() + function test_GasUsageForLatestRoundData() public { + // Sets msg.sender and tx.origin to a valid address + address l2MessengerAddr = address(s_mockOptimismL2CrossDomainMessenger); + vm.startPrank(l2MessengerAddr, l2MessengerAddr); + + // Defines helper variables for measuring gas usage + uint256 expectedGasUsed = 2154; // NOTE: used to be 28523 in hardhat tests + uint256 gasStart; + uint256 gasFinal; + + // Initializes a round + uint256 timestamp = s_optimismSequencerUptimeFeed.latestTimestamp() + 1000; + s_optimismSequencerUptimeFeed.updateStatus(true, uint64(timestamp)); + + // Measures gas usage + gasStart = gasleft(); + s_optimismSequencerUptimeFeed.latestRoundData(); + gasFinal = gasleft(); + + // Checks that gas usage is within expected range + assertGasUsageIsCloseTo(expectedGasUsed, gasStart, gasFinal, GAS_USED_DEVIATION); + } + + /// @notice it should consume a known amount of gas for latestAnswer() + function test_GasUsageForLatestAnswer() public { + // Sets msg.sender and tx.origin to a valid address + address l2MessengerAddr = address(s_mockOptimismL2CrossDomainMessenger); + vm.startPrank(l2MessengerAddr, l2MessengerAddr); + + // Defines helper variables for measuring gas usage + uint256 expectedGasUsed = 1722; // NOTE: used to be 28329 in hardhat tests + uint256 gasStart; + uint256 gasFinal; + + // Initializes a round + uint256 timestamp = s_optimismSequencerUptimeFeed.latestTimestamp() + 1000; + s_optimismSequencerUptimeFeed.updateStatus(true, uint64(timestamp)); + + // Measures gas usage + gasStart = gasleft(); + s_optimismSequencerUptimeFeed.latestAnswer(); + gasFinal = gasleft(); + + // Checks that gas usage is within expected range + assertGasUsageIsCloseTo(expectedGasUsed, gasStart, gasFinal, GAS_USED_DEVIATION); + } + + /// @notice it should consume a known amount of gas for latestTimestamp() + function test_GasUsageForLatestTimestamp() public { + // Sets msg.sender and tx.origin to a valid address + address l2MessengerAddr = address(s_mockOptimismL2CrossDomainMessenger); + vm.startPrank(l2MessengerAddr, l2MessengerAddr); + + // Defines helper variables for measuring gas usage + uint256 expectedGasUsed = 1598; // NOTE: used to be 28229 in hardhat tests + uint256 gasStart; + uint256 gasFinal; + + // Initializes a round + uint256 timestamp = s_optimismSequencerUptimeFeed.latestTimestamp() + 1000; + s_optimismSequencerUptimeFeed.updateStatus(true, uint64(timestamp)); + + // Measures gas usage + gasStart = gasleft(); + s_optimismSequencerUptimeFeed.latestTimestamp(); + gasFinal = gasleft(); + + // Checks that gas usage is within expected range + assertGasUsageIsCloseTo(expectedGasUsed, gasStart, gasFinal, GAS_USED_DEVIATION); + } + + /// @notice it should consume a known amount of gas for latestRound() + function test_GasUsageForLatestRound() public { + // Sets msg.sender and tx.origin to a valid address + address l2MessengerAddr = address(s_mockOptimismL2CrossDomainMessenger); + vm.startPrank(l2MessengerAddr, l2MessengerAddr); + + // Defines helper variables for measuring gas usage + uint256 expectedGasUsed = 1632; // NOTE: used to be 28245 in hardhat tests + uint256 gasStart; + uint256 gasFinal; + + // Initializes a round + uint256 timestamp = s_optimismSequencerUptimeFeed.latestTimestamp() + 1000; + s_optimismSequencerUptimeFeed.updateStatus(true, uint64(timestamp)); + + // Measures gas usage + gasStart = gasleft(); + s_optimismSequencerUptimeFeed.latestRound(); + gasFinal = gasleft(); + + // Checks that gas usage is within expected range + assertGasUsageIsCloseTo(expectedGasUsed, gasStart, gasFinal, GAS_USED_DEVIATION); + } + + /// @notice it should consume a known amount of gas for getAnswer() + function test_GasUsageForGetAnswer() public { + // Sets msg.sender and tx.origin to a valid address + address l2MessengerAddr = address(s_mockOptimismL2CrossDomainMessenger); + vm.startPrank(l2MessengerAddr, l2MessengerAddr); + + // Defines helper variables for measuring gas usage + uint256 expectedGasUsed = 3929; // NOTE: used to be 30682 in hardhat tests + uint256 gasStart; + uint256 gasFinal; + + // Initializes a round + uint256 timestamp = s_optimismSequencerUptimeFeed.latestTimestamp() + 1000; + s_optimismSequencerUptimeFeed.updateStatus(true, uint64(timestamp)); + + // Measures gas usage + gasStart = gasleft(); + s_optimismSequencerUptimeFeed.getAnswer(1); + gasFinal = gasleft(); + + // Checks that gas usage is within expected range + assertGasUsageIsCloseTo(expectedGasUsed, gasStart, gasFinal, GAS_USED_DEVIATION); + } + + /// @notice it should consume a known amount of gas for getTimestamp() + function test_GasUsageForGetTimestamp() public { + // Sets msg.sender and tx.origin to a valid address + address l2MessengerAddr = address(s_mockOptimismL2CrossDomainMessenger); + vm.startPrank(l2MessengerAddr, l2MessengerAddr); + + // Defines helper variables for measuring gas usage + uint256 expectedGasUsed = 3817; // NOTE: used to be 30570 in hardhat tests + uint256 gasStart; + uint256 gasFinal; + + // Initializes a round + uint256 timestamp = s_optimismSequencerUptimeFeed.latestTimestamp() + 1000; + s_optimismSequencerUptimeFeed.updateStatus(true, uint64(timestamp)); + + // Measures gas usage + gasStart = gasleft(); + s_optimismSequencerUptimeFeed.getTimestamp(1); + gasFinal = gasleft(); + + // Checks that gas usage is within expected range + assertGasUsageIsCloseTo(expectedGasUsed, gasStart, gasFinal, GAS_USED_DEVIATION); + } +} diff --git a/contracts/src/v0.8/l2ep/test/v1_0_0/optimism/OptimismValidator.t.sol b/contracts/src/v0.8/l2ep/test/v1_0_0/optimism/OptimismValidator.t.sol new file mode 100644 index 0000000000..9364396817 --- /dev/null +++ b/contracts/src/v0.8/l2ep/test/v1_0_0/optimism/OptimismValidator.t.sol @@ -0,0 +1,108 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.19; + +import {MockOptimismL1CrossDomainMessenger} from "../../../../tests/MockOptimismL1CrossDomainMessenger.sol"; +import {MockOptimismL2CrossDomainMessenger} from "../../../../tests/MockOptimismL2CrossDomainMessenger.sol"; +import {OptimismSequencerUptimeFeed} from "../../../dev/optimism/OptimismSequencerUptimeFeed.sol"; +import {OptimismValidator} from "../../../dev/optimism/OptimismValidator.sol"; +import {L2EPTest} from "../L2EPTest.t.sol"; + +contract OptimismValidatorTest is L2EPTest { + /// Helper constants + address internal constant L2_SEQ_STATUS_RECORDER_ADDRESS = 0x491B1dDA0A8fa069bbC1125133A975BF4e85a91b; + uint32 internal constant INIT_GAS_LIMIT = 1900000; + + /// L2EP contracts + MockOptimismL1CrossDomainMessenger internal s_mockOptimismL1CrossDomainMessenger; + MockOptimismL2CrossDomainMessenger internal s_mockOptimismL2CrossDomainMessenger; + OptimismSequencerUptimeFeed internal s_optimismSequencerUptimeFeed; + OptimismValidator internal s_optimismValidator; + + /// Events + event SentMessage(address indexed target, address sender, bytes message, uint256 messageNonce, uint256 gasLimit); + + /// Setup + function setUp() public { + s_mockOptimismL1CrossDomainMessenger = new MockOptimismL1CrossDomainMessenger(); + s_mockOptimismL2CrossDomainMessenger = new MockOptimismL2CrossDomainMessenger(); + + s_optimismSequencerUptimeFeed = new OptimismSequencerUptimeFeed( + address(s_mockOptimismL1CrossDomainMessenger), + address(s_mockOptimismL2CrossDomainMessenger), + true + ); + + s_optimismValidator = new OptimismValidator( + address(s_mockOptimismL1CrossDomainMessenger), + address(s_optimismSequencerUptimeFeed), + INIT_GAS_LIMIT + ); + } +} + +contract OptimismValidator_SetGasLimit is OptimismValidatorTest { + /// @notice it correctly updates the gas limit + function test_CorrectlyUpdatesTheGasLimit() public { + uint32 newGasLimit = 2000000; + assertEq(s_optimismValidator.getGasLimit(), INIT_GAS_LIMIT); + s_optimismValidator.setGasLimit(newGasLimit); + assertEq(s_optimismValidator.getGasLimit(), newGasLimit); + } +} + +contract OptimismValidator_Validate is OptimismValidatorTest { + /// @notice it reverts if called by account with no access + function test_RevertsIfCalledByAnAccountWithNoAccess() public { + vm.startPrank(s_strangerAddr); + vm.expectRevert("No access"); + s_optimismValidator.validate(0, 0, 1, 1); + } + + /// @notice it posts sequencer status when there is not status change + function test_PostSequencerStatusWhenThereIsNotStatusChange() public { + // Gives access to the s_eoaValidator + s_optimismValidator.addAccess(s_eoaValidator); + + // Sets block.timestamp to a later date + uint256 futureTimestampInSeconds = block.timestamp + 5000; + vm.startPrank(s_eoaValidator); + vm.warp(futureTimestampInSeconds); + + // Sets up the expected event data + vm.expectEmit(false, false, false, true); + emit SentMessage( + L2_SEQ_STATUS_RECORDER_ADDRESS, // target + address(s_optimismValidator), // sender + abi.encodeWithSelector(OptimismSequencerUptimeFeed.updateStatus.selector, false, futureTimestampInSeconds), // message + 0, // nonce + INIT_GAS_LIMIT // gas limit + ); + + // Runs the function (which produces the event to test) + s_optimismValidator.validate(0, 0, 0, 0); + } + + /// @notice it post sequencer offline + function test_PostSequencerOffline() public { + // Gives access to the s_eoaValidator + s_optimismValidator.addAccess(s_eoaValidator); + + // Sets block.timestamp to a later date + uint256 futureTimestampInSeconds = block.timestamp + 10000; + vm.startPrank(s_eoaValidator); + vm.warp(futureTimestampInSeconds); + + // Sets up the expected event data + vm.expectEmit(false, false, false, true); + emit SentMessage( + L2_SEQ_STATUS_RECORDER_ADDRESS, // target + address(s_optimismValidator), // sender + abi.encodeWithSelector(OptimismSequencerUptimeFeed.updateStatus.selector, true, futureTimestampInSeconds), // message + 0, // nonce + INIT_GAS_LIMIT // gas limit + ); + + // Runs the function (which produces the event to test) + s_optimismValidator.validate(0, 0, 1, 1); + } +} diff --git a/contracts/src/v0.8/l2ep/test/v1_0_0/scroll/ScrollCrossDomainForwarder.t.sol b/contracts/src/v0.8/l2ep/test/v1_0_0/scroll/ScrollCrossDomainForwarder.t.sol new file mode 100644 index 0000000000..f921fa9242 --- /dev/null +++ b/contracts/src/v0.8/l2ep/test/v1_0_0/scroll/ScrollCrossDomainForwarder.t.sol @@ -0,0 +1,191 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.19; + +import {MockScrollCrossDomainMessenger} from "../../mocks/scroll/MockScrollCrossDomainMessenger.sol"; +import {ScrollCrossDomainForwarder} from "../../../dev/scroll/ScrollCrossDomainForwarder.sol"; +import {Greeter} from "../../../../tests/Greeter.sol"; +import {L2EPTest} from "../L2EPTest.t.sol"; + +contract ScrollCrossDomainForwarderTest is L2EPTest { + /// Contracts + MockScrollCrossDomainMessenger internal s_mockScrollCrossDomainMessenger; + ScrollCrossDomainForwarder internal s_scrollCrossDomainForwarder; + Greeter internal s_greeter; + + /// Events + event L1OwnershipTransferRequested(address indexed from, address indexed to); + event L1OwnershipTransferred(address indexed from, address indexed to); + + /// Setup + function setUp() public { + // Deploys contracts + vm.startPrank(s_l1OwnerAddr); + s_mockScrollCrossDomainMessenger = new MockScrollCrossDomainMessenger(s_l1OwnerAddr); + s_scrollCrossDomainForwarder = new ScrollCrossDomainForwarder(s_mockScrollCrossDomainMessenger, s_l1OwnerAddr); + s_greeter = new Greeter(address(s_scrollCrossDomainForwarder)); + vm.stopPrank(); + } +} + +contract ScrollCrossDomainForwarder_Constructor is ScrollCrossDomainForwarderTest { + /// @notice it should have been deployed with the correct initial state + function test_InitialState() public { + // it should set the owner correctly + assertEq(s_scrollCrossDomainForwarder.owner(), s_l1OwnerAddr); + + // it should set the l1Owner correctly + assertEq(s_scrollCrossDomainForwarder.l1Owner(), s_l1OwnerAddr); + + // it should set the crossdomain messenger correctly + assertEq(s_scrollCrossDomainForwarder.crossDomainMessenger(), address(s_mockScrollCrossDomainMessenger)); + + // it should set the typeAndVersion correctly + assertEq(s_scrollCrossDomainForwarder.typeAndVersion(), "ScrollCrossDomainForwarder 1.0.0"); + } +} + +contract ScrollCrossDomainForwarder_Forward is ScrollCrossDomainForwarderTest { + /// @notice it should not be callable by unknown address + function test_NotCallableByUnknownAddress() public { + vm.startPrank(s_strangerAddr); + vm.expectRevert("Sender is not the L2 messenger"); + s_scrollCrossDomainForwarder.forward(address(s_greeter), abi.encode("")); + } + + /// @notice it should be callable by crossdomain messenger address / L1 owner + function test_Forward() public { + // Sets msg.sender and tx.origin + vm.startPrank(s_strangerAddr); + + // Defines the cross domain message to send + string memory greeting = "hello"; + + // Sends the message + s_mockScrollCrossDomainMessenger.sendMessage( + address(s_scrollCrossDomainForwarder), // target + 0, // value + encodeCrossDomainSetGreetingMsg(s_scrollCrossDomainForwarder.forward.selector, address(s_greeter), greeting), // message + 0 // gas limit + ); + + // Checks that the greeter got the message + assertEq(s_greeter.greeting(), greeting); + } + + /// @notice it should revert when contract call reverts + function test_ForwardRevert() public { + // Sets msg.sender and tx.origin + vm.startPrank(s_strangerAddr); + + // Sends an invalid message + vm.expectRevert("Invalid greeting length"); + s_mockScrollCrossDomainMessenger.sendMessage( + address(s_scrollCrossDomainForwarder), // target + 0, // value + encodeCrossDomainSetGreetingMsg(s_scrollCrossDomainForwarder.forward.selector, address(s_greeter), ""), // message + 0 // gas limit + ); + } +} + +contract ScrollCrossDomainForwarder_TransferL1Ownership is ScrollCrossDomainForwarderTest { + /// @notice it should not be callable by non-owners + function test_NotCallableByNonOwners() public { + vm.startPrank(s_strangerAddr); + vm.expectRevert("Sender is not the L2 messenger"); + s_scrollCrossDomainForwarder.transferL1Ownership(s_strangerAddr); + } + + /// @notice it should not be callable by L2 owner + function test_NotCallableByL2Owner() public { + vm.startPrank(s_l1OwnerAddr); + assertEq(s_scrollCrossDomainForwarder.owner(), s_l1OwnerAddr); + vm.expectRevert("Sender is not the L2 messenger"); + s_scrollCrossDomainForwarder.transferL1Ownership(s_strangerAddr); + } + + /// @notice it should be callable by current L1 owner + function test_CallableByL1Owner() public { + // Sets msg.sender and tx.origin + vm.startPrank(s_strangerAddr); + + // Defines the cross domain message to send + vm.expectEmit(); + emit L1OwnershipTransferRequested(s_scrollCrossDomainForwarder.l1Owner(), s_strangerAddr); + + // Sends the message + s_mockScrollCrossDomainMessenger.sendMessage( + address(s_scrollCrossDomainForwarder), // target + 0, // value + abi.encodeWithSelector(s_scrollCrossDomainForwarder.transferL1Ownership.selector, s_strangerAddr), // message + 0 // gas limit + ); + } + + /// @notice it should be callable by current L1 owner to zero address + function test_CallableByL1OwnerOrZeroAddress() public { + // Sets msg.sender and tx.origin + vm.startPrank(s_strangerAddr); + + // Defines the cross domain message to send + vm.expectEmit(); + emit L1OwnershipTransferRequested(s_scrollCrossDomainForwarder.l1Owner(), address(0)); + + // Sends the message + s_mockScrollCrossDomainMessenger.sendMessage( + address(s_scrollCrossDomainForwarder), // target + 0, // value + abi.encodeWithSelector(s_scrollCrossDomainForwarder.transferL1Ownership.selector, address(0)), // message + 0 // gas limit + ); + } +} + +contract ScrollCrossDomainForwarder_AcceptL1Ownership is ScrollCrossDomainForwarderTest { + /// @notice it should not be callable by non pending-owners + function test_NotCallableByNonPendingOwners() public { + // Sets msg.sender and tx.origin + vm.startPrank(s_strangerAddr); + + // Sends the message + vm.expectRevert("Must be proposed L1 owner"); + s_mockScrollCrossDomainMessenger.sendMessage( + address(s_scrollCrossDomainForwarder), // target + 0, // value + abi.encodeWithSelector(s_scrollCrossDomainForwarder.acceptL1Ownership.selector), // message + 0 // gas limit + ); + } + + /// @notice it should be callable by pending L1 owner + function test_CallableByPendingL1Owner() public { + // Sets msg.sender and tx.origin + vm.startPrank(s_strangerAddr); + + // Request ownership transfer + s_mockScrollCrossDomainMessenger.sendMessage( + address(s_scrollCrossDomainForwarder), // target + 0, // value + abi.encodeWithSelector(s_scrollCrossDomainForwarder.transferL1Ownership.selector, s_strangerAddr), // message + 0 // gas limit + ); + + // Sets a mock message sender + s_mockScrollCrossDomainMessenger._setMockMessageSender(s_strangerAddr); + + // Prepares expected event payload + vm.expectEmit(); + emit L1OwnershipTransferred(s_l1OwnerAddr, s_strangerAddr); + + // Accepts ownership transfer request + s_mockScrollCrossDomainMessenger.sendMessage( + address(s_scrollCrossDomainForwarder), // target + 0, // value + abi.encodeWithSelector(s_scrollCrossDomainForwarder.acceptL1Ownership.selector, s_strangerAddr), // message + 0 // gas limit + ); + + // Asserts that the ownership was actually transferred + assertEq(s_scrollCrossDomainForwarder.l1Owner(), s_strangerAddr); + } +} diff --git a/contracts/src/v0.8/l2ep/test/v1_0_0/scroll/ScrollCrossDomainGovernor.t.sol b/contracts/src/v0.8/l2ep/test/v1_0_0/scroll/ScrollCrossDomainGovernor.t.sol new file mode 100644 index 0000000000..9c44460494 --- /dev/null +++ b/contracts/src/v0.8/l2ep/test/v1_0_0/scroll/ScrollCrossDomainGovernor.t.sol @@ -0,0 +1,305 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.19; + +import {MockScrollCrossDomainMessenger} from "../../mocks/scroll/MockScrollCrossDomainMessenger.sol"; +import {ScrollCrossDomainGovernor} from "../../../dev/scroll/ScrollCrossDomainGovernor.sol"; +import {Greeter} from "../../../../tests/Greeter.sol"; +import {L2EPTest} from "../L2EPTest.t.sol"; + +import {MultiSend} from "../../../../vendor/MultiSend.sol"; + +contract ScrollCrossDomainGovernorTest is L2EPTest { + /// Contracts + MockScrollCrossDomainMessenger internal s_mockScrollCrossDomainMessenger; + ScrollCrossDomainGovernor internal s_scrollCrossDomainGovernor; + MultiSend internal s_multiSend; + Greeter internal s_greeter; + + /// Events + event L1OwnershipTransferRequested(address indexed from, address indexed to); + event L1OwnershipTransferred(address indexed from, address indexed to); + + /// Setup + function setUp() public { + // Deploys contracts + vm.startPrank(s_l1OwnerAddr); + s_mockScrollCrossDomainMessenger = new MockScrollCrossDomainMessenger(s_l1OwnerAddr); + s_scrollCrossDomainGovernor = new ScrollCrossDomainGovernor(s_mockScrollCrossDomainMessenger, s_l1OwnerAddr); + s_greeter = new Greeter(address(s_scrollCrossDomainGovernor)); + s_multiSend = new MultiSend(); + vm.stopPrank(); + } +} + +contract ScrollCrossDomainGovernor_Constructor is ScrollCrossDomainGovernorTest { + /// @notice it should have been deployed with the correct initial state + function test_InitialState() public { + // it should set the owner correctly + assertEq(s_scrollCrossDomainGovernor.owner(), s_l1OwnerAddr); + + // it should set the l1Owner correctly + assertEq(s_scrollCrossDomainGovernor.l1Owner(), s_l1OwnerAddr); + + // it should set the crossdomain messenger correctly + assertEq(s_scrollCrossDomainGovernor.crossDomainMessenger(), address(s_mockScrollCrossDomainMessenger)); + + // it should set the typeAndVersion correctly + assertEq(s_scrollCrossDomainGovernor.typeAndVersion(), "ScrollCrossDomainGovernor 1.0.0"); + } +} + +contract ScrollCrossDomainGovernor_Forward is ScrollCrossDomainGovernorTest { + /// @notice it should not be callable by unknown address + function test_NotCallableByUnknownAddress() public { + vm.startPrank(s_strangerAddr); + vm.expectRevert("Sender is not the L2 messenger or owner"); + s_scrollCrossDomainGovernor.forward(address(s_greeter), abi.encode("")); + } + + /// @notice it should be callable by crossdomain messenger address / L1 owner + function test_Forward() public { + // Sets msg.sender and tx.origin + vm.startPrank(s_strangerAddr); + + // Defines the cross domain message to send + string memory greeting = "hello"; + + // Sends the message + s_mockScrollCrossDomainMessenger.sendMessage( + address(s_scrollCrossDomainGovernor), // target + 0, // value + encodeCrossDomainSetGreetingMsg(s_scrollCrossDomainGovernor.forward.selector, address(s_greeter), greeting), // message + 0 // gas limit + ); + + // Checks that the greeter got the message + assertEq(s_greeter.greeting(), greeting); + } + + /// @notice it should revert when contract call reverts + function test_ForwardRevert() public { + // Sets msg.sender and tx.origin + vm.startPrank(s_strangerAddr); + + // Sends an invalid message + vm.expectRevert("Invalid greeting length"); + s_mockScrollCrossDomainMessenger.sendMessage( + address(s_scrollCrossDomainGovernor), // target + 0, // value + encodeCrossDomainSetGreetingMsg(s_scrollCrossDomainGovernor.forward.selector, address(s_greeter), ""), // message + 0 // gas limit + ); + } + + /// @notice it should be callable by L2 owner + function test_CallableByL2Owner() public { + // Sets msg.sender and tx.origin + vm.startPrank(s_l1OwnerAddr); + + // Defines the cross domain message to send + string memory greeting = "hello"; + + // Sends the message + s_scrollCrossDomainGovernor.forward( + address(s_greeter), + abi.encodeWithSelector(s_greeter.setGreeting.selector, greeting) + ); + + // Checks that the greeter message was updated + assertEq(s_greeter.greeting(), greeting); + } +} + +contract ScrollCrossDomainGovernor_ForwardDelegate is ScrollCrossDomainGovernorTest { + /// @notice it should not be callable by unknown address + function test_NotCallableByUnknownAddress() public { + vm.startPrank(s_strangerAddr); + vm.expectRevert("Sender is not the L2 messenger or owner"); + s_scrollCrossDomainGovernor.forwardDelegate(address(s_greeter), abi.encode("")); + } + + /// @notice it should be callable by crossdomain messenger address / L1 owner + function test_CallableByCrossDomainMessengerAddressOrL1Owner() public { + // Sets msg.sender and tx.origin + vm.startPrank(s_strangerAddr); + + // Sends the message + s_mockScrollCrossDomainMessenger.sendMessage( + address(s_scrollCrossDomainGovernor), // target + 0, // value + encodeCrossDomainMultiSendMsg( + s_scrollCrossDomainGovernor.forwardDelegate.selector, + address(s_multiSend), + abi.encodePacked(encodeMultiSendTx(address(s_greeter), "foo"), encodeMultiSendTx(address(s_greeter), "bar")) + ), // message + 0 // gas limit + ); + + // Checks that the greeter message was updated + assertEq(s_greeter.greeting(), "bar"); + } + + /// @notice it should be callable by L2 owner + function test_CallableByL2Owner() public { + // Sets msg.sender and tx.origin + vm.startPrank(s_l1OwnerAddr); + + // Sends the message + s_mockScrollCrossDomainMessenger.sendMessage( + address(s_scrollCrossDomainGovernor), // target + 0, // value + encodeCrossDomainMultiSendMsg( + s_scrollCrossDomainGovernor.forwardDelegate.selector, + address(s_multiSend), + abi.encodePacked(encodeMultiSendTx(address(s_greeter), "foo"), encodeMultiSendTx(address(s_greeter), "bar")) + ), // message + 0 // gas limit + ); + + // Checks that the greeter message was updated + assertEq(s_greeter.greeting(), "bar"); + } + + /// @notice it should revert batch when one call fails + function test_RevertsBatchWhenOneCallFails() public { + // Sets msg.sender and tx.origin + vm.startPrank(s_strangerAddr); + + // Sends an invalid message (empty transaction data is not allowed) + vm.expectRevert("Governor delegatecall reverted"); + s_mockScrollCrossDomainMessenger.sendMessage( + address(s_scrollCrossDomainGovernor), // target + 0, // value + encodeCrossDomainMultiSendMsg( + s_scrollCrossDomainGovernor.forwardDelegate.selector, + address(s_multiSend), + abi.encodePacked(encodeMultiSendTx(address(s_greeter), "foo"), encodeMultiSendTx(address(s_greeter), "")) + ), // message + 0 // gas limit + ); + + // Checks that the greeter message is unchanged + assertEq(s_greeter.greeting(), ""); + } + + /// @notice it should bubble up revert when contract call reverts + function test_BubbleUpRevert() public { + // Sets msg.sender and tx.origin + vm.startPrank(s_strangerAddr); + + // Sends an invalid message (empty transaction data is not allowed) + vm.expectRevert("Greeter: revert triggered"); + s_mockScrollCrossDomainMessenger.sendMessage( + address(s_scrollCrossDomainGovernor), // target + 0, // value + abi.encodeWithSelector( + ScrollCrossDomainGovernor.forwardDelegate.selector, + address(s_greeter), + abi.encodeWithSelector(Greeter.triggerRevert.selector) + ), // message + 0 // gas limit + ); + } +} + +contract ScrollCrossDomainGovernor_TransferL1Ownership is ScrollCrossDomainGovernorTest { + /// @notice it should not be callable by non-owners + function test_NotCallableByNonOwners() public { + vm.startPrank(s_strangerAddr); + vm.expectRevert("Sender is not the L2 messenger"); + s_scrollCrossDomainGovernor.transferL1Ownership(s_strangerAddr); + } + + /// @notice it should not be callable by L2 owner + function test_NotCallableByL2Owner() public { + vm.startPrank(s_l1OwnerAddr); + assertEq(s_scrollCrossDomainGovernor.owner(), s_l1OwnerAddr); + vm.expectRevert("Sender is not the L2 messenger"); + s_scrollCrossDomainGovernor.transferL1Ownership(s_strangerAddr); + } + + /// @notice it should be callable by current L1 owner + function test_CallableByL1Owner() public { + // Sets msg.sender and tx.origin + vm.startPrank(s_strangerAddr); + + // Defines the cross domain message to send + vm.expectEmit(); + emit L1OwnershipTransferRequested(s_scrollCrossDomainGovernor.l1Owner(), s_strangerAddr); + + // Sends the message + s_mockScrollCrossDomainMessenger.sendMessage( + address(s_scrollCrossDomainGovernor), // target + 0, // value + abi.encodeWithSelector(s_scrollCrossDomainGovernor.transferL1Ownership.selector, s_strangerAddr), // message + 0 // gas limit + ); + } + + /// @notice it should be callable by current L1 owner to zero address + function test_CallableByL1OwnerOrZeroAddress() public { + // Sets msg.sender and tx.origin + vm.startPrank(s_strangerAddr); + + // Defines the cross domain message to send + vm.expectEmit(); + emit L1OwnershipTransferRequested(s_scrollCrossDomainGovernor.l1Owner(), address(0)); + + // Sends the message + s_mockScrollCrossDomainMessenger.sendMessage( + address(s_scrollCrossDomainGovernor), // target + 0, // value + abi.encodeWithSelector(s_scrollCrossDomainGovernor.transferL1Ownership.selector, address(0)), // message + 0 // gas limit + ); + } +} + +contract ScrollCrossDomainGovernor_AcceptL1Ownership is ScrollCrossDomainGovernorTest { + /// @notice it should not be callable by non pending-owners + function test_NotCallableByNonPendingOwners() public { + // Sets msg.sender and tx.origin + vm.startPrank(s_strangerAddr); + + // Sends the message + vm.expectRevert("Must be proposed L1 owner"); + s_mockScrollCrossDomainMessenger.sendMessage( + address(s_scrollCrossDomainGovernor), // target + 0, // value + abi.encodeWithSelector(s_scrollCrossDomainGovernor.acceptL1Ownership.selector), // message + 0 // gas limit + ); + } + + /// @notice it should be callable by pending L1 owner + function test_CallableByPendingL1Owner() public { + // Sets msg.sender and tx.origin + vm.startPrank(s_strangerAddr); + + // Request ownership transfer + s_mockScrollCrossDomainMessenger.sendMessage( + address(s_scrollCrossDomainGovernor), // target + 0, // value + abi.encodeWithSelector(s_scrollCrossDomainGovernor.transferL1Ownership.selector, s_strangerAddr), // message + 0 // gas limit + ); + + // Sets a mock message sender + s_mockScrollCrossDomainMessenger._setMockMessageSender(s_strangerAddr); + + // Prepares expected event payload + vm.expectEmit(); + emit L1OwnershipTransferred(s_l1OwnerAddr, s_strangerAddr); + + // Accepts ownership transfer request + s_mockScrollCrossDomainMessenger.sendMessage( + address(s_scrollCrossDomainGovernor), // target + 0, // value + abi.encodeWithSelector(s_scrollCrossDomainGovernor.acceptL1Ownership.selector, s_strangerAddr), // message + 0 // gas limit + ); + + // Asserts that the ownership was actually transferred + assertEq(s_scrollCrossDomainGovernor.l1Owner(), s_strangerAddr); + } +} diff --git a/contracts/src/v0.8/l2ep/test/v1_0_0/scroll/ScrollSequencerUptimeFeed.t.sol b/contracts/src/v0.8/l2ep/test/v1_0_0/scroll/ScrollSequencerUptimeFeed.t.sol new file mode 100644 index 0000000000..520fbf6dfd --- /dev/null +++ b/contracts/src/v0.8/l2ep/test/v1_0_0/scroll/ScrollSequencerUptimeFeed.t.sol @@ -0,0 +1,528 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.19; + +import {MockScrollL1CrossDomainMessenger} from "../../mocks/scroll/MockScrollL1CrossDomainMessenger.sol"; +import {MockScrollL2CrossDomainMessenger} from "../../mocks/scroll/MockScrollL2CrossDomainMessenger.sol"; +import {ScrollSequencerUptimeFeed} from "../../../dev/scroll/ScrollSequencerUptimeFeed.sol"; +import {FeedConsumer} from "../../../../tests/FeedConsumer.sol"; +import {L2EPTest} from "../L2EPTest.t.sol"; + +contract ScrollSequencerUptimeFeedTest is L2EPTest { + /// Constants + uint256 internal constant GAS_USED_DEVIATION = 100; + + /// L2EP contracts + MockScrollL1CrossDomainMessenger internal s_mockScrollL1CrossDomainMessenger; + MockScrollL2CrossDomainMessenger internal s_mockScrollL2CrossDomainMessenger; + ScrollSequencerUptimeFeed internal s_scrollSequencerUptimeFeed; + + /// Events + event UpdateIgnored(bool latestStatus, uint64 latestTimestamp, bool incomingStatus, uint64 incomingTimestamp); + event AnswerUpdated(int256 indexed current, uint256 indexed roundId, uint256 updatedAt); + event RoundUpdated(int256 status, uint64 updatedAt); + + /// Setup + function setUp() public { + // Deploys contracts + s_mockScrollL1CrossDomainMessenger = new MockScrollL1CrossDomainMessenger(); + s_mockScrollL2CrossDomainMessenger = new MockScrollL2CrossDomainMessenger(); + s_scrollSequencerUptimeFeed = new ScrollSequencerUptimeFeed( + s_l1OwnerAddr, + address(s_mockScrollL2CrossDomainMessenger), + false + ); + + // Sets mock sender in mock L2 messenger contract + s_mockScrollL2CrossDomainMessenger.setSender(s_l1OwnerAddr); + } +} + +contract ScrollSequencerUptimeFeed_Constructor is ScrollSequencerUptimeFeedTest { + /// @notice it should have been deployed with the correct initial state + function test_InitialState() public { + // L2 cross domain messenger address must not be the zero address + vm.expectRevert(ScrollSequencerUptimeFeed.ZeroAddress.selector); + new ScrollSequencerUptimeFeed(s_l1OwnerAddr, address(0), false); + + // Sets msg.sender and tx.origin to a valid address + vm.startPrank(s_l1OwnerAddr, s_l1OwnerAddr); + + // Checks L1 sender + address actualL1Addr = s_scrollSequencerUptimeFeed.l1Sender(); + assertEq(actualL1Addr, s_l1OwnerAddr); + + // Checks latest round data + (uint80 roundId, int256 answer, , , ) = s_scrollSequencerUptimeFeed.latestRoundData(); + assertEq(roundId, 1); + assertEq(answer, 0); + } +} + +contract ScrollSequencerUptimeFeed_UpdateStatus is ScrollSequencerUptimeFeedTest { + /// @notice it should revert if called by an address that is not the L2 Cross Domain Messenger + function test_RevertIfNotL2CrossDomainMessengerAddr() public { + // Sets msg.sender and tx.origin to an unauthorized address + vm.startPrank(s_strangerAddr, s_strangerAddr); + + // Tries to update the status from an unauthorized account + vm.expectRevert(ScrollSequencerUptimeFeed.InvalidSender.selector); + s_scrollSequencerUptimeFeed.updateStatus(true, uint64(1)); + } + + /// @notice it should revert if called by an address that is not the L2 Cross Domain Messenger and is not the L1 sender + function test_RevertIfNotL2CrossDomainMessengerAddrAndNotL1SenderAddr() public { + // Sets msg.sender and tx.origin to an unauthorized address + vm.startPrank(s_strangerAddr, s_strangerAddr); + + // Sets mock sender in mock L2 messenger contract + s_mockScrollL2CrossDomainMessenger.setSender(s_strangerAddr); + + // Tries to update the status from an unauthorized account + vm.expectRevert(ScrollSequencerUptimeFeed.InvalidSender.selector); + s_scrollSequencerUptimeFeed.updateStatus(true, uint64(1)); + } + + /// @notice it should update status when status has not changed and incoming timestamp is the same as latest + function test_UpdateStatusWhenNoChange() public { + // Sets msg.sender and tx.origin to a valid address + address l2MessengerAddr = address(s_mockScrollL2CrossDomainMessenger); + vm.startPrank(l2MessengerAddr, l2MessengerAddr); + + // Fetches the latest timestamp + uint256 timestamp = s_scrollSequencerUptimeFeed.latestTimestamp(); + + // Submits a status update + vm.expectEmit(); + emit AnswerUpdated(1, 2, timestamp); + s_scrollSequencerUptimeFeed.updateStatus(true, uint64(timestamp)); + assertEq(s_scrollSequencerUptimeFeed.latestAnswer(), 1); + assertEq(s_scrollSequencerUptimeFeed.latestTimestamp(), uint64(timestamp)); + + // Stores the current round data before updating it + ( + uint80 roundIdBeforeUpdate, + int256 answerBeforeUpdate, + uint256 startedAtBeforeUpdate, + , + uint80 answeredInRoundBeforeUpdate + ) = s_scrollSequencerUptimeFeed.latestRoundData(); + + // Submit another status update with the same status + vm.expectEmit(); + emit RoundUpdated(1, uint64(block.timestamp)); + s_scrollSequencerUptimeFeed.updateStatus(true, uint64(timestamp + 200)); + assertEq(s_scrollSequencerUptimeFeed.latestAnswer(), 1); + assertEq(s_scrollSequencerUptimeFeed.latestTimestamp(), uint64(timestamp)); + + // Stores the current round data after updating it + ( + uint80 roundIdAfterUpdate, + int256 answerAfterUpdate, + uint256 startedAtAfterUpdate, + uint256 updatedAtAfterUpdate, + uint80 answeredInRoundAfterUpdate + ) = s_scrollSequencerUptimeFeed.latestRoundData(); + + // Verifies the latest round data has been properly updated + assertEq(roundIdAfterUpdate, roundIdBeforeUpdate); + assertEq(answerAfterUpdate, answerBeforeUpdate); + assertEq(startedAtAfterUpdate, startedAtBeforeUpdate); + assertEq(answeredInRoundAfterUpdate, answeredInRoundBeforeUpdate); + assertEq(updatedAtAfterUpdate, block.timestamp); + } + + /// @notice it should update status when status has changed and incoming timestamp is newer than the latest + function test_UpdateStatusWhenStatusChangeAndTimeChange() public { + // Sets msg.sender and tx.origin to a valid address + address l2MessengerAddr = address(s_mockScrollL2CrossDomainMessenger); + vm.startPrank(l2MessengerAddr, l2MessengerAddr); + + // Submits a status update + uint256 timestamp = s_scrollSequencerUptimeFeed.latestTimestamp(); + vm.expectEmit(); + emit AnswerUpdated(1, 2, timestamp); + s_scrollSequencerUptimeFeed.updateStatus(true, uint64(timestamp)); + assertEq(s_scrollSequencerUptimeFeed.latestAnswer(), 1); + assertEq(s_scrollSequencerUptimeFeed.latestTimestamp(), uint64(timestamp)); + + // Submit another status update, different status, newer timestamp should update + timestamp = timestamp + 200; + vm.expectEmit(); + emit AnswerUpdated(0, 3, timestamp); + s_scrollSequencerUptimeFeed.updateStatus(false, uint64(timestamp)); + assertEq(s_scrollSequencerUptimeFeed.latestAnswer(), 0); + assertEq(s_scrollSequencerUptimeFeed.latestTimestamp(), uint64(timestamp)); + } + + /// @notice it should update status when status has changed and incoming timestamp is the same as latest + function test_UpdateStatusWhenStatusChangeAndNoTimeChange() public { + // Sets msg.sender and tx.origin to a valid address + address l2MessengerAddr = address(s_mockScrollL2CrossDomainMessenger); + vm.startPrank(l2MessengerAddr, l2MessengerAddr); + + // Fetches the latest timestamp + uint256 timestamp = s_scrollSequencerUptimeFeed.latestTimestamp(); + + // Submits a status update + vm.expectEmit(); + emit AnswerUpdated(1, 2, timestamp); + s_scrollSequencerUptimeFeed.updateStatus(true, uint64(timestamp)); + assertEq(s_scrollSequencerUptimeFeed.latestAnswer(), 1); + assertEq(s_scrollSequencerUptimeFeed.latestTimestamp(), uint64(timestamp)); + + // Submit another status update, different status, same timestamp should update + vm.expectEmit(); + emit AnswerUpdated(0, 3, timestamp); + s_scrollSequencerUptimeFeed.updateStatus(false, uint64(timestamp)); + assertEq(s_scrollSequencerUptimeFeed.latestAnswer(), 0); + assertEq(s_scrollSequencerUptimeFeed.latestTimestamp(), uint64(timestamp)); + } + + /// @notice it should ignore out-of-order updates + function test_IgnoreOutOfOrderUpdates() public { + // Sets msg.sender and tx.origin to a valid address + address l2MessengerAddr = address(s_mockScrollL2CrossDomainMessenger); + vm.startPrank(l2MessengerAddr, l2MessengerAddr); + + // Submits a status update + uint256 timestamp = s_scrollSequencerUptimeFeed.latestTimestamp() + 10000; + vm.expectEmit(); + emit AnswerUpdated(1, 2, timestamp); + s_scrollSequencerUptimeFeed.updateStatus(true, uint64(timestamp)); + assertEq(s_scrollSequencerUptimeFeed.latestAnswer(), 1); + assertEq(s_scrollSequencerUptimeFeed.latestTimestamp(), uint64(timestamp)); + + // Update with different status, but stale timestamp, should be ignored + timestamp = timestamp - 1000; + vm.expectEmit(false, false, false, false); + emit UpdateIgnored(true, 0, true, 0); // arguments are dummy values + // TODO: how can we check that an AnswerUpdated event was NOT emitted + s_scrollSequencerUptimeFeed.updateStatus(false, uint64(timestamp)); + } +} + +contract ScrollSequencerUptimeFeed_AggregatorV3Interface is ScrollSequencerUptimeFeedTest { + /// @notice it should return valid answer from getRoundData and latestRoundData + function test_AggregatorV3Interface() public { + // Sets msg.sender and tx.origin to a valid address + address l2MessengerAddr = address(s_mockScrollL2CrossDomainMessenger); + vm.startPrank(l2MessengerAddr, l2MessengerAddr); + + // Defines helper variables + uint80 roundId; + int256 answer; + uint256 startedAt; + uint256 updatedAt; + uint80 answeredInRound; + + // Checks initial state + (roundId, answer, startedAt, updatedAt, answeredInRound) = s_scrollSequencerUptimeFeed.latestRoundData(); + assertEq(roundId, 1); + assertEq(answer, 0); + assertEq(answeredInRound, roundId); + assertEq(startedAt, updatedAt); + + // Submits status update with different status and newer timestamp, should update + uint256 timestamp = startedAt + 1000; + s_scrollSequencerUptimeFeed.updateStatus(true, uint64(timestamp)); + (roundId, answer, startedAt, updatedAt, answeredInRound) = s_scrollSequencerUptimeFeed.getRoundData(2); + assertEq(roundId, 2); + assertEq(answer, 1); + assertEq(answeredInRound, roundId); + assertEq(startedAt, timestamp); + assertLe(updatedAt, startedAt); + + // Saves round 2 data + uint80 roundId2 = roundId; + int256 answer2 = answer; + uint256 startedAt2 = startedAt; + uint256 updatedAt2 = updatedAt; + uint80 answeredInRound2 = answeredInRound; + + // Checks that last round is still returning the correct data + (roundId, answer, startedAt, updatedAt, answeredInRound) = s_scrollSequencerUptimeFeed.getRoundData(1); + assertEq(roundId, 1); + assertEq(answer, 0); + assertEq(answeredInRound, roundId); + assertEq(startedAt, updatedAt); + + // Assert latestRoundData corresponds to latest round id + (roundId, answer, startedAt, updatedAt, answeredInRound) = s_scrollSequencerUptimeFeed.latestRoundData(); + assertEq(roundId2, roundId); + assertEq(answer2, answer); + assertEq(startedAt2, startedAt); + assertEq(updatedAt2, updatedAt); + assertEq(answeredInRound2, answeredInRound); + } + + /// @notice it should revert from #getRoundData when round does not yet exist (future roundId) + function test_RevertGetRoundDataWhenRoundDoesNotExistYet() public { + // Sets msg.sender and tx.origin to a valid address + vm.startPrank(s_l1OwnerAddr, s_l1OwnerAddr); + + // Gets data from a round that has not happened yet + vm.expectRevert(ScrollSequencerUptimeFeed.NoDataPresent.selector); + s_scrollSequencerUptimeFeed.getRoundData(2); + } + + /// @notice it should revert from #getAnswer when round does not yet exist (future roundId) + function test_RevertGetAnswerWhenRoundDoesNotExistYet() public { + // Sets msg.sender and tx.origin to a valid address + vm.startPrank(s_l1OwnerAddr, s_l1OwnerAddr); + + // Gets data from a round that has not happened yet + vm.expectRevert(ScrollSequencerUptimeFeed.NoDataPresent.selector); + s_scrollSequencerUptimeFeed.getAnswer(2); + } + + /// @notice it should revert from #getTimestamp when round does not yet exist (future roundId) + function test_RevertGetTimestampWhenRoundDoesNotExistYet() public { + // Sets msg.sender and tx.origin to a valid address + vm.startPrank(s_l1OwnerAddr, s_l1OwnerAddr); + + // Gets data from a round that has not happened yet + vm.expectRevert(ScrollSequencerUptimeFeed.NoDataPresent.selector); + s_scrollSequencerUptimeFeed.getTimestamp(2); + } +} + +contract ScrollSequencerUptimeFeed_ProtectReadsOnAggregatorV2V3InterfaceFunctions is ScrollSequencerUptimeFeedTest { + /// @notice it should disallow reads on AggregatorV2V3Interface functions when consuming contract is not whitelisted + function test_AggregatorV2V3InterfaceDisallowReadsIfConsumingContractIsNotWhitelisted() public { + // Deploys a FeedConsumer contract + FeedConsumer feedConsumer = new FeedConsumer(address(s_scrollSequencerUptimeFeed)); + + // Sanity - consumer is not whitelisted + assertEq(s_scrollSequencerUptimeFeed.checkEnabled(), true); + assertEq(s_scrollSequencerUptimeFeed.hasAccess(address(feedConsumer), abi.encode("")), false); + + // Asserts reads are not possible from consuming contract + vm.expectRevert("No access"); + feedConsumer.latestAnswer(); + vm.expectRevert("No access"); + feedConsumer.latestRoundData(); + } + + /// @notice it should allow reads on AggregatorV2V3Interface functions when consuming contract is whitelisted + function test_AggregatorV2V3InterfaceAllowReadsIfConsumingContractIsWhitelisted() public { + // Deploys a FeedConsumer contract + FeedConsumer feedConsumer = new FeedConsumer(address(s_scrollSequencerUptimeFeed)); + + // Whitelist consumer + s_scrollSequencerUptimeFeed.addAccess(address(feedConsumer)); + + // Sanity - consumer is whitelisted + assertEq(s_scrollSequencerUptimeFeed.checkEnabled(), true); + assertEq(s_scrollSequencerUptimeFeed.hasAccess(address(feedConsumer), abi.encode("")), true); + + // Asserts reads are possible from consuming contract + (uint80 roundId, int256 answer, , , ) = feedConsumer.latestRoundData(); + assertEq(feedConsumer.latestAnswer(), 0); + assertEq(roundId, 1); + assertEq(answer, 0); + } +} + +contract ScrollSequencerUptimeFeed_GasCosts is ScrollSequencerUptimeFeedTest { + /// @notice it should consume a known amount of gas for updates + function test_GasCosts() public { + // Sets msg.sender and tx.origin to a valid address + address l2MessengerAddr = address(s_mockScrollL2CrossDomainMessenger); + vm.startPrank(l2MessengerAddr, l2MessengerAddr); + + // Assert initial conditions + uint256 timestamp = s_scrollSequencerUptimeFeed.latestTimestamp(); + assertEq(s_scrollSequencerUptimeFeed.latestAnswer(), 0); + + // Defines helper variables for measuring gas usage + uint256 expectedGasUsed; + uint256 gasStart; + uint256 gasFinal; + + // measures gas used for no update + expectedGasUsed = 10197; // NOTE: used to be 38594 in hardhat tests + gasStart = gasleft(); + s_scrollSequencerUptimeFeed.updateStatus(false, uint64(timestamp + 1000)); + gasFinal = gasleft(); + assertEq(s_scrollSequencerUptimeFeed.latestAnswer(), 0); + assertGasUsageIsCloseTo(expectedGasUsed, gasStart, gasFinal, GAS_USED_DEVIATION); + + // measures gas used for update + expectedGasUsed = 31644; // NOTE: used to be 58458 in hardhat tests + gasStart = gasleft(); + s_scrollSequencerUptimeFeed.updateStatus(true, uint64(timestamp + 1000)); + gasFinal = gasleft(); + assertEq(s_scrollSequencerUptimeFeed.latestAnswer(), 1); + assertGasUsageIsCloseTo(expectedGasUsed, gasStart, gasFinal, GAS_USED_DEVIATION); + } +} + +contract ScrollSequencerUptimeFeed_AggregatorInterfaceGasCosts is ScrollSequencerUptimeFeedTest { + /// @notice it should consume a known amount of gas for getRoundData(uint80) + function test_GasUsageForGetRoundData() public { + // Sets msg.sender and tx.origin to a valid address + address l2MessengerAddr = address(s_mockScrollL2CrossDomainMessenger); + vm.startPrank(l2MessengerAddr, l2MessengerAddr); + + // Defines helper variables for measuring gas usage + uint256 expectedGasUsed = 4504; // NOTE: used to be 30952 in hardhat tesst + uint256 gasStart; + uint256 gasFinal; + + // Initializes a round + uint256 timestamp = s_scrollSequencerUptimeFeed.latestTimestamp() + 1000; + s_scrollSequencerUptimeFeed.updateStatus(true, uint64(timestamp)); + + // Measures gas usage + gasStart = gasleft(); + s_scrollSequencerUptimeFeed.getRoundData(1); + gasFinal = gasleft(); + + // Checks that gas usage is within expected range + assertGasUsageIsCloseTo(expectedGasUsed, gasStart, gasFinal, GAS_USED_DEVIATION); + } + + /// @notice it should consume a known amount of gas for latestRoundData() + function test_GasUsageForLatestRoundData() public { + // Sets msg.sender and tx.origin to a valid address + address l2MessengerAddr = address(s_mockScrollL2CrossDomainMessenger); + vm.startPrank(l2MessengerAddr, l2MessengerAddr); + + // Defines helper variables for measuring gas usage + uint256 expectedGasUsed = 2154; // NOTE: used to be 28523 in hardhat tests + uint256 gasStart; + uint256 gasFinal; + + // Initializes a round + uint256 timestamp = s_scrollSequencerUptimeFeed.latestTimestamp() + 1000; + s_scrollSequencerUptimeFeed.updateStatus(true, uint64(timestamp)); + + // Measures gas usage + gasStart = gasleft(); + s_scrollSequencerUptimeFeed.latestRoundData(); + gasFinal = gasleft(); + + // Checks that gas usage is within expected range + assertGasUsageIsCloseTo(expectedGasUsed, gasStart, gasFinal, GAS_USED_DEVIATION); + } + + /// @notice it should consume a known amount of gas for latestAnswer() + function test_GasUsageForLatestAnswer() public { + // Sets msg.sender and tx.origin to a valid address + address l2MessengerAddr = address(s_mockScrollL2CrossDomainMessenger); + vm.startPrank(l2MessengerAddr, l2MessengerAddr); + + // Defines helper variables for measuring gas usage + uint256 expectedGasUsed = 1566; // NOTE: used to be 28229 in hardhat tests + uint256 gasStart; + uint256 gasFinal; + + // Initializes a round + uint256 timestamp = s_scrollSequencerUptimeFeed.latestTimestamp() + 1000; + s_scrollSequencerUptimeFeed.updateStatus(true, uint64(timestamp)); + + // Measures gas usage + gasStart = gasleft(); + s_scrollSequencerUptimeFeed.latestAnswer(); + gasFinal = gasleft(); + + // Checks that gas usage is within expected range + assertGasUsageIsCloseTo(expectedGasUsed, gasStart, gasFinal, GAS_USED_DEVIATION); + } + + /// @notice it should consume a known amount of gas for latestTimestamp() + function test_GasUsageForLatestTimestamp() public { + // Sets msg.sender and tx.origin to a valid address + address l2MessengerAddr = address(s_mockScrollL2CrossDomainMessenger); + vm.startPrank(l2MessengerAddr, l2MessengerAddr); + + // Defines helper variables for measuring gas usage + uint256 expectedGasUsed = 1459; // NOTE: used to be 28129 in hardhat tests + uint256 gasStart; + uint256 gasFinal; + + // Initializes a round + uint256 timestamp = s_scrollSequencerUptimeFeed.latestTimestamp() + 1000; + s_scrollSequencerUptimeFeed.updateStatus(true, uint64(timestamp)); + + // Measures gas usage + gasStart = gasleft(); + s_scrollSequencerUptimeFeed.latestTimestamp(); + gasFinal = gasleft(); + + // Checks that gas usage is within expected range + assertGasUsageIsCloseTo(expectedGasUsed, gasStart, gasFinal, GAS_USED_DEVIATION); + } + + /// @notice it should consume a known amount of gas for latestRound() + function test_GasUsageForLatestRound() public { + // Sets msg.sender and tx.origin to a valid address + address l2MessengerAddr = address(s_mockScrollL2CrossDomainMessenger); + vm.startPrank(l2MessengerAddr, l2MessengerAddr); + + // Defines helper variables for measuring gas usage + uint256 expectedGasUsed = 1470; // NOTE: used to be 28145 in hardhat tests + uint256 gasStart; + uint256 gasFinal; + + // Initializes a round + uint256 timestamp = s_scrollSequencerUptimeFeed.latestTimestamp() + 1000; + s_scrollSequencerUptimeFeed.updateStatus(true, uint64(timestamp)); + + // Measures gas usage + gasStart = gasleft(); + s_scrollSequencerUptimeFeed.latestRound(); + gasFinal = gasleft(); + + // Checks that gas usage is within expected range + assertGasUsageIsCloseTo(expectedGasUsed, gasStart, gasFinal, GAS_USED_DEVIATION); + } + + /// @notice it should consume a known amount of gas for getAnswer() + function test_GasUsageForGetAnswer() public { + // Sets msg.sender and tx.origin to a valid address + address l2MessengerAddr = address(s_mockScrollL2CrossDomainMessenger); + vm.startPrank(l2MessengerAddr, l2MessengerAddr); + + // Defines helper variables for measuring gas usage + uint256 expectedGasUsed = 3929; // NOTE: used to be 30682 in hardhat tests + uint256 gasStart; + uint256 gasFinal; + + // Initializes a round + uint256 timestamp = s_scrollSequencerUptimeFeed.latestTimestamp() + 1000; + s_scrollSequencerUptimeFeed.updateStatus(true, uint64(timestamp)); + + // Measures gas usage + gasStart = gasleft(); + s_scrollSequencerUptimeFeed.getAnswer(1); + gasFinal = gasleft(); + + // Checks that gas usage is within expected range + assertGasUsageIsCloseTo(expectedGasUsed, gasStart, gasFinal, GAS_USED_DEVIATION); + } + + /// @notice it should consume a known amount of gas for getTimestamp() + function test_GasUsageForGetTimestamp() public { + // Sets msg.sender and tx.origin to a valid address + address l2MessengerAddr = address(s_mockScrollL2CrossDomainMessenger); + vm.startPrank(l2MessengerAddr, l2MessengerAddr); + + // Defines helper variables for measuring gas usage + uint256 expectedGasUsed = 3817; // NOTE: used to be 30570 in hardhat tests + uint256 gasStart; + uint256 gasFinal; + + // Initializes a round + uint256 timestamp = s_scrollSequencerUptimeFeed.latestTimestamp() + 1000; + s_scrollSequencerUptimeFeed.updateStatus(true, uint64(timestamp)); + + // Measures gas usage + gasStart = gasleft(); + s_scrollSequencerUptimeFeed.getTimestamp(1); + gasFinal = gasleft(); + + // Checks that gas usage is within expected range + assertGasUsageIsCloseTo(expectedGasUsed, gasStart, gasFinal, GAS_USED_DEVIATION); + } +} diff --git a/contracts/src/v0.8/l2ep/test/v1_0_0/scroll/ScrollValidator.t.sol b/contracts/src/v0.8/l2ep/test/v1_0_0/scroll/ScrollValidator.t.sol new file mode 100644 index 0000000000..969c78c72e --- /dev/null +++ b/contracts/src/v0.8/l2ep/test/v1_0_0/scroll/ScrollValidator.t.sol @@ -0,0 +1,117 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.19; + +import {MockScrollL1CrossDomainMessenger} from "../../mocks/scroll/MockScrollL1CrossDomainMessenger.sol"; +import {MockScrollL2CrossDomainMessenger} from "../../mocks/scroll/MockScrollL2CrossDomainMessenger.sol"; +import {ScrollSequencerUptimeFeed} from "../../../dev/scroll/ScrollSequencerUptimeFeed.sol"; +import {ScrollValidator} from "../../../dev/scroll/ScrollValidator.sol"; +import {L2EPTest} from "../L2EPTest.t.sol"; + +contract ScrollValidatorTest is L2EPTest { + /// Helper constants + address internal constant L2_SEQ_STATUS_RECORDER_ADDRESS = 0x491B1dDA0A8fa069bbC1125133A975BF4e85a91b; + uint32 internal constant INIT_GAS_LIMIT = 1900000; + + /// L2EP contracts + MockScrollL1CrossDomainMessenger internal s_mockScrollL1CrossDomainMessenger; + MockScrollL2CrossDomainMessenger internal s_mockScrollL2CrossDomainMessenger; + ScrollSequencerUptimeFeed internal s_scrollSequencerUptimeFeed; + ScrollValidator internal s_scrollValidator; + + /// https://github.com/scroll-tech/scroll/blob/03089eaeee1193ff44c532c7038611ae123e7ef3/contracts/src/libraries/IScrollMessenger.sol#L22 + event SentMessage( + address indexed sender, + address indexed target, + uint256 value, + uint256 messageNonce, + uint256 gasLimit, + bytes message + ); + + /// Setup + function setUp() public { + s_mockScrollL1CrossDomainMessenger = new MockScrollL1CrossDomainMessenger(); + s_mockScrollL2CrossDomainMessenger = new MockScrollL2CrossDomainMessenger(); + + s_scrollSequencerUptimeFeed = new ScrollSequencerUptimeFeed( + address(s_mockScrollL1CrossDomainMessenger), + address(s_mockScrollL2CrossDomainMessenger), + true + ); + + s_scrollValidator = new ScrollValidator( + address(s_mockScrollL1CrossDomainMessenger), + address(s_scrollSequencerUptimeFeed), + INIT_GAS_LIMIT + ); + } +} + +contract ScrollValidator_SetGasLimit is ScrollValidatorTest { + /// @notice it correctly updates the gas limit + function test_CorrectlyUpdatesTheGasLimit() public { + uint32 newGasLimit = 2000000; + assertEq(s_scrollValidator.getGasLimit(), INIT_GAS_LIMIT); + s_scrollValidator.setGasLimit(newGasLimit); + assertEq(s_scrollValidator.getGasLimit(), newGasLimit); + } +} + +contract ScrollValidator_Validate is ScrollValidatorTest { + /// @notice it reverts if called by account with no access + function test_RevertsIfCalledByAnAccountWithNoAccess() public { + vm.startPrank(s_strangerAddr); + vm.expectRevert("No access"); + s_scrollValidator.validate(0, 0, 1, 1); + } + + /// @notice it posts sequencer status when there is not status change + function test_PostSequencerStatusWhenThereIsNotStatusChange() public { + // Gives access to the s_eoaValidator + s_scrollValidator.addAccess(s_eoaValidator); + + // Sets block.timestamp to a later date + uint256 futureTimestampInSeconds = block.timestamp + 5000; + vm.startPrank(s_eoaValidator); + vm.warp(futureTimestampInSeconds); + + // Sets up the expected event data + vm.expectEmit(false, false, false, true); + emit SentMessage( + address(s_scrollValidator), // sender + L2_SEQ_STATUS_RECORDER_ADDRESS, // target + 0, // value + 0, // nonce + INIT_GAS_LIMIT, // gas limit + abi.encodeWithSelector(ScrollSequencerUptimeFeed.updateStatus.selector, false, futureTimestampInSeconds) // message + ); + + // Runs the function (which produces the event to test) + s_scrollValidator.validate(0, 0, 0, 0); + } + + /// @notice it post sequencer offline + function test_PostSequencerOffline() public { + // Gives access to the s_eoaValidator + s_scrollValidator.addAccess(s_eoaValidator); + + // Sets block.timestamp to a later date + uint256 futureTimestampInSeconds = block.timestamp + 10000; + vm.startPrank(s_eoaValidator); + vm.warp(futureTimestampInSeconds); + + // Sets up the expected event data + vm.expectEmit(false, false, false, true); + emit SentMessage( + address(s_scrollValidator), // sender + L2_SEQ_STATUS_RECORDER_ADDRESS, // target + 0, // value + 0, // nonce + INIT_GAS_LIMIT, // gas limit + abi.encodeWithSelector(ScrollSequencerUptimeFeed.updateStatus.selector, true, futureTimestampInSeconds) // message + ); + + // Runs the function (which produces the event to test) + s_scrollValidator.validate(0, 0, 1, 1); + } +} diff --git a/contracts/src/v0.8/shared/test/helpers/ChainReaderTestContract.sol b/contracts/src/v0.8/shared/test/helpers/ChainReaderTestContract.sol new file mode 100644 index 0000000000..050f5fb390 --- /dev/null +++ b/contracts/src/v0.8/shared/test/helpers/ChainReaderTestContract.sol @@ -0,0 +1,117 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8; + +struct TestStruct { + int32 Field; + string DifferentField; + uint8 OracleId; + uint8[32] OracleIds; + address Account; + address[] Accounts; + int192 BigField; + MidLevelTestStruct NestedStruct; +} + +struct MidLevelTestStruct { + bytes2 FixedBytes; + InnerTestStruct Inner; +} + +struct InnerTestStruct { + int64 IntVal; + string S; +} + +contract LatestValueHolder { + event Triggered( + int32 indexed field, + string differentField, + uint8 oracleId, + uint8[32] oracleIds, + address Account, + address[] Accounts, + int192 bigField, + MidLevelTestStruct nestedStruct + ); + + event TriggeredEventWithDynamicTopic(string indexed fieldHash, string field); + + // First topic is event hash + event TriggeredWithFourTopics(int32 indexed field1, int32 indexed field2, int32 indexed field3); + + TestStruct[] private s_seen; + uint64[] private s_arr; + + constructor() { + // See chain_reader_interface_tests.go in chainlink-relay + s_arr.push(3); + s_arr.push(4); + } + + function addTestStruct( + int32 field, + string calldata differentField, + uint8 oracleId, + uint8[32] calldata oracleIds, + address account, + address[] calldata accounts, + int192 bigField, + MidLevelTestStruct calldata nestedStruct + ) public { + s_seen.push(TestStruct(field, differentField, oracleId, oracleIds, account, accounts, bigField, nestedStruct)); + } + + function returnSeen( + int32 field, + string calldata differentField, + uint8 oracleId, + uint8[32] calldata oracleIds, + address account, + address[] calldata accounts, + int192 bigField, + MidLevelTestStruct calldata nestedStruct + ) public pure returns (TestStruct memory) { + return TestStruct(field, differentField, oracleId, oracleIds, account, accounts, bigField, nestedStruct); + } + + function getElementAtIndex(uint256 i) public view returns (TestStruct memory) { + // See chain_reader_interface_tests.go in chainlink-relay + return s_seen[i - 1]; + } + + function getPrimitiveValue() public pure returns (uint64) { + // See chain_reader_interface_tests.go in chainlink-relay + return 3; + } + + function getDifferentPrimitiveValue() public pure returns (uint64) { + // See chain_reader_interface_tests.go in chainlink-relay + return 1990; + } + + function getSliceValue() public view returns (uint64[] memory) { + return s_arr; + } + + function triggerEvent( + int32 field, + string calldata differentField, + uint8 oracleId, + uint8[32] calldata oracleIds, + address account, + address[] calldata accounts, + int192 bigField, + MidLevelTestStruct calldata nestedStruct + ) public { + emit Triggered(field, differentField, oracleId, oracleIds, account, accounts, bigField, nestedStruct); + } + + function triggerEventWithDynamicTopic(string calldata field) public { + emit TriggeredEventWithDynamicTopic(field, field); + } + + // first topic is the event signature + function triggerWithFourTopics(int32 field1, int32 field2, int32 field3) public { + emit TriggeredWithFourTopics(field1, field2, field3); + } +} diff --git a/contracts/src/v0.8/tests/MockArbitrumInbox.sol b/contracts/src/v0.8/tests/MockArbitrumInbox.sol index cd85ed4d6e..445a361b30 100644 --- a/contracts/src/v0.8/tests/MockArbitrumInbox.sol +++ b/contracts/src/v0.8/tests/MockArbitrumInbox.sol @@ -1,3 +1,6 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.9; + import {IInbox} from "../vendor/arb-bridge-eth/v0.8.0-custom/contracts/bridge/interfaces/IInbox.sol"; import {IBridge} from "../vendor/arb-bridge-eth/v0.8.0-custom/contracts/bridge/interfaces/IBridge.sol"; @@ -13,46 +16,46 @@ contract MockArbitrumInbox is IInbox { bytes data ); - function sendL2Message(bytes calldata messageData) external override returns (uint256) { + function sendL2Message(bytes calldata /* messageData */) external pure override returns (uint256) { return 0; } function sendUnsignedTransaction( - uint256 maxGas, - uint256 gasPriceBid, - uint256 nonce, - address destAddr, - uint256 amount, - bytes calldata data - ) external override returns (uint256) { + uint256 /* maxGas */, + uint256 /* gasPriceBid */, + uint256 /* nonce */, + address /* destAddr */, + uint256 /* amount */, + bytes calldata /* data */ + ) external pure override returns (uint256) { return 0; } function sendContractTransaction( - uint256 maxGas, - uint256 gasPriceBid, - address destAddr, - uint256 amount, - bytes calldata data - ) external override returns (uint256) { + uint256 /* maxGas */, + uint256 /* gasPriceBid */, + address /* destAddr */, + uint256 /* amount */, + bytes calldata /* data */ + ) external pure override returns (uint256) { return 0; } function sendL1FundedUnsignedTransaction( - uint256 maxGas, - uint256 gasPriceBid, - uint256 nonce, - address destAddr, - bytes calldata data + uint256 /* maxGas */, + uint256 /* gasPriceBid */, + uint256 /* nonce */, + address /* destAddr */, + bytes calldata /* data */ ) external payable override returns (uint256) { return 0; } function sendL1FundedContractTransaction( - uint256 maxGas, - uint256 gasPriceBid, - address destAddr, - bytes calldata data + uint256 /* maxGas */, + uint256 /* gasPriceBid */, + address /* destAddr */, + bytes calldata /* data */ ) external payable override returns (uint256) { return 0; } @@ -81,32 +84,32 @@ contract MockArbitrumInbox is IInbox { } function createRetryableTicket( - address destAddr, - uint256 arbTxCallValue, - uint256 maxSubmissionCost, - address submissionRefundAddress, - address valueRefundAddress, - uint256 maxGas, - uint256 gasPriceBid, - bytes calldata data + address /* destAddr */, + uint256 /* arbTxCallValue */, + uint256 /* maxSubmissionCost */, + address /* submissionRefundAddress */, + address /* valueRefundAddress */, + uint256 /* maxGas */, + uint256 /* gasPriceBid */, + bytes calldata /* data */ ) external payable override returns (uint256) { return 0; } - function depositEth(address destAddr) external payable override returns (uint256) { + function depositEth(address /* destAddr */) external payable override returns (uint256) { return 0; } function depositEthRetryable( - address destAddr, - uint256 maxSubmissionCost, - uint256 maxGas, - uint256 maxGasPrice + address /* destAddr */, + uint256 /* maxSubmissionCost */, + uint256 /* maxGas */, + uint256 /* maxGasPrice */ ) external payable override returns (uint256) { return 0; } - function bridge() external view override returns (IBridge) { + function bridge() external pure override returns (IBridge) { return IBridge(address(0)); } diff --git a/contracts/src/v0.8/tests/MockOptimismL1CrossDomainMessenger.sol b/contracts/src/v0.8/tests/MockOptimismL1CrossDomainMessenger.sol index 3184e7bb4a..a92ff8fb55 100644 --- a/contracts/src/v0.8/tests/MockOptimismL1CrossDomainMessenger.sol +++ b/contracts/src/v0.8/tests/MockOptimismL1CrossDomainMessenger.sol @@ -8,7 +8,7 @@ contract MockOptimismL1CrossDomainMessenger is IL1CrossDomainMessenger { uint256 private s_nonce; // slither-disable-next-line external-function - function xDomainMessageSender() public view returns (address) { + function xDomainMessageSender() public pure returns (address) { return address(0); } diff --git a/contracts/src/v0.8/vendor/@eth-optimism/contracts/v0.4.7/contracts/optimistic-ethereum/iOVM/bridge/messaging/iOVM_CrossDomainMessenger.sol b/contracts/src/v0.8/vendor/@eth-optimism/contracts/v0.4.7/contracts/optimistic-ethereum/iOVM/bridge/messaging/iOVM_CrossDomainMessenger.sol index 6d74788e35..8b5aad82e5 100644 --- a/contracts/src/v0.8/vendor/@eth-optimism/contracts/v0.4.7/contracts/optimistic-ethereum/iOVM/bridge/messaging/iOVM_CrossDomainMessenger.sol +++ b/contracts/src/v0.8/vendor/@eth-optimism/contracts/v0.4.7/contracts/optimistic-ethereum/iOVM/bridge/messaging/iOVM_CrossDomainMessenger.sol @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: MIT pragma solidity >=0.7.6 <0.9.0; /** @@ -28,9 +29,5 @@ interface iOVM_CrossDomainMessenger { * @param _message Message to send to the target. * @param _gasLimit Gas limit for the provided message. */ - function sendMessage( - address _target, - bytes calldata _message, - uint32 _gasLimit - ) external; + function sendMessage(address _target, bytes calldata _message, uint32 _gasLimit) external; } diff --git a/contracts/src/v0.8/vrf/testhelpers/VRFCoordinatorTestV2.sol b/contracts/src/v0.8/vrf/testhelpers/VRFCoordinatorTestV2.sol new file mode 100644 index 0000000000..04d09e2b9c --- /dev/null +++ b/contracts/src/v0.8/vrf/testhelpers/VRFCoordinatorTestV2.sol @@ -0,0 +1,837 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.4; + +import {LinkTokenInterface} from "../../shared/interfaces/LinkTokenInterface.sol"; +import {BlockhashStoreInterface} from "../interfaces/BlockhashStoreInterface.sol"; +import {AggregatorV3Interface} from "../../shared/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"; + +contract VRFCoordinatorTestV2 is + VRF, + ConfirmedOwner, + TypeAndVersionInterface, + VRFCoordinatorV2Interface, + IERC677Receiver +{ + LinkTokenInterface public immutable LINK; + AggregatorV3Interface public immutable LINK_ETH_FEED; + BlockhashStoreInterface public immutable BLOCKHASH_STORE; + + // 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 subId, 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); + // We use the subscription struct (1 word) + // at fulfillment time. + 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 used for all consumer requests. + uint64 reqCount; // For fee tiers + } + // 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 */ /* subId */ /* nonce */ private s_consumers; + mapping(uint64 => SubscriptionConfig) /* subId */ /* subscriptionConfig */ private s_subscriptionConfigs; + mapping(uint64 => Subscription) /* subId */ /* 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_currentSubId; + // 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 subId, address owner); + event SubscriptionFunded(uint64 indexed subId, uint256 oldBalance, uint256 newBalance); + event SubscriptionConsumerAdded(uint64 indexed subId, address consumer); + event SubscriptionConsumerRemoved(uint64 indexed subId, address consumer); + event SubscriptionCanceled(uint64 indexed subId, address to, uint256 amount); + event SubscriptionOwnerTransferRequested(uint64 indexed subId, address from, address to); + event SubscriptionOwnerTransferred(uint64 indexed subId, address from, address to); + + // Set this maximum to 200 to give us a 56 block window to fulfill + // the request before requiring the block hash feeder. + uint16 public constant MAX_REQUEST_CONFIRMATIONS = 200; + uint32 public constant MAX_NUM_WORDS = 500; + // 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; + error InvalidRequestConfirmations(uint16 have, uint16 min, uint16 max); + error GasLimitTooBig(uint32 have, uint32 want); + error NumWordsTooBig(uint32 have, uint32 want); + 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); + error PaymentTooLarge(); + error Reentrant(); + + struct RequestCommitment { + uint64 blockNum; + uint64 subId; + uint32 callbackGasLimit; + uint32 numWords; + address sender; + } + mapping(bytes32 => address) /* keyHash */ /* oracle */ private s_provingKeys; + bytes32[] private s_provingKeyHashes; + mapping(address => uint96) /* oracle */ /* LINK balance */ private s_withdrawableTokens; + mapping(uint256 => bytes32) /* requestID */ /* commitment */ private s_requestCommitments; + event ProvingKeyRegistered(bytes32 keyHash, address indexed oracle); + event ProvingKeyDeregistered(bytes32 keyHash, address indexed oracle); + event RandomWordsRequested( + bytes32 indexed keyHash, + uint256 requestId, + uint256 preSeed, + uint64 indexed subId, + uint16 minimumRequestConfirmations, + uint32 callbackGasLimit, + uint32 numWords, + address indexed sender + ); + event RandomWordsFulfilled(uint256 indexed requestId, uint256 outputSeed, uint96 payment, bool success); + + struct Config { + uint16 minimumRequestConfirmations; + 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 oracle payment after we calculate the payment. + // We make it configurable in case those operations are repriced. + uint32 gasAfterPaymentCalculation; + } + int256 private s_fallbackWeiPerUnitLink; + Config private s_config; + FeeConfig private s_feeConfig; + struct FeeConfig { + // Flat fee charged per fulfillment in millionths of link + // So fee range is [0, 2^32/10^6]. + uint32 fulfillmentFlatFeeLinkPPMTier1; + uint32 fulfillmentFlatFeeLinkPPMTier2; + uint32 fulfillmentFlatFeeLinkPPMTier3; + uint32 fulfillmentFlatFeeLinkPPMTier4; + uint32 fulfillmentFlatFeeLinkPPMTier5; + uint24 reqsForTier2; + uint24 reqsForTier3; + uint24 reqsForTier4; + uint24 reqsForTier5; + } + event ConfigSet( + uint16 minimumRequestConfirmations, + uint32 maxGasLimit, + uint32 stalenessSeconds, + uint32 gasAfterPaymentCalculation, + int256 fallbackWeiPerUnitLink, + FeeConfig feeConfig + ); + + constructor(address link, address blockhashStore, address linkEthFeed) ConfirmedOwner(msg.sender) { + LINK = LinkTokenInterface(link); + LINK_ETH_FEED = AggregatorV3Interface(linkEthFeed); + BLOCKHASH_STORE = BlockhashStoreInterface(blockhashStore); + } + + /** + * @notice Registers a proving key to an oracle. + * @param oracle address of the oracle + * @param publicProvingKey key that oracle can use to submit vrf fulfillments + */ + function registerProvingKey(address oracle, uint256[2] calldata publicProvingKey) external onlyOwner { + bytes32 kh = hashOfKey(publicProvingKey); + if (s_provingKeys[kh] != address(0)) { + revert ProvingKeyAlreadyRegistered(kh); + } + s_provingKeys[kh] = oracle; + s_provingKeyHashes.push(kh); + emit ProvingKeyRegistered(kh, oracle); + } + + /** + * @notice Deregisters a proving key to an oracle. + * @param publicProvingKey key that oracle can use to submit vrf fulfillments + */ + function deregisterProvingKey(uint256[2] calldata publicProvingKey) external onlyOwner { + bytes32 kh = hashOfKey(publicProvingKey); + address oracle = s_provingKeys[kh]; + if (oracle == address(0)) { + revert NoSuchProvingKey(kh); + } + delete s_provingKeys[kh]; + for (uint256 i = 0; i < s_provingKeyHashes.length; i++) { + if (s_provingKeyHashes[i] == kh) { + bytes32 last = s_provingKeyHashes[s_provingKeyHashes.length - 1]; + // Copy last element and overwrite kh to be deleted with it + s_provingKeyHashes[i] = last; + s_provingKeyHashes.pop(); + } + } + emit ProvingKeyDeregistered(kh, oracle); + } + + /** + * @notice Returns the proving key hash key associated with this public key + * @param publicKey the key to return the hash of + */ + function hashOfKey(uint256[2] memory publicKey) public pure returns (bytes32) { + return keccak256(abi.encode(publicKey)); + } + + /** + * @notice Sets the configuration of the vrfv2 coordinator + * @param minimumRequestConfirmations global min for request confirmations + * @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 feeConfig fee tier configuration + */ + function setConfig( + uint16 minimumRequestConfirmations, + uint32 maxGasLimit, + uint32 stalenessSeconds, + uint32 gasAfterPaymentCalculation, + int256 fallbackWeiPerUnitLink, + FeeConfig memory feeConfig + ) external onlyOwner { + if (minimumRequestConfirmations > MAX_REQUEST_CONFIRMATIONS) { + revert InvalidRequestConfirmations( + minimumRequestConfirmations, + minimumRequestConfirmations, + MAX_REQUEST_CONFIRMATIONS + ); + } + if (fallbackWeiPerUnitLink <= 0) { + revert InvalidLinkWeiPrice(fallbackWeiPerUnitLink); + } + s_config = Config({ + minimumRequestConfirmations: minimumRequestConfirmations, + maxGasLimit: maxGasLimit, + stalenessSeconds: stalenessSeconds, + gasAfterPaymentCalculation: gasAfterPaymentCalculation, + reentrancyLock: false + }); + s_feeConfig = feeConfig; + s_fallbackWeiPerUnitLink = fallbackWeiPerUnitLink; + emit ConfigSet( + minimumRequestConfirmations, + maxGasLimit, + stalenessSeconds, + gasAfterPaymentCalculation, + fallbackWeiPerUnitLink, + s_feeConfig + ); + } + + function getConfig() + external + view + returns ( + uint16 minimumRequestConfirmations, + uint32 maxGasLimit, + uint32 stalenessSeconds, + uint32 gasAfterPaymentCalculation + ) + { + return ( + s_config.minimumRequestConfirmations, + s_config.maxGasLimit, + s_config.stalenessSeconds, + s_config.gasAfterPaymentCalculation + ); + } + + function getFeeConfig() + external + view + returns ( + uint32 fulfillmentFlatFeeLinkPPMTier1, + uint32 fulfillmentFlatFeeLinkPPMTier2, + uint32 fulfillmentFlatFeeLinkPPMTier3, + uint32 fulfillmentFlatFeeLinkPPMTier4, + uint32 fulfillmentFlatFeeLinkPPMTier5, + uint24 reqsForTier2, + uint24 reqsForTier3, + uint24 reqsForTier4, + uint24 reqsForTier5 + ) + { + return ( + s_feeConfig.fulfillmentFlatFeeLinkPPMTier1, + s_feeConfig.fulfillmentFlatFeeLinkPPMTier2, + s_feeConfig.fulfillmentFlatFeeLinkPPMTier3, + s_feeConfig.fulfillmentFlatFeeLinkPPMTier4, + s_feeConfig.fulfillmentFlatFeeLinkPPMTier5, + s_feeConfig.reqsForTier2, + s_feeConfig.reqsForTier3, + s_feeConfig.reqsForTier4, + s_feeConfig.reqsForTier5 + ); + } + + function getTotalBalance() external view returns (uint256) { + return s_totalBalance; + } + + function getFallbackWeiPerUnitLink() external view returns (int256) { + return s_fallbackWeiPerUnitLink; + } + + /** + * @notice Owner cancel subscription, sends remaining link directly to the subscription owner. + * @param subId subscription id + * @dev notably can be called even if there are pending requests, outstanding ones may fail onchain + */ + function ownerCancelSubscription(uint64 subId) external onlyOwner { + if (s_subscriptionConfigs[subId].owner == address(0)) { + revert InvalidSubscription(); + } + cancelSubscriptionHelper(subId, s_subscriptionConfigs[subId].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 VRFCoordinatorV2Interface + */ + function getRequestConfig() external view override returns (uint16, uint32, bytes32[] memory) { + return (s_config.minimumRequestConfirmations, s_config.maxGasLimit, s_provingKeyHashes); + } + + /** + * @inheritdoc VRFCoordinatorV2Interface + */ + function requestRandomWords( + bytes32 keyHash, + uint64 subId, + uint16 requestConfirmations, + uint32 callbackGasLimit, + uint32 numWords + ) external override nonReentrant returns (uint256) { + // Input validation using the subscription storage. + if (s_subscriptionConfigs[subId].owner == address(0)) { + revert InvalidSubscription(); + } + // Its 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[msg.sender][subId]; + if (currentNonce == 0) { + revert InvalidConsumer(subId, msg.sender); + } + // Input validation using the config storage word. + if ( + requestConfirmations < s_config.minimumRequestConfirmations || requestConfirmations > MAX_REQUEST_CONFIRMATIONS + ) { + revert InvalidRequestConfirmations( + requestConfirmations, + s_config.minimumRequestConfirmations, + MAX_REQUEST_CONFIRMATIONS + ); + } + // No lower bound on the requested gas limit. A user could request 0 + // and they would simply be billed for the proof verification and wouldn't be + // able to do anything with the random value. + if (callbackGasLimit > s_config.maxGasLimit) { + revert GasLimitTooBig(callbackGasLimit, s_config.maxGasLimit); + } + if (numWords > MAX_NUM_WORDS) { + revert NumWordsTooBig(numWords, MAX_NUM_WORDS); + } + // Note we do not check whether the keyHash is valid to save gas. + // 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); + + s_requestCommitments[requestId] = keccak256( + abi.encode(requestId, block.number, subId, callbackGasLimit, numWords, msg.sender) + ); + emit RandomWordsRequested( + keyHash, + requestId, + preSeed, + subId, + requestConfirmations, + callbackGasLimit, + numWords, + msg.sender + ); + s_consumers[msg.sender][subId] = nonce; + + return requestId; + } + + /** + * @notice Get request commitment + * @param requestId id of request + * @dev used to determine if a request is fulfilled or not + */ + function getCommitment(uint256 requestId) external view returns (bytes32) { + return s_requestCommitments[requestId]; + } + + function computeRequestId( + bytes32 keyHash, + address sender, + uint64 subId, + uint64 nonce + ) private pure returns (uint256, uint256) { + uint256 preSeed = uint256(keccak256(abi.encode(keyHash, sender, subId, nonce))); + return (uint256(keccak256(abi.encode(keyHash, preSeed))), preSeed); + } + + /** + * @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() + // 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, GAS_FOR_CALL_EXACT_CHECK) { + revert(0, 0) + } + g := sub(g, GAS_FOR_CALL_EXACT_CHECK) + // 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; + } + + function getRandomnessFromProof( + Proof memory proof, + RequestCommitment memory rc + ) private view returns (bytes32 keyHash, uint256 requestId, uint256 randomness) { + keyHash = hashOfKey(proof.pk); + // Only registered proving keys are permitted. + address oracle = s_provingKeys[keyHash]; + if (oracle == address(0)) { + revert NoSuchProvingKey(keyHash); + } + requestId = uint256(keccak256(abi.encode(keyHash, proof.seed))); + bytes32 commitment = s_requestCommitments[requestId]; + if (commitment == 0) { + revert NoCorrespondingRequest(); + } + if ( + commitment != keccak256(abi.encode(requestId, rc.blockNum, rc.subId, rc.callbackGasLimit, rc.numWords, rc.sender)) + ) { + revert IncorrectCommitment(); + } + + bytes32 blockHash = blockhash(rc.blockNum); + if (blockHash == bytes32(0)) { + blockHash = BLOCKHASH_STORE.getBlockhash(rc.blockNum); + if (blockHash == bytes32(0)) { + revert BlockhashNotInStore(rc.blockNum); + } + } + + // 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 + } + + /* + * @notice Compute fee based on the request count + * @param reqCount number of requests + * @return feePPM fee in LINK PPM + */ + function getFeeTier(uint64 reqCount) public view returns (uint32) { + FeeConfig memory fc = s_feeConfig; + if (0 <= reqCount && reqCount <= fc.reqsForTier2) { + return fc.fulfillmentFlatFeeLinkPPMTier1; + } + if (fc.reqsForTier2 < reqCount && reqCount <= fc.reqsForTier3) { + return fc.fulfillmentFlatFeeLinkPPMTier2; + } + if (fc.reqsForTier3 < reqCount && reqCount <= fc.reqsForTier4) { + return fc.fulfillmentFlatFeeLinkPPMTier3; + } + if (fc.reqsForTier4 < reqCount && reqCount <= fc.reqsForTier5) { + return fc.fulfillmentFlatFeeLinkPPMTier4; + } + return fc.fulfillmentFlatFeeLinkPPMTier5; + } + + /* + * @notice Fulfill a randomness request + * @param proof contains the proof and randomness + * @param rc request commitment pre-image, committed to at request time + * @return payment amount billed to the subscription + * @dev simulated offchain to determine if sufficient balance is present to fulfill the request + */ + function fulfillRandomWords(Proof memory proof, RequestCommitment memory rc) external nonReentrant returns (uint96) { + uint256 startGas = gasleft(); + (bytes32 keyHash, uint256 requestId, uint256 randomness) = getRandomnessFromProof(proof, rc); + + uint256[] memory randomWords = new uint256[](rc.numWords); + for (uint256 i = 0; i < rc.numWords; i++) { + randomWords[i] = uint256(keccak256(abi.encode(randomness, i))); + } + + delete s_requestCommitments[requestId]; + VRFConsumerBaseV2 v; + bytes memory resp = abi.encodeWithSelector(v.rawFulfillRandomWords.selector, requestId, randomWords); + // Call with explicitly the amount of callback gas requested + // 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 + // to give the callee their requested amount. + s_config.reentrancyLock = true; + bool success = callWithExactGas(rc.callbackGasLimit, rc.sender, resp); + s_config.reentrancyLock = false; + + // Increment the req count for fee tier selection. + uint64 reqCount = s_subscriptions[rc.subId].reqCount; + s_subscriptions[rc.subId].reqCount += 1; + + // 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. + // 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( + startGas, + s_config.gasAfterPaymentCalculation, + getFeeTier(reqCount), + tx.gasprice + ); + if (s_subscriptions[rc.subId].balance < payment) { + revert InsufficientBalance(); + } + s_subscriptions[rc.subId].balance -= payment; + s_withdrawableTokens[s_provingKeys[keyHash]] += payment; + // Include payment in the event for tracking costs. + emit RandomWordsFulfilled(requestId, randomness, payment, success); + return payment; + } + + // Get the amount of gas used for fulfillment + function calculatePaymentAmount( + uint256 startGas, + uint256 gasAfterPaymentCalculation, + uint32 fulfillmentFlatFeeLinkPPM, + uint256 weiPerUnitGas + ) internal view returns (uint96) { + int256 weiPerUnitLink; + weiPerUnitLink = getFeedData(); + if (weiPerUnitLink <= 0) { + revert InvalidLinkWeiPrice(weiPerUnitLink); + } + // (1e18 juels/link) (wei/gas * gas) / (wei/link) = juels + uint256 paymentNoFee = (1e18 * weiPerUnitGas * (gasAfterPaymentCalculation + startGas - gasleft())) / + uint256(weiPerUnitLink); + uint256 fee = 1e12 * uint256(fulfillmentFlatFeeLinkPPM); + if (paymentNoFee > (1e27 - fee)) { + revert PaymentTooLarge(); // Payment + fee cannot be more than all of the link in existence. + } + return uint96(paymentNoFee + fee); + } + + function getFeedData() private view returns (int256) { + uint32 stalenessSeconds = s_config.stalenessSeconds; + bool staleFallback = stalenessSeconds > 0; + uint256 timestamp; + int256 weiPerUnitLink; + (, weiPerUnitLink, , 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 + * @param recipient where to send the funds + * @param amount amount to withdraw + */ + function oracleWithdraw(address recipient, uint96 amount) external nonReentrant { + 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 { + if (msg.sender != address(LINK)) { + revert OnlyCallableFromLink(); + } + if (data.length != 32) { + revert InvalidCalldata(); + } + uint64 subId = abi.decode(data, (uint64)); + if (s_subscriptionConfigs[subId].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[subId].balance; + s_subscriptions[subId].balance += uint96(amount); + s_totalBalance += uint96(amount); + emit SubscriptionFunded(subId, oldBalance, oldBalance + amount); + } + + function getCurrentSubId() external view returns (uint64) { + return s_currentSubId; + } + + /** + * @inheritdoc VRFCoordinatorV2Interface + */ + function getSubscription( + uint64 subId + ) external view override returns (uint96 balance, uint64 reqCount, address owner, address[] memory consumers) { + if (s_subscriptionConfigs[subId].owner == address(0)) { + revert InvalidSubscription(); + } + return ( + s_subscriptions[subId].balance, + s_subscriptions[subId].reqCount, + s_subscriptionConfigs[subId].owner, + s_subscriptionConfigs[subId].consumers + ); + } + + /** + * @inheritdoc VRFCoordinatorV2Interface + */ + function createSubscription() external override nonReentrant returns (uint64) { + s_currentSubId++; + uint64 currentSubId = s_currentSubId; + address[] memory consumers = new address[](0); + s_subscriptions[currentSubId] = Subscription({balance: 0, reqCount: 0}); + s_subscriptionConfigs[currentSubId] = SubscriptionConfig({ + owner: msg.sender, + requestedOwner: address(0), + consumers: consumers + }); + + emit SubscriptionCreated(currentSubId, msg.sender); + return currentSubId; + } + + /** + * @inheritdoc VRFCoordinatorV2Interface + */ + function requestSubscriptionOwnerTransfer( + uint64 subId, + address newOwner + ) external override onlySubOwner(subId) nonReentrant { + // Proposing to address(0) would never be claimable so don't need to check. + if (s_subscriptionConfigs[subId].requestedOwner != newOwner) { + s_subscriptionConfigs[subId].requestedOwner = newOwner; + emit SubscriptionOwnerTransferRequested(subId, msg.sender, newOwner); + } + } + + /** + * @inheritdoc VRFCoordinatorV2Interface + */ + function acceptSubscriptionOwnerTransfer(uint64 subId) external override nonReentrant { + if (s_subscriptionConfigs[subId].owner == address(0)) { + revert InvalidSubscription(); + } + if (s_subscriptionConfigs[subId].requestedOwner != msg.sender) { + revert MustBeRequestedOwner(s_subscriptionConfigs[subId].requestedOwner); + } + address oldOwner = s_subscriptionConfigs[subId].owner; + s_subscriptionConfigs[subId].owner = msg.sender; + s_subscriptionConfigs[subId].requestedOwner = address(0); + emit SubscriptionOwnerTransferred(subId, oldOwner, msg.sender); + } + + /** + * @inheritdoc VRFCoordinatorV2Interface + */ + function removeConsumer(uint64 subId, address consumer) external override onlySubOwner(subId) nonReentrant { + if (s_consumers[consumer][subId] == 0) { + revert InvalidConsumer(subId, consumer); + } + // Note bounded by MAX_CONSUMERS + address[] memory consumers = s_subscriptionConfigs[subId].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[subId].consumers[i] = last; + // Storage remove last element + s_subscriptionConfigs[subId].consumers.pop(); + break; + } + } + delete s_consumers[consumer][subId]; + emit SubscriptionConsumerRemoved(subId, consumer); + } + + /** + * @inheritdoc VRFCoordinatorV2Interface + */ + function addConsumer(uint64 subId, address consumer) external override onlySubOwner(subId) nonReentrant { + // Already maxed, cannot add any more consumers. + if (s_subscriptionConfigs[subId].consumers.length == MAX_CONSUMERS) { + revert TooManyConsumers(); + } + if (s_consumers[consumer][subId] != 0) { + // Idempotence - do nothing if already added. + // Ensures uniqueness in s_subscriptions[subId].consumers. + return; + } + // Initialize the nonce to 1, indicating the consumer is allocated. + s_consumers[consumer][subId] = 1; + s_subscriptionConfigs[subId].consumers.push(consumer); + + emit SubscriptionConsumerAdded(subId, consumer); + } + + /** + * @inheritdoc VRFCoordinatorV2Interface + */ + function cancelSubscription(uint64 subId, address to) external override onlySubOwner(subId) nonReentrant { + if (pendingRequestExists(subId)) { + revert PendingRequestExists(); + } + cancelSubscriptionHelper(subId, to); + } + + function cancelSubscriptionHelper(uint64 subId, address to) private nonReentrant { + SubscriptionConfig memory subConfig = s_subscriptionConfigs[subId]; + Subscription memory sub = s_subscriptions[subId]; + uint96 balance = sub.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]][subId]; + } + delete s_subscriptionConfigs[subId]; + delete s_subscriptions[subId]; + s_totalBalance -= balance; + if (!LINK.transfer(to, uint256(balance))) { + revert InsufficientBalance(); + } + emit SubscriptionCanceled(subId, to, balance); + } + + /** + * @inheritdoc VRFCoordinatorV2Interface + * @dev Looping is bounded to MAX_CONSUMERS*(number of keyhashes). + * @dev Used to disable subscription canceling while outstanding request are present. + */ + function pendingRequestExists(uint64 subId) public view override returns (bool) { + 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( + s_provingKeyHashes[j], + subConfig.consumers[i], + subId, + s_consumers[subConfig.consumers[i]][subId] + ); + if (s_requestCommitments[reqId] != 0) { + return true; + } + } + } + return false; + } + + modifier onlySubOwner(uint64 subId) { + address owner = s_subscriptionConfigs[subId].owner; + if (owner == address(0)) { + revert InvalidSubscription(); + } + if (msg.sender != owner) { + revert MustBeSubOwner(owner); + } + _; + } + + modifier nonReentrant() { + if (s_config.reentrancyLock) { + revert Reentrant(); + } + _; + } + + /** + * @notice The type and version of this contract + * @return Type and version string + */ + function typeAndVersion() external pure virtual override returns (string memory) { + return "VRFCoordinatorV2 1.0.0"; + } +} diff --git a/contracts/src/v0.8/vrf/testhelpers/VRFMockETHLINKAggregator.sol b/contracts/src/v0.8/vrf/testhelpers/VRFMockETHLINKAggregator.sol new file mode 100644 index 0000000000..86c7720243 --- /dev/null +++ b/contracts/src/v0.8/vrf/testhelpers/VRFMockETHLINKAggregator.sol @@ -0,0 +1,53 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +import "../../shared/interfaces/AggregatorV3Interface.sol"; + +contract VRFMockETHLINKAggregator is AggregatorV3Interface { + int256 public answer; + uint256 private blockTimestampDeduction = 0; + + constructor(int256 _answer) public { + answer = _answer; + } + + function decimals() external view override returns (uint8) { + return 18; + } + + function description() external view override returns (string memory) { + return "VRFMockETHLINKAggregator"; + } + + function version() external view override returns (uint256) { + return 1; + } + + function getRoundData( + uint80 _roundId + ) + external + view + override + returns (uint80 roundId, int256 ans, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound) + { + return (1, answer, getDeductedBlockTimestamp(), getDeductedBlockTimestamp(), 1); + } + + function latestRoundData() + external + view + override + returns (uint80 roundId, int256 ans, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound) + { + return (1, answer, getDeductedBlockTimestamp(), getDeductedBlockTimestamp(), 1); + } + + function getDeductedBlockTimestamp() internal view returns (uint256) { + return block.timestamp - blockTimestampDeduction; + } + + function setBlockTimestampDeduction(uint256 _blockTimestampDeduction) external { + blockTimestampDeduction = _blockTimestampDeduction; + } +} diff --git a/contracts/src/v0.8/vrf/testhelpers/VRFV2LoadTestWithMetrics.sol b/contracts/src/v0.8/vrf/testhelpers/VRFV2LoadTestWithMetrics.sol index d364e5002b..fa44b3eee3 100644 --- a/contracts/src/v0.8/vrf/testhelpers/VRFV2LoadTestWithMetrics.sol +++ b/contracts/src/v0.8/vrf/testhelpers/VRFV2LoadTestWithMetrics.sol @@ -3,16 +3,16 @@ pragma solidity ^0.8.0; import {VRFCoordinatorV2Interface} from "../interfaces/VRFCoordinatorV2Interface.sol"; import {VRFConsumerBaseV2} from "../VRFConsumerBaseV2.sol"; -import {ConfirmedOwner} from "../../shared/access/ConfirmedOwner.sol"; import {ChainSpecificUtil} from "../../ChainSpecificUtil.sol"; +import {LinkTokenInterface} from "../../shared/interfaces/LinkTokenInterface.sol"; /** * @title The VRFLoadTestExternalSubOwner contract. * @notice Allows making many VRF V2 randomness requests in a single transaction for load testing. */ -contract VRFV2LoadTestWithMetrics is VRFConsumerBaseV2, ConfirmedOwner { +contract VRFV2LoadTestWithMetrics is VRFConsumerBaseV2 { VRFCoordinatorV2Interface public immutable COORDINATOR; - + LinkTokenInterface public LINKTOKEN; uint256 public s_responseCount; uint256 public s_requestCount; uint256 public s_averageFulfillmentInMillions = 0; // in millions for better precision @@ -21,6 +21,8 @@ contract VRFV2LoadTestWithMetrics is VRFConsumerBaseV2, ConfirmedOwner { uint256 public s_lastRequestId; mapping(uint256 => uint256) internal requestHeights; // requestIds to block number when rand request was made + event SubscriptionCreatedFundedAndConsumerAdded(uint64 subId, address consumer, uint256 amount); + struct RequestStatus { bool fulfilled; uint256[] randomWords; @@ -32,7 +34,7 @@ contract VRFV2LoadTestWithMetrics is VRFConsumerBaseV2, ConfirmedOwner { mapping(uint256 => RequestStatus) /* requestId */ /* requestStatus */ public s_requests; - constructor(address _vrfCoordinator) VRFConsumerBaseV2(_vrfCoordinator) ConfirmedOwner(msg.sender) { + constructor(address _vrfCoordinator) VRFConsumerBaseV2(_vrfCoordinator) { COORDINATOR = VRFCoordinatorV2Interface(_vrfCoordinator); } @@ -64,28 +66,30 @@ contract VRFV2LoadTestWithMetrics is VRFConsumerBaseV2, ConfirmedOwner { uint32 _callbackGasLimit, uint32 _numWords, uint16 _requestCount - ) external onlyOwner { - for (uint16 i = 0; i < _requestCount; i++) { - uint256 requestId = COORDINATOR.requestRandomWords( - _keyHash, - _subId, - _requestConfirmations, - _callbackGasLimit, - _numWords - ); - s_lastRequestId = requestId; - uint256 requestBlockNumber = ChainSpecificUtil._getBlockNumber(); - s_requests[requestId] = RequestStatus({ - randomWords: new uint256[](0), - fulfilled: false, - requestTimestamp: block.timestamp, - fulfilmentTimestamp: 0, - requestBlockNumber: requestBlockNumber, - fulfilmentBlockNumber: 0 - }); - s_requestCount++; - requestHeights[requestId] = requestBlockNumber; - } + ) external { + _makeLoadTestRequests(_subId, _requestConfirmations, _keyHash, _callbackGasLimit, _numWords, _requestCount); + } + + function requestRandomWordsWithForceFulfill( + uint16 _requestConfirmations, + bytes32 _keyHash, + uint32 _callbackGasLimit, + uint32 _numWords, + uint16 _requestCount, + uint256 _subTopUpAmount, + address _link + ) external { + // create a subscription, address(this) will be the owner + uint64 _subId = COORDINATOR.createSubscription(); + // add address(this) as a consumer on the subscription + COORDINATOR.addConsumer(_subId, address(this)); + topUpSubscription(_subId, _subTopUpAmount, _link); + emit SubscriptionCreatedFundedAndConsumerAdded(_subId, address(this), _subTopUpAmount); + + _makeLoadTestRequests(_subId, _requestConfirmations, _keyHash, _callbackGasLimit, _numWords, _requestCount); + + COORDINATOR.removeConsumer(_subId, address(this)); + COORDINATOR.cancelSubscription(_subId, msg.sender); } function reset() external { @@ -120,4 +124,40 @@ contract VRFV2LoadTestWithMetrics is VRFConsumerBaseV2, ConfirmedOwner { request.fulfilmentBlockNumber ); } + + function _makeLoadTestRequests( + uint64 _subId, + uint16 _requestConfirmations, + bytes32 _keyHash, + uint32 _callbackGasLimit, + uint32 _numWords, + uint16 _requestCount + ) internal { + for (uint16 i = 0; i < _requestCount; i++) { + uint256 requestId = COORDINATOR.requestRandomWords( + _keyHash, + _subId, + _requestConfirmations, + _callbackGasLimit, + _numWords + ); + s_lastRequestId = requestId; + uint256 requestBlockNumber = ChainSpecificUtil._getBlockNumber(); + s_requests[requestId] = RequestStatus({ + randomWords: new uint256[](0), + fulfilled: false, + requestTimestamp: block.timestamp, + fulfilmentTimestamp: 0, + requestBlockNumber: requestBlockNumber, + fulfilmentBlockNumber: 0 + }); + s_requestCount++; + requestHeights[requestId] = requestBlockNumber; + } + } + + function topUpSubscription(uint64 _subId, uint256 _amount, address _link) public { + LINKTOKEN = LinkTokenInterface(_link); + LINKTOKEN.transferAndCall(address(COORDINATOR), _amount, abi.encode(_subId)); + } } diff --git a/contracts/src/v0.8/vrf/testhelpers/VRFV2OwnerTestConsumer.sol b/contracts/src/v0.8/vrf/testhelpers/VRFV2OwnerTestConsumer.sol index dd1af80a92..5961f4e5d4 100644 --- a/contracts/src/v0.8/vrf/testhelpers/VRFV2OwnerTestConsumer.sol +++ b/contracts/src/v0.8/vrf/testhelpers/VRFV2OwnerTestConsumer.sol @@ -5,9 +5,11 @@ import {VRFCoordinatorV2Interface} from "../interfaces/VRFCoordinatorV2Interface import {VRFConsumerBaseV2} from "../VRFConsumerBaseV2.sol"; import {ConfirmedOwner} from "../../shared/access/ConfirmedOwner.sol"; import {ChainSpecificUtil} from "../../ChainSpecificUtil.sol"; +import {LinkTokenInterface} from "../../shared/interfaces/LinkTokenInterface.sol"; contract VRFV2OwnerTestConsumer is VRFConsumerBaseV2, ConfirmedOwner { VRFCoordinatorV2Interface public COORDINATOR; + LinkTokenInterface public LINKTOKEN; uint64 public subId; uint256 public s_responseCount; uint256 public s_requestCount; @@ -17,6 +19,8 @@ contract VRFV2OwnerTestConsumer is VRFConsumerBaseV2, ConfirmedOwner { uint256 public s_lastRequestId; mapping(uint256 => uint256) internal requestHeights; // requestIds to block number when rand request was made + event SubscriptionCreatedFundedAndConsumerAdded(uint64 subId, address consumer, uint256 amount); + struct RequestStatus { bool fulfilled; uint256[] randomWords; @@ -28,12 +32,9 @@ contract VRFV2OwnerTestConsumer is VRFConsumerBaseV2, ConfirmedOwner { mapping(uint256 => RequestStatus) /* requestId */ /* requestStatus */ public s_requests; - constructor(address _vrfCoordinator) VRFConsumerBaseV2(_vrfCoordinator) ConfirmedOwner(msg.sender) { + constructor(address _vrfCoordinator, address _link) VRFConsumerBaseV2(_vrfCoordinator) ConfirmedOwner(msg.sender) { COORDINATOR = VRFCoordinatorV2Interface(_vrfCoordinator); - // create a subscription, address(this) will be the owner - subId = COORDINATOR.createSubscription(); - // add address(this) as a consumer on the subscription - COORDINATOR.addConsumer(subId, address(this)); + LINKTOKEN = LinkTokenInterface(_link); } function fulfillRandomWords(uint256 _requestId, uint256[] memory _randomWords) internal override { @@ -62,8 +63,16 @@ contract VRFV2OwnerTestConsumer is VRFConsumerBaseV2, ConfirmedOwner { bytes32 _keyHash, uint32 _callbackGasLimit, uint32 _numWords, - uint16 _requestCount + uint16 _requestCount, + uint256 _subTopUpAmount ) external onlyOwner { + // create a subscription, address(this) will be the owner + subId = COORDINATOR.createSubscription(); + // add address(this) as a consumer on the subscription + COORDINATOR.addConsumer(subId, address(this)); + topUpSubscription(_subTopUpAmount); + emit SubscriptionCreatedFundedAndConsumerAdded(subId, address(this), _subTopUpAmount); + for (uint16 i = 0; i < _requestCount; i++) { uint256 requestId = COORDINATOR.requestRandomWords( _keyHash, @@ -122,4 +131,8 @@ contract VRFV2OwnerTestConsumer is VRFConsumerBaseV2, ConfirmedOwner { request.fulfilmentBlockNumber ); } + + function topUpSubscription(uint256 amount) public onlyOwner { + LINKTOKEN.transferAndCall(address(COORDINATOR), amount, abi.encode(subId)); + } } diff --git a/contracts/test/v0.8/automation/AutomationRegistrar2_2.test.ts b/contracts/test/v0.8/automation/AutomationRegistrar2_2.test.ts new file mode 100644 index 0000000000..b758546206 --- /dev/null +++ b/contracts/test/v0.8/automation/AutomationRegistrar2_2.test.ts @@ -0,0 +1,1013 @@ +import { ethers } from 'hardhat' +import { ContractFactory, Contract } from 'ethers' +import { assert, expect } from 'chai' +import { evmRevert } from '../../test-helpers/matchers' +import { getUsers, Personas } from '../../test-helpers/setup' +import { BigNumber, Signer } from 'ethers' +import { MockV3Aggregator__factory as MockV3AggregatorFactory } from '../../../typechain/factories/MockV3Aggregator__factory' +import { UpkeepMock__factory as UpkeepMockFactory } from '../../../typechain/factories/UpkeepMock__factory' +import { MockV3Aggregator } from '../../../typechain/MockV3Aggregator' +import { UpkeepMock } from '../../../typechain/UpkeepMock' +import { toWei } from '../../test-helpers/helpers' +import { IKeeperRegistryMaster as IKeeperRegistry } from '../../../typechain/IKeeperRegistryMaster' +import { AutomationRegistrar2_2 as Registrar } from '../../../typechain/AutomationRegistrar2_2' +import { deployRegistry21 } from './helpers' + +// copied from KeeperRegistryBase2_2.sol +enum Trigger { + CONDITION, + LOG, +} + +let linkTokenFactory: ContractFactory +let mockV3AggregatorFactory: MockV3AggregatorFactory +let upkeepMockFactory: UpkeepMockFactory + +let personas: Personas + +before(async () => { + personas = (await getUsers()).personas + + linkTokenFactory = await ethers.getContractFactory( + 'src/v0.4/LinkToken.sol:LinkToken', + ) + mockV3AggregatorFactory = (await ethers.getContractFactory( + 'src/v0.8/tests/MockV3Aggregator.sol:MockV3Aggregator', + )) as unknown as MockV3AggregatorFactory + upkeepMockFactory = await ethers.getContractFactory('UpkeepMock') +}) + +const errorMsgs = { + onlyOwner: 'revert Only callable by owner', + onlyAdmin: 'OnlyAdminOrOwner()', + hashPayload: 'HashMismatch()', + requestNotFound: 'RequestNotFound()', +} + +describe('AutomationRegistrar2_2', () => { + const upkeepName = 'SampleUpkeep' + + const linkEth = BigNumber.from(300000000) + const gasWei = BigNumber.from(100) + const performGas = BigNumber.from(100000) + const paymentPremiumPPB = BigNumber.from(250000000) + const flatFeeMicroLink = BigNumber.from(0) + const maxAllowedAutoApprove = 5 + const trigger = '0xdeadbeef' + const offchainConfig = '0x01234567' + + const emptyBytes = '0x00' + const stalenessSeconds = BigNumber.from(43820) + const gasCeilingMultiplier = BigNumber.from(1) + const checkGasLimit = BigNumber.from(20000000) + const fallbackGasPrice = BigNumber.from(200) + const fallbackLinkPrice = BigNumber.from(200000000) + const maxCheckDataSize = BigNumber.from(10000) + const maxPerformDataSize = BigNumber.from(10000) + const maxRevertDataSize = BigNumber.from(1000) + const maxPerformGas = BigNumber.from(5000000) + const minUpkeepSpend = BigNumber.from('1000000000000000000') + const amount = BigNumber.from('5000000000000000000') + const amount1 = BigNumber.from('6000000000000000000') + const transcoder = ethers.constants.AddressZero + const upkeepManager = ethers.Wallet.createRandom().address + + // Enum values are not auto exported in ABI so have to manually declare + const autoApproveType_DISABLED = 0 + const autoApproveType_ENABLED_SENDER_ALLOWLIST = 1 + const autoApproveType_ENABLED_ALL = 2 + + let owner: Signer + let admin: Signer + let someAddress: Signer + let registrarOwner: Signer + let stranger: Signer + let requestSender: Signer + + let linkToken: Contract + let linkEthFeed: MockV3Aggregator + let gasPriceFeed: MockV3Aggregator + let mock: UpkeepMock + let registry: IKeeperRegistry + let registrar: Registrar + + beforeEach(async () => { + owner = personas.Default + admin = personas.Neil + someAddress = personas.Ned + registrarOwner = personas.Nelly + stranger = personas.Nancy + requestSender = personas.Norbert + + linkToken = await linkTokenFactory.connect(owner).deploy() + gasPriceFeed = await mockV3AggregatorFactory + .connect(owner) + .deploy(0, gasWei) + linkEthFeed = await mockV3AggregatorFactory + .connect(owner) + .deploy(9, linkEth) + + registry = await deployRegistry21( + owner, + 0, + linkToken.address, + linkEthFeed.address, + gasPriceFeed.address, + ) + + mock = await upkeepMockFactory.deploy() + + const registrarFactory = await ethers.getContractFactory( + 'AutomationRegistrar2_2', + ) + registrar = await registrarFactory + .connect(registrarOwner) + .deploy(linkToken.address, registry.address, minUpkeepSpend, [ + { + triggerType: Trigger.CONDITION, + autoApproveType: autoApproveType_DISABLED, + autoApproveMaxAllowed: 0, + }, + { + triggerType: Trigger.LOG, + autoApproveType: autoApproveType_DISABLED, + autoApproveMaxAllowed: 0, + }, + ]) + + await linkToken + .connect(owner) + .transfer(await requestSender.getAddress(), toWei('1000')) + + const keepers = [ + await personas.Carol.getAddress(), + await personas.Nancy.getAddress(), + await personas.Ned.getAddress(), + await personas.Neil.getAddress(), + ] + const onchainConfig = { + paymentPremiumPPB, + flatFeeMicroLink, + checkGasLimit, + stalenessSeconds, + gasCeilingMultiplier, + minUpkeepSpend, + maxCheckDataSize, + maxPerformDataSize, + maxRevertDataSize, + maxPerformGas, + fallbackGasPrice, + fallbackLinkPrice, + transcoder, + registrars: [registrar.address], + upkeepPrivilegeManager: upkeepManager, + } + await registry + .connect(owner) + .setConfigTypeSafe(keepers, keepers, 1, onchainConfig, 1, '0x') + }) + + describe('#typeAndVersion', () => { + it('uses the correct type and version', async () => { + const typeAndVersion = await registrar.typeAndVersion() + assert.equal(typeAndVersion, 'AutomationRegistrar 2.1.0') + }) + }) + + describe('#register', () => { + it('reverts if not called by the LINK token', async () => { + await evmRevert( + registrar + .connect(someAddress) + .register( + upkeepName, + emptyBytes, + mock.address, + performGas, + await admin.getAddress(), + 0, + emptyBytes, + trigger, + offchainConfig, + amount, + await requestSender.getAddress(), + ), + 'OnlyLink()', + ) + }) + + it('reverts if the amount passed in data mismatches actual amount sent', async () => { + await registrar + .connect(registrarOwner) + .setTriggerConfig( + Trigger.CONDITION, + autoApproveType_ENABLED_ALL, + maxAllowedAutoApprove, + ) + + const abiEncodedBytes = registrar.interface.encodeFunctionData( + 'register', + [ + upkeepName, + emptyBytes, + mock.address, + performGas, + await admin.getAddress(), + 0, + emptyBytes, + trigger, + offchainConfig, + amount1, + await requestSender.getAddress(), + ], + ) + + await evmRevert( + linkToken + .connect(requestSender) + .transferAndCall(registrar.address, amount, abiEncodedBytes), + 'AmountMismatch()', + ) + }) + + it('reverts if the sender passed in data mismatches actual sender', async () => { + const abiEncodedBytes = registrar.interface.encodeFunctionData( + 'register', + [ + upkeepName, + emptyBytes, + mock.address, + performGas, + await admin.getAddress(), + 0, + emptyBytes, + trigger, + offchainConfig, + amount, + await admin.getAddress(), // Should have been requestSender.getAddress() + ], + ) + await evmRevert( + linkToken + .connect(requestSender) + .transferAndCall(registrar.address, amount, abiEncodedBytes), + 'SenderMismatch()', + ) + }) + + it('reverts if the admin address is 0x0000...', async () => { + const abiEncodedBytes = registrar.interface.encodeFunctionData( + 'register', + [ + upkeepName, + emptyBytes, + mock.address, + performGas, + '0x0000000000000000000000000000000000000000', + 0, + emptyBytes, + trigger, + offchainConfig, + amount, + await requestSender.getAddress(), + ], + ) + + await evmRevert( + linkToken + .connect(requestSender) + .transferAndCall(registrar.address, amount, abiEncodedBytes), + 'RegistrationRequestFailed()', + ) + }) + + it('Auto Approve ON - registers an upkeep on KeeperRegistry instantly and emits both RegistrationRequested and RegistrationApproved events', async () => { + //set auto approve ON with high threshold limits + await registrar + .connect(registrarOwner) + .setTriggerConfig( + Trigger.CONDITION, + autoApproveType_ENABLED_ALL, + maxAllowedAutoApprove, + ) + + //register with auto approve ON + const abiEncodedBytes = registrar.interface.encodeFunctionData( + 'register', + [ + upkeepName, + emptyBytes, + mock.address, + performGas, + await admin.getAddress(), + 0, + emptyBytes, + trigger, + offchainConfig, + amount, + await requestSender.getAddress(), + ], + ) + const tx = await linkToken + .connect(requestSender) + .transferAndCall(registrar.address, amount, abiEncodedBytes) + + const [id] = await registry.getActiveUpkeepIDs(0, 1) + + //confirm if a new upkeep has been registered and the details are the same as the one just registered + const newupkeep = await registry.getUpkeep(id) + assert.equal(newupkeep.target, mock.address) + assert.equal(newupkeep.admin, await admin.getAddress()) + assert.equal(newupkeep.checkData, emptyBytes) + assert.equal(newupkeep.balance.toString(), amount.toString()) + assert.equal(newupkeep.performGas, performGas.toNumber()) + assert.equal(newupkeep.offchainConfig, offchainConfig) + + await expect(tx).to.emit(registrar, 'RegistrationRequested') + await expect(tx).to.emit(registrar, 'RegistrationApproved') + }) + + it('Auto Approve OFF - does not registers an upkeep on KeeperRegistry, emits only RegistrationRequested event', async () => { + //get upkeep count before attempting registration + const beforeCount = (await registry.getState()).state.numUpkeeps + + //set auto approve OFF, threshold limits dont matter in this case + await registrar + .connect(registrarOwner) + .setTriggerConfig( + Trigger.CONDITION, + autoApproveType_DISABLED, + maxAllowedAutoApprove, + ) + + //register with auto approve OFF + const abiEncodedBytes = registrar.interface.encodeFunctionData( + 'register', + [ + upkeepName, + emptyBytes, + mock.address, + performGas, + await admin.getAddress(), + 0, + emptyBytes, + trigger, + offchainConfig, + amount, + await requestSender.getAddress(), + ], + ) + const tx = await linkToken + .connect(requestSender) + .transferAndCall(registrar.address, amount, abiEncodedBytes) + const receipt = await tx.wait() + + //get upkeep count after attempting registration + const afterCount = (await registry.getState()).state.numUpkeeps + //confirm that a new upkeep has NOT been registered and upkeep count is still the same + assert.deepEqual(beforeCount, afterCount) + + //confirm that only RegistrationRequested event is emitted and RegistrationApproved event is not + await expect(tx).to.emit(registrar, 'RegistrationRequested') + await expect(tx).not.to.emit(registrar, 'RegistrationApproved') + + const hash = receipt.logs[2].topics[1] + const pendingRequest = await registrar.getPendingRequest(hash) + assert.equal(await admin.getAddress(), pendingRequest[0]) + assert.ok(amount.eq(pendingRequest[1])) + }) + + it('Auto Approve ON - Throttle max approvals - does not register an upkeep on KeeperRegistry beyond the max limit, emits only RegistrationRequested event after limit is hit', async () => { + assert.equal((await registry.getState()).state.numUpkeeps.toNumber(), 0) + + //set auto approve on, with max 1 allowed + await registrar + .connect(registrarOwner) + .setTriggerConfig(Trigger.CONDITION, autoApproveType_ENABLED_ALL, 1) + + //set auto approve on, with max 1 allowed + await registrar + .connect(registrarOwner) + .setTriggerConfig(Trigger.LOG, autoApproveType_ENABLED_ALL, 1) + + // register within threshold, new upkeep should be registered + let abiEncodedBytes = registrar.interface.encodeFunctionData('register', [ + upkeepName, + emptyBytes, + mock.address, + performGas, + await admin.getAddress(), + 0, + emptyBytes, + trigger, + offchainConfig, + amount, + await requestSender.getAddress(), + ]) + await linkToken + .connect(requestSender) + .transferAndCall(registrar.address, amount, abiEncodedBytes) + assert.equal((await registry.getState()).state.numUpkeeps.toNumber(), 1) // 0 -> 1 + + // try registering another one, new upkeep should not be registered + abiEncodedBytes = registrar.interface.encodeFunctionData('register', [ + upkeepName, + emptyBytes, + mock.address, + performGas.toNumber() + 1, // make unique hash + await admin.getAddress(), + 0, + emptyBytes, + trigger, + offchainConfig, + amount, + await requestSender.getAddress(), + ]) + await linkToken + .connect(requestSender) + .transferAndCall(registrar.address, amount, abiEncodedBytes) + assert.equal((await registry.getState()).state.numUpkeeps.toNumber(), 1) // Still 1 + + // register a second type of upkeep, different limit + abiEncodedBytes = registrar.interface.encodeFunctionData('register', [ + upkeepName, + emptyBytes, + mock.address, + performGas, + await admin.getAddress(), + Trigger.LOG, + emptyBytes, + trigger, + offchainConfig, + amount, + await requestSender.getAddress(), + ]) + await linkToken + .connect(requestSender) + .transferAndCall(registrar.address, amount, abiEncodedBytes) + assert.equal((await registry.getState()).state.numUpkeeps.toNumber(), 2) // 1 -> 2 + + // Now set new max limit to 2. One more upkeep should get auto approved + await registrar + .connect(registrarOwner) + .setTriggerConfig(Trigger.CONDITION, autoApproveType_ENABLED_ALL, 2) + + abiEncodedBytes = registrar.interface.encodeFunctionData('register', [ + upkeepName, + emptyBytes, + mock.address, + performGas.toNumber() + 2, // make unique hash + await admin.getAddress(), + 0, + emptyBytes, + trigger, + offchainConfig, + amount, + await requestSender.getAddress(), + ]) + await linkToken + .connect(requestSender) + .transferAndCall(registrar.address, amount, abiEncodedBytes) + assert.equal((await registry.getState()).state.numUpkeeps.toNumber(), 3) // 2 -> 3 + + // One more upkeep should not get registered + abiEncodedBytes = registrar.interface.encodeFunctionData('register', [ + upkeepName, + emptyBytes, + mock.address, + performGas.toNumber() + 3, // make unique hash + await admin.getAddress(), + 0, + emptyBytes, + trigger, + offchainConfig, + amount, + await requestSender.getAddress(), + ]) + await linkToken + .connect(requestSender) + .transferAndCall(registrar.address, amount, abiEncodedBytes) + assert.equal((await registry.getState()).state.numUpkeeps.toNumber(), 3) // Still 3 + }) + + it('Auto Approve Sender Allowlist - sender in allowlist - registers an upkeep on KeeperRegistry instantly and emits both RegistrationRequested and RegistrationApproved events', async () => { + const senderAddress = await requestSender.getAddress() + + //set auto approve to ENABLED_SENDER_ALLOWLIST type with high threshold limits + await registrar + .connect(registrarOwner) + .setTriggerConfig( + Trigger.CONDITION, + autoApproveType_ENABLED_SENDER_ALLOWLIST, + maxAllowedAutoApprove, + ) + + // Add sender to allowlist + await registrar + .connect(registrarOwner) + .setAutoApproveAllowedSender(senderAddress, true) + + //register with auto approve ON + const abiEncodedBytes = registrar.interface.encodeFunctionData( + 'register', + [ + upkeepName, + emptyBytes, + mock.address, + performGas, + await admin.getAddress(), + 0, + emptyBytes, + trigger, + offchainConfig, + amount, + await requestSender.getAddress(), + ], + ) + const tx = await linkToken + .connect(requestSender) + .transferAndCall(registrar.address, amount, abiEncodedBytes) + + const [id] = await registry.getActiveUpkeepIDs(0, 1) + + //confirm if a new upkeep has been registered and the details are the same as the one just registered + const newupkeep = await registry.getUpkeep(id) + assert.equal(newupkeep.target, mock.address) + assert.equal(newupkeep.admin, await admin.getAddress()) + assert.equal(newupkeep.checkData, emptyBytes) + assert.equal(newupkeep.balance.toString(), amount.toString()) + assert.equal(newupkeep.performGas, performGas.toNumber()) + + await expect(tx).to.emit(registrar, 'RegistrationRequested') + await expect(tx).to.emit(registrar, 'RegistrationApproved') + }) + + it('Auto Approve Sender Allowlist - sender NOT in allowlist - does not registers an upkeep on KeeperRegistry, emits only RegistrationRequested event', async () => { + const beforeCount = (await registry.getState()).state.numUpkeeps + const senderAddress = await requestSender.getAddress() + + //set auto approve to ENABLED_SENDER_ALLOWLIST type with high threshold limits + await registrar + .connect(registrarOwner) + .setTriggerConfig( + Trigger.CONDITION, + autoApproveType_ENABLED_SENDER_ALLOWLIST, + maxAllowedAutoApprove, + ) + + // Explicitly remove sender from allowlist + await registrar + .connect(registrarOwner) + .setAutoApproveAllowedSender(senderAddress, false) + + //register. auto approve shouldn't happen + const abiEncodedBytes = registrar.interface.encodeFunctionData( + 'register', + [ + upkeepName, + emptyBytes, + mock.address, + performGas, + await admin.getAddress(), + 0, + emptyBytes, + trigger, + offchainConfig, + amount, + await requestSender.getAddress(), + ], + ) + const tx = await linkToken + .connect(requestSender) + .transferAndCall(registrar.address, amount, abiEncodedBytes) + const receipt = await tx.wait() + + //get upkeep count after attempting registration + const afterCount = (await registry.getState()).state.numUpkeeps + //confirm that a new upkeep has NOT been registered and upkeep count is still the same + assert.deepEqual(beforeCount, afterCount) + + //confirm that only RegistrationRequested event is emitted and RegistrationApproved event is not + await expect(tx).to.emit(registrar, 'RegistrationRequested') + await expect(tx).not.to.emit(registrar, 'RegistrationApproved') + + const hash = receipt.logs[2].topics[1] + const pendingRequest = await registrar.getPendingRequest(hash) + assert.equal(await admin.getAddress(), pendingRequest[0]) + assert.ok(amount.eq(pendingRequest[1])) + }) + }) + + describe('#registerUpkeep', () => { + it('reverts with empty message if amount sent is not available in LINK allowance', async () => { + await evmRevert( + registrar.connect(someAddress).registerUpkeep({ + name: upkeepName, + upkeepContract: mock.address, + gasLimit: performGas, + adminAddress: await admin.getAddress(), + triggerType: 0, + checkData: emptyBytes, + triggerConfig: trigger, + offchainConfig: emptyBytes, + amount, + encryptedEmail: emptyBytes, + }), + '', + ) + }) + + it('reverts if the amount passed in data is less than configured minimum', async () => { + await registrar + .connect(registrarOwner) + .setTriggerConfig( + Trigger.CONDITION, + autoApproveType_ENABLED_ALL, + maxAllowedAutoApprove, + ) + + // amt is one order of magnitude less than minUpkeepSpend + const amt = BigNumber.from('100000000000000000') + + await evmRevert( + registrar.connect(someAddress).registerUpkeep({ + name: upkeepName, + upkeepContract: mock.address, + gasLimit: performGas, + adminAddress: await admin.getAddress(), + triggerType: 0, + checkData: emptyBytes, + triggerConfig: trigger, + offchainConfig: emptyBytes, + amount: amt, + encryptedEmail: emptyBytes, + }), + 'InsufficientPayment()', + ) + }) + + it('Auto Approve ON - registers an upkeep on KeeperRegistry instantly and emits both RegistrationRequested and RegistrationApproved events', async () => { + //set auto approve ON with high threshold limits + await registrar + .connect(registrarOwner) + .setTriggerConfig( + Trigger.CONDITION, + autoApproveType_ENABLED_ALL, + maxAllowedAutoApprove, + ) + + await linkToken.connect(requestSender).approve(registrar.address, amount) + + const tx = await registrar.connect(requestSender).registerUpkeep({ + name: upkeepName, + upkeepContract: mock.address, + gasLimit: performGas, + adminAddress: await admin.getAddress(), + triggerType: 0, + checkData: emptyBytes, + triggerConfig: trigger, + offchainConfig, + amount, + encryptedEmail: emptyBytes, + }) + assert.equal((await registry.getState()).state.numUpkeeps.toNumber(), 1) // 0 -> 1 + + //confirm if a new upkeep has been registered and the details are the same as the one just registered + const [id] = await registry.getActiveUpkeepIDs(0, 1) + const newupkeep = await registry.getUpkeep(id) + assert.equal(newupkeep.target, mock.address) + assert.equal(newupkeep.admin, await admin.getAddress()) + assert.equal(newupkeep.checkData, emptyBytes) + assert.equal(newupkeep.balance.toString(), amount.toString()) + assert.equal(newupkeep.performGas, performGas.toNumber()) + assert.equal(newupkeep.offchainConfig, offchainConfig) + + await expect(tx).to.emit(registrar, 'RegistrationRequested') + await expect(tx).to.emit(registrar, 'RegistrationApproved') + }) + }) + + describe('#setAutoApproveAllowedSender', () => { + it('reverts if not called by the owner', async () => { + const tx = registrar + .connect(stranger) + .setAutoApproveAllowedSender(await admin.getAddress(), false) + await evmRevert(tx, 'Only callable by owner') + }) + + it('sets the allowed status correctly and emits log', async () => { + const senderAddress = await stranger.getAddress() + let tx = await registrar + .connect(registrarOwner) + .setAutoApproveAllowedSender(senderAddress, true) + await expect(tx) + .to.emit(registrar, 'AutoApproveAllowedSenderSet') + .withArgs(senderAddress, true) + + let senderAllowedStatus = await registrar + .connect(owner) + .getAutoApproveAllowedSender(senderAddress) + assert.isTrue(senderAllowedStatus) + + tx = await registrar + .connect(registrarOwner) + .setAutoApproveAllowedSender(senderAddress, false) + await expect(tx) + .to.emit(registrar, 'AutoApproveAllowedSenderSet') + .withArgs(senderAddress, false) + + senderAllowedStatus = await registrar + .connect(owner) + .getAutoApproveAllowedSender(senderAddress) + assert.isFalse(senderAllowedStatus) + }) + }) + + describe('#setTriggerConfig', () => { + it('reverts if not called by the owner', async () => { + const tx = registrar + .connect(stranger) + .setTriggerConfig(Trigger.LOG, autoApproveType_ENABLED_ALL, 100) + await evmRevert(tx, 'Only callable by owner') + }) + + it('changes the config', async () => { + const tx = await registrar + .connect(registrarOwner) + .setTriggerConfig(Trigger.LOG, autoApproveType_ENABLED_ALL, 100) + await registrar.getTriggerRegistrationDetails(Trigger.LOG) + await expect(tx) + .to.emit(registrar, 'TriggerConfigSet') + .withArgs(Trigger.LOG, autoApproveType_ENABLED_ALL, 100) + }) + }) + + describe('#approve', () => { + let hash: string + + beforeEach(async () => { + await registrar + .connect(registrarOwner) + .setTriggerConfig( + Trigger.CONDITION, + autoApproveType_DISABLED, + maxAllowedAutoApprove, + ) + + //register with auto approve OFF + const abiEncodedBytes = registrar.interface.encodeFunctionData( + 'register', + [ + upkeepName, + emptyBytes, + mock.address, + performGas, + await admin.getAddress(), + 0, + emptyBytes, + trigger, + offchainConfig, + amount, + await requestSender.getAddress(), + ], + ) + + const tx = await linkToken + .connect(requestSender) + .transferAndCall(registrar.address, amount, abiEncodedBytes) + const receipt = await tx.wait() + hash = receipt.logs[2].topics[1] + }) + + it('reverts if not called by the owner', async () => { + const tx = registrar + .connect(stranger) + .approve( + upkeepName, + mock.address, + performGas, + await admin.getAddress(), + 0, + emptyBytes, + trigger, + emptyBytes, + hash, + ) + await evmRevert(tx, 'Only callable by owner') + }) + + it('reverts if the hash does not exist', async () => { + const tx = registrar + .connect(registrarOwner) + .approve( + upkeepName, + mock.address, + performGas, + await admin.getAddress(), + 0, + emptyBytes, + trigger, + emptyBytes, + '0x000000000000000000000000322813fd9a801c5507c9de605d63cea4f2ce6c44', + ) + await evmRevert(tx, errorMsgs.requestNotFound) + }) + + it('reverts if any member of the payload changes', async () => { + let tx = registrar + .connect(registrarOwner) + .approve( + upkeepName, + ethers.Wallet.createRandom().address, + performGas, + await admin.getAddress(), + 0, + emptyBytes, + trigger, + emptyBytes, + hash, + ) + await evmRevert(tx, errorMsgs.hashPayload) + tx = registrar + .connect(registrarOwner) + .approve( + upkeepName, + mock.address, + 10000, + await admin.getAddress(), + 0, + emptyBytes, + trigger, + emptyBytes, + hash, + ) + await evmRevert(tx, errorMsgs.hashPayload) + tx = registrar + .connect(registrarOwner) + .approve( + upkeepName, + mock.address, + performGas, + ethers.Wallet.createRandom().address, + 0, + emptyBytes, + trigger, + emptyBytes, + hash, + ) + await evmRevert(tx, errorMsgs.hashPayload) + tx = registrar + .connect(registrarOwner) + .approve( + upkeepName, + mock.address, + performGas, + await admin.getAddress(), + 0, + '0x1234', + trigger, + emptyBytes, + hash, + ) + await evmRevert(tx, errorMsgs.hashPayload) + }) + + it('approves an existing registration request', async () => { + const tx = await registrar + .connect(registrarOwner) + .approve( + upkeepName, + mock.address, + performGas, + await admin.getAddress(), + 0, + emptyBytes, + trigger, + offchainConfig, + hash, + ) + await expect(tx).to.emit(registrar, 'RegistrationApproved') + }) + + it('deletes the request afterwards / reverts if the request DNE', async () => { + await registrar + .connect(registrarOwner) + .approve( + upkeepName, + mock.address, + performGas, + await admin.getAddress(), + 0, + emptyBytes, + trigger, + offchainConfig, + hash, + ) + const tx = registrar + .connect(registrarOwner) + .approve( + upkeepName, + mock.address, + performGas, + await admin.getAddress(), + 0, + emptyBytes, + trigger, + offchainConfig, + hash, + ) + await evmRevert(tx, errorMsgs.requestNotFound) + }) + }) + + describe('#cancel', () => { + let hash: string + + beforeEach(async () => { + await registrar + .connect(registrarOwner) + .setTriggerConfig( + Trigger.CONDITION, + autoApproveType_DISABLED, + maxAllowedAutoApprove, + ) + + //register with auto approve OFF + const abiEncodedBytes = registrar.interface.encodeFunctionData( + 'register', + [ + upkeepName, + emptyBytes, + mock.address, + performGas, + await admin.getAddress(), + 0, + emptyBytes, + trigger, + offchainConfig, + amount, + await requestSender.getAddress(), + ], + ) + const tx = await linkToken + .connect(requestSender) + .transferAndCall(registrar.address, amount, abiEncodedBytes) + const receipt = await tx.wait() + hash = receipt.logs[2].topics[1] + // submit duplicate request (increase balance) + await linkToken + .connect(requestSender) + .transferAndCall(registrar.address, amount, abiEncodedBytes) + }) + + it('reverts if not called by the admin / owner', async () => { + const tx = registrar.connect(stranger).cancel(hash) + await evmRevert(tx, errorMsgs.onlyAdmin) + }) + + it('reverts if the hash does not exist', async () => { + const tx = registrar + .connect(registrarOwner) + .cancel( + '0x000000000000000000000000322813fd9a801c5507c9de605d63cea4f2ce6c44', + ) + await evmRevert(tx, errorMsgs.requestNotFound) + }) + + it('refunds the total request balance to the admin address if owner cancels', async () => { + const before = await linkToken.balanceOf(await admin.getAddress()) + const tx = await registrar.connect(registrarOwner).cancel(hash) + const after = await linkToken.balanceOf(await admin.getAddress()) + assert.isTrue(after.sub(before).eq(amount.mul(BigNumber.from(2)))) + await expect(tx).to.emit(registrar, 'RegistrationRejected') + }) + + it('refunds the total request balance to the admin address if admin cancels', async () => { + const before = await linkToken.balanceOf(await admin.getAddress()) + const tx = await registrar.connect(admin).cancel(hash) + const after = await linkToken.balanceOf(await admin.getAddress()) + assert.isTrue(after.sub(before).eq(amount.mul(BigNumber.from(2)))) + await expect(tx).to.emit(registrar, 'RegistrationRejected') + }) + + it('deletes the request hash', async () => { + await registrar.connect(registrarOwner).cancel(hash) + let tx = registrar.connect(registrarOwner).cancel(hash) + await evmRevert(tx, errorMsgs.requestNotFound) + tx = registrar + .connect(registrarOwner) + .approve( + upkeepName, + mock.address, + performGas, + await admin.getAddress(), + 0, + emptyBytes, + trigger, + emptyBytes, + hash, + ) + await evmRevert(tx, errorMsgs.requestNotFound) + }) + }) +}) diff --git a/contracts/test/v0.8/automation/AutomationRegistry2_2.test.ts b/contracts/test/v0.8/automation/AutomationRegistry2_2.test.ts new file mode 100644 index 0000000000..bb460aa60c --- /dev/null +++ b/contracts/test/v0.8/automation/AutomationRegistry2_2.test.ts @@ -0,0 +1,5757 @@ +import { ethers } from 'hardhat' +import { loadFixture } from '@nomicfoundation/hardhat-network-helpers' +import { assert, expect } from 'chai' +import { + BigNumber, + BigNumberish, + BytesLike, + Contract, + ContractFactory, + ContractReceipt, + ContractTransaction, + Signer, + Wallet, +} from 'ethers' +import { evmRevert } from '../../test-helpers/matchers' +import { getUsers, Personas } from '../../test-helpers/setup' +import { randomAddress, toWei } from '../../test-helpers/helpers' +import { StreamsLookupUpkeep__factory as StreamsLookupUpkeepFactory } from '../../../typechain/factories/StreamsLookupUpkeep__factory' +import { MockV3Aggregator__factory as MockV3AggregatorFactory } from '../../../typechain/factories/MockV3Aggregator__factory' +import { UpkeepMock__factory as UpkeepMockFactory } from '../../../typechain/factories/UpkeepMock__factory' +import { UpkeepAutoFunder__factory as UpkeepAutoFunderFactory } from '../../../typechain/factories/UpkeepAutoFunder__factory' +import { MockArbGasInfo__factory as MockArbGasInfoFactory } from '../../../typechain/factories/MockArbGasInfo__factory' +import { MockOVMGasPriceOracle__factory as MockOVMGasPriceOracleFactory } from '../../../typechain/factories/MockOVMGasPriceOracle__factory' +import { ILogAutomation__factory as ILogAutomationactory } from '../../../typechain/factories/ILogAutomation__factory' +import { IAutomationForwarder__factory as IAutomationForwarderFactory } from '../../../typechain/factories/IAutomationForwarder__factory' +import { MockArbSys__factory as MockArbSysFactory } from '../../../typechain/factories/MockArbSys__factory' +import { AutomationUtils2_2 as AutomationUtils } from '../../../typechain/AutomationUtils2_2' +import { StreamsLookupUpkeep } from '../../../typechain/StreamsLookupUpkeep' +import { MockV3Aggregator } from '../../../typechain/MockV3Aggregator' +import { UpkeepMock } from '../../../typechain/UpkeepMock' +import { MockArbGasInfo } from '../../../typechain/MockArbGasInfo' +import { MockOVMGasPriceOracle } from '../../../typechain/MockOVMGasPriceOracle' +import { UpkeepTranscoder } from '../../../typechain/UpkeepTranscoder' +import { UpkeepAutoFunder } from '../../../typechain' +import { + CancelledUpkeepReportEvent, + IAutomationRegistryMaster as IAutomationRegistry, + InsufficientFundsUpkeepReportEvent, + ReorgedUpkeepReportEvent, + StaleUpkeepReportEvent, + UpkeepPerformedEvent, +} from '../../../typechain/IAutomationRegistryMaster' +import { + deployMockContract, + MockContract, +} from '@ethereum-waffle/mock-contract' +import { deployRegistry22 } from './helpers' + +const describeMaybe = process.env.SKIP_SLOW ? describe.skip : describe +const itMaybe = process.env.SKIP_SLOW ? it.skip : it + +// copied from AutomationRegistryInterface2_2.sol +enum UpkeepFailureReason { + NONE, + UPKEEP_CANCELLED, + UPKEEP_PAUSED, + TARGET_CHECK_REVERTED, + UPKEEP_NOT_NEEDED, + PERFORM_DATA_EXCEEDS_LIMIT, + INSUFFICIENT_BALANCE, + CHECK_CALLBACK_REVERTED, + REVERT_DATA_EXCEEDS_LIMIT, + REGISTRY_PAUSED, +} + +// copied from AutomationRegistryInterface2_2.sol +enum Mode { + DEFAULT, + ARBITRUM, + OPTIMISM, +} + +// copied from AutomationRegistryBase2_2.sol +enum Trigger { + CONDITION, + LOG, +} + +// un-exported types that must be extracted from the utils contract +type Report = Parameters[0] +type OnChainConfig = Parameters[0] +type LogTrigger = Parameters[0] +type ConditionalTrigger = Parameters[0] +type Log = Parameters[0] + +// ----------------------------------------------------------------------------------------------- + +// These values should match the constants declared in registry +let registryConditionalOverhead: BigNumber +let registryLogOverhead: BigNumber +let registryPerSignerGasOverhead: BigNumber +let registryPerPerformByteGasOverhead: BigNumber +let cancellationDelay: number + +// This is the margin for gas that we test for. Gas charged should always be greater +// than total gas used in tx but should not increase beyond this margin +const gasCalculationMargin = BigNumber.from(8000) + +const linkEth = BigNumber.from(5000000000000000) // 1 Link = 0.005 Eth +const gasWei = BigNumber.from(1000000000) // 1 gwei +// ----------------------------------------------------------------------------------------------- +// test-wide configs for upkeeps +const linkDivisibility = BigNumber.from('1000000000000000000') +const performGas = BigNumber.from('1000000') +const paymentPremiumBase = BigNumber.from('1000000000') +const paymentPremiumPPB = BigNumber.from('250000000') +const flatFeeMicroLink = BigNumber.from(0) + +const randomBytes = '0x1234abcd' +const emptyBytes = '0x' +const emptyBytes32 = + '0x0000000000000000000000000000000000000000000000000000000000000000' + +const transmitGasOverhead = 1_000_000 +const checkGasOverhead = 400_000 + +const stalenessSeconds = BigNumber.from(43820) +const gasCeilingMultiplier = BigNumber.from(2) +const checkGasLimit = BigNumber.from(10000000) +const fallbackGasPrice = gasWei.mul(BigNumber.from('2')) +const fallbackLinkPrice = linkEth.div(BigNumber.from('2')) +const maxCheckDataSize = BigNumber.from(1000) +const maxPerformDataSize = BigNumber.from(1000) +const maxRevertDataSize = BigNumber.from(1000) +const maxPerformGas = BigNumber.from(5000000) +const minUpkeepSpend = BigNumber.from(0) +const f = 1 +const offchainVersion = 1 +const offchainBytes = '0x' +const zeroAddress = ethers.constants.AddressZero +const epochAndRound5_1 = + '0x0000000000000000000000000000000000000000000000000000000000000501' + +let logTriggerConfig: string + +// ----------------------------------------------------------------------------------------------- + +// Smart contract factories +let linkTokenFactory: ContractFactory +let mockV3AggregatorFactory: MockV3AggregatorFactory +let upkeepMockFactory: UpkeepMockFactory +let upkeepAutoFunderFactory: UpkeepAutoFunderFactory +let mockArbGasInfoFactory: MockArbGasInfoFactory +let mockOVMGasPriceOracleFactory: MockOVMGasPriceOracleFactory +let streamsLookupUpkeepFactory: StreamsLookupUpkeepFactory +let personas: Personas + +// contracts +let linkToken: Contract +let linkEthFeed: MockV3Aggregator +let gasPriceFeed: MockV3Aggregator +let registry: IAutomationRegistry // default registry, used for most tests +let arbRegistry: IAutomationRegistry // arbitrum registry +let opRegistry: IAutomationRegistry // optimism registry +let mgRegistry: IAutomationRegistry // "migrate registry" used in migration tests +let blankRegistry: IAutomationRegistry // used to test initial configurations +let mock: UpkeepMock +let autoFunderUpkeep: UpkeepAutoFunder +let ltUpkeep: MockContract +let transcoder: UpkeepTranscoder +let mockArbGasInfo: MockArbGasInfo +let mockOVMGasPriceOracle: MockOVMGasPriceOracle +let streamsLookupUpkeep: StreamsLookupUpkeep +let automationUtils: AutomationUtils + +function now() { + return Math.floor(Date.now() / 1000) +} + +async function getUpkeepID(tx: ContractTransaction): Promise { + const receipt = await tx.wait() + for (const event of receipt.events || []) { + if ( + event.args && + event.eventSignature == 'UpkeepRegistered(uint256,uint32,address)' + ) { + return event.args[0] + } + } + throw new Error('could not find upkeep ID in tx event logs') +} + +const getTriggerType = (upkeepId: BigNumber): Trigger => { + const hexBytes = ethers.utils.defaultAbiCoder.encode(['uint256'], [upkeepId]) + const bytes = ethers.utils.arrayify(hexBytes) + for (let idx = 4; idx < 15; idx++) { + if (bytes[idx] != 0) { + return Trigger.CONDITION + } + } + return bytes[15] as Trigger +} + +const encodeConfig = (onchainConfig: OnChainConfig) => { + return ( + '0x' + + automationUtils.interface + .encodeFunctionData('_onChainConfig', [onchainConfig]) + .slice(10) + ) +} + +const encodeBlockTrigger = (conditionalTrigger: ConditionalTrigger) => { + return ( + '0x' + + automationUtils.interface + .encodeFunctionData('_conditionalTrigger', [conditionalTrigger]) + .slice(10) + ) +} + +const encodeLogTrigger = (logTrigger: LogTrigger) => { + return ( + '0x' + + automationUtils.interface + .encodeFunctionData('_logTrigger', [logTrigger]) + .slice(10) + ) +} + +const encodeLog = (log: Log) => { + return ( + '0x' + automationUtils.interface.encodeFunctionData('_log', [log]).slice(10) + ) +} + +const encodeReport = (report: Report) => { + return ( + '0x' + + automationUtils.interface.encodeFunctionData('_report', [report]).slice(10) + ) +} + +type UpkeepData = { + Id: BigNumberish + performGas: BigNumberish + performData: BytesLike + trigger: BytesLike +} + +const makeReport = (upkeeps: UpkeepData[]) => { + const upkeepIds = upkeeps.map((u) => u.Id) + const performGases = upkeeps.map((u) => u.performGas) + const triggers = upkeeps.map((u) => u.trigger) + const performDatas = upkeeps.map((u) => u.performData) + return encodeReport({ + fastGasWei: gasWei, + linkNative: linkEth, + upkeepIds, + gasLimits: performGases, + triggers, + performDatas, + }) +} + +const makeLatestBlockReport = async (upkeepsIDs: BigNumberish[]) => { + const latestBlock = await ethers.provider.getBlock('latest') + const upkeeps: UpkeepData[] = [] + for (let i = 0; i < upkeepsIDs.length; i++) { + upkeeps.push({ + Id: upkeepsIDs[i], + performGas, + trigger: encodeBlockTrigger({ + blockNum: latestBlock.number, + blockHash: latestBlock.hash, + }), + performData: '0x', + }) + } + return makeReport(upkeeps) +} + +const signReport = ( + reportContext: string[], + report: any, + signers: Wallet[], +) => { + const reportDigest = ethers.utils.keccak256(report) + const packedArgs = ethers.utils.solidityPack( + ['bytes32', 'bytes32[3]'], + [reportDigest, reportContext], + ) + const packedDigest = ethers.utils.keccak256(packedArgs) + + const signatures = [] + for (const signer of signers) { + signatures.push(signer._signingKey().signDigest(packedDigest)) + } + const vs = signatures.map((i) => '0' + (i.v - 27).toString(16)).join('') + return { + vs: '0x' + vs.padEnd(64, '0'), + rs: signatures.map((i) => i.r), + ss: signatures.map((i) => i.s), + } +} + +const parseUpkeepPerformedLogs = (receipt: ContractReceipt) => { + const parsedLogs = [] + for (const rawLog of receipt.logs) { + try { + const log = registry.interface.parseLog(rawLog) + if ( + log.name == + registry.interface.events[ + 'UpkeepPerformed(uint256,bool,uint96,uint256,uint256,bytes)' + ].name + ) { + parsedLogs.push(log as unknown as UpkeepPerformedEvent) + } + } catch { + continue + } + } + return parsedLogs +} + +const parseReorgedUpkeepReportLogs = (receipt: ContractReceipt) => { + const parsedLogs = [] + for (const rawLog of receipt.logs) { + try { + const log = registry.interface.parseLog(rawLog) + if ( + log.name == + registry.interface.events['ReorgedUpkeepReport(uint256,bytes)'].name + ) { + parsedLogs.push(log as unknown as ReorgedUpkeepReportEvent) + } + } catch { + continue + } + } + return parsedLogs +} + +const parseStaleUpkeepReportLogs = (receipt: ContractReceipt) => { + const parsedLogs = [] + for (const rawLog of receipt.logs) { + try { + const log = registry.interface.parseLog(rawLog) + if ( + log.name == + registry.interface.events['StaleUpkeepReport(uint256,bytes)'].name + ) { + parsedLogs.push(log as unknown as StaleUpkeepReportEvent) + } + } catch { + continue + } + } + return parsedLogs +} + +const parseInsufficientFundsUpkeepReportLogs = (receipt: ContractReceipt) => { + const parsedLogs = [] + for (const rawLog of receipt.logs) { + try { + const log = registry.interface.parseLog(rawLog) + if ( + log.name == + registry.interface.events[ + 'InsufficientFundsUpkeepReport(uint256,bytes)' + ].name + ) { + parsedLogs.push(log as unknown as InsufficientFundsUpkeepReportEvent) + } + } catch { + continue + } + } + return parsedLogs +} + +const parseCancelledUpkeepReportLogs = (receipt: ContractReceipt) => { + const parsedLogs = [] + for (const rawLog of receipt.logs) { + try { + const log = registry.interface.parseLog(rawLog) + if ( + log.name == + registry.interface.events['CancelledUpkeepReport(uint256,bytes)'].name + ) { + parsedLogs.push(log as unknown as CancelledUpkeepReportEvent) + } + } catch { + continue + } + } + return parsedLogs +} + +describe('AutomationRegistry2_2', () => { + let owner: Signer + let keeper1: Signer + let keeper2: Signer + let keeper3: Signer + let keeper4: Signer + let keeper5: Signer + let nonkeeper: Signer + let signer1: Wallet + let signer2: Wallet + let signer3: Wallet + let signer4: Wallet + let signer5: Wallet + let admin: Signer + let payee1: Signer + let payee2: Signer + let payee3: Signer + let payee4: Signer + let payee5: Signer + + let upkeepId: BigNumber // conditional upkeep + let afUpkeepId: BigNumber // auto funding upkeep + let logUpkeepId: BigNumber // log trigger upkeepID + let streamsLookupUpkeepId: BigNumber // streams lookup upkeep + const numUpkeeps = 4 // see above + let keeperAddresses: string[] + let payees: string[] + let signers: Wallet[] + let signerAddresses: string[] + let config: any + let baseConfig: Parameters + let upkeepManager: string + + before(async () => { + personas = (await getUsers()).personas + + const utilsFactory = await ethers.getContractFactory('AutomationUtils2_2') + automationUtils = await utilsFactory.deploy() + + linkTokenFactory = await ethers.getContractFactory( + 'src/v0.4/LinkToken.sol:LinkToken', + ) + // need full path because there are two contracts with name MockV3Aggregator + mockV3AggregatorFactory = (await ethers.getContractFactory( + 'src/v0.8/tests/MockV3Aggregator.sol:MockV3Aggregator', + )) as unknown as MockV3AggregatorFactory + upkeepMockFactory = await ethers.getContractFactory('UpkeepMock') + upkeepAutoFunderFactory = + await ethers.getContractFactory('UpkeepAutoFunder') + mockArbGasInfoFactory = await ethers.getContractFactory('MockArbGasInfo') + mockOVMGasPriceOracleFactory = await ethers.getContractFactory( + 'MockOVMGasPriceOracle', + ) + streamsLookupUpkeepFactory = await ethers.getContractFactory( + 'StreamsLookupUpkeep', + ) + + owner = personas.Default + keeper1 = personas.Carol + keeper2 = personas.Eddy + keeper3 = personas.Nancy + keeper4 = personas.Norbert + keeper5 = personas.Nick + nonkeeper = personas.Ned + admin = personas.Neil + payee1 = personas.Nelly + payee2 = personas.Norbert + payee3 = personas.Nick + payee4 = personas.Eddy + payee5 = personas.Carol + upkeepManager = await personas.Norbert.getAddress() + // signers + signer1 = new ethers.Wallet( + '0x7777777000000000000000000000000000000000000000000000000000000001', + ) + signer2 = new ethers.Wallet( + '0x7777777000000000000000000000000000000000000000000000000000000002', + ) + signer3 = new ethers.Wallet( + '0x7777777000000000000000000000000000000000000000000000000000000003', + ) + signer4 = new ethers.Wallet( + '0x7777777000000000000000000000000000000000000000000000000000000004', + ) + signer5 = new ethers.Wallet( + '0x7777777000000000000000000000000000000000000000000000000000000005', + ) + + keeperAddresses = [ + await keeper1.getAddress(), + await keeper2.getAddress(), + await keeper3.getAddress(), + await keeper4.getAddress(), + await keeper5.getAddress(), + ] + payees = [ + await payee1.getAddress(), + await payee2.getAddress(), + await payee3.getAddress(), + await payee4.getAddress(), + await payee5.getAddress(), + ] + signers = [signer1, signer2, signer3, signer4, signer5] + + // We append 26 random addresses to keepers, payees and signers to get a system of 31 oracles + // This allows f value of 1 - 10 + for (let i = 0; i < 26; i++) { + keeperAddresses.push(randomAddress()) + payees.push(randomAddress()) + signers.push(ethers.Wallet.createRandom()) + } + signerAddresses = [] + for (const signer of signers) { + signerAddresses.push(await signer.getAddress()) + } + + logTriggerConfig = + '0x' + + automationUtils.interface + .encodeFunctionData('_logTriggerConfig', [ + { + contractAddress: randomAddress(), + filterSelector: 0, + topic0: ethers.utils.randomBytes(32), + topic1: ethers.utils.randomBytes(32), + topic2: ethers.utils.randomBytes(32), + topic3: ethers.utils.randomBytes(32), + }, + ]) + .slice(10) + }) + + const linkForGas = ( + upkeepGasSpent: BigNumber, + gasOverhead: BigNumber, + gasMultiplier: BigNumber, + premiumPPB: BigNumber, + flatFee: BigNumber, + l1CostWei?: BigNumber, + numUpkeepsBatch?: BigNumber, + ) => { + l1CostWei = l1CostWei === undefined ? BigNumber.from(0) : l1CostWei + numUpkeepsBatch = + numUpkeepsBatch === undefined ? BigNumber.from(1) : numUpkeepsBatch + + const gasSpent = gasOverhead.add(BigNumber.from(upkeepGasSpent)) + const base = gasWei + .mul(gasMultiplier) + .mul(gasSpent) + .mul(linkDivisibility) + .div(linkEth) + const l1Fee = l1CostWei + .mul(gasMultiplier) + .div(numUpkeepsBatch) + .mul(linkDivisibility) + .div(linkEth) + const gasPayment = base.add(l1Fee) + + const premium = gasWei + .mul(gasMultiplier) + .mul(upkeepGasSpent) + .add(l1CostWei.mul(gasMultiplier).div(numUpkeepsBatch)) + .mul(linkDivisibility) + .div(linkEth) + .mul(premiumPPB) + .div(paymentPremiumBase) + .add(BigNumber.from(flatFee).mul('1000000000000')) + + return { + total: gasPayment.add(premium), + gasPaymemnt: gasPayment, + premium, + } + } + + const verifyMaxPayment = async ( + registry: IAutomationRegistry, + l1CostWei?: BigNumber, + ) => { + type TestCase = { + name: string + multiplier: number + gas: number + premium: number + flatFee: number + } + + const tests: TestCase[] = [ + { + name: 'no fees', + multiplier: 1, + gas: 100000, + premium: 0, + flatFee: 0, + }, + { + name: 'basic fees', + multiplier: 1, + gas: 100000, + premium: 250000000, + flatFee: 1000000, + }, + { + name: 'max fees', + multiplier: 3, + gas: 10000000, + premium: 250000000, + flatFee: 1000000, + }, + ] + + const fPlusOne = BigNumber.from(f + 1) + const totalConditionalOverhead = registryConditionalOverhead + .add(registryPerSignerGasOverhead.mul(fPlusOne)) + .add(registryPerPerformByteGasOverhead.mul(maxPerformDataSize)) + const totalLogOverhead = registryLogOverhead + .add(registryPerSignerGasOverhead.mul(fPlusOne)) + .add(registryPerPerformByteGasOverhead.mul(maxPerformDataSize)) + + for (const test of tests) { + await registry.connect(owner).setConfig( + signerAddresses, + keeperAddresses, + f, + encodeConfig({ + paymentPremiumPPB: test.premium, + flatFeeMicroLink: test.flatFee, + checkGasLimit, + stalenessSeconds, + gasCeilingMultiplier: test.multiplier, + minUpkeepSpend, + maxCheckDataSize, + maxPerformDataSize, + maxRevertDataSize, + maxPerformGas, + fallbackGasPrice, + fallbackLinkPrice, + transcoder: transcoder.address, + registrars: [], + upkeepPrivilegeManager: upkeepManager, + }), + offchainVersion, + offchainBytes, + ) + + const conditionalPrice = await registry.getMaxPaymentForGas( + Trigger.CONDITION, + test.gas, + ) + expect(conditionalPrice).to.equal( + linkForGas( + BigNumber.from(test.gas), + totalConditionalOverhead, + BigNumber.from(test.multiplier), + BigNumber.from(test.premium), + BigNumber.from(test.flatFee), + l1CostWei, + ).total, + ) + + const logPrice = await registry.getMaxPaymentForGas(Trigger.LOG, test.gas) + expect(logPrice).to.equal( + linkForGas( + BigNumber.from(test.gas), + totalLogOverhead, + BigNumber.from(test.multiplier), + BigNumber.from(test.premium), + BigNumber.from(test.flatFee), + l1CostWei, + ).total, + ) + } + } + + const verifyConsistentAccounting = async ( + maxAllowedSpareChange: BigNumber, + ) => { + const expectedLinkBalance = (await registry.getState()).state + .expectedLinkBalance + const linkTokenBalance = await linkToken.balanceOf(registry.address) + const upkeepIdBalance = (await registry.getUpkeep(upkeepId)).balance + let totalKeeperBalance = BigNumber.from(0) + for (let i = 0; i < keeperAddresses.length; i++) { + totalKeeperBalance = totalKeeperBalance.add( + (await registry.getTransmitterInfo(keeperAddresses[i])).balance, + ) + } + const ownerBalance = (await registry.getState()).state.ownerLinkBalance + assert.isTrue(expectedLinkBalance.eq(linkTokenBalance)) + assert.isTrue( + upkeepIdBalance + .add(totalKeeperBalance) + .add(ownerBalance) + .lte(expectedLinkBalance), + ) + assert.isTrue( + expectedLinkBalance + .sub(upkeepIdBalance) + .sub(totalKeeperBalance) + .sub(ownerBalance) + .lte(maxAllowedSpareChange), + ) + } + + interface GetTransmitTXOptions { + numSigners?: number + startingSignerIndex?: number + gasLimit?: BigNumberish + gasPrice?: BigNumberish + performGas?: BigNumberish + performData?: string + checkBlockNum?: number + checkBlockHash?: string + logBlockHash?: BytesLike + txHash?: BytesLike + logIndex?: number + timestamp?: number + } + + const getTransmitTx = async ( + registry: IAutomationRegistry, + transmitter: Signer, + upkeepIds: BigNumber[], + overrides: GetTransmitTXOptions = {}, + ) => { + const latestBlock = await ethers.provider.getBlock('latest') + const configDigest = (await registry.getState()).state.latestConfigDigest + const config = { + numSigners: f + 1, + startingSignerIndex: 0, + performData: '0x', + performGas, + checkBlockNum: latestBlock.number, + checkBlockHash: latestBlock.hash, + logIndex: 0, + txHash: undefined, // assigned uniquely below + logBlockHash: undefined, // assigned uniquely below + timestamp: now(), + gasLimit: undefined, + gasPrice: undefined, + } + Object.assign(config, overrides) + const upkeeps: UpkeepData[] = [] + for (let i = 0; i < upkeepIds.length; i++) { + let trigger: string + switch (getTriggerType(upkeepIds[i])) { + case Trigger.CONDITION: + trigger = encodeBlockTrigger({ + blockNum: config.checkBlockNum, + blockHash: config.checkBlockHash, + }) + break + case Trigger.LOG: + trigger = encodeLogTrigger({ + logBlockHash: config.logBlockHash || ethers.utils.randomBytes(32), + txHash: config.txHash || ethers.utils.randomBytes(32), + logIndex: config.logIndex, + blockNum: config.checkBlockNum, + blockHash: config.checkBlockHash, + }) + break + } + upkeeps.push({ + Id: upkeepIds[i], + performGas: config.performGas, + trigger, + performData: config.performData, + }) + } + + const report = makeReport(upkeeps) + const reportContext = [configDigest, epochAndRound5_1, emptyBytes32] + const sigs = signReport( + reportContext, + report, + signers.slice( + config.startingSignerIndex, + config.startingSignerIndex + config.numSigners, + ), + ) + + type txOverride = { + gasLimit?: BigNumberish | Promise + gasPrice?: BigNumberish | Promise + } + const txOverrides: txOverride = {} + if (config.gasLimit) { + txOverrides.gasLimit = config.gasLimit + } + if (config.gasPrice) { + txOverrides.gasPrice = config.gasPrice + } + + return registry + .connect(transmitter) + .transmit( + [configDigest, epochAndRound5_1, emptyBytes32], + report, + sigs.rs, + sigs.ss, + sigs.vs, + txOverrides, + ) + } + + const getTransmitTxWithReport = async ( + registry: IAutomationRegistry, + transmitter: Signer, + report: BytesLike, + ) => { + const configDigest = (await registry.getState()).state.latestConfigDigest + const reportContext = [configDigest, epochAndRound5_1, emptyBytes32] + const sigs = signReport(reportContext, report, signers.slice(0, f + 1)) + + return registry + .connect(transmitter) + .transmit( + [configDigest, epochAndRound5_1, emptyBytes32], + report, + sigs.rs, + sigs.ss, + sigs.vs, + ) + } + + const setup = async () => { + linkToken = await linkTokenFactory.connect(owner).deploy() + gasPriceFeed = await mockV3AggregatorFactory + .connect(owner) + .deploy(0, gasWei) + linkEthFeed = await mockV3AggregatorFactory + .connect(owner) + .deploy(9, linkEth) + const upkeepTranscoderFactory = await ethers.getContractFactory( + 'UpkeepTranscoder4_0', + ) + transcoder = await upkeepTranscoderFactory.connect(owner).deploy() + mockArbGasInfo = await mockArbGasInfoFactory.connect(owner).deploy() + mockOVMGasPriceOracle = await mockOVMGasPriceOracleFactory + .connect(owner) + .deploy() + streamsLookupUpkeep = await streamsLookupUpkeepFactory + .connect(owner) + .deploy( + BigNumber.from('10000'), + BigNumber.from('100'), + false /* useArbBlock */, + true /* staging */, + false /* verify mercury response */, + ) + + const arbOracleCode = await ethers.provider.send('eth_getCode', [ + mockArbGasInfo.address, + ]) + await ethers.provider.send('hardhat_setCode', [ + '0x000000000000000000000000000000000000006C', + arbOracleCode, + ]) + + const optOracleCode = await ethers.provider.send('eth_getCode', [ + mockOVMGasPriceOracle.address, + ]) + await ethers.provider.send('hardhat_setCode', [ + '0x420000000000000000000000000000000000000F', + optOracleCode, + ]) + + const mockArbSys = await new MockArbSysFactory(owner).deploy() + const arbSysCode = await ethers.provider.send('eth_getCode', [ + mockArbSys.address, + ]) + await ethers.provider.send('hardhat_setCode', [ + '0x0000000000000000000000000000000000000064', + arbSysCode, + ]) + + config = { + paymentPremiumPPB, + flatFeeMicroLink, + checkGasLimit, + stalenessSeconds, + gasCeilingMultiplier, + minUpkeepSpend, + maxCheckDataSize, + maxPerformDataSize, + maxRevertDataSize, + maxPerformGas, + fallbackGasPrice, + fallbackLinkPrice, + transcoder: transcoder.address, + registrars: [], + upkeepPrivilegeManager: upkeepManager, + } + + baseConfig = [ + signerAddresses, + keeperAddresses, + f, + encodeConfig(config), + offchainVersion, + offchainBytes, + ] + + registry = await deployRegistry22( + owner, + Mode.DEFAULT, + linkToken.address, + linkEthFeed.address, + gasPriceFeed.address, + ) + + arbRegistry = await deployRegistry22( + owner, + Mode.ARBITRUM, + linkToken.address, + linkEthFeed.address, + gasPriceFeed.address, + ) + + opRegistry = await deployRegistry22( + owner, + Mode.OPTIMISM, + linkToken.address, + linkEthFeed.address, + gasPriceFeed.address, + ) + + mgRegistry = await deployRegistry22( + owner, + Mode.DEFAULT, + linkToken.address, + linkEthFeed.address, + gasPriceFeed.address, + ) + + blankRegistry = await deployRegistry22( + owner, + Mode.DEFAULT, + linkToken.address, + linkEthFeed.address, + gasPriceFeed.address, + ) + + registryConditionalOverhead = await registry.getConditionalGasOverhead() + registryLogOverhead = await registry.getLogGasOverhead() + registryPerSignerGasOverhead = await registry.getPerSignerGasOverhead() + registryPerPerformByteGasOverhead = + await registry.getPerPerformByteGasOverhead() + cancellationDelay = (await registry.getCancellationDelay()).toNumber() + + for (const reg of [registry, arbRegistry, opRegistry, mgRegistry]) { + await reg.connect(owner).setConfig(...baseConfig) + await reg.connect(owner).setPayees(payees) + await linkToken.connect(admin).approve(reg.address, toWei('1000')) + await linkToken.connect(owner).approve(reg.address, toWei('1000')) + } + + mock = await upkeepMockFactory.deploy() + await linkToken + .connect(owner) + .transfer(await admin.getAddress(), toWei('1000')) + let tx = await registry + .connect(owner) + ['registerUpkeep(address,uint32,address,bytes,bytes)']( + mock.address, + performGas, + await admin.getAddress(), + randomBytes, + '0x', + ) + upkeepId = await getUpkeepID(tx) + + autoFunderUpkeep = await upkeepAutoFunderFactory + .connect(owner) + .deploy(linkToken.address, registry.address) + tx = await registry + .connect(owner) + ['registerUpkeep(address,uint32,address,bytes,bytes)']( + autoFunderUpkeep.address, + performGas, + autoFunderUpkeep.address, + randomBytes, + '0x', + ) + afUpkeepId = await getUpkeepID(tx) + + ltUpkeep = await deployMockContract(owner, ILogAutomationactory.abi) + tx = await registry + .connect(owner) + ['registerUpkeep(address,uint32,address,uint8,bytes,bytes,bytes)']( + ltUpkeep.address, + performGas, + await admin.getAddress(), + Trigger.LOG, + '0x', + logTriggerConfig, + emptyBytes, + ) + logUpkeepId = await getUpkeepID(tx) + + await autoFunderUpkeep.setUpkeepId(afUpkeepId) + // Give enough funds for upkeep as well as to the upkeep contract + await linkToken + .connect(owner) + .transfer(autoFunderUpkeep.address, toWei('1000')) + + tx = await registry + .connect(owner) + ['registerUpkeep(address,uint32,address,bytes,bytes)']( + streamsLookupUpkeep.address, + performGas, + await admin.getAddress(), + randomBytes, + '0x', + ) + streamsLookupUpkeepId = await getUpkeepID(tx) + } + + const getMultipleUpkeepsDeployedAndFunded = async ( + numPassingConditionalUpkeeps: number, + numPassingLogUpkeeps: number, + numFailingUpkeeps: number, + ) => { + const passingConditionalUpkeepIds = [] + const passingLogUpkeepIds = [] + const failingUpkeepIds = [] + for (let i = 0; i < numPassingConditionalUpkeeps; i++) { + const mock = await upkeepMockFactory.deploy() + await mock.setCanPerform(true) + await mock.setPerformGasToBurn(BigNumber.from('0')) + const tx = await registry + .connect(owner) + ['registerUpkeep(address,uint32,address,bytes,bytes)']( + mock.address, + performGas, + await admin.getAddress(), + randomBytes, + '0x', + ) + const condUpkeepId = await getUpkeepID(tx) + passingConditionalUpkeepIds.push(condUpkeepId) + + // Add funds to passing upkeeps + await registry.connect(admin).addFunds(condUpkeepId, toWei('100')) + } + for (let i = 0; i < numPassingLogUpkeeps; i++) { + const mock = await upkeepMockFactory.deploy() + await mock.setCanPerform(true) + await mock.setPerformGasToBurn(BigNumber.from('0')) + const tx = await registry + .connect(owner) + ['registerUpkeep(address,uint32,address,uint8,bytes,bytes,bytes)']( + mock.address, + performGas, + await admin.getAddress(), + Trigger.LOG, + '0x', + logTriggerConfig, + emptyBytes, + ) + const logUpkeepId = await getUpkeepID(tx) + passingLogUpkeepIds.push(logUpkeepId) + + // Add funds to passing upkeeps + await registry.connect(admin).addFunds(logUpkeepId, toWei('100')) + } + for (let i = 0; i < numFailingUpkeeps; i++) { + const mock = await upkeepMockFactory.deploy() + await mock.setCanPerform(true) + await mock.setPerformGasToBurn(BigNumber.from('0')) + const tx = await registry + .connect(owner) + ['registerUpkeep(address,uint32,address,bytes,bytes)']( + mock.address, + performGas, + await admin.getAddress(), + randomBytes, + '0x', + ) + const failingUpkeepId = await getUpkeepID(tx) + failingUpkeepIds.push(failingUpkeepId) + } + return { + passingConditionalUpkeepIds, + passingLogUpkeepIds, + failingUpkeepIds, + } + } + + beforeEach(async () => { + await loadFixture(setup) + }) + + describe('#transmit', () => { + const fArray = [1, 5, 10] + + it('reverts when registry is paused', async () => { + await registry.connect(owner).pause() + await evmRevert( + getTransmitTx(registry, keeper1, [upkeepId]), + 'RegistryPaused()', + ) + }) + + it('reverts when called by non active transmitter', async () => { + await evmRevert( + getTransmitTx(registry, payee1, [upkeepId]), + 'OnlyActiveTransmitters()', + ) + }) + + it('reverts when report data lengths mismatches', async () => { + const upkeepIds = [] + const gasLimits: BigNumber[] = [] + const triggers: string[] = [] + const performDatas = [] + + upkeepIds.push(upkeepId) + gasLimits.push(performGas) + triggers.push('0x') + performDatas.push('0x') + // Push an extra perform data + performDatas.push('0x') + + const report = encodeReport({ + fastGasWei: 0, + linkNative: 0, + upkeepIds, + gasLimits, + triggers, + performDatas, + }) + + await evmRevert( + getTransmitTxWithReport(registry, keeper1, report), + 'InvalidReport()', + ) + }) + + it('returns early when invalid upkeepIds are included in report', async () => { + const tx = await getTransmitTx(registry, keeper1, [ + upkeepId.add(BigNumber.from('1')), + ]) + + const receipt = await tx.wait() + const cancelledUpkeepReportLogs = parseCancelledUpkeepReportLogs(receipt) + // exactly 1 CancelledUpkeepReport log should be emitted + assert.equal(cancelledUpkeepReportLogs.length, 1) + }) + + it('returns early when upkeep has insufficient funds', async () => { + const tx = await getTransmitTx(registry, keeper1, [upkeepId]) + const receipt = await tx.wait() + const insufficientFundsUpkeepReportLogs = + parseInsufficientFundsUpkeepReportLogs(receipt) + // exactly 1 InsufficientFundsUpkeepReportLogs log should be emitted + assert.equal(insufficientFundsUpkeepReportLogs.length, 1) + }) + + it('permits retrying log triggers after funds are added', async () => { + const txHash = ethers.utils.randomBytes(32) + let tx = await getTransmitTx(registry, keeper1, [logUpkeepId], { + txHash, + logIndex: 0, + }) + let receipt = await tx.wait() + const insufficientFundsLogs = + parseInsufficientFundsUpkeepReportLogs(receipt) + assert.equal(insufficientFundsLogs.length, 1) + registry.connect(admin).addFunds(logUpkeepId, toWei('100')) + tx = await getTransmitTx(registry, keeper1, [logUpkeepId], { + txHash, + logIndex: 0, + }) + receipt = await tx.wait() + const performedLogs = parseUpkeepPerformedLogs(receipt) + assert.equal(performedLogs.length, 1) + }) + + context('When the upkeep is funded', async () => { + beforeEach(async () => { + // Fund the upkeep + await Promise.all([ + registry.connect(admin).addFunds(upkeepId, toWei('100')), + registry.connect(admin).addFunds(logUpkeepId, toWei('100')), + ]) + }) + + it('handles duplicate upkeepIDs', async () => { + const tests: [string, BigNumber, number, number][] = [ + // [name, upkeep, num stale, num performed] + ['conditional', upkeepId, 1, 1], // checkBlocks must be sequential + ['log-trigger', logUpkeepId, 0, 2], // logs are deduped based on the "trigger ID" + ] + for (const [type, id, nStale, nPerformed] of tests) { + const tx = await getTransmitTx(registry, keeper1, [id, id]) + const receipt = await tx.wait() + const staleUpkeepReport = parseStaleUpkeepReportLogs(receipt) + const upkeepPerformedLogs = parseUpkeepPerformedLogs(receipt) + assert.equal( + staleUpkeepReport.length, + nStale, + `wrong log count for ${type} upkeep`, + ) + assert.equal( + upkeepPerformedLogs.length, + nPerformed, + `wrong log count for ${type} upkeep`, + ) + } + }) + + it('handles duplicate log triggers', async () => { + const logBlockHash = ethers.utils.randomBytes(32) + const txHash = ethers.utils.randomBytes(32) + const logIndex = 0 + const expectedDedupKey = ethers.utils.solidityKeccak256( + ['uint256', 'bytes32', 'bytes32', 'uint32'], + [logUpkeepId, logBlockHash, txHash, logIndex], + ) + assert.isFalse(await registry.hasDedupKey(expectedDedupKey)) + const tx = await getTransmitTx( + registry, + keeper1, + [logUpkeepId, logUpkeepId], + { logBlockHash, txHash, logIndex }, // will result in the same dedup key + ) + const receipt = await tx.wait() + const staleUpkeepReport = parseStaleUpkeepReportLogs(receipt) + const upkeepPerformedLogs = parseUpkeepPerformedLogs(receipt) + assert.equal(staleUpkeepReport.length, 1) + assert.equal(upkeepPerformedLogs.length, 1) + assert.isTrue(await registry.hasDedupKey(expectedDedupKey)) + await expect(tx) + .to.emit(registry, 'DedupKeyAdded') + .withArgs(expectedDedupKey) + }) + + it('returns early when check block number is less than last perform (block)', async () => { + // First perform an upkeep to put last perform block number on upkeep state + const tx = await getTransmitTx(registry, keeper1, [upkeepId]) + await tx.wait() + const lastPerformed = (await registry.getUpkeep(upkeepId)) + .lastPerformedBlockNumber + const lastPerformBlock = await ethers.provider.getBlock(lastPerformed) + assert.equal(lastPerformed.toString(), tx.blockNumber?.toString()) + // Try to transmit a report which has checkBlockNumber = lastPerformed-1, should result in stale report + const transmitTx = await getTransmitTx(registry, keeper1, [upkeepId], { + checkBlockNum: lastPerformBlock.number - 1, + checkBlockHash: lastPerformBlock.parentHash, + }) + const receipt = await transmitTx.wait() + const staleUpkeepReportLogs = parseStaleUpkeepReportLogs(receipt) + // exactly 1 StaleUpkeepReportLogs log should be emitted + assert.equal(staleUpkeepReportLogs.length, 1) + }) + + it('handles case when check block hash does not match', async () => { + const tests: [string, BigNumber][] = [ + ['conditional', upkeepId], + ['log-trigger', logUpkeepId], + ] + for (const [type, id] of tests) { + const latestBlock = await ethers.provider.getBlock('latest') + // Try to transmit a report which has incorrect checkBlockHash + const tx = await getTransmitTx(registry, keeper1, [id], { + checkBlockNum: latestBlock.number - 1, + checkBlockHash: latestBlock.hash, // should be latestBlock.parentHash + }) + + const receipt = await tx.wait() + const reorgedUpkeepReportLogs = parseReorgedUpkeepReportLogs(receipt) + // exactly 1 ReorgedUpkeepReportLogs log should be emitted + assert.equal( + reorgedUpkeepReportLogs.length, + 1, + `wrong log count for ${type} upkeep`, + ) + } + }) + + it('handles case when check block number is older than 256 blocks', async () => { + for (let i = 0; i < 256; i++) { + await ethers.provider.send('evm_mine', []) + } + const tests: [string, BigNumber][] = [ + ['conditional', upkeepId], + ['log-trigger', logUpkeepId], + ] + for (const [type, id] of tests) { + const latestBlock = await ethers.provider.getBlock('latest') + const old = await ethers.provider.getBlock(latestBlock.number - 256) + // Try to transmit a report which has incorrect checkBlockHash + const tx = await getTransmitTx(registry, keeper1, [id], { + checkBlockNum: old.number, + checkBlockHash: old.hash, + }) + + const receipt = await tx.wait() + const reorgedUpkeepReportLogs = parseReorgedUpkeepReportLogs(receipt) + // exactly 1 ReorgedUpkeepReportLogs log should be emitted + assert.equal( + reorgedUpkeepReportLogs.length, + 1, + `wrong log count for ${type} upkeep`, + ) + } + }) + + it('allows bypassing reorg protection with empty blockhash', async () => { + const tests: [string, BigNumber][] = [ + ['conditional', upkeepId], + ['log-trigger', logUpkeepId], + ] + for (const [type, id] of tests) { + const latestBlock = await ethers.provider.getBlock('latest') + const tx = await getTransmitTx(registry, keeper1, [id], { + checkBlockNum: latestBlock.number, + checkBlockHash: emptyBytes32, + }) + const receipt = await tx.wait() + const upkeepPerformedLogs = parseUpkeepPerformedLogs(receipt) + assert.equal( + upkeepPerformedLogs.length, + 1, + `wrong log count for ${type} upkeep`, + ) + } + }) + + it('allows very old trigger block numbers when bypassing reorg protection with empty blockhash', async () => { + // mine enough blocks so that blockhash(1) is unavailable + for (let i = 0; i <= 256; i++) { + await ethers.provider.send('evm_mine', []) + } + const tests: [string, BigNumber][] = [ + ['conditional', upkeepId], + ['log-trigger', logUpkeepId], + ] + for (const [type, id] of tests) { + const tx = await getTransmitTx(registry, keeper1, [id], { + checkBlockNum: 1, + checkBlockHash: emptyBytes32, + }) + const receipt = await tx.wait() + const upkeepPerformedLogs = parseUpkeepPerformedLogs(receipt) + assert.equal( + upkeepPerformedLogs.length, + 1, + `wrong log count for ${type} upkeep`, + ) + } + }) + + it('returns early when future block number is provided as trigger, irrespective of blockhash being present', async () => { + const tests: [string, BigNumber][] = [ + ['conditional', upkeepId], + ['log-trigger', logUpkeepId], + ] + for (const [type, id] of tests) { + const latestBlock = await ethers.provider.getBlock('latest') + + // Should fail when blockhash is empty + let tx = await getTransmitTx(registry, keeper1, [id], { + checkBlockNum: latestBlock.number + 100, + checkBlockHash: emptyBytes32, + }) + let receipt = await tx.wait() + let reorgedUpkeepReportLogs = parseReorgedUpkeepReportLogs(receipt) + // exactly 1 ReorgedUpkeepReportLogs log should be emitted + assert.equal( + reorgedUpkeepReportLogs.length, + 1, + `wrong log count for ${type} upkeep`, + ) + + // Should also fail when blockhash is not empty + tx = await getTransmitTx(registry, keeper1, [id], { + checkBlockNum: latestBlock.number + 100, + checkBlockHash: latestBlock.hash, + }) + receipt = await tx.wait() + reorgedUpkeepReportLogs = parseReorgedUpkeepReportLogs(receipt) + // exactly 1 ReorgedUpkeepReportLogs log should be emitted + assert.equal( + reorgedUpkeepReportLogs.length, + 1, + `wrong log count for ${type} upkeep`, + ) + } + }) + + it('returns early when upkeep is cancelled and cancellation delay has gone', async () => { + const latestBlockReport = await makeLatestBlockReport([upkeepId]) + await registry.connect(admin).cancelUpkeep(upkeepId) + + for (let i = 0; i < cancellationDelay; i++) { + await ethers.provider.send('evm_mine', []) + } + + const tx = await getTransmitTxWithReport( + registry, + keeper1, + latestBlockReport, + ) + + const receipt = await tx.wait() + const cancelledUpkeepReportLogs = + parseCancelledUpkeepReportLogs(receipt) + // exactly 1 CancelledUpkeepReport log should be emitted + assert.equal(cancelledUpkeepReportLogs.length, 1) + }) + + it('does not revert if the target cannot execute', async () => { + await mock.setCanPerform(false) + const tx = await getTransmitTx(registry, keeper1, [upkeepId]) + + const receipt = await tx.wait() + const upkeepPerformedLogs = parseUpkeepPerformedLogs(receipt) + // exactly 1 Upkeep Performed should be emitted + assert.equal(upkeepPerformedLogs.length, 1) + const upkeepPerformedLog = upkeepPerformedLogs[0] + + const success = upkeepPerformedLog.args.success + assert.equal(success, false) + }) + + it('does not revert if the target runs out of gas', async () => { + await mock.setCanPerform(false) + + const tx = await getTransmitTx(registry, keeper1, [upkeepId], { + performGas: 10, // too little gas + }) + + const receipt = await tx.wait() + const upkeepPerformedLogs = parseUpkeepPerformedLogs(receipt) + // exactly 1 Upkeep Performed should be emitted + assert.equal(upkeepPerformedLogs.length, 1) + const upkeepPerformedLog = upkeepPerformedLogs[0] + + const success = upkeepPerformedLog.args.success + assert.equal(success, false) + }) + + it('reverts if not enough gas supplied', async () => { + await evmRevert( + getTransmitTx(registry, keeper1, [upkeepId], { + gasLimit: performGas, + }), + ) + }) + + it('executes the data passed to the registry', async () => { + await mock.setCanPerform(true) + + const tx = await getTransmitTx(registry, keeper1, [upkeepId], { + performData: randomBytes, + }) + const receipt = await tx.wait() + + const upkeepPerformedWithABI = [ + 'event UpkeepPerformedWith(bytes upkeepData)', + ] + const iface = new ethers.utils.Interface(upkeepPerformedWithABI) + const parsedLogs = [] + for (let i = 0; i < receipt.logs.length; i++) { + const log = receipt.logs[i] + try { + parsedLogs.push(iface.parseLog(log)) + } catch (e) { + // ignore log + } + } + assert.equal(parsedLogs.length, 1) + assert.equal(parsedLogs[0].args.upkeepData, randomBytes) + }) + + it('uses actual execution price for payment and premium calculation', async () => { + // Actual multiplier is 2, but we set gasPrice to be 1x gasWei + const gasPrice = gasWei.mul(BigNumber.from('1')) + await mock.setCanPerform(true) + const registryPremiumBefore = (await registry.getState()).state + .totalPremium + const tx = await getTransmitTx(registry, keeper1, [upkeepId], { + gasPrice, + }) + const receipt = await tx.wait() + const registryPremiumAfter = (await registry.getState()).state + .totalPremium + const premium = registryPremiumAfter.sub(registryPremiumBefore) + + const upkeepPerformedLogs = parseUpkeepPerformedLogs(receipt) + // exactly 1 Upkeep Performed should be emitted + assert.equal(upkeepPerformedLogs.length, 1) + const upkeepPerformedLog = upkeepPerformedLogs[0] + + const gasUsed = upkeepPerformedLog.args.gasUsed + const gasOverhead = upkeepPerformedLog.args.gasOverhead + const totalPayment = upkeepPerformedLog.args.totalPayment + + assert.equal( + linkForGas( + gasUsed, + gasOverhead, + BigNumber.from('1'), // Not the config multiplier, but the actual gas used + paymentPremiumPPB, + flatFeeMicroLink, + ).total.toString(), + totalPayment.toString(), + ) + + assert.equal( + linkForGas( + gasUsed, + gasOverhead, + BigNumber.from('1'), // Not the config multiplier, but the actual gas used + paymentPremiumPPB, + flatFeeMicroLink, + ).premium.toString(), + premium.toString(), + ) + }) + + it('only pays at a rate up to the gas ceiling [ @skip-coverage ]', async () => { + // Actual multiplier is 2, but we set gasPrice to be 10x + const gasPrice = gasWei.mul(BigNumber.from('10')) + await mock.setCanPerform(true) + + const tx = await getTransmitTx(registry, keeper1, [upkeepId], { + gasPrice, + }) + const receipt = await tx.wait() + const upkeepPerformedLogs = parseUpkeepPerformedLogs(receipt) + // exactly 1 Upkeep Performed should be emitted + assert.equal(upkeepPerformedLogs.length, 1) + const upkeepPerformedLog = upkeepPerformedLogs[0] + + const gasUsed = upkeepPerformedLog.args.gasUsed + const gasOverhead = upkeepPerformedLog.args.gasOverhead + const totalPayment = upkeepPerformedLog.args.totalPayment + + assert.equal( + linkForGas( + gasUsed, + gasOverhead, + gasCeilingMultiplier, // Should be same with exisitng multiplier + paymentPremiumPPB, + flatFeeMicroLink, + ).total.toString(), + totalPayment.toString(), + ) + }) + + it('correctly accounts for l payment', async () => { + await mock.setCanPerform(true) + // Same as MockArbGasInfo.sol + const l1CostWeiArb = BigNumber.from(1000000) + + let tx = await arbRegistry + .connect(owner) + ['registerUpkeep(address,uint32,address,bytes,bytes)']( + mock.address, + performGas, + await admin.getAddress(), + randomBytes, + '0x', + ) + const testUpkeepId = await getUpkeepID(tx) + await arbRegistry.connect(owner).addFunds(testUpkeepId, toWei('100')) + + // Do the thing + tx = await getTransmitTx( + arbRegistry, + keeper1, + [testUpkeepId], + + { gasPrice: gasWei.mul('5') }, // High gas price so that it gets capped + ) + const receipt = await tx.wait() + const upkeepPerformedLogs = parseUpkeepPerformedLogs(receipt) + // exactly 1 Upkeep Performed should be emitted + assert.equal(upkeepPerformedLogs.length, 1) + const upkeepPerformedLog = upkeepPerformedLogs[0] + + const gasUsed = upkeepPerformedLog.args.gasUsed + const gasOverhead = upkeepPerformedLog.args.gasOverhead + const totalPayment = upkeepPerformedLog.args.totalPayment + + assert.equal( + linkForGas( + gasUsed, + gasOverhead, + gasCeilingMultiplier, + paymentPremiumPPB, + flatFeeMicroLink, + l1CostWeiArb.div(gasCeilingMultiplier), // Dividing by gasCeilingMultiplier as it gets multiplied later + ).total.toString(), + totalPayment.toString(), + ) + }) + + itMaybe('can self fund', async () => { + const maxPayment = await registry.getMaxPaymentForGas( + Trigger.CONDITION, + performGas, + ) + + // First set auto funding amount to 0 and verify that balance is deducted upon performUpkeep + let initialBalance = toWei('100') + await registry.connect(owner).addFunds(afUpkeepId, initialBalance) + await autoFunderUpkeep.setAutoFundLink(0) + await autoFunderUpkeep.setIsEligible(true) + await getTransmitTx(registry, keeper1, [afUpkeepId]) + + let postUpkeepBalance = (await registry.getUpkeep(afUpkeepId)).balance + assert.isTrue(postUpkeepBalance.lt(initialBalance)) // Balance should be deducted + assert.isTrue(postUpkeepBalance.gte(initialBalance.sub(maxPayment))) // Balance should not be deducted more than maxPayment + + // Now set auto funding amount to 100 wei and verify that the balance increases + initialBalance = postUpkeepBalance + const autoTopupAmount = toWei('100') + await autoFunderUpkeep.setAutoFundLink(autoTopupAmount) + await autoFunderUpkeep.setIsEligible(true) + await getTransmitTx(registry, keeper1, [afUpkeepId]) + + postUpkeepBalance = (await registry.getUpkeep(afUpkeepId)).balance + // Balance should increase by autoTopupAmount and decrease by max maxPayment + assert.isTrue( + postUpkeepBalance.gte( + initialBalance.add(autoTopupAmount).sub(maxPayment), + ), + ) + }) + + it('can self cancel', async () => { + await registry.connect(owner).addFunds(afUpkeepId, toWei('100')) + + await autoFunderUpkeep.setIsEligible(true) + await autoFunderUpkeep.setShouldCancel(true) + + let registration = await registry.getUpkeep(afUpkeepId) + const oldExpiration = registration.maxValidBlocknumber + + // Do the thing + await getTransmitTx(registry, keeper1, [afUpkeepId]) + + // Verify upkeep gets cancelled + registration = await registry.getUpkeep(afUpkeepId) + const newExpiration = registration.maxValidBlocknumber + assert.isTrue(newExpiration.lt(oldExpiration)) + }) + + it('reverts when configDigest mismatches', async () => { + const report = await makeLatestBlockReport([upkeepId]) + const reportContext = [emptyBytes32, epochAndRound5_1, emptyBytes32] // wrong config digest + const sigs = signReport(reportContext, report, signers.slice(0, f + 1)) + await evmRevert( + registry + .connect(keeper1) + .transmit( + [reportContext[0], reportContext[1], reportContext[2]], + report, + sigs.rs, + sigs.ss, + sigs.vs, + ), + 'ConfigDigestMismatch()', + ) + }) + + it('reverts with incorrect number of signatures', async () => { + const configDigest = (await registry.getState()).state + .latestConfigDigest + const report = await makeLatestBlockReport([upkeepId]) + const reportContext = [configDigest, epochAndRound5_1, emptyBytes32] // wrong config digest + const sigs = signReport(reportContext, report, signers.slice(0, f + 2)) + await evmRevert( + registry + .connect(keeper1) + .transmit( + [reportContext[0], reportContext[1], reportContext[2]], + report, + sigs.rs, + sigs.ss, + sigs.vs, + ), + 'IncorrectNumberOfSignatures()', + ) + }) + + it('reverts with invalid signature for inactive signers', async () => { + const configDigest = (await registry.getState()).state + .latestConfigDigest + const report = await makeLatestBlockReport([upkeepId]) + const reportContext = [configDigest, epochAndRound5_1, emptyBytes32] // wrong config digest + const sigs = signReport(reportContext, report, [ + new ethers.Wallet(ethers.Wallet.createRandom()), + new ethers.Wallet(ethers.Wallet.createRandom()), + ]) + await evmRevert( + registry + .connect(keeper1) + .transmit( + [reportContext[0], reportContext[1], reportContext[2]], + report, + sigs.rs, + sigs.ss, + sigs.vs, + ), + 'OnlyActiveSigners()', + ) + }) + + it('reverts with invalid signature for duplicated signers', async () => { + const configDigest = (await registry.getState()).state + .latestConfigDigest + const report = await makeLatestBlockReport([upkeepId]) + const reportContext = [configDigest, epochAndRound5_1, emptyBytes32] // wrong config digest + const sigs = signReport(reportContext, report, [signer1, signer1]) + await evmRevert( + registry + .connect(keeper1) + .transmit( + [reportContext[0], reportContext[1], reportContext[2]], + report, + sigs.rs, + sigs.ss, + sigs.vs, + ), + 'DuplicateSigners()', + ) + }) + + itMaybe( + 'has a large enough gas overhead to cover upkeep that use all its gas [ @skip-coverage ]', + async () => { + await registry.connect(owner).setConfigTypeSafe( + signerAddresses, + keeperAddresses, + 10, // maximise f to maximise overhead + config, + offchainVersion, + offchainBytes, + ) + const tx = await registry + .connect(owner) + ['registerUpkeep(address,uint32,address,bytes,bytes)']( + mock.address, + maxPerformGas, // max allowed gas + await admin.getAddress(), + randomBytes, + '0x', + ) + const testUpkeepId = await getUpkeepID(tx) + await registry.connect(admin).addFunds(testUpkeepId, toWei('100')) + + let performData = '0x' + for (let i = 0; i < maxPerformDataSize.toNumber(); i++) { + performData += '11' + } // max allowed performData + + await mock.setCanPerform(true) + await mock.setPerformGasToBurn(maxPerformGas) + + await getTransmitTx(registry, keeper1, [testUpkeepId], { + gasLimit: maxPerformGas.add(transmitGasOverhead), + numSigners: 11, + performData, + }) // Should not revert + }, + ) + + itMaybe( + 'performs upkeep, deducts payment, updates lastPerformed and emits events', + async () => { + await mock.setCanPerform(true) + + for (const i in fArray) { + const newF = fArray[i] + await registry + .connect(owner) + .setConfigTypeSafe( + signerAddresses, + keeperAddresses, + newF, + config, + offchainVersion, + offchainBytes, + ) + const checkBlock = await ethers.provider.getBlock('latest') + + const keeperBefore = await registry.getTransmitterInfo( + await keeper1.getAddress(), + ) + const registrationBefore = await registry.getUpkeep(upkeepId) + const registryPremiumBefore = (await registry.getState()).state + .totalPremium + const keeperLinkBefore = await linkToken.balanceOf( + await keeper1.getAddress(), + ) + const registryLinkBefore = await linkToken.balanceOf( + registry.address, + ) + + // Do the thing + const tx = await getTransmitTx(registry, keeper1, [upkeepId], { + checkBlockNum: checkBlock.number, + checkBlockHash: checkBlock.hash, + numSigners: newF + 1, + }) + + const receipt = await tx.wait() + + const upkeepPerformedLogs = parseUpkeepPerformedLogs(receipt) + // exactly 1 Upkeep Performed should be emitted + assert.equal(upkeepPerformedLogs.length, 1) + const upkeepPerformedLog = upkeepPerformedLogs[0] + + const id = upkeepPerformedLog.args.id + const success = upkeepPerformedLog.args.success + const trigger = upkeepPerformedLog.args.trigger + const gasUsed = upkeepPerformedLog.args.gasUsed + const gasOverhead = upkeepPerformedLog.args.gasOverhead + const totalPayment = upkeepPerformedLog.args.totalPayment + assert.equal(id.toString(), upkeepId.toString()) + assert.equal(success, true) + assert.equal( + trigger, + encodeBlockTrigger({ + blockNum: checkBlock.number, + blockHash: checkBlock.hash, + }), + ) + assert.isTrue(gasUsed.gt(BigNumber.from('0'))) + assert.isTrue(gasOverhead.gt(BigNumber.from('0'))) + assert.isTrue(totalPayment.gt(BigNumber.from('0'))) + + const keeperAfter = await registry.getTransmitterInfo( + await keeper1.getAddress(), + ) + const registrationAfter = await registry.getUpkeep(upkeepId) + const keeperLinkAfter = await linkToken.balanceOf( + await keeper1.getAddress(), + ) + const registryLinkAfter = await linkToken.balanceOf( + registry.address, + ) + const registryPremiumAfter = (await registry.getState()).state + .totalPremium + const premium = registryPremiumAfter.sub(registryPremiumBefore) + // Keeper payment is gasPayment + premium / num keepers + const keeperPayment = totalPayment + .sub(premium) + .add(premium.div(BigNumber.from(keeperAddresses.length))) + + assert.equal( + keeperAfter.balance.sub(keeperPayment).toString(), + keeperBefore.balance.toString(), + ) + assert.equal( + registrationBefore.balance.sub(totalPayment).toString(), + registrationAfter.balance.toString(), + ) + assert.isTrue(keeperLinkAfter.eq(keeperLinkBefore)) + assert.isTrue(registryLinkBefore.eq(registryLinkAfter)) + + // Amount spent should be updated correctly + assert.equal( + registrationAfter.amountSpent.sub(totalPayment).toString(), + registrationBefore.amountSpent.toString(), + ) + assert.isTrue( + registrationAfter.amountSpent + .sub(registrationBefore.amountSpent) + .eq(registrationBefore.balance.sub(registrationAfter.balance)), + ) + // Last perform block number should be updated + assert.equal( + registrationAfter.lastPerformedBlockNumber.toString(), + tx.blockNumber?.toString(), + ) + + // Latest epoch should be 5 + assert.equal((await registry.getState()).state.latestEpoch, 5) + } + }, + ) + + describeMaybe( + 'Gas benchmarking conditional upkeeps [ @skip-coverage ]', + function () { + const fs = [1, 10] + fs.forEach(function (newF) { + it( + 'When f=' + + newF + + ' calculates gas overhead appropriately within a margin for different scenarios', + async () => { + // Perform the upkeep once to remove non-zero storage slots and have predictable gas measurement + let tx = await getTransmitTx(registry, keeper1, [upkeepId]) + await tx.wait() + + // Different test scenarios + let longBytes = '0x' + for (let i = 0; i < maxPerformDataSize.toNumber(); i++) { + longBytes += '11' + } + const upkeepSuccessArray = [true, false] + const performGasArray = [5000, performGas] + const performDataArray = ['0x', longBytes] + + for (const i in upkeepSuccessArray) { + for (const j in performGasArray) { + for (const k in performDataArray) { + const upkeepSuccess = upkeepSuccessArray[i] + const performGas = performGasArray[j] + const performData = performDataArray[k] + + await mock.setCanPerform(upkeepSuccess) + await mock.setPerformGasToBurn(performGas) + await registry + .connect(owner) + .setConfigTypeSafe( + signerAddresses, + keeperAddresses, + newF, + config, + offchainVersion, + offchainBytes, + ) + tx = await getTransmitTx(registry, keeper1, [upkeepId], { + numSigners: newF + 1, + performData, + }) + const receipt = await tx.wait() + const upkeepPerformedLogs = + parseUpkeepPerformedLogs(receipt) + // exactly 1 Upkeep Performed should be emitted + assert.equal(upkeepPerformedLogs.length, 1) + const upkeepPerformedLog = upkeepPerformedLogs[0] + + const upkeepGasUsed = upkeepPerformedLog.args.gasUsed + const chargedGasOverhead = + upkeepPerformedLog.args.gasOverhead + const actualGasOverhead = + receipt.gasUsed.sub(upkeepGasUsed) + + assert.isTrue(upkeepGasUsed.gt(BigNumber.from('0'))) + assert.isTrue(chargedGasOverhead.gt(BigNumber.from('0'))) + + console.log( + 'Gas Benchmarking conditional upkeeps:', + 'upkeepSuccess=', + upkeepSuccess, + 'performGas=', + performGas.toString(), + 'performData length=', + performData.length / 2 - 1, + 'sig verification ( f =', + newF, + '): calculated overhead: ', + chargedGasOverhead.toString(), + ' actual overhead: ', + actualGasOverhead.toString(), + ' margin over gasUsed: ', + chargedGasOverhead.sub(actualGasOverhead).toString(), + ) + + // Overhead should not get capped + const gasOverheadCap = registryConditionalOverhead + .add( + registryPerSignerGasOverhead.mul( + BigNumber.from(newF + 1), + ), + ) + .add( + BigNumber.from( + registryPerPerformByteGasOverhead.toNumber() * + performData.length, + ), + ) + const gasCapMinusOverhead = + gasOverheadCap.sub(chargedGasOverhead) + assert.isTrue( + gasCapMinusOverhead.gt(BigNumber.from(0)), + 'Gas overhead got capped. Verify gas overhead variables in test match those in the registry. To not have the overheads capped increase REGISTRY_GAS_OVERHEAD by atleast ' + + gasCapMinusOverhead.toString(), + ) + // total gas charged should be greater than tx gas but within gasCalculationMargin + assert.isTrue( + chargedGasOverhead.gt(actualGasOverhead), + 'Gas overhead calculated is too low, increase account gas variables (ACCOUNTING_FIXED_GAS_OVERHEAD/ACCOUNTING_PER_SIGNER_GAS_OVERHEAD) by atleast ' + + actualGasOverhead.sub(chargedGasOverhead).toString(), + ) + + assert.isTrue( + chargedGasOverhead + .sub(actualGasOverhead) + .lt(gasCalculationMargin), + ), + 'Gas overhead calculated is too high, decrease account gas variables (ACCOUNTING_FIXED_GAS_OVERHEAD/ACCOUNTING_PER_SIGNER_GAS_OVERHEAD) by atleast ' + + chargedGasOverhead + .sub(chargedGasOverhead) + .sub(gasCalculationMargin) + .toString() + } + } + } + }, + ) + }) + }, + ) + + describeMaybe( + 'Gas benchmarking log upkeeps [ @skip-coverage ]', + function () { + const fs = [1, 10] + fs.forEach(function (newF) { + it( + 'When f=' + + newF + + ' calculates gas overhead appropriately within a margin', + async () => { + // Perform the upkeep once to remove non-zero storage slots and have predictable gas measurement + let tx = await getTransmitTx(registry, keeper1, [logUpkeepId]) + await tx.wait() + const performData = '0x' + await mock.setCanPerform(true) + await mock.setPerformGasToBurn(performGas) + await registry.setConfigTypeSafe( + signerAddresses, + keeperAddresses, + newF, + config, + offchainVersion, + offchainBytes, + ) + tx = await getTransmitTx(registry, keeper1, [logUpkeepId], { + numSigners: newF + 1, + performData, + }) + const receipt = await tx.wait() + const upkeepPerformedLogs = parseUpkeepPerformedLogs(receipt) + // exactly 1 Upkeep Performed should be emitted + assert.equal(upkeepPerformedLogs.length, 1) + const upkeepPerformedLog = upkeepPerformedLogs[0] + + const upkeepGasUsed = upkeepPerformedLog.args.gasUsed + const chargedGasOverhead = upkeepPerformedLog.args.gasOverhead + const actualGasOverhead = receipt.gasUsed.sub(upkeepGasUsed) + + assert.isTrue(upkeepGasUsed.gt(BigNumber.from('0'))) + assert.isTrue(chargedGasOverhead.gt(BigNumber.from('0'))) + + console.log( + 'Gas Benchmarking log upkeeps:', + 'upkeepSuccess=', + true, + 'performGas=', + performGas.toString(), + 'performData length=', + performData.length / 2 - 1, + 'sig verification ( f =', + newF, + '): calculated overhead: ', + chargedGasOverhead.toString(), + ' actual overhead: ', + actualGasOverhead.toString(), + ' margin over gasUsed: ', + chargedGasOverhead.sub(actualGasOverhead).toString(), + ) + + // Overhead should not get capped + const gasOverheadCap = registryLogOverhead + .add( + registryPerSignerGasOverhead.mul(BigNumber.from(newF + 1)), + ) + .add( + BigNumber.from( + registryPerPerformByteGasOverhead.toNumber() * + performData.length, + ), + ) + const gasCapMinusOverhead = + gasOverheadCap.sub(chargedGasOverhead) + assert.isTrue( + gasCapMinusOverhead.gt(BigNumber.from(0)), + 'Gas overhead got capped. Verify gas overhead variables in test match those in the registry. To not have the overheads capped increase REGISTRY_GAS_OVERHEAD by atleast ' + + gasCapMinusOverhead.toString(), + ) + // total gas charged should be greater than tx gas but within gasCalculationMargin + assert.isTrue( + chargedGasOverhead.gt(actualGasOverhead), + 'Gas overhead calculated is too low, increase account gas variables (ACCOUNTING_FIXED_GAS_OVERHEAD/ACCOUNTING_PER_SIGNER_GAS_OVERHEAD) by atleast ' + + actualGasOverhead.sub(chargedGasOverhead).toString(), + ) + + assert.isTrue( + chargedGasOverhead + .sub(actualGasOverhead) + .lt(gasCalculationMargin), + ), + 'Gas overhead calculated is too high, decrease account gas variables (ACCOUNTING_FIXED_GAS_OVERHEAD/ACCOUNTING_PER_SIGNER_GAS_OVERHEAD) by atleast ' + + chargedGasOverhead + .sub(chargedGasOverhead) + .sub(gasCalculationMargin) + .toString() + }, + ) + }) + }, + ) + }) + }) + + describeMaybe( + '#transmit with upkeep batches [ @skip-coverage ]', + function () { + const numPassingConditionalUpkeepsArray = [0, 1, 5] + const numPassingLogUpkeepsArray = [0, 1, 5] + const numFailingUpkeepsArray = [0, 3] + + for (let idx = 0; idx < numPassingConditionalUpkeepsArray.length; idx++) { + for (let jdx = 0; jdx < numPassingLogUpkeepsArray.length; jdx++) { + for (let kdx = 0; kdx < numFailingUpkeepsArray.length; kdx++) { + const numPassingConditionalUpkeeps = + numPassingConditionalUpkeepsArray[idx] + const numPassingLogUpkeeps = numPassingLogUpkeepsArray[jdx] + const numFailingUpkeeps = numFailingUpkeepsArray[kdx] + if ( + numPassingConditionalUpkeeps == 0 && + numPassingLogUpkeeps == 0 + ) { + continue + } + it( + '[Conditional:' + + numPassingConditionalUpkeeps + + ',Log:' + + numPassingLogUpkeeps + + ',Failures:' + + numFailingUpkeeps + + '] performs successful upkeeps and does not charge failing upkeeps', + async () => { + const allUpkeeps = await getMultipleUpkeepsDeployedAndFunded( + numPassingConditionalUpkeeps, + numPassingLogUpkeeps, + numFailingUpkeeps, + ) + const passingConditionalUpkeepIds = + allUpkeeps.passingConditionalUpkeepIds + const passingLogUpkeepIds = allUpkeeps.passingLogUpkeepIds + const failingUpkeepIds = allUpkeeps.failingUpkeepIds + + const keeperBefore = await registry.getTransmitterInfo( + await keeper1.getAddress(), + ) + const keeperLinkBefore = await linkToken.balanceOf( + await keeper1.getAddress(), + ) + const registryLinkBefore = await linkToken.balanceOf( + registry.address, + ) + const registryPremiumBefore = (await registry.getState()).state + .totalPremium + const registrationConditionalPassingBefore = await Promise.all( + passingConditionalUpkeepIds.map(async (id) => { + const reg = await registry.getUpkeep(BigNumber.from(id)) + assert.equal(reg.lastPerformedBlockNumber.toString(), '0') + return reg + }), + ) + const registrationLogPassingBefore = await Promise.all( + passingLogUpkeepIds.map(async (id) => { + const reg = await registry.getUpkeep(BigNumber.from(id)) + assert.equal(reg.lastPerformedBlockNumber.toString(), '0') + return reg + }), + ) + const registrationFailingBefore = await Promise.all( + failingUpkeepIds.map(async (id) => { + const reg = await registry.getUpkeep(BigNumber.from(id)) + assert.equal(reg.lastPerformedBlockNumber.toString(), '0') + return reg + }), + ) + + const tx = await getTransmitTx( + registry, + keeper1, + passingConditionalUpkeepIds.concat( + passingLogUpkeepIds.concat(failingUpkeepIds), + ), + ) + + const receipt = await tx.wait() + const upkeepPerformedLogs = parseUpkeepPerformedLogs(receipt) + // exactly numPassingUpkeeps Upkeep Performed should be emitted + assert.equal( + upkeepPerformedLogs.length, + numPassingConditionalUpkeeps + numPassingLogUpkeeps, + ) + const insufficientFundsLogs = + parseInsufficientFundsUpkeepReportLogs(receipt) + // exactly numFailingUpkeeps Upkeep Performed should be emitted + assert.equal(insufficientFundsLogs.length, numFailingUpkeeps) + + const keeperAfter = await registry.getTransmitterInfo( + await keeper1.getAddress(), + ) + const keeperLinkAfter = await linkToken.balanceOf( + await keeper1.getAddress(), + ) + const registryLinkAfter = await linkToken.balanceOf( + registry.address, + ) + const registrationConditionalPassingAfter = await Promise.all( + passingConditionalUpkeepIds.map(async (id) => { + return await registry.getUpkeep(BigNumber.from(id)) + }), + ) + const registrationLogPassingAfter = await Promise.all( + passingLogUpkeepIds.map(async (id) => { + return await registry.getUpkeep(BigNumber.from(id)) + }), + ) + const registrationFailingAfter = await Promise.all( + failingUpkeepIds.map(async (id) => { + return await registry.getUpkeep(BigNumber.from(id)) + }), + ) + const registryPremiumAfter = (await registry.getState()).state + .totalPremium + const premium = registryPremiumAfter.sub(registryPremiumBefore) + + let netPayment = BigNumber.from('0') + for (let i = 0; i < numPassingConditionalUpkeeps; i++) { + const id = upkeepPerformedLogs[i].args.id + const gasUsed = upkeepPerformedLogs[i].args.gasUsed + const gasOverhead = upkeepPerformedLogs[i].args.gasOverhead + const totalPayment = upkeepPerformedLogs[i].args.totalPayment + + expect(id).to.equal(passingConditionalUpkeepIds[i]) + assert.isTrue(gasUsed.gt(BigNumber.from('0'))) + assert.isTrue(gasOverhead.gt(BigNumber.from('0'))) + assert.isTrue(totalPayment.gt(BigNumber.from('0'))) + + // Balance should be deducted + assert.equal( + registrationConditionalPassingBefore[i].balance + .sub(totalPayment) + .toString(), + registrationConditionalPassingAfter[i].balance.toString(), + ) + + // Amount spent should be updated correctly + assert.equal( + registrationConditionalPassingAfter[i].amountSpent + .sub(totalPayment) + .toString(), + registrationConditionalPassingBefore[ + i + ].amountSpent.toString(), + ) + + // Last perform block number should be updated + assert.equal( + registrationConditionalPassingAfter[ + i + ].lastPerformedBlockNumber.toString(), + tx.blockNumber?.toString(), + ) + + netPayment = netPayment.add(totalPayment) + } + + for (let i = 0; i < numPassingLogUpkeeps; i++) { + const id = + upkeepPerformedLogs[numPassingConditionalUpkeeps + i].args + .id + const gasUsed = + upkeepPerformedLogs[numPassingConditionalUpkeeps + i].args + .gasUsed + const gasOverhead = + upkeepPerformedLogs[numPassingConditionalUpkeeps + i].args + .gasOverhead + const totalPayment = + upkeepPerformedLogs[numPassingConditionalUpkeeps + i].args + .totalPayment + + expect(id).to.equal(passingLogUpkeepIds[i]) + assert.isTrue(gasUsed.gt(BigNumber.from('0'))) + assert.isTrue(gasOverhead.gt(BigNumber.from('0'))) + assert.isTrue(totalPayment.gt(BigNumber.from('0'))) + + // Balance should be deducted + assert.equal( + registrationLogPassingBefore[i].balance + .sub(totalPayment) + .toString(), + registrationLogPassingAfter[i].balance.toString(), + ) + + // Amount spent should be updated correctly + assert.equal( + registrationLogPassingAfter[i].amountSpent + .sub(totalPayment) + .toString(), + registrationLogPassingBefore[i].amountSpent.toString(), + ) + + // Last perform block number should not be updated for log triggers + assert.equal( + registrationLogPassingAfter[ + i + ].lastPerformedBlockNumber.toString(), + '0', + ) + + netPayment = netPayment.add(totalPayment) + } + + for (let i = 0; i < numFailingUpkeeps; i++) { + // InsufficientFunds log should be emitted + const id = insufficientFundsLogs[i].args.id + expect(id).to.equal(failingUpkeepIds[i]) + + // Balance and amount spent should be same + assert.equal( + registrationFailingBefore[i].balance.toString(), + registrationFailingAfter[i].balance.toString(), + ) + assert.equal( + registrationFailingBefore[i].amountSpent.toString(), + registrationFailingAfter[i].amountSpent.toString(), + ) + + // Last perform block number should not be updated + assert.equal( + registrationFailingAfter[ + i + ].lastPerformedBlockNumber.toString(), + '0', + ) + } + + // Keeper payment is gasPayment + premium / num keepers + const keeperPayment = netPayment + .sub(premium) + .add(premium.div(BigNumber.from(keeperAddresses.length))) + + // Keeper should be paid net payment for all passed upkeeps + assert.equal( + keeperAfter.balance.sub(keeperPayment).toString(), + keeperBefore.balance.toString(), + ) + + assert.isTrue(keeperLinkAfter.eq(keeperLinkBefore)) + assert.isTrue(registryLinkBefore.eq(registryLinkAfter)) + }, + ) + + it( + '[Conditional:' + + numPassingConditionalUpkeeps + + ',Log' + + numPassingLogUpkeeps + + ',Failures:' + + numFailingUpkeeps + + '] splits gas overhead appropriately among performed upkeeps [ @skip-coverage ]', + async () => { + const allUpkeeps = await getMultipleUpkeepsDeployedAndFunded( + numPassingConditionalUpkeeps, + numPassingLogUpkeeps, + numFailingUpkeeps, + ) + const passingConditionalUpkeepIds = + allUpkeeps.passingConditionalUpkeepIds + const passingLogUpkeepIds = allUpkeeps.passingLogUpkeepIds + const failingUpkeepIds = allUpkeeps.failingUpkeepIds + + // Perform the upkeeps once to remove non-zero storage slots and have predictable gas measurement + let tx = await getTransmitTx( + registry, + keeper1, + passingConditionalUpkeepIds.concat( + passingLogUpkeepIds.concat(failingUpkeepIds), + ), + ) + + await tx.wait() + + // Do the actual thing + + tx = await getTransmitTx( + registry, + keeper1, + passingConditionalUpkeepIds.concat( + passingLogUpkeepIds.concat(failingUpkeepIds), + ), + ) + + const receipt = await tx.wait() + const upkeepPerformedLogs = parseUpkeepPerformedLogs(receipt) + // exactly numPassingUpkeeps Upkeep Performed should be emitted + assert.equal( + upkeepPerformedLogs.length, + numPassingConditionalUpkeeps + numPassingLogUpkeeps, + ) + + const gasConditionalOverheadCap = + registryConditionalOverhead.add( + registryPerSignerGasOverhead.mul(BigNumber.from(f + 1)), + ) + const gasLogOverheadCap = registryLogOverhead.add( + registryPerSignerGasOverhead.mul(BigNumber.from(f + 1)), + ) + + const overheadCanGetCapped = + numFailingUpkeeps > 0 && + numPassingConditionalUpkeeps <= 1 && + numPassingLogUpkeeps <= 1 + // Can happen if there are failing upkeeps and only 1 successful upkeep of each type + let netGasUsedPlusOverhead = BigNumber.from('0') + + for (let i = 0; i < numPassingConditionalUpkeeps; i++) { + const gasUsed = upkeepPerformedLogs[i].args.gasUsed + const gasOverhead = upkeepPerformedLogs[i].args.gasOverhead + + assert.isTrue(gasUsed.gt(BigNumber.from('0'))) + assert.isTrue(gasOverhead.gt(BigNumber.from('0'))) + + // Overhead should not exceed capped + assert.isTrue(gasOverhead.lte(gasConditionalOverheadCap)) + + // Overhead should be same for every upkeep since they have equal performData, hence same caps + assert.isTrue( + gasOverhead.eq(upkeepPerformedLogs[0].args.gasOverhead), + ) + + netGasUsedPlusOverhead = netGasUsedPlusOverhead + .add(gasUsed) + .add(gasOverhead) + } + for (let i = 0; i < numPassingLogUpkeeps; i++) { + const gasUsed = + upkeepPerformedLogs[numPassingConditionalUpkeeps + i].args + .gasUsed + const gasOverhead = + upkeepPerformedLogs[numPassingConditionalUpkeeps + i].args + .gasOverhead + + assert.isTrue(gasUsed.gt(BigNumber.from('0'))) + assert.isTrue(gasOverhead.gt(BigNumber.from('0'))) + + // Overhead should not exceed capped + assert.isTrue(gasOverhead.lte(gasLogOverheadCap)) + + // Overhead should be same for every upkeep since they have equal performData, hence same caps + assert.isTrue( + gasOverhead.eq( + upkeepPerformedLogs[numPassingConditionalUpkeeps].args + .gasOverhead, + ), + ) + + netGasUsedPlusOverhead = netGasUsedPlusOverhead + .add(gasUsed) + .add(gasOverhead) + } + + const overheadsGotCapped = + (numPassingConditionalUpkeeps > 0 && + upkeepPerformedLogs[0].args.gasOverhead.eq( + gasConditionalOverheadCap, + )) || + (numPassingLogUpkeeps > 0 && + upkeepPerformedLogs[ + numPassingConditionalUpkeeps + ].args.gasOverhead.eq(gasLogOverheadCap)) + // Should only get capped in certain scenarios + if (overheadsGotCapped) { + assert.isTrue( + overheadCanGetCapped, + 'Gas overhead got capped. Verify gas overhead variables in test match those in the registry. To not have the overheads capped increase REGISTRY_GAS_OVERHEAD', + ) + } + + console.log( + 'Gas Benchmarking - batching (passedConditionalUpkeeps: ', + numPassingConditionalUpkeeps, + 'passedLogUpkeeps:', + numPassingLogUpkeeps, + 'failedUpkeeps:', + numFailingUpkeeps, + '): ', + 'overheadsGotCapped', + overheadsGotCapped, + numPassingConditionalUpkeeps > 0 + ? 'calculated conditional overhead' + : '', + numPassingConditionalUpkeeps > 0 + ? upkeepPerformedLogs[0].args.gasOverhead.toString() + : '', + numPassingLogUpkeeps > 0 ? 'calculated log overhead' : '', + numPassingLogUpkeeps > 0 + ? upkeepPerformedLogs[ + numPassingConditionalUpkeeps + ].args.gasOverhead.toString() + : '', + ' margin over gasUsed', + netGasUsedPlusOverhead.sub(receipt.gasUsed).toString(), + ) + + // If overheads dont get capped then total gas charged should be greater than tx gas + // We don't check whether the net is within gasMargin as the margin changes with numFailedUpkeeps + // Which is ok, as long as individual gas overhead is capped + if (!overheadsGotCapped) { + assert.isTrue( + netGasUsedPlusOverhead.gt(receipt.gasUsed), + 'Gas overhead is too low, increase ACCOUNTING_PER_UPKEEP_GAS_OVERHEAD', + ) + } + }, + ) + } + } + } + + it('has enough perform gas overhead for large batches [ @skip-coverage ]', async () => { + const numUpkeeps = 20 + const upkeepIds: BigNumber[] = [] + let totalPerformGas = BigNumber.from('0') + for (let i = 0; i < numUpkeeps; i++) { + const mock = await upkeepMockFactory.deploy() + const tx = await registry + .connect(owner) + ['registerUpkeep(address,uint32,address,bytes,bytes)']( + mock.address, + performGas, + await admin.getAddress(), + randomBytes, + '0x', + ) + const testUpkeepId = await getUpkeepID(tx) + upkeepIds.push(testUpkeepId) + + // Add funds to passing upkeeps + await registry.connect(owner).addFunds(testUpkeepId, toWei('10')) + + await mock.setCanPerform(true) + await mock.setPerformGasToBurn(performGas) + + totalPerformGas = totalPerformGas.add(performGas) + } + + // Should revert with no overhead added + await evmRevert( + getTransmitTx(registry, keeper1, upkeepIds, { + gasLimit: totalPerformGas, + }), + ) + // Should not revert with overhead added + await getTransmitTx(registry, keeper1, upkeepIds, { + gasLimit: totalPerformGas.add(transmitGasOverhead), + }) + }) + + it('splits l2 payment among performed upkeeps', async () => { + const numUpkeeps = 7 + const upkeepIds: BigNumber[] = [] + // Same as MockArbGasInfo.sol + const l1CostWeiArb = BigNumber.from(1000000) + + for (let i = 0; i < numUpkeeps; i++) { + const mock = await upkeepMockFactory.deploy() + const tx = await arbRegistry + .connect(owner) + ['registerUpkeep(address,uint32,address,bytes,bytes)']( + mock.address, + performGas, + await admin.getAddress(), + randomBytes, + '0x', + ) + const testUpkeepId = await getUpkeepID(tx) + upkeepIds.push(testUpkeepId) + + // Add funds to passing upkeeps + await arbRegistry.connect(owner).addFunds(testUpkeepId, toWei('100')) + } + + // Do the thing + const tx = await getTransmitTx( + arbRegistry, + keeper1, + upkeepIds, + + { gasPrice: gasWei.mul('5') }, // High gas price so that it gets capped + ) + + const receipt = await tx.wait() + const upkeepPerformedLogs = parseUpkeepPerformedLogs(receipt) + // exactly numPassingUpkeeps Upkeep Performed should be emitted + assert.equal(upkeepPerformedLogs.length, numUpkeeps) + + // Verify the payment calculation in upkeepPerformed[0] + const upkeepPerformedLog = upkeepPerformedLogs[0] + + const gasUsed = upkeepPerformedLog.args.gasUsed + const gasOverhead = upkeepPerformedLog.args.gasOverhead + const totalPayment = upkeepPerformedLog.args.totalPayment + + assert.equal( + linkForGas( + gasUsed, + gasOverhead, + gasCeilingMultiplier, + paymentPremiumPPB, + flatFeeMicroLink, + l1CostWeiArb.div(gasCeilingMultiplier), // Dividing by gasCeilingMultiplier as it gets multiplied later + BigNumber.from(numUpkeeps), + ).total.toString(), + totalPayment.toString(), + ) + }) + }, + ) + + describe('#recoverFunds', () => { + const sent = toWei('7') + + beforeEach(async () => { + await linkToken.connect(admin).approve(registry.address, toWei('100')) + await linkToken + .connect(owner) + .transfer(await keeper1.getAddress(), toWei('1000')) + + // add funds to upkeep 1 and perform and withdraw some payment + const tx = await registry + .connect(owner) + ['registerUpkeep(address,uint32,address,bytes,bytes)']( + mock.address, + performGas, + await admin.getAddress(), + emptyBytes, + emptyBytes, + ) + + const id1 = await getUpkeepID(tx) + await registry.connect(admin).addFunds(id1, toWei('5')) + + await getTransmitTx(registry, keeper1, [id1]) + await getTransmitTx(registry, keeper2, [id1]) + await getTransmitTx(registry, keeper3, [id1]) + + await registry + .connect(payee1) + .withdrawPayment( + await keeper1.getAddress(), + await nonkeeper.getAddress(), + ) + + // transfer funds directly to the registry + await linkToken.connect(keeper1).transfer(registry.address, sent) + + // add funds to upkeep 2 and perform and withdraw some payment + const tx2 = await registry + .connect(owner) + ['registerUpkeep(address,uint32,address,bytes,bytes)']( + mock.address, + performGas, + await admin.getAddress(), + emptyBytes, + emptyBytes, + ) + const id2 = await getUpkeepID(tx2) + await registry.connect(admin).addFunds(id2, toWei('5')) + + await getTransmitTx(registry, keeper1, [id2]) + await getTransmitTx(registry, keeper2, [id2]) + await getTransmitTx(registry, keeper3, [id2]) + + await registry + .connect(payee2) + .withdrawPayment( + await keeper2.getAddress(), + await nonkeeper.getAddress(), + ) + + // transfer funds using onTokenTransfer + const data = ethers.utils.defaultAbiCoder.encode(['uint256'], [id2]) + await linkToken + .connect(owner) + .transferAndCall(registry.address, toWei('1'), data) + + // withdraw some funds + await registry.connect(owner).cancelUpkeep(id1) + await registry + .connect(admin) + .withdrawFunds(id1, await nonkeeper.getAddress()) + }) + + it('reverts if not called by owner', async () => { + await evmRevert( + registry.connect(keeper1).recoverFunds(), + 'Only callable by owner', + ) + }) + + it('allows any funds that have been accidentally transfered to be moved', async () => { + const balanceBefore = await linkToken.balanceOf(registry.address) + const ownerBefore = await linkToken.balanceOf(await owner.getAddress()) + + await registry.connect(owner).recoverFunds() + + const balanceAfter = await linkToken.balanceOf(registry.address) + const ownerAfter = await linkToken.balanceOf(await owner.getAddress()) + + assert.isTrue(balanceBefore.eq(balanceAfter.add(sent))) + assert.isTrue(ownerAfter.eq(ownerBefore.add(sent))) + }) + }) + + describe('#getMinBalanceForUpkeep / #checkUpkeep / #transmit', () => { + it('calculates the minimum balance appropriately', async () => { + await mock.setCanCheck(true) + + const oneWei = BigNumber.from(1) + const minBalance = await registry.getMinBalanceForUpkeep(upkeepId) + const tooLow = minBalance.sub(oneWei) + + await registry.connect(admin).addFunds(upkeepId, tooLow) + let checkUpkeepResult = await registry + .connect(zeroAddress) + .callStatic['checkUpkeep(uint256)'](upkeepId) + + assert.equal(checkUpkeepResult.upkeepNeeded, false) + assert.equal( + checkUpkeepResult.upkeepFailureReason, + UpkeepFailureReason.INSUFFICIENT_BALANCE, + ) + + await registry.connect(admin).addFunds(upkeepId, oneWei) + checkUpkeepResult = await registry + .connect(zeroAddress) + .callStatic['checkUpkeep(uint256)'](upkeepId) + assert.equal(checkUpkeepResult.upkeepNeeded, true) + }) + + it('uses maxPerformData size in checkUpkeep but actual performDataSize in transmit', async () => { + const tx1 = await registry + .connect(owner) + ['registerUpkeep(address,uint32,address,bytes,bytes)']( + mock.address, + performGas, + await admin.getAddress(), + randomBytes, + '0x', + ) + const upkeepID1 = await getUpkeepID(tx1) + const tx2 = await registry + .connect(owner) + ['registerUpkeep(address,uint32,address,bytes,bytes)']( + mock.address, + performGas, + await admin.getAddress(), + randomBytes, + '0x', + ) + const upkeepID2 = await getUpkeepID(tx2) + await mock.setCanCheck(true) + await mock.setCanPerform(true) + + // upkeep 1 is underfunded, 2 is fully funded + const minBalance1 = ( + await registry.getMinBalanceForUpkeep(upkeepID1) + ).sub(1) + const minBalance2 = await registry.getMinBalanceForUpkeep(upkeepID2) + await registry.connect(owner).addFunds(upkeepID1, minBalance1) + await registry.connect(owner).addFunds(upkeepID2, minBalance2) + + // upkeep 1 check should return false, 2 should return true + let checkUpkeepResult = await registry + .connect(zeroAddress) + .callStatic['checkUpkeep(uint256)'](upkeepID1) + assert.equal(checkUpkeepResult.upkeepNeeded, false) + assert.equal( + checkUpkeepResult.upkeepFailureReason, + UpkeepFailureReason.INSUFFICIENT_BALANCE, + ) + + checkUpkeepResult = await registry + .connect(zeroAddress) + .callStatic['checkUpkeep(uint256)'](upkeepID2) + assert.equal(checkUpkeepResult.upkeepNeeded, true) + + // upkeep 1 perform should return with insufficient balance using max performData size + let maxPerformData = '0x' + for (let i = 0; i < maxPerformDataSize.toNumber(); i++) { + maxPerformData += '11' + } + + const tx = await getTransmitTx(registry, keeper1, [upkeepID1], { + gasPrice: gasWei.mul(gasCeilingMultiplier), + performData: maxPerformData, + }) + + const receipt = await tx.wait() + const insufficientFundsUpkeepReportLogs = + parseInsufficientFundsUpkeepReportLogs(receipt) + // exactly 1 InsufficientFundsUpkeepReportLogs log should be emitted + assert.equal(insufficientFundsUpkeepReportLogs.length, 1) + + // upkeep 1 perform should succeed with empty performData + await getTransmitTx(registry, keeper1, [upkeepID1], { + gasPrice: gasWei.mul(gasCeilingMultiplier), + }), + // upkeep 2 perform should succeed with max performData size + await getTransmitTx(registry, keeper1, [upkeepID2], { + gasPrice: gasWei.mul(gasCeilingMultiplier), + performData: maxPerformData, + }) + }) + }) + + describe('#withdrawFunds', () => { + let upkeepId2: BigNumber + + beforeEach(async () => { + const tx = await registry + .connect(owner) + ['registerUpkeep(address,uint32,address,bytes,bytes)']( + mock.address, + performGas, + await admin.getAddress(), + randomBytes, + '0x', + ) + upkeepId2 = await getUpkeepID(tx) + + await registry.connect(admin).addFunds(upkeepId, toWei('100')) + await registry.connect(admin).addFunds(upkeepId2, toWei('100')) + + // Do a perform so that upkeep is charged some amount + await getTransmitTx(registry, keeper1, [upkeepId]) + await getTransmitTx(registry, keeper1, [upkeepId2]) + }) + + it('reverts if called on a non existing ID', async () => { + await evmRevert( + registry + .connect(admin) + .withdrawFunds(upkeepId.add(1), await payee1.getAddress()), + 'OnlyCallableByAdmin()', + ) + }) + + it('reverts if called by anyone but the admin', async () => { + await evmRevert( + registry + .connect(owner) + .withdrawFunds(upkeepId, await payee1.getAddress()), + 'OnlyCallableByAdmin()', + ) + }) + + it('reverts if called on an uncanceled upkeep', async () => { + await evmRevert( + registry + .connect(admin) + .withdrawFunds(upkeepId, await payee1.getAddress()), + 'UpkeepNotCanceled()', + ) + }) + + it('reverts if called with the 0 address', async () => { + await evmRevert( + registry.connect(admin).withdrawFunds(upkeepId, zeroAddress), + 'InvalidRecipient()', + ) + }) + + describe('after the registration is paused, then cancelled', () => { + it('allows the admin to withdraw', async () => { + const balance = await registry.getBalance(upkeepId) + const payee = await payee1.getAddress() + await registry.connect(admin).pauseUpkeep(upkeepId) + await registry.connect(owner).cancelUpkeep(upkeepId) + await expect(() => + registry.connect(admin).withdrawFunds(upkeepId, payee), + ).to.changeTokenBalance(linkToken, payee1, balance) + }) + }) + + describe('after the registration is cancelled', () => { + beforeEach(async () => { + await registry.connect(owner).cancelUpkeep(upkeepId) + await registry.connect(owner).cancelUpkeep(upkeepId2) + }) + + it('can be called successively on two upkeeps', async () => { + await registry + .connect(admin) + .withdrawFunds(upkeepId, await payee1.getAddress()) + await registry + .connect(admin) + .withdrawFunds(upkeepId2, await payee1.getAddress()) + }) + + it('moves the funds out and updates the balance and emits an event', async () => { + const payee1Before = await linkToken.balanceOf( + await payee1.getAddress(), + ) + const registryBefore = await linkToken.balanceOf(registry.address) + + let registration = await registry.getUpkeep(upkeepId) + const previousBalance = registration.balance + + const tx = await registry + .connect(admin) + .withdrawFunds(upkeepId, await payee1.getAddress()) + await expect(tx) + .to.emit(registry, 'FundsWithdrawn') + .withArgs(upkeepId, previousBalance, await payee1.getAddress()) + + const payee1After = await linkToken.balanceOf(await payee1.getAddress()) + const registryAfter = await linkToken.balanceOf(registry.address) + + assert.isTrue(payee1Before.add(previousBalance).eq(payee1After)) + assert.isTrue(registryBefore.sub(previousBalance).eq(registryAfter)) + + registration = await registry.getUpkeep(upkeepId) + assert.equal(0, registration.balance.toNumber()) + }) + }) + }) + + describe('#simulatePerformUpkeep', () => { + it('reverts if called by non zero address', async () => { + await evmRevert( + registry + .connect(await owner.getAddress()) + .callStatic.simulatePerformUpkeep(upkeepId, '0x'), + 'OnlySimulatedBackend()', + ) + }) + + it('reverts when registry is paused', async () => { + await registry.connect(owner).pause() + await evmRevert( + registry + .connect(zeroAddress) + .callStatic.simulatePerformUpkeep(upkeepId, '0x'), + 'RegistryPaused()', + ) + }) + + it('returns false and gasUsed when perform fails', async () => { + await mock.setCanPerform(false) + + const simulatePerformResult = await registry + .connect(zeroAddress) + .callStatic.simulatePerformUpkeep(upkeepId, '0x') + + assert.equal(simulatePerformResult.success, false) + assert.isTrue(simulatePerformResult.gasUsed.gt(BigNumber.from('0'))) // Some gas should be used + }) + + it('returns true, gasUsed, and performGas when perform succeeds', async () => { + await mock.setCanPerform(true) + + const simulatePerformResult = await registry + .connect(zeroAddress) + .callStatic.simulatePerformUpkeep(upkeepId, '0x') + + assert.equal(simulatePerformResult.success, true) + assert.isTrue(simulatePerformResult.gasUsed.gt(BigNumber.from('0'))) // Some gas should be used + }) + + it('returns correct amount of gasUsed when perform succeeds', async () => { + await mock.setCanPerform(true) + await mock.setPerformGasToBurn(performGas) + + const simulatePerformResult = await registry + .connect(zeroAddress) + .callStatic.simulatePerformUpkeep(upkeepId, '0x') + + assert.equal(simulatePerformResult.success, true) + // Full execute gas should be used, with some performGasBuffer(1000) + assert.isTrue( + simulatePerformResult.gasUsed.gt( + performGas.sub(BigNumber.from('1000')), + ), + ) + }) + }) + + describe('#checkUpkeep', () => { + it('reverts if called by non zero address', async () => { + await evmRevert( + registry + .connect(await owner.getAddress()) + .callStatic['checkUpkeep(uint256)'](upkeepId), + 'OnlySimulatedBackend()', + ) + }) + + it('returns false and error code if the upkeep is cancelled by admin', async () => { + await registry.connect(admin).cancelUpkeep(upkeepId) + + const checkUpkeepResult = await registry + .connect(zeroAddress) + .callStatic['checkUpkeep(uint256)'](upkeepId) + + assert.equal(checkUpkeepResult.upkeepNeeded, false) + assert.equal(checkUpkeepResult.performData, '0x') + assert.equal( + checkUpkeepResult.upkeepFailureReason, + UpkeepFailureReason.UPKEEP_CANCELLED, + ) + expect(checkUpkeepResult.gasUsed).to.equal(0) + expect(checkUpkeepResult.gasLimit).to.equal(performGas) + }) + + it('returns false and error code if the upkeep is cancelled by owner', async () => { + await registry.connect(owner).cancelUpkeep(upkeepId) + + const checkUpkeepResult = await registry + .connect(zeroAddress) + .callStatic['checkUpkeep(uint256)'](upkeepId) + + assert.equal(checkUpkeepResult.upkeepNeeded, false) + assert.equal(checkUpkeepResult.performData, '0x') + assert.equal( + checkUpkeepResult.upkeepFailureReason, + UpkeepFailureReason.UPKEEP_CANCELLED, + ) + expect(checkUpkeepResult.gasUsed).to.equal(0) + expect(checkUpkeepResult.gasLimit).to.equal(performGas) + }) + + it('returns false and error code if the registry is paused', async () => { + await registry.connect(owner).pause() + + const checkUpkeepResult = await registry + .connect(zeroAddress) + .callStatic['checkUpkeep(uint256)'](upkeepId) + + assert.equal(checkUpkeepResult.upkeepNeeded, false) + assert.equal(checkUpkeepResult.performData, '0x') + assert.equal( + checkUpkeepResult.upkeepFailureReason, + UpkeepFailureReason.REGISTRY_PAUSED, + ) + expect(checkUpkeepResult.gasUsed).to.equal(0) + expect(checkUpkeepResult.gasLimit).to.equal(performGas) + }) + + it('returns false and error code if the upkeep is paused', async () => { + await registry.connect(admin).pauseUpkeep(upkeepId) + + const checkUpkeepResult = await registry + .connect(zeroAddress) + .callStatic['checkUpkeep(uint256)'](upkeepId) + + assert.equal(checkUpkeepResult.upkeepNeeded, false) + assert.equal(checkUpkeepResult.performData, '0x') + assert.equal( + checkUpkeepResult.upkeepFailureReason, + UpkeepFailureReason.UPKEEP_PAUSED, + ) + expect(checkUpkeepResult.gasUsed).to.equal(0) + expect(checkUpkeepResult.gasLimit).to.equal(performGas) + }) + + it('returns false and error code if user is out of funds', async () => { + const checkUpkeepResult = await registry + .connect(zeroAddress) + .callStatic['checkUpkeep(uint256)'](upkeepId) + + assert.equal(checkUpkeepResult.upkeepNeeded, false) + assert.equal(checkUpkeepResult.performData, '0x') + assert.equal( + checkUpkeepResult.upkeepFailureReason, + UpkeepFailureReason.INSUFFICIENT_BALANCE, + ) + expect(checkUpkeepResult.gasUsed).to.equal(0) + expect(checkUpkeepResult.gasLimit).to.equal(performGas) + }) + + context('when the registration is funded', () => { + beforeEach(async () => { + await linkToken.connect(admin).approve(registry.address, toWei('200')) + await registry.connect(admin).addFunds(upkeepId, toWei('100')) + await registry.connect(admin).addFunds(logUpkeepId, toWei('100')) + }) + + it('returns false, error code, and revert data if the target check reverts', async () => { + await mock.setShouldRevertCheck(true) + await mock.setCheckRevertReason( + 'custom revert error, clever way to insert offchain data', + ) + const checkUpkeepResult = await registry + .connect(zeroAddress) + .callStatic['checkUpkeep(uint256)'](upkeepId) + assert.equal(checkUpkeepResult.upkeepNeeded, false) + + const revertReasonBytes = `0x${checkUpkeepResult.performData.slice(10)}` // remove sighash + assert.equal( + ethers.utils.defaultAbiCoder.decode(['string'], revertReasonBytes)[0], + 'custom revert error, clever way to insert offchain data', + ) + assert.equal( + checkUpkeepResult.upkeepFailureReason, + UpkeepFailureReason.TARGET_CHECK_REVERTED, + ) + assert.isTrue(checkUpkeepResult.gasUsed.gt(BigNumber.from('0'))) // Some gas should be used + expect(checkUpkeepResult.gasLimit).to.equal(performGas) + // Feed data should be returned here + assert.isTrue(checkUpkeepResult.fastGasWei.gt(BigNumber.from('0'))) + assert.isTrue(checkUpkeepResult.linkNative.gt(BigNumber.from('0'))) + }) + + it('returns false, error code, and no revert data if the target check revert data exceeds maxRevertDataSize', async () => { + await mock.setShouldRevertCheck(true) + let longRevertReason = '' + for (let i = 0; i <= maxRevertDataSize.toNumber(); i++) { + longRevertReason += 'x' + } + await mock.setCheckRevertReason(longRevertReason) + const checkUpkeepResult = await registry + .connect(zeroAddress) + .callStatic['checkUpkeep(uint256)'](upkeepId) + assert.equal(checkUpkeepResult.upkeepNeeded, false) + + assert.equal(checkUpkeepResult.performData, '0x') + assert.equal( + checkUpkeepResult.upkeepFailureReason, + UpkeepFailureReason.REVERT_DATA_EXCEEDS_LIMIT, + ) + assert.isTrue(checkUpkeepResult.gasUsed.gt(BigNumber.from('0'))) // Some gas should be used + expect(checkUpkeepResult.gasLimit).to.equal(performGas) + }) + + it('returns false and error code if the upkeep is not needed', async () => { + await mock.setCanCheck(false) + const checkUpkeepResult = await registry + .connect(zeroAddress) + .callStatic['checkUpkeep(uint256)'](upkeepId) + + assert.equal(checkUpkeepResult.upkeepNeeded, false) + assert.equal(checkUpkeepResult.performData, '0x') + assert.equal( + checkUpkeepResult.upkeepFailureReason, + UpkeepFailureReason.UPKEEP_NOT_NEEDED, + ) + assert.isTrue(checkUpkeepResult.gasUsed.gt(BigNumber.from('0'))) // Some gas should be used + expect(checkUpkeepResult.gasLimit).to.equal(performGas) + }) + + it('returns false and error code if the performData exceeds limit', async () => { + let longBytes = '0x' + for (let i = 0; i < 5000; i++) { + longBytes += '1' + } + await mock.setCanCheck(true) + await mock.setPerformData(longBytes) + + const checkUpkeepResult = await registry + .connect(zeroAddress) + .callStatic['checkUpkeep(uint256)'](upkeepId) + + assert.equal(checkUpkeepResult.upkeepNeeded, false) + assert.equal(checkUpkeepResult.performData, '0x') + assert.equal( + checkUpkeepResult.upkeepFailureReason, + UpkeepFailureReason.PERFORM_DATA_EXCEEDS_LIMIT, + ) + assert.isTrue(checkUpkeepResult.gasUsed.gt(BigNumber.from('0'))) // Some gas should be used + expect(checkUpkeepResult.gasLimit).to.equal(performGas) + }) + + it('returns true with gas used if the target can execute', async () => { + await mock.setCanCheck(true) + await mock.setPerformData(randomBytes) + + const latestBlock = await ethers.provider.getBlock('latest') + + const checkUpkeepResult = await registry + .connect(zeroAddress) + .callStatic['checkUpkeep(uint256)'](upkeepId, { + blockTag: latestBlock.number, + }) + + assert.equal(checkUpkeepResult.upkeepNeeded, true) + assert.equal(checkUpkeepResult.performData, randomBytes) + assert.equal( + checkUpkeepResult.upkeepFailureReason, + UpkeepFailureReason.NONE, + ) + assert.isTrue(checkUpkeepResult.gasUsed.gt(BigNumber.from('0'))) // Some gas should be used + expect(checkUpkeepResult.gasLimit).to.equal(performGas) + assert.isTrue(checkUpkeepResult.fastGasWei.eq(gasWei)) + assert.isTrue(checkUpkeepResult.linkNative.eq(linkEth)) + }) + + it('calls checkLog for log-trigger upkeeps', async () => { + const log: Log = { + index: 0, + timestamp: 0, + txHash: ethers.utils.randomBytes(32), + blockNumber: 100, + blockHash: ethers.utils.randomBytes(32), + source: randomAddress(), + topics: [ethers.utils.randomBytes(32), ethers.utils.randomBytes(32)], + data: ethers.utils.randomBytes(1000), + } + + await ltUpkeep.mock.checkLog.withArgs(log, '0x').returns(true, '0x1234') + + const checkData = encodeLog(log) + + const checkUpkeepResult = await registry + .connect(zeroAddress) + .callStatic['checkUpkeep(uint256,bytes)'](logUpkeepId, checkData) + + expect(checkUpkeepResult.upkeepNeeded).to.be.true + expect(checkUpkeepResult.performData).to.equal('0x1234') + }) + + itMaybe( + 'has a large enough gas overhead to cover upkeeps that use all their gas [ @skip-coverage ]', + async () => { + await mock.setCanCheck(true) + await mock.setCheckGasToBurn(checkGasLimit) + const gas = checkGasLimit.add(checkGasOverhead) + const checkUpkeepResult = await registry + .connect(zeroAddress) + .callStatic['checkUpkeep(uint256)'](upkeepId, { + gasLimit: gas, + }) + + assert.equal(checkUpkeepResult.upkeepNeeded, true) + }, + ) + }) + }) + + describe('#addFunds', () => { + const amount = toWei('1') + + it('reverts if the registration does not exist', async () => { + await evmRevert( + registry.connect(keeper1).addFunds(upkeepId.add(1), amount), + 'UpkeepCancelled()', + ) + }) + + it('adds to the balance of the registration', async () => { + await registry.connect(admin).addFunds(upkeepId, amount) + const registration = await registry.getUpkeep(upkeepId) + assert.isTrue(amount.eq(registration.balance)) + }) + + it('lets anyone add funds to an upkeep not just admin', async () => { + await linkToken.connect(owner).transfer(await payee1.getAddress(), amount) + await linkToken.connect(payee1).approve(registry.address, amount) + + await registry.connect(payee1).addFunds(upkeepId, amount) + const registration = await registry.getUpkeep(upkeepId) + assert.isTrue(amount.eq(registration.balance)) + }) + + it('emits a log', async () => { + const tx = await registry.connect(admin).addFunds(upkeepId, amount) + await expect(tx) + .to.emit(registry, 'FundsAdded') + .withArgs(upkeepId, await admin.getAddress(), amount) + }) + + it('reverts if the upkeep is canceled', async () => { + await registry.connect(admin).cancelUpkeep(upkeepId) + await evmRevert( + registry.connect(keeper1).addFunds(upkeepId, amount), + 'UpkeepCancelled()', + ) + }) + }) + + describe('#getActiveUpkeepIDs', () => { + it('reverts if startIndex is out of bounds ', async () => { + await evmRevert( + registry.getActiveUpkeepIDs(numUpkeeps, 0), + 'IndexOutOfRange()', + ) + await evmRevert( + registry.getActiveUpkeepIDs(numUpkeeps + 1, 0), + 'IndexOutOfRange()', + ) + }) + + it('returns upkeep IDs bounded by maxCount', async () => { + let upkeepIds = await registry.getActiveUpkeepIDs(0, 1) + assert(upkeepIds.length == 1) + assert(upkeepIds[0].eq(upkeepId)) + upkeepIds = await registry.getActiveUpkeepIDs(1, 3) + assert(upkeepIds.length == 3) + expect(upkeepIds).to.deep.equal([ + afUpkeepId, + logUpkeepId, + streamsLookupUpkeepId, + ]) + }) + + it('returns as many ids as possible if maxCount > num available', async () => { + const upkeepIds = await registry.getActiveUpkeepIDs(1, numUpkeeps + 100) + assert(upkeepIds.length == numUpkeeps - 1) + }) + + it('returns all upkeep IDs if maxCount is 0', async () => { + let upkeepIds = await registry.getActiveUpkeepIDs(0, 0) + assert(upkeepIds.length == numUpkeeps) + upkeepIds = await registry.getActiveUpkeepIDs(2, 0) + assert(upkeepIds.length == numUpkeeps - 2) + }) + }) + + describe('#getMaxPaymentForGas', () => { + const arbL1PriceinWei = BigNumber.from(1000) // Same as MockArbGasInfo.sol + const l1CostWeiArb = arbL1PriceinWei.mul(16).mul(maxPerformDataSize) + const l1CostWeiOpt = BigNumber.from(2000000) // Same as MockOVMGasPriceOracle.sol + itMaybe('calculates the max fee appropriately', async () => { + await verifyMaxPayment(registry) + }) + + itMaybe('calculates the max fee appropriately for Arbitrum', async () => { + await verifyMaxPayment(arbRegistry, l1CostWeiArb) + }) + + itMaybe('calculates the max fee appropriately for Optimism', async () => { + await verifyMaxPayment(opRegistry, l1CostWeiOpt) + }) + + it('uses the fallback gas price if the feed has issues', async () => { + const expectedFallbackMaxPayment = linkForGas( + performGas, + registryConditionalOverhead + .add(registryPerSignerGasOverhead.mul(f + 1)) + .add(maxPerformDataSize.mul(registryPerPerformByteGasOverhead)), + gasCeilingMultiplier.mul('2'), // fallbackGasPrice is 2x gas price + paymentPremiumPPB, + flatFeeMicroLink, + ).total + + // Stale feed + let roundId = 99 + const answer = 100 + let updatedAt = 946684800 // New Years 2000 🥳 + let startedAt = 946684799 + await gasPriceFeed + .connect(owner) + .updateRoundData(roundId, answer, updatedAt, startedAt) + + assert.equal( + expectedFallbackMaxPayment.toString(), + ( + await registry.getMaxPaymentForGas(Trigger.CONDITION, performGas) + ).toString(), + ) + + // Negative feed price + roundId = 100 + updatedAt = now() + startedAt = 946684799 + await gasPriceFeed + .connect(owner) + .updateRoundData(roundId, -100, updatedAt, startedAt) + + assert.equal( + expectedFallbackMaxPayment.toString(), + ( + await registry.getMaxPaymentForGas(Trigger.CONDITION, performGas) + ).toString(), + ) + + // Zero feed price + roundId = 101 + updatedAt = now() + startedAt = 946684799 + await gasPriceFeed + .connect(owner) + .updateRoundData(roundId, 0, updatedAt, startedAt) + + assert.equal( + expectedFallbackMaxPayment.toString(), + ( + await registry.getMaxPaymentForGas(Trigger.CONDITION, performGas) + ).toString(), + ) + }) + + it('uses the fallback link price if the feed has issues', async () => { + const expectedFallbackMaxPayment = linkForGas( + performGas, + registryConditionalOverhead + .add(registryPerSignerGasOverhead.mul(f + 1)) + .add(maxPerformDataSize.mul(registryPerPerformByteGasOverhead)), + gasCeilingMultiplier.mul('2'), // fallbackLinkPrice is 1/2 link price, so multiply by 2 + paymentPremiumPPB, + flatFeeMicroLink, + ).total + + // Stale feed + let roundId = 99 + const answer = 100 + let updatedAt = 946684800 // New Years 2000 🥳 + let startedAt = 946684799 + await linkEthFeed + .connect(owner) + .updateRoundData(roundId, answer, updatedAt, startedAt) + + assert.equal( + expectedFallbackMaxPayment.toString(), + ( + await registry.getMaxPaymentForGas(Trigger.CONDITION, performGas) + ).toString(), + ) + + // Negative feed price + roundId = 100 + updatedAt = now() + startedAt = 946684799 + await linkEthFeed + .connect(owner) + .updateRoundData(roundId, -100, updatedAt, startedAt) + + assert.equal( + expectedFallbackMaxPayment.toString(), + ( + await registry.getMaxPaymentForGas(Trigger.CONDITION, performGas) + ).toString(), + ) + + // Zero feed price + roundId = 101 + updatedAt = now() + startedAt = 946684799 + await linkEthFeed + .connect(owner) + .updateRoundData(roundId, 0, updatedAt, startedAt) + + assert.equal( + expectedFallbackMaxPayment.toString(), + ( + await registry.getMaxPaymentForGas(Trigger.CONDITION, performGas) + ).toString(), + ) + }) + }) + + describe('#typeAndVersion', () => { + it('uses the correct type and version', async () => { + const typeAndVersion = await registry.typeAndVersion() + assert.equal(typeAndVersion, 'AutomationRegistry 2.2.0') + }) + }) + + describe('#onTokenTransfer', () => { + const amount = toWei('1') + + it('reverts if not called by the LINK token', async () => { + const data = ethers.utils.defaultAbiCoder.encode(['uint256'], [upkeepId]) + + await evmRevert( + registry + .connect(keeper1) + .onTokenTransfer(await keeper1.getAddress(), amount, data), + 'OnlyCallableByLINKToken()', + ) + }) + + it('reverts if not called with more or less than 32 bytes', async () => { + const longData = ethers.utils.defaultAbiCoder.encode( + ['uint256', 'uint256'], + ['33', '34'], + ) + const shortData = '0x12345678' + + await evmRevert( + linkToken + .connect(owner) + .transferAndCall(registry.address, amount, longData), + ) + await evmRevert( + linkToken + .connect(owner) + .transferAndCall(registry.address, amount, shortData), + ) + }) + + it('reverts if the upkeep is canceled', async () => { + await registry.connect(admin).cancelUpkeep(upkeepId) + await evmRevert( + registry.connect(keeper1).addFunds(upkeepId, amount), + 'UpkeepCancelled()', + ) + }) + + it('updates the funds of the job id passed', async () => { + const data = ethers.utils.defaultAbiCoder.encode(['uint256'], [upkeepId]) + + const before = (await registry.getUpkeep(upkeepId)).balance + await linkToken + .connect(owner) + .transferAndCall(registry.address, amount, data) + const after = (await registry.getUpkeep(upkeepId)).balance + + assert.isTrue(before.add(amount).eq(after)) + }) + }) + + describeMaybe('#setConfig - onchain', () => { + const payment = BigNumber.from(1) + const flatFee = BigNumber.from(2) + const maxGas = BigNumber.from(6) + const staleness = BigNumber.from(4) + const ceiling = BigNumber.from(5) + const newMinUpkeepSpend = BigNumber.from(9) + const newMaxCheckDataSize = BigNumber.from(10000) + const newMaxPerformDataSize = BigNumber.from(10000) + const newMaxRevertDataSize = BigNumber.from(10000) + const newMaxPerformGas = BigNumber.from(10000000) + const fbGasEth = BigNumber.from(7) + const fbLinkEth = BigNumber.from(8) + const newTranscoder = randomAddress() + const newRegistrars = [randomAddress(), randomAddress()] + const upkeepManager = randomAddress() + + const newConfig: OnChainConfig = { + paymentPremiumPPB: payment, + flatFeeMicroLink: flatFee, + checkGasLimit: maxGas, + stalenessSeconds: staleness, + gasCeilingMultiplier: ceiling, + minUpkeepSpend: newMinUpkeepSpend, + maxCheckDataSize: newMaxCheckDataSize, + maxPerformDataSize: newMaxPerformDataSize, + maxRevertDataSize: newMaxRevertDataSize, + maxPerformGas: newMaxPerformGas, + fallbackGasPrice: fbGasEth, + fallbackLinkPrice: fbLinkEth, + transcoder: newTranscoder, + registrars: newRegistrars, + upkeepPrivilegeManager: upkeepManager, + } + + it('reverts when called by anyone but the proposed owner', async () => { + await evmRevert( + registry + .connect(payee1) + .setConfigTypeSafe( + signerAddresses, + keeperAddresses, + f, + newConfig, + offchainVersion, + offchainBytes, + ), + 'Only callable by owner', + ) + }) + + it('reverts if signers or transmitters are the zero address', async () => { + await evmRevert( + registry + .connect(owner) + .setConfigTypeSafe( + [randomAddress(), randomAddress(), randomAddress(), zeroAddress], + [ + randomAddress(), + randomAddress(), + randomAddress(), + randomAddress(), + ], + f, + newConfig, + offchainVersion, + offchainBytes, + ), + 'InvalidSigner()', + ) + + await evmRevert( + registry + .connect(owner) + .setConfigTypeSafe( + [ + randomAddress(), + randomAddress(), + randomAddress(), + randomAddress(), + ], + [randomAddress(), randomAddress(), randomAddress(), zeroAddress], + f, + newConfig, + offchainVersion, + offchainBytes, + ), + 'InvalidTransmitter()', + ) + }) + + it('updates the onchainConfig and configDigest', async () => { + const old = await registry.getState() + const oldConfig = old.config + const oldState = old.state + assert.isTrue(paymentPremiumPPB.eq(oldConfig.paymentPremiumPPB)) + assert.isTrue(flatFeeMicroLink.eq(oldConfig.flatFeeMicroLink)) + assert.isTrue(stalenessSeconds.eq(oldConfig.stalenessSeconds)) + assert.isTrue(gasCeilingMultiplier.eq(oldConfig.gasCeilingMultiplier)) + + await registry + .connect(owner) + .setConfigTypeSafe( + signerAddresses, + keeperAddresses, + f, + newConfig, + offchainVersion, + offchainBytes, + ) + + const updated = await registry.getState() + const updatedConfig = updated.config + const updatedState = updated.state + assert.equal(updatedConfig.paymentPremiumPPB, payment.toNumber()) + assert.equal(updatedConfig.flatFeeMicroLink, flatFee.toNumber()) + assert.equal(updatedConfig.stalenessSeconds, staleness.toNumber()) + assert.equal(updatedConfig.gasCeilingMultiplier, ceiling.toNumber()) + assert.equal( + updatedConfig.minUpkeepSpend.toString(), + newMinUpkeepSpend.toString(), + ) + assert.equal( + updatedConfig.maxCheckDataSize, + newMaxCheckDataSize.toNumber(), + ) + assert.equal( + updatedConfig.maxPerformDataSize, + newMaxPerformDataSize.toNumber(), + ) + assert.equal( + updatedConfig.maxRevertDataSize, + newMaxRevertDataSize.toNumber(), + ) + assert.equal(updatedConfig.maxPerformGas, newMaxPerformGas.toNumber()) + assert.equal(updatedConfig.checkGasLimit, maxGas.toNumber()) + assert.equal( + updatedConfig.fallbackGasPrice.toNumber(), + fbGasEth.toNumber(), + ) + assert.equal( + updatedConfig.fallbackLinkPrice.toNumber(), + fbLinkEth.toNumber(), + ) + assert.equal(updatedState.latestEpoch, 0) + + assert(oldState.configCount + 1 == updatedState.configCount) + assert( + oldState.latestConfigBlockNumber != + updatedState.latestConfigBlockNumber, + ) + assert(oldState.latestConfigDigest != updatedState.latestConfigDigest) + + assert.equal(updatedConfig.transcoder, newTranscoder) + assert.deepEqual(updatedConfig.registrars, newRegistrars) + assert.equal(updatedConfig.upkeepPrivilegeManager, upkeepManager) + }) + + it('maintains paused state when config is changed', async () => { + await registry.pause() + const old = await registry.getState() + assert.isTrue(old.state.paused) + + await registry + .connect(owner) + .setConfigTypeSafe( + signerAddresses, + keeperAddresses, + f, + newConfig, + offchainVersion, + offchainBytes, + ) + + const updated = await registry.getState() + assert.isTrue(updated.state.paused) + }) + + it('emits an event', async () => { + const tx = await registry + .connect(owner) + .setConfigTypeSafe( + signerAddresses, + keeperAddresses, + f, + newConfig, + offchainVersion, + offchainBytes, + ) + await expect(tx).to.emit(registry, 'ConfigSet') + }) + }) + + describe('#setConfig - offchain', () => { + let newKeepers: string[] + + beforeEach(async () => { + newKeepers = [ + await personas.Eddy.getAddress(), + await personas.Nick.getAddress(), + await personas.Neil.getAddress(), + await personas.Carol.getAddress(), + ] + }) + + it('reverts when called by anyone but the owner', async () => { + await evmRevert( + registry + .connect(payee1) + .setConfigTypeSafe( + newKeepers, + newKeepers, + f, + config, + offchainVersion, + offchainBytes, + ), + 'Only callable by owner', + ) + }) + + it('reverts if too many keeperAddresses set', async () => { + for (let i = 0; i < 40; i++) { + newKeepers.push(randomAddress()) + } + await evmRevert( + registry + .connect(owner) + .setConfigTypeSafe( + newKeepers, + newKeepers, + f, + config, + offchainVersion, + offchainBytes, + ), + 'TooManyOracles()', + ) + }) + + it('reverts if f=0', async () => { + await evmRevert( + registry + .connect(owner) + .setConfigTypeSafe( + newKeepers, + newKeepers, + 0, + config, + offchainVersion, + offchainBytes, + ), + 'IncorrectNumberOfFaultyOracles()', + ) + }) + + it('reverts if signers != transmitters length', async () => { + const signers = [randomAddress()] + await evmRevert( + registry + .connect(owner) + .setConfigTypeSafe( + signers, + newKeepers, + f, + config, + offchainVersion, + offchainBytes, + ), + 'IncorrectNumberOfSigners()', + ) + }) + + it('reverts if signers <= 3f', async () => { + newKeepers.pop() + await evmRevert( + registry + .connect(owner) + .setConfigTypeSafe( + newKeepers, + newKeepers, + f, + config, + offchainVersion, + offchainBytes, + ), + 'IncorrectNumberOfSigners()', + ) + }) + + it('reverts on repeated signers', async () => { + const newSigners = [ + await personas.Eddy.getAddress(), + await personas.Eddy.getAddress(), + await personas.Eddy.getAddress(), + await personas.Eddy.getAddress(), + ] + await evmRevert( + registry + .connect(owner) + .setConfigTypeSafe( + newSigners, + newKeepers, + f, + config, + offchainVersion, + offchainBytes, + ), + 'RepeatedSigner()', + ) + }) + + it('reverts on repeated transmitters', async () => { + const newTransmitters = [ + await personas.Eddy.getAddress(), + await personas.Eddy.getAddress(), + await personas.Eddy.getAddress(), + await personas.Eddy.getAddress(), + ] + await evmRevert( + registry + .connect(owner) + .setConfigTypeSafe( + newKeepers, + newTransmitters, + f, + config, + offchainVersion, + offchainBytes, + ), + 'RepeatedTransmitter()', + ) + }) + + itMaybe('stores new config and emits event', async () => { + // Perform an upkeep so that totalPremium is updated + await registry.connect(admin).addFunds(upkeepId, toWei('100')) + let tx = await getTransmitTx(registry, keeper1, [upkeepId]) + await tx.wait() + + const newOffChainVersion = BigNumber.from('2') + const newOffChainConfig = '0x1122' + + const old = await registry.getState() + const oldState = old.state + assert(oldState.totalPremium.gt(BigNumber.from('0'))) + + const newSigners = newKeepers + tx = await registry + .connect(owner) + .setConfigTypeSafe( + newSigners, + newKeepers, + f, + config, + newOffChainVersion, + newOffChainConfig, + ) + + const updated = await registry.getState() + const updatedState = updated.state + assert(oldState.totalPremium.eq(updatedState.totalPremium)) + + // Old signer addresses which are not in new signers should be non active + for (let i = 0; i < signerAddresses.length; i++) { + const signer = signerAddresses[i] + if (!newSigners.includes(signer)) { + assert((await registry.getSignerInfo(signer)).active == false) + assert((await registry.getSignerInfo(signer)).index == 0) + } + } + // New signer addresses should be active + for (let i = 0; i < newSigners.length; i++) { + const signer = newSigners[i] + assert((await registry.getSignerInfo(signer)).active == true) + assert((await registry.getSignerInfo(signer)).index == i) + } + // Old transmitter addresses which are not in new transmitter should be non active, update lastCollected but retain other info + for (let i = 0; i < keeperAddresses.length; i++) { + const transmitter = keeperAddresses[i] + if (!newKeepers.includes(transmitter)) { + assert( + (await registry.getTransmitterInfo(transmitter)).active == false, + ) + assert((await registry.getTransmitterInfo(transmitter)).index == i) + assert( + (await registry.getTransmitterInfo(transmitter)).lastCollected.eq( + oldState.totalPremium.sub( + oldState.totalPremium.mod(keeperAddresses.length), + ), + ), + ) + } + } + // New transmitter addresses should be active + for (let i = 0; i < newKeepers.length; i++) { + const transmitter = newKeepers[i] + assert((await registry.getTransmitterInfo(transmitter)).active == true) + assert((await registry.getTransmitterInfo(transmitter)).index == i) + assert( + (await registry.getTransmitterInfo(transmitter)).lastCollected.eq( + oldState.totalPremium, + ), + ) + } + + // config digest should be updated + assert(oldState.configCount + 1 == updatedState.configCount) + assert( + oldState.latestConfigBlockNumber != + updatedState.latestConfigBlockNumber, + ) + assert(oldState.latestConfigDigest != updatedState.latestConfigDigest) + + //New config should be updated + assert.deepEqual(updated.signers, newKeepers) + assert.deepEqual(updated.transmitters, newKeepers) + + // Event should have been emitted + await expect(tx).to.emit(registry, 'ConfigSet') + }) + }) + + describe('#setPeerRegistryMigrationPermission() / #getPeerRegistryMigrationPermission()', () => { + const peer = randomAddress() + it('allows the owner to set the peer registries', async () => { + let permission = await registry.getPeerRegistryMigrationPermission(peer) + expect(permission).to.equal(0) + await registry.setPeerRegistryMigrationPermission(peer, 1) + permission = await registry.getPeerRegistryMigrationPermission(peer) + expect(permission).to.equal(1) + await registry.setPeerRegistryMigrationPermission(peer, 2) + permission = await registry.getPeerRegistryMigrationPermission(peer) + expect(permission).to.equal(2) + await registry.setPeerRegistryMigrationPermission(peer, 0) + permission = await registry.getPeerRegistryMigrationPermission(peer) + expect(permission).to.equal(0) + }) + it('reverts if passed an unsupported permission', async () => { + await expect( + registry.connect(admin).setPeerRegistryMigrationPermission(peer, 10), + ).to.be.reverted + }) + it('reverts if not called by the owner', async () => { + await expect( + registry.connect(admin).setPeerRegistryMigrationPermission(peer, 1), + ).to.be.revertedWith('Only callable by owner') + }) + }) + + describe('#registerUpkeep', () => { + it('reverts when registry is paused', async () => { + await registry.connect(owner).pause() + await evmRevert( + registry + .connect(owner) + ['registerUpkeep(address,uint32,address,bytes,bytes)']( + mock.address, + performGas, + await admin.getAddress(), + emptyBytes, + '0x', + ), + 'RegistryPaused()', + ) + }) + + it('reverts if the target is not a contract', async () => { + await evmRevert( + registry + .connect(owner) + ['registerUpkeep(address,uint32,address,bytes,bytes)']( + zeroAddress, + performGas, + await admin.getAddress(), + emptyBytes, + '0x', + ), + 'NotAContract()', + ) + }) + + it('reverts if called by a non-owner', async () => { + await evmRevert( + registry + .connect(keeper1) + ['registerUpkeep(address,uint32,address,bytes,bytes)']( + mock.address, + performGas, + await admin.getAddress(), + emptyBytes, + '0x', + ), + 'OnlyCallableByOwnerOrRegistrar()', + ) + }) + + it('reverts if execute gas is too low', async () => { + await evmRevert( + registry + .connect(owner) + ['registerUpkeep(address,uint32,address,bytes,bytes)']( + mock.address, + 2299, + await admin.getAddress(), + emptyBytes, + '0x', + ), + 'GasLimitOutsideRange()', + ) + }) + + it('reverts if execute gas is too high', async () => { + await evmRevert( + registry + .connect(owner) + ['registerUpkeep(address,uint32,address,bytes,bytes)']( + mock.address, + 5000001, + await admin.getAddress(), + emptyBytes, + '0x', + ), + 'GasLimitOutsideRange()', + ) + }) + + it('reverts if checkData is too long', async () => { + let longBytes = '0x' + for (let i = 0; i < 10000; i++) { + longBytes += '1' + } + await evmRevert( + registry + .connect(owner) + ['registerUpkeep(address,uint32,address,bytes,bytes)']( + mock.address, + performGas, + await admin.getAddress(), + longBytes, + '0x', + ), + 'CheckDataExceedsLimit()', + ) + }) + + it('creates a record of the registration', async () => { + const performGases = [100000, 500000] + const checkDatas = [emptyBytes, '0x12'] + + for (let jdx = 0; jdx < performGases.length; jdx++) { + const performGas = performGases[jdx] + for (let kdx = 0; kdx < checkDatas.length; kdx++) { + const checkData = checkDatas[kdx] + const tx = await registry + .connect(owner) + ['registerUpkeep(address,uint32,address,bytes,bytes)']( + mock.address, + performGas, + await admin.getAddress(), + checkData, + '0x', + ) + + //confirm the upkeep details and verify emitted events + const testUpkeepId = await getUpkeepID(tx) + await expect(tx) + .to.emit(registry, 'UpkeepRegistered') + .withArgs(testUpkeepId, performGas, await admin.getAddress()) + + await expect(tx) + .to.emit(registry, 'UpkeepCheckDataSet') + .withArgs(testUpkeepId, checkData) + await expect(tx) + .to.emit(registry, 'UpkeepTriggerConfigSet') + .withArgs(testUpkeepId, '0x') + + const registration = await registry.getUpkeep(testUpkeepId) + + assert.equal(mock.address, registration.target) + assert.notEqual( + ethers.constants.AddressZero, + await registry.getForwarder(testUpkeepId), + ) + assert.equal( + performGas.toString(), + registration.performGas.toString(), + ) + assert.equal(await admin.getAddress(), registration.admin) + assert.equal(0, registration.balance.toNumber()) + assert.equal(0, registration.amountSpent.toNumber()) + assert.equal(0, registration.lastPerformedBlockNumber) + assert.equal(checkData, registration.checkData) + assert.equal(registration.paused, false) + assert.equal(registration.offchainConfig, '0x') + assert(registration.maxValidBlocknumber.eq('0xffffffff')) + } + } + }) + }) + + describe('#pauseUpkeep', () => { + it('reverts if the registration does not exist', async () => { + await evmRevert( + registry.connect(keeper1).pauseUpkeep(upkeepId.add(1)), + 'OnlyCallableByAdmin()', + ) + }) + + it('reverts if the upkeep is already canceled', async () => { + await registry.connect(admin).cancelUpkeep(upkeepId) + + await evmRevert( + registry.connect(admin).pauseUpkeep(upkeepId), + 'UpkeepCancelled()', + ) + }) + + it('reverts if the upkeep is already paused', async () => { + await registry.connect(admin).pauseUpkeep(upkeepId) + + await evmRevert( + registry.connect(admin).pauseUpkeep(upkeepId), + 'OnlyUnpausedUpkeep()', + ) + }) + + it('reverts if the caller is not the upkeep admin', async () => { + await evmRevert( + registry.connect(keeper1).pauseUpkeep(upkeepId), + 'OnlyCallableByAdmin()', + ) + }) + + it('pauses the upkeep and emits an event', async () => { + const tx = await registry.connect(admin).pauseUpkeep(upkeepId) + await expect(tx).to.emit(registry, 'UpkeepPaused').withArgs(upkeepId) + + const registration = await registry.getUpkeep(upkeepId) + assert.equal(registration.paused, true) + }) + }) + + describe('#unpauseUpkeep', () => { + it('reverts if the registration does not exist', async () => { + await evmRevert( + registry.connect(keeper1).unpauseUpkeep(upkeepId.add(1)), + 'OnlyCallableByAdmin()', + ) + }) + + it('reverts if the upkeep is already canceled', async () => { + await registry.connect(owner).cancelUpkeep(upkeepId) + + await evmRevert( + registry.connect(admin).unpauseUpkeep(upkeepId), + 'UpkeepCancelled()', + ) + }) + + it('marks the contract as paused', async () => { + assert.isFalse((await registry.getState()).state.paused) + + await registry.connect(owner).pause() + + assert.isTrue((await registry.getState()).state.paused) + }) + + it('reverts if the upkeep is not paused', async () => { + await evmRevert( + registry.connect(admin).unpauseUpkeep(upkeepId), + 'OnlyPausedUpkeep()', + ) + }) + + it('reverts if the caller is not the upkeep admin', async () => { + await registry.connect(admin).pauseUpkeep(upkeepId) + + const registration = await registry.getUpkeep(upkeepId) + + assert.equal(registration.paused, true) + + await evmRevert( + registry.connect(keeper1).unpauseUpkeep(upkeepId), + 'OnlyCallableByAdmin()', + ) + }) + + it('unpauses the upkeep and emits an event', async () => { + const originalCount = (await registry.getActiveUpkeepIDs(0, 0)).length + + await registry.connect(admin).pauseUpkeep(upkeepId) + + const tx = await registry.connect(admin).unpauseUpkeep(upkeepId) + + await expect(tx).to.emit(registry, 'UpkeepUnpaused').withArgs(upkeepId) + + const registration = await registry.getUpkeep(upkeepId) + assert.equal(registration.paused, false) + + const upkeepIds = await registry.getActiveUpkeepIDs(0, 0) + assert.equal(upkeepIds.length, originalCount) + }) + }) + + describe('#setUpkeepCheckData', () => { + it('reverts if the registration does not exist', async () => { + await evmRevert( + registry + .connect(keeper1) + .setUpkeepCheckData(upkeepId.add(1), randomBytes), + 'OnlyCallableByAdmin()', + ) + }) + + it('reverts if the caller is not upkeep admin', async () => { + await evmRevert( + registry.connect(keeper1).setUpkeepCheckData(upkeepId, randomBytes), + 'OnlyCallableByAdmin()', + ) + }) + + it('reverts if the upkeep is cancelled', async () => { + await registry.connect(admin).cancelUpkeep(upkeepId) + + await evmRevert( + registry.connect(admin).setUpkeepCheckData(upkeepId, randomBytes), + 'UpkeepCancelled()', + ) + }) + + it('is allowed to update on paused upkeep', async () => { + await registry.connect(admin).pauseUpkeep(upkeepId) + await registry.connect(admin).setUpkeepCheckData(upkeepId, randomBytes) + + const registration = await registry.getUpkeep(upkeepId) + assert.equal(randomBytes, registration.checkData) + }) + + it('reverts if new data exceeds limit', async () => { + let longBytes = '0x' + for (let i = 0; i < 10000; i++) { + longBytes += '1' + } + + await evmRevert( + registry.connect(admin).setUpkeepCheckData(upkeepId, longBytes), + 'CheckDataExceedsLimit()', + ) + }) + + it('updates the upkeep check data and emits an event', async () => { + const tx = await registry + .connect(admin) + .setUpkeepCheckData(upkeepId, randomBytes) + await expect(tx) + .to.emit(registry, 'UpkeepCheckDataSet') + .withArgs(upkeepId, randomBytes) + + const registration = await registry.getUpkeep(upkeepId) + assert.equal(randomBytes, registration.checkData) + }) + }) + + describe('#setUpkeepGasLimit', () => { + const newGasLimit = BigNumber.from('300000') + + it('reverts if the registration does not exist', async () => { + await evmRevert( + registry.connect(admin).setUpkeepGasLimit(upkeepId.add(1), newGasLimit), + 'OnlyCallableByAdmin()', + ) + }) + + it('reverts if the upkeep is canceled', async () => { + await registry.connect(admin).cancelUpkeep(upkeepId) + await evmRevert( + registry.connect(admin).setUpkeepGasLimit(upkeepId, newGasLimit), + 'UpkeepCancelled()', + ) + }) + + it('reverts if called by anyone but the admin', async () => { + await evmRevert( + registry.connect(owner).setUpkeepGasLimit(upkeepId, newGasLimit), + 'OnlyCallableByAdmin()', + ) + }) + + it('reverts if new gas limit is out of bounds', async () => { + await evmRevert( + registry + .connect(admin) + .setUpkeepGasLimit(upkeepId, BigNumber.from('100')), + 'GasLimitOutsideRange()', + ) + await evmRevert( + registry + .connect(admin) + .setUpkeepGasLimit(upkeepId, BigNumber.from('6000000')), + 'GasLimitOutsideRange()', + ) + }) + + it('updates the gas limit successfully', async () => { + const initialGasLimit = (await registry.getUpkeep(upkeepId)).performGas + assert.equal(initialGasLimit, performGas.toNumber()) + await registry.connect(admin).setUpkeepGasLimit(upkeepId, newGasLimit) + const updatedGasLimit = (await registry.getUpkeep(upkeepId)).performGas + assert.equal(updatedGasLimit, newGasLimit.toNumber()) + }) + + it('emits a log', async () => { + const tx = await registry + .connect(admin) + .setUpkeepGasLimit(upkeepId, newGasLimit) + await expect(tx) + .to.emit(registry, 'UpkeepGasLimitSet') + .withArgs(upkeepId, newGasLimit) + }) + }) + + describe('#setUpkeepOffchainConfig', () => { + const newConfig = '0xc0ffeec0ffee' + + it('reverts if the registration does not exist', async () => { + await evmRevert( + registry + .connect(admin) + .setUpkeepOffchainConfig(upkeepId.add(1), newConfig), + 'OnlyCallableByAdmin()', + ) + }) + + it('reverts if the upkeep is canceled', async () => { + await registry.connect(admin).cancelUpkeep(upkeepId) + await evmRevert( + registry.connect(admin).setUpkeepOffchainConfig(upkeepId, newConfig), + 'UpkeepCancelled()', + ) + }) + + it('reverts if called by anyone but the admin', async () => { + await evmRevert( + registry.connect(owner).setUpkeepOffchainConfig(upkeepId, newConfig), + 'OnlyCallableByAdmin()', + ) + }) + + it('updates the config successfully', async () => { + const initialConfig = (await registry.getUpkeep(upkeepId)).offchainConfig + assert.equal(initialConfig, '0x') + await registry.connect(admin).setUpkeepOffchainConfig(upkeepId, newConfig) + const updatedConfig = (await registry.getUpkeep(upkeepId)).offchainConfig + assert.equal(newConfig, updatedConfig) + }) + + it('emits a log', async () => { + const tx = await registry + .connect(admin) + .setUpkeepOffchainConfig(upkeepId, newConfig) + await expect(tx) + .to.emit(registry, 'UpkeepOffchainConfigSet') + .withArgs(upkeepId, newConfig) + }) + }) + + describe('#setUpkeepTriggerConfig', () => { + const newConfig = '0xdeadbeef' + + it('reverts if the registration does not exist', async () => { + await evmRevert( + registry + .connect(admin) + .setUpkeepTriggerConfig(upkeepId.add(1), newConfig), + 'OnlyCallableByAdmin()', + ) + }) + + it('reverts if the upkeep is canceled', async () => { + await registry.connect(admin).cancelUpkeep(upkeepId) + await evmRevert( + registry.connect(admin).setUpkeepTriggerConfig(upkeepId, newConfig), + 'UpkeepCancelled()', + ) + }) + + it('reverts if called by anyone but the admin', async () => { + await evmRevert( + registry.connect(owner).setUpkeepTriggerConfig(upkeepId, newConfig), + 'OnlyCallableByAdmin()', + ) + }) + + it('emits a log', async () => { + const tx = await registry + .connect(admin) + .setUpkeepTriggerConfig(upkeepId, newConfig) + await expect(tx) + .to.emit(registry, 'UpkeepTriggerConfigSet') + .withArgs(upkeepId, newConfig) + }) + }) + + describe('#transferUpkeepAdmin', () => { + it('reverts when called by anyone but the current upkeep admin', async () => { + await evmRevert( + registry + .connect(payee1) + .transferUpkeepAdmin(upkeepId, await payee2.getAddress()), + 'OnlyCallableByAdmin()', + ) + }) + + it('reverts when transferring to self', async () => { + await evmRevert( + registry + .connect(admin) + .transferUpkeepAdmin(upkeepId, await admin.getAddress()), + 'ValueNotChanged()', + ) + }) + + it('reverts when the upkeep is cancelled', async () => { + await registry.connect(admin).cancelUpkeep(upkeepId) + + await evmRevert( + registry + .connect(admin) + .transferUpkeepAdmin(upkeepId, await keeper1.getAddress()), + 'UpkeepCancelled()', + ) + }) + + it('allows cancelling transfer by reverting to zero address', async () => { + await registry + .connect(admin) + .transferUpkeepAdmin(upkeepId, await payee1.getAddress()) + const tx = await registry + .connect(admin) + .transferUpkeepAdmin(upkeepId, ethers.constants.AddressZero) + + await expect(tx) + .to.emit(registry, 'UpkeepAdminTransferRequested') + .withArgs( + upkeepId, + await admin.getAddress(), + ethers.constants.AddressZero, + ) + }) + + it('does not change the upkeep admin', async () => { + await registry + .connect(admin) + .transferUpkeepAdmin(upkeepId, await payee1.getAddress()) + + const upkeep = await registry.getUpkeep(upkeepId) + assert.equal(await admin.getAddress(), upkeep.admin) + }) + + it('emits an event announcing the new upkeep admin', async () => { + const tx = await registry + .connect(admin) + .transferUpkeepAdmin(upkeepId, await payee1.getAddress()) + + await expect(tx) + .to.emit(registry, 'UpkeepAdminTransferRequested') + .withArgs(upkeepId, await admin.getAddress(), await payee1.getAddress()) + }) + + it('does not emit an event when called with the same proposed upkeep admin', async () => { + await registry + .connect(admin) + .transferUpkeepAdmin(upkeepId, await payee1.getAddress()) + + const tx = await registry + .connect(admin) + .transferUpkeepAdmin(upkeepId, await payee1.getAddress()) + const receipt = await tx.wait() + assert.equal(0, receipt.logs.length) + }) + }) + + describe('#acceptUpkeepAdmin', () => { + beforeEach(async () => { + // Start admin transfer to payee1 + await registry + .connect(admin) + .transferUpkeepAdmin(upkeepId, await payee1.getAddress()) + }) + + it('reverts when not called by the proposed upkeep admin', async () => { + await evmRevert( + registry.connect(payee2).acceptUpkeepAdmin(upkeepId), + 'OnlyCallableByProposedAdmin()', + ) + }) + + it('reverts when the upkeep is cancelled', async () => { + await registry.connect(admin).cancelUpkeep(upkeepId) + + await evmRevert( + registry.connect(payee1).acceptUpkeepAdmin(upkeepId), + 'UpkeepCancelled()', + ) + }) + + it('does change the admin', async () => { + await registry.connect(payee1).acceptUpkeepAdmin(upkeepId) + + const upkeep = await registry.getUpkeep(upkeepId) + assert.equal(await payee1.getAddress(), upkeep.admin) + }) + + it('emits an event announcing the new upkeep admin', async () => { + const tx = await registry.connect(payee1).acceptUpkeepAdmin(upkeepId) + await expect(tx) + .to.emit(registry, 'UpkeepAdminTransferred') + .withArgs(upkeepId, await admin.getAddress(), await payee1.getAddress()) + }) + }) + + describe('#withdrawOwnerFunds', () => { + it('can only be called by owner', async () => { + await evmRevert( + registry.connect(keeper1).withdrawOwnerFunds(), + 'Only callable by owner', + ) + }) + + itMaybe('withdraws the collected fees to owner', async () => { + await registry.connect(admin).addFunds(upkeepId, toWei('100')) + // Very high min spend, whole balance as cancellation fees + const minUpkeepSpend = toWei('1000') + await registry.connect(owner).setConfigTypeSafe( + signerAddresses, + keeperAddresses, + f, + { + paymentPremiumPPB, + flatFeeMicroLink, + checkGasLimit, + stalenessSeconds, + gasCeilingMultiplier, + minUpkeepSpend, + maxCheckDataSize, + maxPerformDataSize, + maxRevertDataSize, + maxPerformGas, + fallbackGasPrice, + fallbackLinkPrice, + transcoder: transcoder.address, + registrars: [], + upkeepPrivilegeManager: upkeepManager, + }, + offchainVersion, + offchainBytes, + ) + const upkeepBalance = (await registry.getUpkeep(upkeepId)).balance + const ownerBefore = await linkToken.balanceOf(await owner.getAddress()) + + await registry.connect(owner).cancelUpkeep(upkeepId) + + // Transfered to owner balance on registry + let ownerRegistryBalance = (await registry.getState()).state + .ownerLinkBalance + assert.isTrue(ownerRegistryBalance.eq(upkeepBalance)) + + // Now withdraw + await registry.connect(owner).withdrawOwnerFunds() + + ownerRegistryBalance = (await registry.getState()).state.ownerLinkBalance + const ownerAfter = await linkToken.balanceOf(await owner.getAddress()) + + // Owner registry balance should be changed to 0 + assert.isTrue(ownerRegistryBalance.eq(BigNumber.from('0'))) + + // Owner should be credited with the balance + assert.isTrue(ownerBefore.add(upkeepBalance).eq(ownerAfter)) + }) + }) + + describe('#transferPayeeship', () => { + it('reverts when called by anyone but the current payee', async () => { + await evmRevert( + registry + .connect(payee2) + .transferPayeeship( + await keeper1.getAddress(), + await payee2.getAddress(), + ), + 'OnlyCallableByPayee()', + ) + }) + + it('reverts when transferring to self', async () => { + await evmRevert( + registry + .connect(payee1) + .transferPayeeship( + await keeper1.getAddress(), + await payee1.getAddress(), + ), + 'ValueNotChanged()', + ) + }) + + it('does not change the payee', async () => { + await registry + .connect(payee1) + .transferPayeeship( + await keeper1.getAddress(), + await payee2.getAddress(), + ) + + const info = await registry.getTransmitterInfo(await keeper1.getAddress()) + assert.equal(await payee1.getAddress(), info.payee) + }) + + it('emits an event announcing the new payee', async () => { + const tx = await registry + .connect(payee1) + .transferPayeeship( + await keeper1.getAddress(), + await payee2.getAddress(), + ) + await expect(tx) + .to.emit(registry, 'PayeeshipTransferRequested') + .withArgs( + await keeper1.getAddress(), + await payee1.getAddress(), + await payee2.getAddress(), + ) + }) + + it('does not emit an event when called with the same proposal', async () => { + await registry + .connect(payee1) + .transferPayeeship( + await keeper1.getAddress(), + await payee2.getAddress(), + ) + + const tx = await registry + .connect(payee1) + .transferPayeeship( + await keeper1.getAddress(), + await payee2.getAddress(), + ) + const receipt = await tx.wait() + assert.equal(0, receipt.logs.length) + }) + }) + + describe('#acceptPayeeship', () => { + beforeEach(async () => { + await registry + .connect(payee1) + .transferPayeeship( + await keeper1.getAddress(), + await payee2.getAddress(), + ) + }) + + it('reverts when called by anyone but the proposed payee', async () => { + await evmRevert( + registry.connect(payee1).acceptPayeeship(await keeper1.getAddress()), + 'OnlyCallableByProposedPayee()', + ) + }) + + it('emits an event announcing the new payee', async () => { + const tx = await registry + .connect(payee2) + .acceptPayeeship(await keeper1.getAddress()) + await expect(tx) + .to.emit(registry, 'PayeeshipTransferred') + .withArgs( + await keeper1.getAddress(), + await payee1.getAddress(), + await payee2.getAddress(), + ) + }) + + it('does change the payee', async () => { + await registry.connect(payee2).acceptPayeeship(await keeper1.getAddress()) + + const info = await registry.getTransmitterInfo(await keeper1.getAddress()) + assert.equal(await payee2.getAddress(), info.payee) + }) + }) + + describe('#pause', () => { + it('reverts if called by a non-owner', async () => { + await evmRevert( + registry.connect(keeper1).pause(), + 'Only callable by owner', + ) + }) + + it('marks the contract as paused', async () => { + assert.isFalse((await registry.getState()).state.paused) + + await registry.connect(owner).pause() + + assert.isTrue((await registry.getState()).state.paused) + }) + + it('Does not allow transmits when paused', async () => { + await registry.connect(owner).pause() + + await evmRevert( + getTransmitTx(registry, keeper1, [upkeepId]), + 'RegistryPaused()', + ) + }) + + it('Does not allow creation of new upkeeps when paused', async () => { + await registry.connect(owner).pause() + + await evmRevert( + registry + .connect(owner) + ['registerUpkeep(address,uint32,address,bytes,bytes)']( + mock.address, + performGas, + await admin.getAddress(), + emptyBytes, + '0x', + ), + 'RegistryPaused()', + ) + }) + }) + + describe('#unpause', () => { + beforeEach(async () => { + await registry.connect(owner).pause() + }) + + it('reverts if called by a non-owner', async () => { + await evmRevert( + registry.connect(keeper1).unpause(), + 'Only callable by owner', + ) + }) + + it('marks the contract as not paused', async () => { + assert.isTrue((await registry.getState()).state.paused) + + await registry.connect(owner).unpause() + + assert.isFalse((await registry.getState()).state.paused) + }) + }) + + describe('#migrateUpkeeps() / #receiveUpkeeps()', async () => { + context('when permissions are set', () => { + beforeEach(async () => { + await linkToken.connect(owner).approve(registry.address, toWei('100')) + await registry.connect(owner).addFunds(upkeepId, toWei('100')) + await registry.setPeerRegistryMigrationPermission(mgRegistry.address, 1) + await mgRegistry.setPeerRegistryMigrationPermission(registry.address, 2) + }) + + it('migrates an upkeep', async () => { + const offchainBytes = '0x987654abcd' + await registry + .connect(admin) + .setUpkeepOffchainConfig(upkeepId, offchainBytes) + const reg1Upkeep = await registry.getUpkeep(upkeepId) + const forwarderAddress = await registry.getForwarder(upkeepId) + expect(reg1Upkeep.balance).to.equal(toWei('100')) + expect(reg1Upkeep.checkData).to.equal(randomBytes) + expect(forwarderAddress).to.not.equal(ethers.constants.AddressZero) + expect(reg1Upkeep.offchainConfig).to.equal(offchainBytes) + expect((await registry.getState()).state.numUpkeeps).to.equal( + numUpkeeps, + ) + const forwarder = await IAutomationForwarderFactory.connect( + forwarderAddress, + owner, + ) + expect(await forwarder.getRegistry()).to.equal(registry.address) + // Set an upkeep admin transfer in progress too + await registry + .connect(admin) + .transferUpkeepAdmin(upkeepId, await payee1.getAddress()) + + // migrate + await registry + .connect(admin) + .migrateUpkeeps([upkeepId], mgRegistry.address) + expect((await registry.getState()).state.numUpkeeps).to.equal( + numUpkeeps - 1, + ) + expect((await mgRegistry.getState()).state.numUpkeeps).to.equal(1) + expect((await registry.getUpkeep(upkeepId)).balance).to.equal(0) + expect((await registry.getUpkeep(upkeepId)).checkData).to.equal('0x') + expect((await mgRegistry.getUpkeep(upkeepId)).balance).to.equal( + toWei('100'), + ) + expect( + (await mgRegistry.getState()).state.expectedLinkBalance, + ).to.equal(toWei('100')) + expect((await mgRegistry.getUpkeep(upkeepId)).checkData).to.equal( + randomBytes, + ) + expect((await mgRegistry.getUpkeep(upkeepId)).offchainConfig).to.equal( + offchainBytes, + ) + expect(await mgRegistry.getForwarder(upkeepId)).to.equal( + forwarderAddress, + ) + // test that registry is updated on forwarder + expect(await forwarder.getRegistry()).to.equal(mgRegistry.address) + // migration will delete the upkeep and nullify admin transfer + await expect( + registry.connect(payee1).acceptUpkeepAdmin(upkeepId), + ).to.be.revertedWith('UpkeepCancelled()') + await expect( + mgRegistry.connect(payee1).acceptUpkeepAdmin(upkeepId), + ).to.be.revertedWith('OnlyCallableByProposedAdmin()') + }) + + it('migrates a paused upkeep', async () => { + expect((await registry.getUpkeep(upkeepId)).balance).to.equal( + toWei('100'), + ) + expect((await registry.getUpkeep(upkeepId)).checkData).to.equal( + randomBytes, + ) + expect((await registry.getState()).state.numUpkeeps).to.equal( + numUpkeeps, + ) + await registry.connect(admin).pauseUpkeep(upkeepId) + // verify the upkeep is paused + expect((await registry.getUpkeep(upkeepId)).paused).to.equal(true) + // migrate + await registry + .connect(admin) + .migrateUpkeeps([upkeepId], mgRegistry.address) + expect((await registry.getState()).state.numUpkeeps).to.equal( + numUpkeeps - 1, + ) + expect((await mgRegistry.getState()).state.numUpkeeps).to.equal(1) + expect((await registry.getUpkeep(upkeepId)).balance).to.equal(0) + expect((await mgRegistry.getUpkeep(upkeepId)).balance).to.equal( + toWei('100'), + ) + expect((await registry.getUpkeep(upkeepId)).checkData).to.equal('0x') + expect((await mgRegistry.getUpkeep(upkeepId)).checkData).to.equal( + randomBytes, + ) + expect( + (await mgRegistry.getState()).state.expectedLinkBalance, + ).to.equal(toWei('100')) + // verify the upkeep is still paused after migration + expect((await mgRegistry.getUpkeep(upkeepId)).paused).to.equal(true) + }) + + it('emits an event on both contracts', async () => { + expect((await registry.getUpkeep(upkeepId)).balance).to.equal( + toWei('100'), + ) + expect((await registry.getUpkeep(upkeepId)).checkData).to.equal( + randomBytes, + ) + expect((await registry.getState()).state.numUpkeeps).to.equal( + numUpkeeps, + ) + const tx = registry + .connect(admin) + .migrateUpkeeps([upkeepId], mgRegistry.address) + await expect(tx) + .to.emit(registry, 'UpkeepMigrated') + .withArgs(upkeepId, toWei('100'), mgRegistry.address) + await expect(tx) + .to.emit(mgRegistry, 'UpkeepReceived') + .withArgs(upkeepId, toWei('100'), registry.address) + }) + + it('is only migratable by the admin', async () => { + await expect( + registry + .connect(owner) + .migrateUpkeeps([upkeepId], mgRegistry.address), + ).to.be.revertedWith('OnlyCallableByAdmin()') + await registry + .connect(admin) + .migrateUpkeeps([upkeepId], mgRegistry.address) + }) + }) + + context('when permissions are not set', () => { + it('reverts', async () => { + // no permissions + await registry.setPeerRegistryMigrationPermission(mgRegistry.address, 0) + await mgRegistry.setPeerRegistryMigrationPermission(registry.address, 0) + await expect(registry.migrateUpkeeps([upkeepId], mgRegistry.address)).to + .be.reverted + // only outgoing permissions + await registry.setPeerRegistryMigrationPermission(mgRegistry.address, 1) + await mgRegistry.setPeerRegistryMigrationPermission(registry.address, 0) + await expect(registry.migrateUpkeeps([upkeepId], mgRegistry.address)).to + .be.reverted + // only incoming permissions + await registry.setPeerRegistryMigrationPermission(mgRegistry.address, 0) + await mgRegistry.setPeerRegistryMigrationPermission(registry.address, 2) + await expect(registry.migrateUpkeeps([upkeepId], mgRegistry.address)).to + .be.reverted + // permissions opposite direction + await registry.setPeerRegistryMigrationPermission(mgRegistry.address, 2) + await mgRegistry.setPeerRegistryMigrationPermission(registry.address, 1) + await expect(registry.migrateUpkeeps([upkeepId], mgRegistry.address)).to + .be.reverted + }) + }) + }) + + describe('#setPayees', () => { + const IGNORE_ADDRESS = '0xFFfFfFffFFfffFFfFFfFFFFFffFFFffffFfFFFfF' + + it('reverts when not called by the owner', async () => { + await evmRevert( + registry.connect(keeper1).setPayees(payees), + 'Only callable by owner', + ) + }) + + it('reverts with different numbers of payees than transmitters', async () => { + await evmRevert( + registry.connect(owner).setPayees([...payees, randomAddress()]), + 'ParameterLengthError()', + ) + }) + + it('reverts if the payee is the zero address', async () => { + await blankRegistry.connect(owner).setConfig(...baseConfig) // used to test initial config + + await evmRevert( + blankRegistry // used to test initial config + .connect(owner) + .setPayees([ethers.constants.AddressZero, ...payees.slice(1)]), + 'InvalidPayee()', + ) + }) + + itMaybe( + 'sets the payees when exisitng payees are zero address', + async () => { + //Initial payees should be zero address + await blankRegistry.connect(owner).setConfig(...baseConfig) // used to test initial config + + for (let i = 0; i < keeperAddresses.length; i++) { + const payee = ( + await blankRegistry.getTransmitterInfo(keeperAddresses[i]) + ).payee // used to test initial config + assert.equal(payee, zeroAddress) + } + + await blankRegistry.connect(owner).setPayees(payees) // used to test initial config + + for (let i = 0; i < keeperAddresses.length; i++) { + const payee = ( + await blankRegistry.getTransmitterInfo(keeperAddresses[i]) + ).payee + assert.equal(payee, payees[i]) + } + }, + ) + + it('does not change the payee if IGNORE_ADDRESS is used as payee', async () => { + const signers = Array.from({ length: 5 }, randomAddress) + const keepers = Array.from({ length: 5 }, randomAddress) + const payees = Array.from({ length: 5 }, randomAddress) + const newTransmitter = randomAddress() + const newPayee = randomAddress() + const ignoreAddresses = new Array(payees.length).fill(IGNORE_ADDRESS) + const newPayees = [...ignoreAddresses, newPayee] + // arbitrum registry + // configure registry with 5 keepers // optimism registry + await blankRegistry // used to test initial configurations + .connect(owner) + .setConfigTypeSafe( + signers, + keepers, + f, + config, + offchainVersion, + offchainBytes, + ) + // arbitrum registry + // set initial payees // optimism registry + await blankRegistry.connect(owner).setPayees(payees) // used to test initial configurations + // arbitrum registry + // add another keeper // optimism registry + await blankRegistry // used to test initial configurations + .connect(owner) + .setConfigTypeSafe( + [...signers, randomAddress()], + [...keepers, newTransmitter], + f, + config, + offchainVersion, + offchainBytes, + ) + // arbitrum registry + // update payee list // optimism registry // arbitrum registry + await blankRegistry.connect(owner).setPayees(newPayees) // used to test initial configurations // optimism registry + const ignored = await blankRegistry.getTransmitterInfo(newTransmitter) // used to test initial configurations + assert.equal(newPayee, ignored.payee) + assert.equal(true, ignored.active) + }) + + it('reverts if payee is non zero and owner tries to change payee', async () => { + const newPayees = [randomAddress(), ...payees.slice(1)] + + await evmRevert( + registry.connect(owner).setPayees(newPayees), + 'InvalidPayee()', + ) + }) + + it('emits events for every payee added and removed', async () => { + const tx = await registry.connect(owner).setPayees(payees) + await expect(tx) + .to.emit(registry, 'PayeesUpdated') + .withArgs(keeperAddresses, payees) + }) + }) + + describe('#cancelUpkeep', () => { + it('reverts if the ID is not valid', async () => { + await evmRevert( + registry.connect(owner).cancelUpkeep(upkeepId.add(1)), + 'CannotCancel()', + ) + }) + + it('reverts if called by a non-owner/non-admin', async () => { + await evmRevert( + registry.connect(keeper1).cancelUpkeep(upkeepId), + 'OnlyCallableByOwnerOrAdmin()', + ) + }) + + describe('when called by the owner', async () => { + it('sets the registration to invalid immediately', async () => { + const tx = await registry.connect(owner).cancelUpkeep(upkeepId) + const receipt = await tx.wait() + const registration = await registry.getUpkeep(upkeepId) + assert.equal( + registration.maxValidBlocknumber.toNumber(), + receipt.blockNumber, + ) + }) + + it('emits an event', async () => { + const tx = await registry.connect(owner).cancelUpkeep(upkeepId) + const receipt = await tx.wait() + await expect(tx) + .to.emit(registry, 'UpkeepCanceled') + .withArgs(upkeepId, BigNumber.from(receipt.blockNumber)) + }) + + it('immediately prevents upkeep', async () => { + await registry.connect(owner).cancelUpkeep(upkeepId) + + const tx = await getTransmitTx(registry, keeper1, [upkeepId]) + const receipt = await tx.wait() + const cancelledUpkeepReportLogs = + parseCancelledUpkeepReportLogs(receipt) + // exactly 1 CancelledUpkeepReport log should be emitted + assert.equal(cancelledUpkeepReportLogs.length, 1) + }) + + it('does not revert if reverts if called multiple times', async () => { + await registry.connect(owner).cancelUpkeep(upkeepId) + await evmRevert( + registry.connect(owner).cancelUpkeep(upkeepId), + 'CannotCancel()', + ) + }) + + describe('when called by the owner when the admin has just canceled', () => { + let oldExpiration: BigNumber + + beforeEach(async () => { + await registry.connect(admin).cancelUpkeep(upkeepId) + const registration = await registry.getUpkeep(upkeepId) + oldExpiration = registration.maxValidBlocknumber + }) + + it('allows the owner to cancel it more quickly', async () => { + await registry.connect(owner).cancelUpkeep(upkeepId) + + const registration = await registry.getUpkeep(upkeepId) + const newExpiration = registration.maxValidBlocknumber + assert.isTrue(newExpiration.lt(oldExpiration)) + }) + }) + }) + + describe('when called by the admin', async () => { + it('reverts if called again by the admin', async () => { + await registry.connect(admin).cancelUpkeep(upkeepId) + + await evmRevert( + registry.connect(admin).cancelUpkeep(upkeepId), + 'CannotCancel()', + ) + }) + + it('reverts if called by the owner after the timeout', async () => { + await registry.connect(admin).cancelUpkeep(upkeepId) + + for (let i = 0; i < cancellationDelay; i++) { + await ethers.provider.send('evm_mine', []) + } + + await evmRevert( + registry.connect(owner).cancelUpkeep(upkeepId), + 'CannotCancel()', + ) + }) + + it('sets the registration to invalid in 50 blocks', async () => { + const tx = await registry.connect(admin).cancelUpkeep(upkeepId) + const receipt = await tx.wait() + const registration = await registry.getUpkeep(upkeepId) + assert.equal( + registration.maxValidBlocknumber.toNumber(), + receipt.blockNumber + 50, + ) + }) + + it('emits an event', async () => { + const tx = await registry.connect(admin).cancelUpkeep(upkeepId) + const receipt = await tx.wait() + await expect(tx) + .to.emit(registry, 'UpkeepCanceled') + .withArgs( + upkeepId, + BigNumber.from(receipt.blockNumber + cancellationDelay), + ) + }) + + it('immediately prevents upkeep', async () => { + await linkToken.connect(owner).approve(registry.address, toWei('100')) + await registry.connect(owner).addFunds(upkeepId, toWei('100')) + await registry.connect(admin).cancelUpkeep(upkeepId) + + await getTransmitTx(registry, keeper1, [upkeepId]) + + for (let i = 0; i < cancellationDelay; i++) { + await ethers.provider.send('evm_mine', []) + } + + const tx = await getTransmitTx(registry, keeper1, [upkeepId]) + + const receipt = await tx.wait() + const cancelledUpkeepReportLogs = + parseCancelledUpkeepReportLogs(receipt) + // exactly 1 CancelledUpkeepReport log should be emitted + assert.equal(cancelledUpkeepReportLogs.length, 1) + }) + + describeMaybe('when an upkeep has been performed', async () => { + beforeEach(async () => { + await linkToken.connect(owner).approve(registry.address, toWei('100')) + await registry.connect(owner).addFunds(upkeepId, toWei('100')) + await getTransmitTx(registry, keeper1, [upkeepId]) + }) + + it('deducts a cancellation fee from the upkeep and gives to owner', async () => { + const minUpkeepSpend = toWei('10') + + await registry.connect(owner).setConfigTypeSafe( + signerAddresses, + keeperAddresses, + f, + { + paymentPremiumPPB, + flatFeeMicroLink, + checkGasLimit, + stalenessSeconds, + gasCeilingMultiplier, + minUpkeepSpend, + maxCheckDataSize, + maxPerformDataSize, + maxRevertDataSize, + maxPerformGas, + fallbackGasPrice, + fallbackLinkPrice, + transcoder: transcoder.address, + registrars: [], + upkeepPrivilegeManager: upkeepManager, + }, + offchainVersion, + offchainBytes, + ) + + const payee1Before = await linkToken.balanceOf( + await payee1.getAddress(), + ) + const upkeepBefore = (await registry.getUpkeep(upkeepId)).balance + const ownerBefore = (await registry.getState()).state.ownerLinkBalance + + const amountSpent = toWei('100').sub(upkeepBefore) + const cancellationFee = minUpkeepSpend.sub(amountSpent) + + await registry.connect(admin).cancelUpkeep(upkeepId) + + const payee1After = await linkToken.balanceOf( + await payee1.getAddress(), + ) + const upkeepAfter = (await registry.getUpkeep(upkeepId)).balance + const ownerAfter = (await registry.getState()).state.ownerLinkBalance + + // post upkeep balance should be previous balance minus cancellation fee + assert.isTrue(upkeepBefore.sub(cancellationFee).eq(upkeepAfter)) + // payee balance should not change + assert.isTrue(payee1Before.eq(payee1After)) + // owner should receive the cancellation fee + assert.isTrue(ownerAfter.sub(ownerBefore).eq(cancellationFee)) + }) + + it('deducts up to balance as cancellation fee', async () => { + // Very high min spend, should deduct whole balance as cancellation fees + const minUpkeepSpend = toWei('1000') + await registry.connect(owner).setConfigTypeSafe( + signerAddresses, + keeperAddresses, + f, + { + paymentPremiumPPB, + flatFeeMicroLink, + checkGasLimit, + stalenessSeconds, + gasCeilingMultiplier, + minUpkeepSpend, + maxCheckDataSize, + maxPerformDataSize, + maxRevertDataSize, + maxPerformGas, + fallbackGasPrice, + fallbackLinkPrice, + transcoder: transcoder.address, + registrars: [], + upkeepPrivilegeManager: upkeepManager, + }, + offchainVersion, + offchainBytes, + ) + const payee1Before = await linkToken.balanceOf( + await payee1.getAddress(), + ) + const upkeepBefore = (await registry.getUpkeep(upkeepId)).balance + const ownerBefore = (await registry.getState()).state.ownerLinkBalance + + await registry.connect(admin).cancelUpkeep(upkeepId) + const payee1After = await linkToken.balanceOf( + await payee1.getAddress(), + ) + const ownerAfter = (await registry.getState()).state.ownerLinkBalance + const upkeepAfter = (await registry.getUpkeep(upkeepId)).balance + + // all upkeep balance is deducted for cancellation fee + assert.equal(0, upkeepAfter.toNumber()) + // payee balance should not change + assert.isTrue(payee1After.eq(payee1Before)) + // all upkeep balance is transferred to the owner + assert.isTrue(ownerAfter.sub(ownerBefore).eq(upkeepBefore)) + }) + + it('does not deduct cancellation fee if more than minUpkeepSpend is spent', async () => { + // Very low min spend, already spent in one perform upkeep + const minUpkeepSpend = BigNumber.from(420) + await registry.connect(owner).setConfigTypeSafe( + signerAddresses, + keeperAddresses, + f, + { + paymentPremiumPPB, + flatFeeMicroLink, + checkGasLimit, + stalenessSeconds, + gasCeilingMultiplier, + minUpkeepSpend, + maxCheckDataSize, + maxPerformDataSize, + maxRevertDataSize, + maxPerformGas, + fallbackGasPrice, + fallbackLinkPrice, + transcoder: transcoder.address, + registrars: [], + upkeepPrivilegeManager: upkeepManager, + }, + offchainVersion, + offchainBytes, + ) + const payee1Before = await linkToken.balanceOf( + await payee1.getAddress(), + ) + const upkeepBefore = (await registry.getUpkeep(upkeepId)).balance + const ownerBefore = (await registry.getState()).state.ownerLinkBalance + + await registry.connect(admin).cancelUpkeep(upkeepId) + const payee1After = await linkToken.balanceOf( + await payee1.getAddress(), + ) + const ownerAfter = (await registry.getState()).state.ownerLinkBalance + const upkeepAfter = (await registry.getUpkeep(upkeepId)).balance + + // upkeep does not pay cancellation fee after cancellation because minimum upkeep spent is met + assert.isTrue(upkeepBefore.eq(upkeepAfter)) + // owner balance does not change + assert.isTrue(ownerAfter.eq(ownerBefore)) + // payee balance does not change + assert.isTrue(payee1Before.eq(payee1After)) + }) + }) + }) + }) + + describe('#withdrawPayment', () => { + beforeEach(async () => { + await linkToken.connect(owner).approve(registry.address, toWei('100')) + await registry.connect(owner).addFunds(upkeepId, toWei('100')) + await getTransmitTx(registry, keeper1, [upkeepId]) + }) + + it('reverts if called by anyone but the payee', async () => { + await evmRevert( + registry + .connect(payee2) + .withdrawPayment( + await keeper1.getAddress(), + await nonkeeper.getAddress(), + ), + 'OnlyCallableByPayee()', + ) + }) + + it('reverts if called with the 0 address', async () => { + await evmRevert( + registry + .connect(payee2) + .withdrawPayment(await keeper1.getAddress(), zeroAddress), + 'InvalidRecipient()', + ) + }) + + it('updates the balances', async () => { + const to = await nonkeeper.getAddress() + const keeperBefore = await registry.getTransmitterInfo( + await keeper1.getAddress(), + ) + const registrationBefore = (await registry.getUpkeep(upkeepId)).balance + const toLinkBefore = await linkToken.balanceOf(to) + const registryLinkBefore = await linkToken.balanceOf(registry.address) + const registryPremiumBefore = (await registry.getState()).state + .totalPremium + const ownerBefore = (await registry.getState()).state.ownerLinkBalance + + // Withdrawing for first time, last collected = 0 + assert.equal(keeperBefore.lastCollected.toString(), '0') + + //// Do the thing + await registry + .connect(payee1) + .withdrawPayment(await keeper1.getAddress(), to) + + const keeperAfter = await registry.getTransmitterInfo( + await keeper1.getAddress(), + ) + const registrationAfter = (await registry.getUpkeep(upkeepId)).balance + const toLinkAfter = await linkToken.balanceOf(to) + const registryLinkAfter = await linkToken.balanceOf(registry.address) + const registryPremiumAfter = (await registry.getState()).state + .totalPremium + const ownerAfter = (await registry.getState()).state.ownerLinkBalance + + // registry total premium should not change + assert.isTrue(registryPremiumBefore.eq(registryPremiumAfter)) + + // Last collected should be updated to premium-change + assert.isTrue( + keeperAfter.lastCollected.eq( + registryPremiumBefore.sub( + registryPremiumBefore.mod(keeperAddresses.length), + ), + ), + ) + + // owner balance should remain unchanged + assert.isTrue(ownerAfter.eq(ownerBefore)) + + assert.isTrue(keeperAfter.balance.eq(BigNumber.from(0))) + assert.isTrue(registrationBefore.eq(registrationAfter)) + assert.isTrue(toLinkBefore.add(keeperBefore.balance).eq(toLinkAfter)) + assert.isTrue( + registryLinkBefore.sub(keeperBefore.balance).eq(registryLinkAfter), + ) + }) + + it('emits a log announcing the withdrawal', async () => { + const balance = ( + await registry.getTransmitterInfo(await keeper1.getAddress()) + ).balance + const tx = await registry + .connect(payee1) + .withdrawPayment( + await keeper1.getAddress(), + await nonkeeper.getAddress(), + ) + await expect(tx) + .to.emit(registry, 'PaymentWithdrawn') + .withArgs( + await keeper1.getAddress(), + balance, + await nonkeeper.getAddress(), + await payee1.getAddress(), + ) + }) + }) + + describe('#checkCallback', () => { + it('returns false with appropriate failure reason when target callback reverts', async () => { + await streamsLookupUpkeep.setShouldRevertCallback(true) + + const values: any[] = ['0x1234', '0xabcd'] + const res = await registry + .connect(zeroAddress) + .callStatic.checkCallback(streamsLookupUpkeepId, values, '0x') + + assert.isFalse(res.upkeepNeeded) + assert.equal(res.performData, '0x') + assert.equal( + res.upkeepFailureReason, + UpkeepFailureReason.CHECK_CALLBACK_REVERTED, + ) + assert.isTrue(res.gasUsed.gt(BigNumber.from('0'))) // Some gas should be used + }) + + it('returns false with appropriate failure reason when target callback returns big performData', async () => { + let longBytes = '0x' + for (let i = 0; i <= maxPerformDataSize.toNumber(); i++) { + longBytes += '11' + } + const values: any[] = [longBytes, longBytes] + const res = await registry + .connect(zeroAddress) + .callStatic.checkCallback(streamsLookupUpkeepId, values, '0x') + + assert.isFalse(res.upkeepNeeded) + assert.equal(res.performData, '0x') + assert.equal( + res.upkeepFailureReason, + UpkeepFailureReason.PERFORM_DATA_EXCEEDS_LIMIT, + ) + assert.isTrue(res.gasUsed.gt(BigNumber.from('0'))) // Some gas should be used + }) + + it('returns false with appropriate failure reason when target callback returns false', async () => { + await streamsLookupUpkeep.setCallbackReturnBool(false) + const values: any[] = ['0x1234', '0xabcd'] + const res = await registry + .connect(zeroAddress) + .callStatic.checkCallback(streamsLookupUpkeepId, values, '0x') + + assert.isFalse(res.upkeepNeeded) + assert.equal(res.performData, '0x') + assert.equal( + res.upkeepFailureReason, + UpkeepFailureReason.UPKEEP_NOT_NEEDED, + ) + assert.isTrue(res.gasUsed.gt(BigNumber.from('0'))) // Some gas should be used + }) + + it('succeeds with upkeep needed', async () => { + const values: any[] = ['0x1234', '0xabcd'] + + const res = await registry + .connect(zeroAddress) + .callStatic.checkCallback(streamsLookupUpkeepId, values, '0x') + const expectedPerformData = ethers.utils.defaultAbiCoder.encode( + ['bytes[]', 'bytes'], + [values, '0x'], + ) + + assert.isTrue(res.upkeepNeeded) + assert.equal(res.performData, expectedPerformData) + assert.equal(res.upkeepFailureReason, UpkeepFailureReason.NONE) + assert.isTrue(res.gasUsed.gt(BigNumber.from('0'))) // Some gas should be used + }) + }) + + describe('#setUpkeepPrivilegeConfig() / #getUpkeepPrivilegeConfig()', () => { + it('reverts when non manager tries to set privilege config', async () => { + await evmRevert( + registry.connect(payee3).setUpkeepPrivilegeConfig(upkeepId, '0x1234'), + 'OnlyCallableByUpkeepPrivilegeManager()', + ) + }) + + it('returns empty bytes for upkeep privilege config before setting', async () => { + const cfg = await registry.getUpkeepPrivilegeConfig(upkeepId) + assert.equal(cfg, '0x') + }) + + it('allows upkeep manager to set privilege config', async () => { + const tx = await registry + .connect(personas.Norbert) + .setUpkeepPrivilegeConfig(upkeepId, '0x1234') + await expect(tx) + .to.emit(registry, 'UpkeepPrivilegeConfigSet') + .withArgs(upkeepId, '0x1234') + + const cfg = await registry.getUpkeepPrivilegeConfig(upkeepId) + assert.equal(cfg, '0x1234') + }) + }) + + describe('#setAdminPrivilegeConfig() / #getAdminPrivilegeConfig()', () => { + const admin = randomAddress() + + it('reverts when non manager tries to set privilege config', async () => { + await evmRevert( + registry.connect(payee3).setAdminPrivilegeConfig(admin, '0x1234'), + 'OnlyCallableByUpkeepPrivilegeManager()', + ) + }) + + it('returns empty bytes for upkeep privilege config before setting', async () => { + const cfg = await registry.getAdminPrivilegeConfig(admin) + assert.equal(cfg, '0x') + }) + + it('allows upkeep manager to set privilege config', async () => { + const tx = await registry + .connect(personas.Norbert) + .setAdminPrivilegeConfig(admin, '0x1234') + await expect(tx) + .to.emit(registry, 'AdminPrivilegeConfigSet') + .withArgs(admin, '0x1234') + + const cfg = await registry.getAdminPrivilegeConfig(admin) + assert.equal(cfg, '0x1234') + }) + }) + + describe('transmitterPremiumSplit [ @skip-coverage ]', () => { + beforeEach(async () => { + await linkToken.connect(owner).approve(registry.address, toWei('100')) + await registry.connect(owner).addFunds(upkeepId, toWei('100')) + }) + + it('splits premium evenly across transmitters', async () => { + // Do a transmit from keeper1 + await getTransmitTx(registry, keeper1, [upkeepId]) + + const registryPremium = (await registry.getState()).state.totalPremium + assert.isTrue(registryPremium.gt(BigNumber.from(0))) + + const premiumPerTransmitter = registryPremium.div( + BigNumber.from(keeperAddresses.length), + ) + const k1Balance = ( + await registry.getTransmitterInfo(await keeper1.getAddress()) + ).balance + // transmitter should be reimbursed for gas and get the premium + assert.isTrue(k1Balance.gt(premiumPerTransmitter)) + const k1GasReimbursement = k1Balance.sub(premiumPerTransmitter) + + const k2Balance = ( + await registry.getTransmitterInfo(await keeper2.getAddress()) + ).balance + // non transmitter should get its share of premium + assert.isTrue(k2Balance.eq(premiumPerTransmitter)) + + // Now do a transmit from keeper 2 + await getTransmitTx(registry, keeper2, [upkeepId]) + const registryPremiumNew = (await registry.getState()).state.totalPremium + assert.isTrue(registryPremiumNew.gt(registryPremium)) + const premiumPerTransmitterNew = registryPremiumNew.div( + BigNumber.from(keeperAddresses.length), + ) + const additionalPremium = premiumPerTransmitterNew.sub( + premiumPerTransmitter, + ) + + const k1BalanceNew = ( + await registry.getTransmitterInfo(await keeper1.getAddress()) + ).balance + // k1 should get the new premium + assert.isTrue( + k1BalanceNew.eq(k1GasReimbursement.add(premiumPerTransmitterNew)), + ) + + const k2BalanceNew = ( + await registry.getTransmitterInfo(await keeper2.getAddress()) + ).balance + // k2 should get gas reimbursement in addition to new premium + assert.isTrue(k2BalanceNew.gt(k2Balance.add(additionalPremium))) + }) + + it('updates last collected upon payment withdrawn', async () => { + // Do a transmit from keeper1 + await getTransmitTx(registry, keeper1, [upkeepId]) + + const registryPremium = (await registry.getState()).state.totalPremium + const k1 = await registry.getTransmitterInfo(await keeper1.getAddress()) + const k2 = await registry.getTransmitterInfo(await keeper2.getAddress()) + + // Withdrawing for first time, last collected = 0 + assert.isTrue(k1.lastCollected.eq(BigNumber.from(0))) + assert.isTrue(k2.lastCollected.eq(BigNumber.from(0))) + + //// Do the thing + await registry + .connect(payee1) + .withdrawPayment( + await keeper1.getAddress(), + await nonkeeper.getAddress(), + ) + + const k1New = await registry.getTransmitterInfo( + await keeper1.getAddress(), + ) + const k2New = await registry.getTransmitterInfo( + await keeper2.getAddress(), + ) + + // transmitter info lastCollected should be updated for k1, not for k2 + assert.isTrue( + k1New.lastCollected.eq( + registryPremium.sub(registryPremium.mod(keeperAddresses.length)), + ), + ) + assert.isTrue(k2New.lastCollected.eq(BigNumber.from(0))) + }) + + itMaybe( + 'maintains consistent balance information across all parties', + async () => { + // throughout transmits, withdrawals, setConfigs total claim on balances should remain less than expected balance + // some spare change can get lost but it should be less than maxAllowedSpareChange + + let maxAllowedSpareChange = BigNumber.from('0') + await verifyConsistentAccounting(maxAllowedSpareChange) + + await getTransmitTx(registry, keeper1, [upkeepId]) + maxAllowedSpareChange = maxAllowedSpareChange.add(BigNumber.from('31')) + await verifyConsistentAccounting(maxAllowedSpareChange) + + await registry + .connect(payee1) + .withdrawPayment( + await keeper1.getAddress(), + await nonkeeper.getAddress(), + ) + await verifyConsistentAccounting(maxAllowedSpareChange) + + await registry + .connect(payee2) + .withdrawPayment( + await keeper2.getAddress(), + await nonkeeper.getAddress(), + ) + await verifyConsistentAccounting(maxAllowedSpareChange) + + await getTransmitTx(registry, keeper1, [upkeepId]) + maxAllowedSpareChange = maxAllowedSpareChange.add(BigNumber.from('31')) + await verifyConsistentAccounting(maxAllowedSpareChange) + + await registry.connect(owner).setConfigTypeSafe( + signerAddresses.slice(2, 15), // only use 2-14th index keepers + keeperAddresses.slice(2, 15), + f, + config, + offchainVersion, + offchainBytes, + ) + await verifyConsistentAccounting(maxAllowedSpareChange) + + await getTransmitTx(registry, keeper3, [upkeepId], { + startingSignerIndex: 2, + }) + maxAllowedSpareChange = maxAllowedSpareChange.add(BigNumber.from('13')) + await verifyConsistentAccounting(maxAllowedSpareChange) + + await registry + .connect(payee1) + .withdrawPayment( + await keeper1.getAddress(), + await nonkeeper.getAddress(), + ) + await verifyConsistentAccounting(maxAllowedSpareChange) + + await registry + .connect(payee3) + .withdrawPayment( + await keeper3.getAddress(), + await nonkeeper.getAddress(), + ) + await verifyConsistentAccounting(maxAllowedSpareChange) + + await registry.connect(owner).setConfigTypeSafe( + signerAddresses.slice(0, 4), // only use 0-3rd index keepers + keeperAddresses.slice(0, 4), + f, + config, + offchainVersion, + offchainBytes, + ) + await verifyConsistentAccounting(maxAllowedSpareChange) + await getTransmitTx(registry, keeper1, [upkeepId]) + maxAllowedSpareChange = maxAllowedSpareChange.add(BigNumber.from('4')) + await getTransmitTx(registry, keeper3, [upkeepId]) + maxAllowedSpareChange = maxAllowedSpareChange.add(BigNumber.from('4')) + + await verifyConsistentAccounting(maxAllowedSpareChange) + await registry + .connect(payee5) + .withdrawPayment( + await keeper5.getAddress(), + await nonkeeper.getAddress(), + ) + await verifyConsistentAccounting(maxAllowedSpareChange) + + await registry + .connect(payee1) + .withdrawPayment( + await keeper1.getAddress(), + await nonkeeper.getAddress(), + ) + await verifyConsistentAccounting(maxAllowedSpareChange) + }, + ) + }) +}) diff --git a/contracts/test/v0.8/automation/helpers.ts b/contracts/test/v0.8/automation/helpers.ts index e2aa762577..3490bc72c4 100644 --- a/contracts/test/v0.8/automation/helpers.ts +++ b/contracts/test/v0.8/automation/helpers.ts @@ -3,6 +3,9 @@ import { ethers } from 'hardhat' import { KeeperRegistryLogicB2_1__factory as KeeperRegistryLogicBFactory } from '../../../typechain/factories/KeeperRegistryLogicB2_1__factory' import { IKeeperRegistryMaster as IKeeperRegistry } from '../../../typechain/IKeeperRegistryMaster' import { IKeeperRegistryMaster__factory as IKeeperRegistryMasterFactory } from '../../../typechain/factories/IKeeperRegistryMaster__factory' +import { AutomationRegistryLogicB2_2__factory as AutomationRegistryLogicBFactory } from '../../../typechain/factories/AutomationRegistryLogicB2_2__factory' +import { IAutomationRegistryMaster as IAutomationRegistry } from '../../../typechain/IAutomationRegistryMaster' +import { IAutomationRegistryMaster__factory as IAutomationRegistryMasterFactory } from '../../../typechain/factories/IAutomationRegistryMaster__factory' export const deployRegistry21 = async ( from: Signer, @@ -29,3 +32,31 @@ export const deployRegistry21 = async ( const master = await registryFactory.connect(from).deploy(logicA.address) return IKeeperRegistryMasterFactory.connect(master.address, from) } + +export const deployRegistry22 = async ( + from: Signer, + mode: Parameters[0], + link: Parameters[1], + linkNative: Parameters[2], + fastgas: Parameters[3], +): Promise => { + const logicBFactory = await ethers.getContractFactory( + 'AutomationRegistryLogicB2_2', + ) + const logicAFactory = await ethers.getContractFactory( + 'AutomationRegistryLogicA2_2', + ) + const registryFactory = await ethers.getContractFactory( + 'AutomationRegistry2_2', + ) + const forwarderLogicFactory = await ethers.getContractFactory( + 'AutomationForwarderLogic', + ) + const forwarderLogic = await forwarderLogicFactory.connect(from).deploy() + const logicB = await logicBFactory + .connect(from) + .deploy(mode, link, linkNative, fastgas, forwarderLogic.address) + const logicA = await logicAFactory.connect(from).deploy(logicB.address) + const master = await registryFactory.connect(from).deploy(logicA.address) + return IAutomationRegistryMasterFactory.connect(master.address, from) +} diff --git a/contracts/test/v0.8/dev/ScrollSequencerUptimeFeed.test.ts b/contracts/test/v0.8/dev/ScrollSequencerUptimeFeed.test.ts index b294032e73..1d93497b9f 100644 --- a/contracts/test/v0.8/dev/ScrollSequencerUptimeFeed.test.ts +++ b/contracts/test/v0.8/dev/ScrollSequencerUptimeFeed.test.ts @@ -21,7 +21,7 @@ describe('ScrollSequencerUptimeFeed', () => { dummy = accounts[3] const l2CrossDomainMessengerFactory = await ethers.getContractFactory( - 'src/v0.8/l2ep/test/mocks/MockScrollL2CrossDomainMessenger.sol:MockScrollL2CrossDomainMessenger', + 'src/v0.8/l2ep/test/mocks/scroll/MockScrollL2CrossDomainMessenger.sol:MockScrollL2CrossDomainMessenger', deployer, ) diff --git a/contracts/test/v0.8/dev/ScrollValidator.test.ts b/contracts/test/v0.8/dev/ScrollValidator.test.ts index 866d52b202..c5ec59c5c9 100644 --- a/contracts/test/v0.8/dev/ScrollValidator.test.ts +++ b/contracts/test/v0.8/dev/ScrollValidator.test.ts @@ -30,7 +30,7 @@ describe('ScrollValidator', () => { // Scroll Messenger contract on L1 const mockScrollL1CrossDomainMessengerFactory = await ethers.getContractFactory( - 'src/v0.8/l2ep/test/mocks/MockScrollL1CrossDomainMessenger.sol:MockScrollL1CrossDomainMessenger', + 'src/v0.8/l2ep/test/mocks/scroll/MockScrollL1CrossDomainMessenger.sol:MockScrollL1CrossDomainMessenger', ) mockScrollL1CrossDomainMessenger = await mockScrollL1CrossDomainMessengerFactory.deploy() diff --git a/core/chains/evm/config/toml/defaults/Scroll_Mainnet.toml b/core/chains/evm/config/toml/defaults/Scroll_Mainnet.toml index 56ed84c7f3..e087b86fe3 100644 --- a/core/chains/evm/config/toml/defaults/Scroll_Mainnet.toml +++ b/core/chains/evm/config/toml/defaults/Scroll_Mainnet.toml @@ -1,5 +1,6 @@ ChainID = '534352' FinalityDepth = 1 +ChainType = 'scroll' LogPollInterval = '3s' MinIncomingConfirmations = 1 # Scroll only emits blocks when a new tx is received, so this method of liveness detection is not useful diff --git a/core/chains/evm/config/toml/defaults/Scroll_Sepolia.toml b/core/chains/evm/config/toml/defaults/Scroll_Sepolia.toml index af17c4d485..9db7a8ebed 100644 --- a/core/chains/evm/config/toml/defaults/Scroll_Sepolia.toml +++ b/core/chains/evm/config/toml/defaults/Scroll_Sepolia.toml @@ -1,5 +1,6 @@ ChainID = '534351' FinalityDepth = 1 +ChainType = 'scroll' LogPollInterval = '3s' MinIncomingConfirmations = 1 # Scroll only emits blocks when a new tx is received, so this method of liveness detection is not useful 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 4513afa2ee..bd12ac91cf 100644 --- a/core/chains/evm/gas/rollups/l1_gas_price_oracle.go +++ b/core/chains/evm/gas/rollups/l1_gas_price_oracle.go @@ -65,11 +65,18 @@ const ( // `function l1BaseFee() external view returns (uint256);` KromaGasOracle_l1BaseFee = "519b4bd3" + // GasOracleAddress is the address of the precompiled contract that exists on scroll chain. + // This is the case for Scroll. + ScrollGasOracleAddress = "0x5300000000000000000000000000000000000002" + // GasOracle_l1BaseFee is the a hex encoded call to: + // `function l1BaseFee() external view returns (uint256);` + ScrollGasOracle_l1BaseFee = "519b4bd3" + // Interval at which to poll for L1BaseFee. A good starting point is the L1 block time. PollPeriod = 12 * time.Second ) -var supportedChainTypes = []config.ChainType{config.ChainArbitrum, config.ChainOptimismBedrock, config.ChainKroma} +var supportedChainTypes = []config.ChainType{config.ChainArbitrum, config.ChainOptimismBedrock, config.ChainKroma, config.ChainScroll} func IsRollupWithL1Support(chainType config.ChainType) bool { return slices.Contains(supportedChainTypes, chainType) @@ -87,6 +94,9 @@ func NewL1GasPriceOracle(lggr logger.Logger, ethClient ethClient, chainType conf case config.ChainKroma: address = KromaGasOracleAddress callArgs = KromaGasOracle_l1BaseFee + case config.ChainScroll: + address = ScrollGasOracleAddress + callArgs = ScrollGasOracle_l1BaseFee default: panic(fmt.Sprintf("Received unspported chaintype %s", chainType)) } diff --git a/core/chains/evm/gas/rollups/l1_gas_price_oracle_test.go b/core/chains/evm/gas/rollups/l1_gas_price_oracle_test.go index c5773173b8..1ad25c3f7a 100644 --- a/core/chains/evm/gas/rollups/l1_gas_price_oracle_test.go +++ b/core/chains/evm/gas/rollups/l1_gas_price_oracle_test.go @@ -122,4 +122,26 @@ func TestL1GasPriceOracle(t *testing.T) { assert.Equal(t, assets.NewWei(l1BaseFee), gasPrice) }) + + t.Run("Calling GasPrice on started Scroll L1Oracle returns Scroll l1GasPrice", func(t *testing.T) { + l1BaseFee := big.NewInt(200) + + ethClient := mocks.NewETHClient(t) + ethClient.On("CallContract", mock.Anything, mock.IsType(ethereum.CallMsg{}), mock.IsType(&big.Int{})).Run(func(args mock.Arguments) { + callMsg := args.Get(1).(ethereum.CallMsg) + blockNumber := args.Get(2).(*big.Int) + assert.Equal(t, ScrollGasOracleAddress, callMsg.To.String()) + assert.Equal(t, ScrollGasOracle_l1BaseFee, fmt.Sprintf("%x", callMsg.Data)) + assert.Nil(t, blockNumber) + }).Return(common.BigToHash(l1BaseFee).Bytes(), nil) + + oracle := NewL1GasPriceOracle(logger.Test(t), ethClient, config.ChainScroll) + require.NoError(t, oracle.Start(testutils.Context(t))) + t.Cleanup(func() { assert.NoError(t, oracle.Close()) }) + + gasPrice, err := oracle.GasPrice(testutils.Context(t)) + require.NoError(t, err) + + assert.Equal(t, assets.NewWei(l1BaseFee), gasPrice) + }) } diff --git a/core/chains/evm/logpoller/log_poller_test.go b/core/chains/evm/logpoller/log_poller_test.go index 4bfc403e34..2508e676e6 100644 --- a/core/chains/evm/logpoller/log_poller_test.go +++ b/core/chains/evm/logpoller/log_poller_test.go @@ -71,14 +71,14 @@ func populateDatabase(t testing.TB, o *logpoller.DbORM, chainID *big.Int) (commo EventSig: event1, Topics: [][]byte{event1[:], logpoller.EvmWord(uint64(i + 1000*j)).Bytes()}, Address: addr, - TxHash: utils.RandomAddress().Hash(), + TxHash: utils.RandomHash(), 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)) + require.NoError(t, o.InsertBlock(utils.RandomHash(), int64((j+1)*1000-1), startDate.Add(time.Duration(j*1000)*time.Hour), 0)) } return event1, address1, address2 diff --git a/core/chains/evm/logpoller/orm_test.go b/core/chains/evm/logpoller/orm_test.go index b8468d28e9..0af62ebd54 100644 --- a/core/chains/evm/logpoller/orm_test.go +++ b/core/chains/evm/logpoller/orm_test.go @@ -1106,7 +1106,7 @@ func TestSelectLatestBlockNumberEventSigsAddrsWithConfs(t *testing.T) { 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(utils.RandomAddress().Hash(), 3, time.Now(), 1)) + require.NoError(t, th.ORM.InsertBlock(utils.RandomHash(), 3, time.Now(), 1)) tests := []struct { name string @@ -1205,9 +1205,9 @@ func TestSelectLogsCreatedAfter(t *testing.T) { 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)) + require.NoError(t, th.ORM.InsertBlock(utils.RandomHash(), 1, block1ts, 0)) + require.NoError(t, th.ORM.InsertBlock(utils.RandomHash(), 2, block2ts, 1)) + require.NoError(t, th.ORM.InsertBlock(utils.RandomHash(), 3, block3ts, 2)) type expectedLog struct { block int64 @@ -1309,7 +1309,7 @@ func TestNestedLogPollerBlocksQuery(t *testing.T) { require.Len(t, logs, 0) // Persist block - require.NoError(t, th.ORM.InsertBlock(utils.RandomAddress().Hash(), 10, time.Now(), 0)) + require.NoError(t, th.ORM.InsertBlock(utils.RandomHash(), 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) @@ -1542,12 +1542,12 @@ func Benchmark_LogsDataWordBetween(b *testing.B) { EventSig: commitReportAccepted, Topics: [][]byte{}, Address: commitStoreAddress, - TxHash: utils.RandomAddress().Hash(), + TxHash: utils.RandomHash(), Data: data, CreatedAt: time.Now(), }) } - require.NoError(b, o.InsertBlock(utils.RandomAddress().Hash(), int64(numberOfReports*numberOfMessagesPerReport), time.Now(), int64(numberOfReports*numberOfMessagesPerReport))) + require.NoError(b, o.InsertBlock(utils.RandomHash(), int64(numberOfReports*numberOfMessagesPerReport), time.Now(), int64(numberOfReports*numberOfMessagesPerReport))) require.NoError(b, o.InsertLogs(dbLogs)) b.ResetTimer() diff --git a/core/chains/evm/txmgr/tracker_test.go b/core/chains/evm/txmgr/tracker_test.go index 3e0bef5156..d308337278 100644 --- a/core/chains/evm/txmgr/tracker_test.go +++ b/core/chains/evm/txmgr/tracker_test.go @@ -49,6 +49,7 @@ func containsID(txes []*txmgr.Tx, id int64) bool { } func TestEvmTracker_Initialization(t *testing.T) { + t.Skip("BCI-2638 tracker disabled") t.Parallel() tracker, _, _, _ := newTestEvmTrackerSetup(t) @@ -65,6 +66,7 @@ func TestEvmTracker_Initialization(t *testing.T) { } func TestEvmTracker_AddressTracking(t *testing.T) { + t.Skip("BCI-2638 tracker disabled") t.Parallel() t.Run("track abandoned addresses", func(t *testing.T) { @@ -94,6 +96,7 @@ func TestEvmTracker_AddressTracking(t *testing.T) { }) t.Run("stop tracking finalized tx", func(t *testing.T) { + t.Skip("BCI-2638 tracker disabled") tracker, txStore, _, _ := newTestEvmTrackerSetup(t) confirmedAddr := cltest.MustGenerateRandomKey(t).Address _ = mustInsertConfirmedEthTxWithReceipt(t, txStore, confirmedAddr, 123, 1) @@ -118,6 +121,7 @@ func TestEvmTracker_AddressTracking(t *testing.T) { } func TestEvmTracker_ExceedingTTL(t *testing.T) { + t.Skip("BCI-2638 tracker disabled") t.Parallel() t.Run("confirmed but unfinalized transaction still tracked", func(t *testing.T) { diff --git a/core/chains/evm/utils/utils.go b/core/chains/evm/utils/utils.go index 97aaf3b2bd..6784d33cdb 100644 --- a/core/chains/evm/utils/utils.go +++ b/core/chains/evm/utils/utils.go @@ -33,6 +33,12 @@ func RandomAddress() common.Address { return common.BytesToAddress(b) } +func RandomHash() common.Hash { + b := make([]byte, 32) + _, _ = rand.Read(b) // Assignment for errcheck. Only used in tests so we can ignore. + return common.BytesToHash(b) +} + // IsEmptyAddress checks that the address is empty, synonymous with the zero // account/address. No logs can come from this address, as there is no contract // present there. diff --git a/core/chains/legacyevm/chain.go b/core/chains/legacyevm/chain.go index 0e0e1e65ac..92936299cd 100644 --- a/core/chains/legacyevm/chain.go +++ b/core/chains/legacyevm/chain.go @@ -474,15 +474,13 @@ func newEthClientFromCfg(cfg evmconfig.NodePool, noNewHeadsThreshold time.Durati var sendonlys []commonclient.SendOnlyNode[*big.Int, evmclient.RPCCLient] for i, node := range nodes { if node.SendOnly != nil && *node.SendOnly { - name := fmt.Sprintf("eth-sendonly-rpc-%d", i) - rpc := evmclient.NewRPCClient(lggr, empty, (*url.URL)(node.HTTPURL), name, int32(i), chainID, + rpc := evmclient.NewRPCClient(lggr, empty, (*url.URL)(node.HTTPURL), *node.Name, int32(i), chainID, commonclient.Secondary) sendonly := commonclient.NewSendOnlyNode[*big.Int, evmclient.RPCCLient](lggr, (url.URL)(*node.HTTPURL), *node.Name, chainID, rpc) sendonlys = append(sendonlys, sendonly) } else { - name := fmt.Sprintf("eth-primary-rpc-%d", i) - rpc := evmclient.NewRPCClient(lggr, (url.URL)(*node.WSURL), (*url.URL)(node.HTTPURL), name, int32(i), + rpc := evmclient.NewRPCClient(lggr, (url.URL)(*node.WSURL), (*url.URL)(node.HTTPURL), *node.Name, int32(i), chainID, commonclient.Primary) primaryNode := commonclient.NewNode[*big.Int, *evmtypes.Head, evmclient.RPCCLient](cfg, noNewHeadsThreshold, lggr, (url.URL)(*node.WSURL), (*url.URL)(node.HTTPURL), *node.Name, int32(i), chainID, *node.Order, diff --git a/core/cmd/shell.go b/core/cmd/shell.go index b2298ab399..5ca938b1b4 100644 --- a/core/cmd/shell.go +++ b/core/cmd/shell.go @@ -8,6 +8,7 @@ import ( "encoding/json" "fmt" "io" + "log/slog" "net" "net/http" "net/url" @@ -56,6 +57,12 @@ import ( "github.com/smartcontractkit/chainlink/v2/plugins" ) +func init() { + // hack to undo geth's disruption of the std default logger + // remove with geth v1.13.10 + slog.SetDefault(slog.New(slog.NewTextHandler(os.Stderr, nil))) +} + var ( initGlobalsOnce sync.Once prometheus *ginprom.Prometheus diff --git a/core/cmd/shell_test.go b/core/cmd/shell_test.go index ec9606e0ac..f265d5f478 100644 --- a/core/cmd/shell_test.go +++ b/core/cmd/shell_test.go @@ -380,6 +380,17 @@ func TestSetupSolanaRelayer(t *testing.T) { } }) + t2Config := configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { + c.Solana = solana.TOMLConfigs{ + &solana.TOMLConfig{ + ChainID: ptr[string]("solana-id-1"), + Enabled: ptr(true), + Chain: solcfg.Chain{}, + Nodes: []*solcfg.Node{}, + }, + } + }) + rf := chainlink.RelayerFactory{ Logger: lggr, LoopRegistry: reg, @@ -435,6 +446,23 @@ func TestSetupSolanaRelayer(t *testing.T) { _, err := rf.NewSolana(ks, duplicateConfig.SolanaConfigs()) require.Error(t, err) }) + + t.Run("plugin env parsing fails", func(t *testing.T) { + t.Setenv("CL_SOLANA_CMD", "phony_solana_cmd") + t.Setenv("CL_SOLANA_ENV", "fake_path") + + _, err := rf.NewSolana(ks, t2Config.SolanaConfigs()) + require.Error(t, err) + require.Contains(t, err.Error(), "failed to parse Solana env file") + }) + + t.Run("plugin already registered", func(t *testing.T) { + t.Setenv("CL_SOLANA_CMD", "phony_solana_cmd") + + _, err := rf.NewSolana(ks, tConfig.SolanaConfigs()) + require.Error(t, err) + require.Contains(t, err.Error(), "failed to create Solana LOOP command") + }) } func TestSetupStarkNetRelayer(t *testing.T) { @@ -465,6 +493,17 @@ func TestSetupStarkNetRelayer(t *testing.T) { }, } }) + + t2Config := configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { + c.Starknet = stkcfg.TOMLConfigs{ + &stkcfg.TOMLConfig{ + ChainID: ptr[string]("starknet-id-3"), + Enabled: ptr(true), + Chain: stkcfg.Chain{}, + Nodes: []*config.Node{}, + }, + } + }) rf := chainlink.RelayerFactory{ Logger: lggr, LoopRegistry: reg, @@ -520,6 +559,23 @@ func TestSetupStarkNetRelayer(t *testing.T) { _, err := rf.NewStarkNet(ks, duplicateConfig.StarknetConfigs()) require.Error(t, err) }) + + t.Run("plugin env parsing fails", func(t *testing.T) { + t.Setenv("CL_STARKNET_CMD", "phony_starknet_cmd") + t.Setenv("CL_STARKNET_ENV", "fake_path") + + _, err := rf.NewStarkNet(ks, t2Config.StarknetConfigs()) + require.Error(t, err) + require.Contains(t, err.Error(), "failed to parse Starknet env file") + }) + + t.Run("plugin already registered", func(t *testing.T) { + t.Setenv("CL_STARKNET_CMD", "phony_starknet_cmd") + + _, err := rf.NewStarkNet(ks, tConfig.StarknetConfigs()) + require.Error(t, err) + require.Contains(t, err.Error(), "failed to create StarkNet LOOP command") + }) } // flagSetApplyFromAction applies the flags from action to the flagSet. diff --git a/core/config/docs/chains-evm.toml b/core/config/docs/chains-evm.toml index 711889b3fa..53f5cb6852 100644 --- a/core/config/docs/chains-evm.toml +++ b/core/config/docs/chains-evm.toml @@ -14,7 +14,7 @@ BlockBackfillDepth = 10 # Default # BlockBackfillSkip enables skipping of very long backfills. BlockBackfillSkip = false # Default # ChainType is automatically detected from chain ID. Set this to force a certain chain type regardless of chain ID. -# Available types: arbitrum, metis, optimismBedrock, xdai, celo, kroma, wemix, zksync +# Available types: arbitrum, metis, optimismBedrock, xdai, celo, kroma, wemix, zksync, scroll ChainType = 'arbitrum' # Example # FinalityDepth is the number of blocks after which an ethereum transaction is considered "final". Note that the default is automatically set based on chain ID so it should not be necessary to change this under normal operation. # BlocksConsideredFinal determines how deeply we look back to ensure that transactions are confirmed onto the longest chain diff --git a/core/config/docs/core.toml b/core/config/docs/core.toml index a2c19a0e69..70b1d15f20 100644 --- a/core/config/docs/core.toml +++ b/core/config/docs/core.toml @@ -90,10 +90,6 @@ 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. This field will be removed in a furture version -ServerPubKey = 'test-pub-key' # Example -# 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 # MaxBatchSize is the maximum number of messages to batch into one telemetry request. diff --git a/core/config/docs/docs_test.go b/core/config/docs/docs_test.go index 508bd62e33..dc1e0f2af1 100644 --- a/core/config/docs/docs_test.go +++ b/core/config/docs/docs_test.go @@ -15,7 +15,6 @@ import ( stkcfg "github.com/smartcontractkit/chainlink-starknet/relayer/pkg/chainlink/config" "github.com/smartcontractkit/chainlink-common/pkg/config" - commonconfig "github.com/smartcontractkit/chainlink-common/pkg/config" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" evmcfg "github.com/smartcontractkit/chainlink/v2/core/chains/evm/config/toml" "github.com/smartcontractkit/chainlink/v2/core/config/docs" @@ -38,12 +37,6 @@ 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(commonconfig.URL) - cfgtest.AssertFieldsNotNil(t, c) var defaults chainlink.Config diff --git a/core/config/env/env.go b/core/config/env/env.go index 37ae131ddf..f22310a6cf 100644 --- a/core/config/env/env.go +++ b/core/config/env/env.go @@ -1,6 +1,7 @@ package env import ( + "fmt" "os" "strings" @@ -8,12 +9,24 @@ import ( ) var ( - Config = Var("CL_CONFIG") + Config = Var("CL_CONFIG") + DatabaseAllowSimplePasswords = Var("CL_DATABASE_ALLOW_SIMPLE_PASSWORDS") + DatabaseURL = Secret("CL_DATABASE_URL") + DatabaseBackupURL = Secret("CL_DATABASE_BACKUP_URL") + PasswordKeystore = Secret("CL_PASSWORD_KEYSTORE") + PasswordVRF = Secret("CL_PASSWORD_VRF") + PyroscopeAuthToken = Secret("CL_PYROSCOPE_AUTH_TOKEN") + PrometheusAuthToken = Secret("CL_PROMETHEUS_AUTH_TOKEN") + ThresholdKeyShare = Secret("CL_THRESHOLD_KEY_SHARE") + // Migrations env vars + EVMChainIDNotNullMigration0195 = "CL_EVM_CHAINID_NOT_NULL_MIGRATION_0195" +) - // LOOPP commands and vars - MedianPluginCmd = Var("CL_MEDIAN_CMD") - SolanaPluginCmd = Var("CL_SOLANA_CMD") - StarknetPluginCmd = Var("CL_STARKNET_CMD") +// LOOPP commands and vars +var ( + MedianPlugin = NewPlugin("median") + SolanaPlugin = NewPlugin("solana") + StarknetPlugin = NewPlugin("starknet") // PrometheusDiscoveryHostName is the externally accessible hostname // published by the node in the `/discovery` endpoint. Generally, it is expected to match // the public hostname of node. @@ -22,24 +35,13 @@ var ( // In house we observed that the resolved value of os.Hostname was not accessible to // outside of the given pod PrometheusDiscoveryHostName = Var("CL_PROMETHEUS_DISCOVERY_HOSTNAME") - // EnvLooopHostName is the hostname used for HTTP communication between the + // LOOPPHostName is the hostname used for HTTP communication between the // node and LOOPps. In most cases this does not need to be set explicitly. LOOPPHostName = Var("CL_LOOPP_HOSTNAME") // Work around for Solana LOOPPs configured with zero values. MinOCR2MaxDurationQuery = Var("CL_MIN_OCR2_MAX_DURATION_QUERY") // PipelineOvertime is an undocumented escape hatch for overriding the default padding in pipeline executions. PipelineOvertime = Var("CL_PIPELINE_OVERTIME") - - DatabaseAllowSimplePasswords = Var("CL_DATABASE_ALLOW_SIMPLE_PASSWORDS") - DatabaseURL = Secret("CL_DATABASE_URL") - DatabaseBackupURL = Secret("CL_DATABASE_BACKUP_URL") - PasswordKeystore = Secret("CL_PASSWORD_KEYSTORE") - PasswordVRF = Secret("CL_PASSWORD_VRF") - PyroscopeAuthToken = Secret("CL_PYROSCOPE_AUTH_TOKEN") - PrometheusAuthToken = Secret("CL_PROMETHEUS_AUTH_TOKEN") - ThresholdKeyShare = Secret("CL_THRESHOLD_KEY_SHARE") - // Migrations env vars - EVMChainIDNotNullMigration0195 = "CL_EVM_CHAINID_NOT_NULL_MIGRATION_0195" ) type Var string @@ -54,3 +56,16 @@ func (e Var) IsTrue() bool { return strings.ToLower(e.Get()) == "true" } type Secret string func (e Secret) Get() models.Secret { return models.Secret(os.Getenv(string(e))) } + +type Plugin struct { + Cmd Var + Env Var +} + +func NewPlugin(kind string) Plugin { + kind = strings.ToUpper(kind) + return Plugin{ + Cmd: Var(fmt.Sprintf("CL_%s_CMD", kind)), + Env: Var(fmt.Sprintf("CL_%s_ENV", kind)), + } +} diff --git a/core/config/env/env_test.go b/core/config/env/env_test.go new file mode 100644 index 0000000000..b6638758d6 --- /dev/null +++ b/core/config/env/env_test.go @@ -0,0 +1,24 @@ +package env + +import ( + "testing" + + "github.com/stretchr/testify/require" +) + +func TestNewPlugin(t *testing.T) { + for _, tt := range []struct { + name string + kind string + exp Plugin + }{ + {"lower", "foo", Plugin{Cmd: "CL_FOO_CMD", Env: "CL_FOO_ENV"}}, + {"upper", "BAR", Plugin{Cmd: "CL_BAR_CMD", Env: "CL_BAR_ENV"}}, + {"mixed", "Baz", Plugin{Cmd: "CL_BAZ_CMD", Env: "CL_BAZ_ENV"}}, + } { + t.Run(tt.name, func(t *testing.T) { + got := NewPlugin(tt.kind) + require.Equal(t, tt.exp, got) + }) + } +} diff --git a/core/config/mercury_config.go b/core/config/mercury_config.go index 6a483c593e..1210fd282e 100644 --- a/core/config/mercury_config.go +++ b/core/config/mercury_config.go @@ -3,7 +3,7 @@ package config import ( "time" - ocr2models "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/models" + "github.com/smartcontractkit/chainlink-common/pkg/types" ) type MercuryCache interface { @@ -17,7 +17,7 @@ type MercuryTLS interface { } type Mercury interface { - Credentials(credName string) *ocr2models.MercuryCredentials + Credentials(credName string) *types.MercuryCredentials Cache() MercuryCache TLS() MercuryTLS } diff --git a/core/config/mocks/telemetry_ingress.go b/core/config/mocks/telemetry_ingress.go index ed5dbc4cf5..1a21c89e9a 100644 --- a/core/config/mocks/telemetry_ingress.go +++ b/core/config/mocks/telemetry_ingress.go @@ -7,8 +7,6 @@ import ( mock "github.com/stretchr/testify/mock" time "time" - - url "net/url" ) // TelemetryIngress is an autogenerated mock type for the TelemetryIngress type @@ -126,44 +124,6 @@ func (_m *TelemetryIngress) SendTimeout() time.Duration { return r0 } -// ServerPubKey provides a mock function with given fields: -func (_m *TelemetryIngress) ServerPubKey() string { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for ServerPubKey") - } - - 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() - - if len(ret) == 0 { - panic("no return value specified for URL") - } - - 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() diff --git a/core/config/telemetry_ingress_config.go b/core/config/telemetry_ingress_config.go index f6c9fa3f85..a492339101 100644 --- a/core/config/telemetry_ingress_config.go +++ b/core/config/telemetry_ingress_config.go @@ -16,9 +16,6 @@ type TelemetryIngress interface { 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 diff --git a/core/config/toml/types.go b/core/config/toml/types.go index acb12dad69..7f4cd6752c 100644 --- a/core/config/toml/types.go +++ b/core/config/toml/types.go @@ -442,9 +442,6 @@ type TelemetryIngress struct { SendTimeout *commonconfig.Duration UseBatchSend *bool Endpoints []TelemetryIngressEndpoint `toml:",omitempty"` - - URL *commonconfig.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 { @@ -479,26 +476,6 @@ func (t *TelemetryIngress) setFrom(f *TelemetryIngress) { 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 { diff --git a/core/gethwrappers/ccip/generation/generated-wrapper-dependency-versions-do-not-edit.txt b/core/gethwrappers/ccip/generation/generated-wrapper-dependency-versions-do-not-edit.txt index 95686e9301..fc593dc699 100644 --- a/core/gethwrappers/ccip/generation/generated-wrapper-dependency-versions-do-not-edit.txt +++ b/core/gethwrappers/ccip/generation/generated-wrapper-dependency-versions-do-not-edit.txt @@ -1,4 +1,4 @@ -GETH_VERSION: 1.12.2 +GETH_VERSION: 1.13.8 arm_contract: ../../../contracts/solc/v0.8.19/ARM/ARM.abi ../../../contracts/solc/v0.8.19/ARM/ARM.bin 893a2d007f5ffad2a118beccee72cf28913a2d6207f22b2028543139a5fdece0 arm_proxy_contract: ../../../contracts/solc/v0.8.19/ARMProxy/ARMProxy.abi ../../../contracts/solc/v0.8.19/ARMProxy/ARMProxy.bin f7b818c2ba31d8b12ea2dbaebc72c74e69640b7349b76c7415226cc4946075f2 burn_from_mint_token_pool: ../../../contracts/solc/v0.8.19/BurnFromMintTokenPool/BurnFromMintTokenPool.abi ../../../contracts/solc/v0.8.19/BurnFromMintTokenPool/BurnFromMintTokenPool.bin 7e07b03c59c01dfaef99dc9addd1bac1a30934d7b3c00e7b0f6d7fe61b053acd diff --git a/core/gethwrappers/functions/generated/functions_allow_list/functions_allow_list.go b/core/gethwrappers/functions/generated/functions_allow_list/functions_allow_list.go index b0c4894f14..ff15cc75d4 100644 --- a/core/gethwrappers/functions/generated/functions_allow_list/functions_allow_list.go +++ b/core/gethwrappers/functions/generated/functions_allow_list/functions_allow_list.go @@ -36,8 +36,8 @@ type TermsOfServiceAllowListConfig struct { } var TermsOfServiceAllowListMetaData = &bind.MetaData{ - ABI: "[{\"inputs\":[{\"components\":[{\"internalType\":\"bool\",\"name\":\"enabled\",\"type\":\"bool\"},{\"internalType\":\"address\",\"name\":\"signerPublicKey\",\"type\":\"address\"}],\"internalType\":\"structTermsOfServiceAllowListConfig\",\"name\":\"config\",\"type\":\"tuple\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"InvalidSignature\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidUsage\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"RecipientIsBlocked\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"user\",\"type\":\"address\"}],\"name\":\"AddedAccess\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"user\",\"type\":\"address\"}],\"name\":\"BlockedAccess\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"components\":[{\"internalType\":\"bool\",\"name\":\"enabled\",\"type\":\"bool\"},{\"internalType\":\"address\",\"name\":\"signerPublicKey\",\"type\":\"address\"}],\"indexed\":false,\"internalType\":\"structTermsOfServiceAllowListConfig\",\"name\":\"config\",\"type\":\"tuple\"}],\"name\":\"ConfigUpdated\",\"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\":\"user\",\"type\":\"address\"}],\"name\":\"UnblockedAccess\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"acceptOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"acceptor\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"r\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"s\",\"type\":\"bytes32\"},{\"internalType\":\"uint8\",\"name\":\"v\",\"type\":\"uint8\"}],\"name\":\"acceptTermsOfService\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"blockSender\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getAllAllowedSenders\",\"outputs\":[{\"internalType\":\"address[]\",\"name\":\"\",\"type\":\"address[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getConfig\",\"outputs\":[{\"components\":[{\"internalType\":\"bool\",\"name\":\"enabled\",\"type\":\"bool\"},{\"internalType\":\"address\",\"name\":\"signerPublicKey\",\"type\":\"address\"}],\"internalType\":\"structTermsOfServiceAllowListConfig\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"acceptor\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"}],\"name\":\"getMessage\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"user\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"name\":\"hasAccess\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"isBlockedSender\",\"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\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"typeAndVersion\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"unblockSender\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"bool\",\"name\":\"enabled\",\"type\":\"bool\"},{\"internalType\":\"address\",\"name\":\"signerPublicKey\",\"type\":\"address\"}],\"internalType\":\"structTermsOfServiceAllowListConfig\",\"name\":\"config\",\"type\":\"tuple\"}],\"name\":\"updateConfig\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", - Bin: "0x60806040523480156200001157600080fd5b50604051620012c9380380620012c9833981016040819052620000349162000269565b33806000816200008b5760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b0384811691909117909155811615620000be57620000be81620000d9565b505050620000d2816200018460201b60201c565b50620002ea565b336001600160a01b03821603620001335760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c66000000000000000000604482015260640162000082565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b6200018e6200020b565b805160058054602080850180516001600160a81b0319909316941515610100600160a81b03198116959095176101006001600160a01b039485160217909355604080519485529251909116908301527f0d22b8a99f411b3dd338c961284f608489ca0dab9cdad17366a343c361bcf80a910160405180910390a150565b6000546001600160a01b03163314620002675760405162461bcd60e51b815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e657200000000000000000000604482015260640162000082565b565b6000604082840312156200027c57600080fd5b604080519081016001600160401b0381118282101715620002ad57634e487b7160e01b600052604160045260246000fd5b60405282518015158114620002c157600080fd5b815260208301516001600160a01b0381168114620002de57600080fd5b60208201529392505050565b610fcf80620002fa6000396000f3fe608060405234801561001057600080fd5b50600436106100df5760003560e01c806382184c7b1161008c578063a39b06e311610066578063a39b06e3146101b8578063a5e1d61d146101d9578063c3f909d4146101ec578063f2fde38b1461024b57600080fd5b806382184c7b1461016a57806389f9a2c41461017d5780638da5cb5b1461019057600080fd5b80636b14daf8116100bd5780636b14daf81461012a57806379ba50971461014d578063817ef62e1461015557600080fd5b8063181f5a77146100e45780633908c4d41461010257806347663acb14610117575b600080fd5b6100ec61025e565b6040516100f99190610c54565b60405180910390f35b610115610110366004610ce9565b61027a565b005b610115610125366004610d4a565b6104f5565b61013d610138366004610d65565b610580565b60405190151581526020016100f9565b6101156105aa565b61015d6106ac565b6040516100f99190610de8565b610115610178366004610d4a565b6106bd565b61011561018b366004610e42565b610750565b60005460405173ffffffffffffffffffffffffffffffffffffffff90911681526020016100f9565b6101cb6101c6366004610ecb565b61080b565b6040519081526020016100f9565b61013d6101e7366004610d4a565b610869565b60408051808201825260008082526020918201528151808301835260055460ff8116151580835273ffffffffffffffffffffffffffffffffffffffff6101009092048216928401928352845190815291511691810191909152016100f9565b610115610259366004610d4a565b6108aa565b6040518060600160405280602c8152602001610f97602c913981565b73ffffffffffffffffffffffffffffffffffffffff841660009081526004602052604090205460ff16156102da576040517f62b7a34d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60006102e6868661080b565b6040517f19457468657265756d205369676e6564204d6573736167653a0a3332000000006020820152603c810191909152605c01604080518083037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe001815282825280516020918201206005546000855291840180845281905260ff8616928401929092526060830187905260808301869052909250610100900473ffffffffffffffffffffffffffffffffffffffff169060019060a0016020604051602081039080840390855afa1580156103c0573d6000803e3d6000fd5b5050506020604051035173ffffffffffffffffffffffffffffffffffffffff1614610417576040517f8baa579f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b3373ffffffffffffffffffffffffffffffffffffffff861614158061045c57503373ffffffffffffffffffffffffffffffffffffffff87161480159061045c5750333b155b15610493576040517f381cfcbd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61049e6002866108be565b156104ed5760405173ffffffffffffffffffffffffffffffffffffffff861681527f87286ad1f399c8e82bf0c4ef4fcdc570ea2e1e92176e5c848b6413545b885db49060200160405180910390a15b505050505050565b6104fd6108e0565b73ffffffffffffffffffffffffffffffffffffffff811660008181526004602090815260409182902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016905590519182527f28bbd0761309a99e8fb5e5d02ada0b7b2db2e5357531ff5dbfc205c3f5b6592b91015b60405180910390a150565b60055460009060ff16610595575060016105a3565b6105a0600285610963565b90505b9392505050565b60015473ffffffffffffffffffffffffffffffffffffffff163314610630576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e65720000000000000000000060448201526064015b60405180910390fd5b60008054337fffffffffffffffffffffffff00000000000000000000000000000000000000008083168217845560018054909116905560405173ffffffffffffffffffffffffffffffffffffffff90921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b60606106b86002610992565b905090565b6106c56108e0565b6106d060028261099f565b5073ffffffffffffffffffffffffffffffffffffffff811660008181526004602090815260409182902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016600117905590519182527f337cd0f3f594112b6d830afb510072d3b08556b446514f73b8109162fd1151e19101610575565b6107586108e0565b805160058054602080850180517fffffffffffffffffffffff0000000000000000000000000000000000000000009093169415157fffffffffffffffffffffff0000000000000000000000000000000000000000ff81169590951761010073ffffffffffffffffffffffffffffffffffffffff9485160217909355604080519485529251909116908301527f0d22b8a99f411b3dd338c961284f608489ca0dab9cdad17366a343c361bcf80a9101610575565b6040517fffffffffffffffffffffffffffffffffffffffff000000000000000000000000606084811b8216602084015283901b1660348201526000906048016040516020818303038152906040528051906020012090505b92915050565b60055460009060ff1661087e57506000919050565b5073ffffffffffffffffffffffffffffffffffffffff1660009081526004602052604090205460ff1690565b6108b26108e0565b6108bb816109c1565b50565b60006105a38373ffffffffffffffffffffffffffffffffffffffff8416610ab6565b60005473ffffffffffffffffffffffffffffffffffffffff163314610961576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e6572000000000000000000006044820152606401610627565b565b73ffffffffffffffffffffffffffffffffffffffff8116600090815260018301602052604081205415156105a3565b606060006105a383610b05565b60006105a38373ffffffffffffffffffffffffffffffffffffffff8416610b61565b3373ffffffffffffffffffffffffffffffffffffffff821603610a40576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c660000000000000000006044820152606401610627565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b6000818152600183016020526040812054610afd57508154600181810184556000848152602080822090930184905584548482528286019093526040902091909155610863565b506000610863565b606081600001805480602002602001604051908101604052809291908181526020018280548015610b5557602002820191906000526020600020905b815481526020019060010190808311610b41575b50505050509050919050565b60008181526001830160205260408120548015610c4a576000610b85600183610efe565b8554909150600090610b9990600190610efe565b9050818114610bfe576000866000018281548110610bb957610bb9610f38565b9060005260206000200154905080876000018481548110610bdc57610bdc610f38565b6000918252602080832090910192909255918252600188019052604090208390555b8554869080610c0f57610c0f610f67565b600190038181906000526020600020016000905590558560010160008681526020019081526020016000206000905560019350505050610863565b6000915050610863565b600060208083528351808285015260005b81811015610c8157858101830151858201604001528201610c65565b5060006040828601015260407fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8301168501019250505092915050565b803573ffffffffffffffffffffffffffffffffffffffff81168114610ce457600080fd5b919050565b600080600080600060a08688031215610d0157600080fd5b610d0a86610cc0565b9450610d1860208701610cc0565b93506040860135925060608601359150608086013560ff81168114610d3c57600080fd5b809150509295509295909350565b600060208284031215610d5c57600080fd5b6105a382610cc0565b600080600060408486031215610d7a57600080fd5b610d8384610cc0565b9250602084013567ffffffffffffffff80821115610da057600080fd5b818601915086601f830112610db457600080fd5b813581811115610dc357600080fd5b876020828501011115610dd557600080fd5b6020830194508093505050509250925092565b6020808252825182820181905260009190848201906040850190845b81811015610e3657835173ffffffffffffffffffffffffffffffffffffffff1683529284019291840191600101610e04565b50909695505050505050565b600060408284031215610e5457600080fd5b6040516040810181811067ffffffffffffffff82111715610e9e577f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b60405282358015158114610eb157600080fd5b8152610ebf60208401610cc0565b60208201529392505050565b60008060408385031215610ede57600080fd5b610ee783610cc0565b9150610ef560208401610cc0565b90509250929050565b81810381811115610863577f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fdfe46756e6374696f6e73205465726d73206f66205365727669636520416c6c6f77204c6973742076312e312e30a164736f6c6343000813000a", + ABI: "[{\"inputs\":[{\"components\":[{\"internalType\":\"bool\",\"name\":\"enabled\",\"type\":\"bool\"},{\"internalType\":\"address\",\"name\":\"signerPublicKey\",\"type\":\"address\"}],\"internalType\":\"structTermsOfServiceAllowListConfig\",\"name\":\"config\",\"type\":\"tuple\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"InvalidCalldata\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidSignature\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidUsage\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"RecipientIsBlocked\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"user\",\"type\":\"address\"}],\"name\":\"AddedAccess\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"user\",\"type\":\"address\"}],\"name\":\"BlockedAccess\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"components\":[{\"internalType\":\"bool\",\"name\":\"enabled\",\"type\":\"bool\"},{\"internalType\":\"address\",\"name\":\"signerPublicKey\",\"type\":\"address\"}],\"indexed\":false,\"internalType\":\"structTermsOfServiceAllowListConfig\",\"name\":\"config\",\"type\":\"tuple\"}],\"name\":\"ConfigUpdated\",\"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\":\"user\",\"type\":\"address\"}],\"name\":\"UnblockedAccess\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"acceptOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"acceptor\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"r\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"s\",\"type\":\"bytes32\"},{\"internalType\":\"uint8\",\"name\":\"v\",\"type\":\"uint8\"}],\"name\":\"acceptTermsOfService\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"blockSender\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getAllAllowedSenders\",\"outputs\":[{\"internalType\":\"address[]\",\"name\":\"\",\"type\":\"address[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getAllowedSendersCount\",\"outputs\":[{\"internalType\":\"uint64\",\"name\":\"\",\"type\":\"uint64\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"allowedSenderIdxStart\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"allowedSenderIdxEnd\",\"type\":\"uint64\"}],\"name\":\"getAllowedSendersInRange\",\"outputs\":[{\"internalType\":\"address[]\",\"name\":\"allowedSenders\",\"type\":\"address[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getBlockedSendersCount\",\"outputs\":[{\"internalType\":\"uint64\",\"name\":\"\",\"type\":\"uint64\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"blockedSenderIdxStart\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"blockedSenderIdxEnd\",\"type\":\"uint64\"}],\"name\":\"getBlockedSendersInRange\",\"outputs\":[{\"internalType\":\"address[]\",\"name\":\"blockedSenders\",\"type\":\"address[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getConfig\",\"outputs\":[{\"components\":[{\"internalType\":\"bool\",\"name\":\"enabled\",\"type\":\"bool\"},{\"internalType\":\"address\",\"name\":\"signerPublicKey\",\"type\":\"address\"}],\"internalType\":\"structTermsOfServiceAllowListConfig\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"acceptor\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"}],\"name\":\"getMessage\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"user\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"name\":\"hasAccess\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"isBlockedSender\",\"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\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"typeAndVersion\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"unblockSender\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"bool\",\"name\":\"enabled\",\"type\":\"bool\"},{\"internalType\":\"address\",\"name\":\"signerPublicKey\",\"type\":\"address\"}],\"internalType\":\"structTermsOfServiceAllowListConfig\",\"name\":\"config\",\"type\":\"tuple\"}],\"name\":\"updateConfig\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", + Bin: "0x60806040523480156200001157600080fd5b506040516200173438038062001734833981016040819052620000349162000269565b33806000816200008b5760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b0384811691909117909155811615620000be57620000be81620000d9565b505050620000d2816200018460201b60201c565b50620002ea565b336001600160a01b03821603620001335760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c66000000000000000000604482015260640162000082565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b6200018e6200020b565b805160068054602080850180516001600160a81b0319909316941515610100600160a81b03198116959095176101006001600160a01b039485160217909355604080519485529251909116908301527f0d22b8a99f411b3dd338c961284f608489ca0dab9cdad17366a343c361bcf80a910160405180910390a150565b6000546001600160a01b03163314620002675760405162461bcd60e51b815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e657200000000000000000000604482015260640162000082565b565b6000604082840312156200027c57600080fd5b604080519081016001600160401b0381118282101715620002ad57634e487b7160e01b600052604160045260246000fd5b60405282518015158114620002c157600080fd5b815260208301516001600160a01b0381168114620002de57600080fd5b60208201529392505050565b61143a80620002fa6000396000f3fe608060405234801561001057600080fd5b506004361061011b5760003560e01c8063817ef62e116100b2578063a39b06e311610081578063c3f909d411610066578063c3f909d4146102c3578063cc7ebf4914610322578063f2fde38b1461032a57600080fd5b8063a39b06e314610237578063a5e1d61d146102b057600080fd5b8063817ef62e146101e157806382184c7b146101e957806389f9a2c4146101fc5780638da5cb5b1461020f57600080fd5b80633908c4d4116100ee5780633908c4d41461018e57806347663acb146101a35780636b14daf8146101b657806379ba5097146101d957600080fd5b806301a05958146101205780630a8c9c2414610146578063181f5a771461016657806320229a861461017b575b600080fd5b61012861033d565b60405167ffffffffffffffff90911681526020015b60405180910390f35b610159610154366004610fd6565b61034e565b60405161013d9190611009565b61016e6104bc565b60405161013d9190611063565b610159610189366004610fd6565b6104d8565b6101a161019c3660046110f3565b61063e565b005b6101a16101b1366004611154565b6108e9565b6101c96101c436600461116f565b61094a565b604051901515815260200161013d565b6101a1610974565b610159610a76565b6101a16101f7366004611154565b610a82565b6101a161020a366004611221565b610ae8565b60005460405173ffffffffffffffffffffffffffffffffffffffff909116815260200161013d565b6102a26102453660046112aa565b6040517fffffffffffffffffffffffffffffffffffffffff000000000000000000000000606084811b8216602084015283901b16603482015260009060480160405160208183030381529060405280519060200120905092915050565b60405190815260200161013d565b6101c96102be366004611154565b610ba3565b60408051808201825260008082526020918201528151808301835260065460ff8116151580835273ffffffffffffffffffffffffffffffffffffffff61010090920482169284019283528451908152915116918101919091520161013d565b610128610bc3565b6101a1610338366004611154565b610bcf565b60006103496004610be3565b905090565b60608167ffffffffffffffff168367ffffffffffffffff16118061038557506103776002610be3565b8267ffffffffffffffff1610155b8061039757506103956002610be3565b155b156103ce576040517f8129bbcd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6103d88383611303565b6103e3906001611324565b67ffffffffffffffff1667ffffffffffffffff811115610405576104056111f2565b60405190808252806020026020018201604052801561042e578160200160208202803683370190505b50905060005b61043e8484611303565b67ffffffffffffffff1681116104b45761046d6104658267ffffffffffffffff8716611345565b600290610bed565b82828151811061047f5761047f611358565b73ffffffffffffffffffffffffffffffffffffffff909216602092830291909101909101526104ad81611387565b9050610434565b505b92915050565b6040518060600160405280602c8152602001611402602c913981565b60608167ffffffffffffffff168367ffffffffffffffff16118061050f57506105016004610be3565b8267ffffffffffffffff1610155b80610521575061051f6004610be3565b155b15610558576040517f8129bbcd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6105628383611303565b61056d906001611324565b67ffffffffffffffff1667ffffffffffffffff81111561058f5761058f6111f2565b6040519080825280602002602001820160405280156105b8578160200160208202803683370190505b50905060005b6105c88484611303565b67ffffffffffffffff1681116104b4576105f76105ef8267ffffffffffffffff8716611345565b600490610bed565b82828151811061060957610609611358565b73ffffffffffffffffffffffffffffffffffffffff9092166020928302919091019091015261063781611387565b90506105be565b610649600485610bf9565b15610680576040517f62b7a34d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60408051606087811b7fffffffffffffffffffffffffffffffffffffffff0000000000000000000000009081166020808501919091529188901b16603483015282516028818403018152604890920190925280519101206000906040517f19457468657265756d205369676e6564204d6573736167653a0a3332000000006020820152603c810191909152605c01604080518083037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe001815282825280516020918201206006546000855291840180845281905260ff8616928401929092526060830187905260808301869052909250610100900473ffffffffffffffffffffffffffffffffffffffff169060019060a0016020604051602081039080840390855afa1580156107b4573d6000803e3d6000fd5b5050506020604051035173ffffffffffffffffffffffffffffffffffffffff161461080b576040517f8baa579f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b3373ffffffffffffffffffffffffffffffffffffffff861614158061085057503373ffffffffffffffffffffffffffffffffffffffff8716148015906108505750333b155b15610887576040517f381cfcbd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610892600286610c28565b156108e15760405173ffffffffffffffffffffffffffffffffffffffff861681527f87286ad1f399c8e82bf0c4ef4fcdc570ea2e1e92176e5c848b6413545b885db49060200160405180910390a15b505050505050565b6108f1610c4a565b6108fc600482610ccd565b5060405173ffffffffffffffffffffffffffffffffffffffff821681527f28bbd0761309a99e8fb5e5d02ada0b7b2db2e5357531ff5dbfc205c3f5b6592b906020015b60405180910390a150565b60065460009060ff1661095f5750600161096d565b61096a600285610bf9565b90505b9392505050565b60015473ffffffffffffffffffffffffffffffffffffffff1633146109fa576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e65720000000000000000000060448201526064015b60405180910390fd5b60008054337fffffffffffffffffffffffff00000000000000000000000000000000000000008083168217845560018054909116905560405173ffffffffffffffffffffffffffffffffffffffff90921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b60606103496002610cef565b610a8a610c4a565b610a95600282610ccd565b50610aa1600482610c28565b5060405173ffffffffffffffffffffffffffffffffffffffff821681527f337cd0f3f594112b6d830afb510072d3b08556b446514f73b8109162fd1151e19060200161093f565b610af0610c4a565b805160068054602080850180517fffffffffffffffffffffff0000000000000000000000000000000000000000009093169415157fffffffffffffffffffffff0000000000000000000000000000000000000000ff81169590951761010073ffffffffffffffffffffffffffffffffffffffff9485160217909355604080519485529251909116908301527f0d22b8a99f411b3dd338c961284f608489ca0dab9cdad17366a343c361bcf80a910161093f565b60065460009060ff16610bb857506000919050565b6104b6600483610bf9565b60006103496002610be3565b610bd7610c4a565b610be081610cfc565b50565b60006104b6825490565b600061096d8383610df1565b73ffffffffffffffffffffffffffffffffffffffff81166000908152600183016020526040812054151561096d565b600061096d8373ffffffffffffffffffffffffffffffffffffffff8416610e1b565b60005473ffffffffffffffffffffffffffffffffffffffff163314610ccb576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e65720000000000000000000060448201526064016109f1565b565b600061096d8373ffffffffffffffffffffffffffffffffffffffff8416610e6a565b6060600061096d83610f5d565b3373ffffffffffffffffffffffffffffffffffffffff821603610d7b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c6600000000000000000060448201526064016109f1565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b6000826000018281548110610e0857610e08611358565b9060005260206000200154905092915050565b6000818152600183016020526040812054610e62575081546001818101845560008481526020808220909301849055845484825282860190935260409020919091556104b6565b5060006104b6565b60008181526001830160205260408120548015610f53576000610e8e6001836113bf565b8554909150600090610ea2906001906113bf565b9050818114610f07576000866000018281548110610ec257610ec2611358565b9060005260206000200154905080876000018481548110610ee557610ee5611358565b6000918252602080832090910192909255918252600188019052604090208390555b8554869080610f1857610f186113d2565b6001900381819060005260206000200160009055905585600101600086815260200190815260200160002060009055600193505050506104b6565b60009150506104b6565b606081600001805480602002602001604051908101604052809291908181526020018280548015610fad57602002820191906000526020600020905b815481526020019060010190808311610f99575b50505050509050919050565b803567ffffffffffffffff81168114610fd157600080fd5b919050565b60008060408385031215610fe957600080fd5b610ff283610fb9565b915061100060208401610fb9565b90509250929050565b6020808252825182820181905260009190848201906040850190845b8181101561105757835173ffffffffffffffffffffffffffffffffffffffff1683529284019291840191600101611025565b50909695505050505050565b600060208083528351808285015260005b8181101561109057858101830151858201604001528201611074565b5060006040828601015260407fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8301168501019250505092915050565b803573ffffffffffffffffffffffffffffffffffffffff81168114610fd157600080fd5b600080600080600060a0868803121561110b57600080fd5b611114866110cf565b9450611122602087016110cf565b93506040860135925060608601359150608086013560ff8116811461114657600080fd5b809150509295509295909350565b60006020828403121561116657600080fd5b61096d826110cf565b60008060006040848603121561118457600080fd5b61118d846110cf565b9250602084013567ffffffffffffffff808211156111aa57600080fd5b818601915086601f8301126111be57600080fd5b8135818111156111cd57600080fd5b8760208285010111156111df57600080fd5b6020830194508093505050509250925092565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b60006040828403121561123357600080fd5b6040516040810181811067ffffffffffffffff8211171561127d577f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6040528235801515811461129057600080fd5b815261129e602084016110cf565b60208201529392505050565b600080604083850312156112bd57600080fd5b6112c6836110cf565b9150611000602084016110cf565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b67ffffffffffffffff8281168282160390808211156104b4576104b46112d4565b67ffffffffffffffff8181168382160190808211156104b4576104b46112d4565b808201808211156104b6576104b66112d4565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82036113b8576113b86112d4565b5060010190565b818103818111156104b6576104b66112d4565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fdfe46756e6374696f6e73205465726d73206f66205365727669636520416c6c6f77204c6973742076312e312e30a164736f6c6343000813000a", } var TermsOfServiceAllowListABI = TermsOfServiceAllowListMetaData.ABI @@ -198,6 +198,94 @@ func (_TermsOfServiceAllowList *TermsOfServiceAllowListCallerSession) GetAllAllo return _TermsOfServiceAllowList.Contract.GetAllAllowedSenders(&_TermsOfServiceAllowList.CallOpts) } +func (_TermsOfServiceAllowList *TermsOfServiceAllowListCaller) GetAllowedSendersCount(opts *bind.CallOpts) (uint64, error) { + var out []interface{} + err := _TermsOfServiceAllowList.contract.Call(opts, &out, "getAllowedSendersCount") + + if err != nil { + return *new(uint64), err + } + + out0 := *abi.ConvertType(out[0], new(uint64)).(*uint64) + + return out0, err + +} + +func (_TermsOfServiceAllowList *TermsOfServiceAllowListSession) GetAllowedSendersCount() (uint64, error) { + return _TermsOfServiceAllowList.Contract.GetAllowedSendersCount(&_TermsOfServiceAllowList.CallOpts) +} + +func (_TermsOfServiceAllowList *TermsOfServiceAllowListCallerSession) GetAllowedSendersCount() (uint64, error) { + return _TermsOfServiceAllowList.Contract.GetAllowedSendersCount(&_TermsOfServiceAllowList.CallOpts) +} + +func (_TermsOfServiceAllowList *TermsOfServiceAllowListCaller) GetAllowedSendersInRange(opts *bind.CallOpts, allowedSenderIdxStart uint64, allowedSenderIdxEnd uint64) ([]common.Address, error) { + var out []interface{} + err := _TermsOfServiceAllowList.contract.Call(opts, &out, "getAllowedSendersInRange", allowedSenderIdxStart, allowedSenderIdxEnd) + + if err != nil { + return *new([]common.Address), err + } + + out0 := *abi.ConvertType(out[0], new([]common.Address)).(*[]common.Address) + + return out0, err + +} + +func (_TermsOfServiceAllowList *TermsOfServiceAllowListSession) GetAllowedSendersInRange(allowedSenderIdxStart uint64, allowedSenderIdxEnd uint64) ([]common.Address, error) { + return _TermsOfServiceAllowList.Contract.GetAllowedSendersInRange(&_TermsOfServiceAllowList.CallOpts, allowedSenderIdxStart, allowedSenderIdxEnd) +} + +func (_TermsOfServiceAllowList *TermsOfServiceAllowListCallerSession) GetAllowedSendersInRange(allowedSenderIdxStart uint64, allowedSenderIdxEnd uint64) ([]common.Address, error) { + return _TermsOfServiceAllowList.Contract.GetAllowedSendersInRange(&_TermsOfServiceAllowList.CallOpts, allowedSenderIdxStart, allowedSenderIdxEnd) +} + +func (_TermsOfServiceAllowList *TermsOfServiceAllowListCaller) GetBlockedSendersCount(opts *bind.CallOpts) (uint64, error) { + var out []interface{} + err := _TermsOfServiceAllowList.contract.Call(opts, &out, "getBlockedSendersCount") + + if err != nil { + return *new(uint64), err + } + + out0 := *abi.ConvertType(out[0], new(uint64)).(*uint64) + + return out0, err + +} + +func (_TermsOfServiceAllowList *TermsOfServiceAllowListSession) GetBlockedSendersCount() (uint64, error) { + return _TermsOfServiceAllowList.Contract.GetBlockedSendersCount(&_TermsOfServiceAllowList.CallOpts) +} + +func (_TermsOfServiceAllowList *TermsOfServiceAllowListCallerSession) GetBlockedSendersCount() (uint64, error) { + return _TermsOfServiceAllowList.Contract.GetBlockedSendersCount(&_TermsOfServiceAllowList.CallOpts) +} + +func (_TermsOfServiceAllowList *TermsOfServiceAllowListCaller) GetBlockedSendersInRange(opts *bind.CallOpts, blockedSenderIdxStart uint64, blockedSenderIdxEnd uint64) ([]common.Address, error) { + var out []interface{} + err := _TermsOfServiceAllowList.contract.Call(opts, &out, "getBlockedSendersInRange", blockedSenderIdxStart, blockedSenderIdxEnd) + + if err != nil { + return *new([]common.Address), err + } + + out0 := *abi.ConvertType(out[0], new([]common.Address)).(*[]common.Address) + + return out0, err + +} + +func (_TermsOfServiceAllowList *TermsOfServiceAllowListSession) GetBlockedSendersInRange(blockedSenderIdxStart uint64, blockedSenderIdxEnd uint64) ([]common.Address, error) { + return _TermsOfServiceAllowList.Contract.GetBlockedSendersInRange(&_TermsOfServiceAllowList.CallOpts, blockedSenderIdxStart, blockedSenderIdxEnd) +} + +func (_TermsOfServiceAllowList *TermsOfServiceAllowListCallerSession) GetBlockedSendersInRange(blockedSenderIdxStart uint64, blockedSenderIdxEnd uint64) ([]common.Address, error) { + return _TermsOfServiceAllowList.Contract.GetBlockedSendersInRange(&_TermsOfServiceAllowList.CallOpts, blockedSenderIdxStart, blockedSenderIdxEnd) +} + func (_TermsOfServiceAllowList *TermsOfServiceAllowListCaller) GetConfig(opts *bind.CallOpts) (TermsOfServiceAllowListConfig, error) { var out []interface{} err := _TermsOfServiceAllowList.contract.Call(opts, &out, "getConfig") @@ -1193,6 +1281,14 @@ func (_TermsOfServiceAllowList *TermsOfServiceAllowList) Address() common.Addres type TermsOfServiceAllowListInterface interface { GetAllAllowedSenders(opts *bind.CallOpts) ([]common.Address, error) + GetAllowedSendersCount(opts *bind.CallOpts) (uint64, error) + + GetAllowedSendersInRange(opts *bind.CallOpts, allowedSenderIdxStart uint64, allowedSenderIdxEnd uint64) ([]common.Address, error) + + GetBlockedSendersCount(opts *bind.CallOpts) (uint64, error) + + GetBlockedSendersInRange(opts *bind.CallOpts, blockedSenderIdxStart uint64, blockedSenderIdxEnd uint64) ([]common.Address, error) + GetConfig(opts *bind.CallOpts) (TermsOfServiceAllowListConfig, error) GetMessage(opts *bind.CallOpts, acceptor common.Address, recipient common.Address) ([32]byte, error) 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 0a77e57c88..16bb718e7c 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,6 +1,6 @@ -GETH_VERSION: 1.12.2 +GETH_VERSION: 1.13.8 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 6beec092fbb3b619dfe69f1ad23392b0bbaf00327b335e4080f921c7122a57e4 +functions_allow_list: ../../../contracts/solc/v0.8.19/functions/v1_X/TermsOfServiceAllowList.abi ../../../contracts/solc/v0.8.19/functions/v1_X/TermsOfServiceAllowList.bin 586696a0cacc0e5112bdd6c99535748a3fbf08c9319360aee868831d38a96d7b 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_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 diff --git a/core/gethwrappers/generated/automation_registrar_wrapper2_2/automation_registrar_wrapper2_2.go b/core/gethwrappers/generated/automation_registrar_wrapper2_2/automation_registrar_wrapper2_2.go new file mode 100644 index 0000000000..c8a8480044 --- /dev/null +++ b/core/gethwrappers/generated/automation_registrar_wrapper2_2/automation_registrar_wrapper2_2.go @@ -0,0 +1,1685 @@ +// Code generated - DO NOT EDIT. +// This file is a generated binding and any manual changes will be lost. + +package automation_registrar_wrapper2_2 + +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 +) + +type AutomationRegistrar22InitialTriggerConfig struct { + TriggerType uint8 + AutoApproveType uint8 + AutoApproveMaxAllowed uint32 +} + +type AutomationRegistrar22RegistrationParams struct { + Name string + EncryptedEmail []byte + UpkeepContract common.Address + GasLimit uint32 + AdminAddress common.Address + TriggerType uint8 + CheckData []byte + TriggerConfig []byte + OffchainConfig []byte + Amount *big.Int +} + +type AutomationRegistrar22TriggerRegistrationStorage struct { + AutoApproveType uint8 + AutoApproveMaxAllowed uint32 + ApprovedCount uint32 +} + +var AutomationRegistrarMetaData = &bind.MetaData{ + ABI: "[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"LINKAddress\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"AutomationRegistry\",\"type\":\"address\"},{\"internalType\":\"uint96\",\"name\":\"minLINKJuels\",\"type\":\"uint96\"},{\"components\":[{\"internalType\":\"uint8\",\"name\":\"triggerType\",\"type\":\"uint8\"},{\"internalType\":\"enumAutomationRegistrar2_2.AutoApproveType\",\"name\":\"autoApproveType\",\"type\":\"uint8\"},{\"internalType\":\"uint32\",\"name\":\"autoApproveMaxAllowed\",\"type\":\"uint32\"}],\"internalType\":\"structAutomationRegistrar2_2.InitialTriggerConfig[]\",\"name\":\"triggerConfigs\",\"type\":\"tuple[]\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"AmountMismatch\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"FunctionNotPermitted\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"HashMismatch\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InsufficientPayment\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidAdminAddress\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidDataLength\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"LinkTransferFailed\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyAdminOrOwner\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyLink\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"RegistrationRequestFailed\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"RequestNotFound\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"SenderMismatch\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"senderAddress\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"allowed\",\"type\":\"bool\"}],\"name\":\"AutoApproveAllowedSenderSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"AutomationRegistry\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint96\",\"name\":\"minLINKJuels\",\"type\":\"uint96\"}],\"name\":\"ConfigChanged\",\"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\":true,\"internalType\":\"bytes32\",\"name\":\"hash\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"string\",\"name\":\"displayName\",\"type\":\"string\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"upkeepId\",\"type\":\"uint256\"}],\"name\":\"RegistrationApproved\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"hash\",\"type\":\"bytes32\"}],\"name\":\"RegistrationRejected\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"hash\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"string\",\"name\":\"name\",\"type\":\"string\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"encryptedEmail\",\"type\":\"bytes\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"upkeepContract\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"gasLimit\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"adminAddress\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint8\",\"name\":\"triggerType\",\"type\":\"uint8\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"triggerConfig\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"offchainConfig\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"checkData\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"uint96\",\"name\":\"amount\",\"type\":\"uint96\"}],\"name\":\"RegistrationRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint8\",\"name\":\"triggerType\",\"type\":\"uint8\"},{\"indexed\":false,\"internalType\":\"enumAutomationRegistrar2_2.AutoApproveType\",\"name\":\"autoApproveType\",\"type\":\"uint8\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"autoApproveMaxAllowed\",\"type\":\"uint32\"}],\"name\":\"TriggerConfigSet\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"LINK\",\"outputs\":[{\"internalType\":\"contractLinkTokenInterface\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"acceptOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"name\",\"type\":\"string\"},{\"internalType\":\"address\",\"name\":\"upkeepContract\",\"type\":\"address\"},{\"internalType\":\"uint32\",\"name\":\"gasLimit\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"adminAddress\",\"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\"},{\"internalType\":\"bytes32\",\"name\":\"hash\",\"type\":\"bytes32\"}],\"name\":\"approve\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"hash\",\"type\":\"bytes32\"}],\"name\":\"cancel\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"senderAddress\",\"type\":\"address\"}],\"name\":\"getAutoApproveAllowedSender\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getConfig\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"AutomationRegistry\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"minLINKJuels\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"hash\",\"type\":\"bytes32\"}],\"name\":\"getPendingRequest\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"uint96\",\"name\":\"\",\"type\":\"uint96\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint8\",\"name\":\"triggerType\",\"type\":\"uint8\"}],\"name\":\"getTriggerRegistrationDetails\",\"outputs\":[{\"components\":[{\"internalType\":\"enumAutomationRegistrar2_2.AutoApproveType\",\"name\":\"autoApproveType\",\"type\":\"uint8\"},{\"internalType\":\"uint32\",\"name\":\"autoApproveMaxAllowed\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"approvedCount\",\"type\":\"uint32\"}],\"internalType\":\"structAutomationRegistrar2_2.TriggerRegistrationStorage\",\"name\":\"\",\"type\":\"tuple\"}],\"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\":\"string\",\"name\":\"name\",\"type\":\"string\"},{\"internalType\":\"bytes\",\"name\":\"encryptedEmail\",\"type\":\"bytes\"},{\"internalType\":\"address\",\"name\":\"upkeepContract\",\"type\":\"address\"},{\"internalType\":\"uint32\",\"name\":\"gasLimit\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"adminAddress\",\"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\"},{\"internalType\":\"uint96\",\"name\":\"amount\",\"type\":\"uint96\"},{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"register\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"string\",\"name\":\"name\",\"type\":\"string\"},{\"internalType\":\"bytes\",\"name\":\"encryptedEmail\",\"type\":\"bytes\"},{\"internalType\":\"address\",\"name\":\"upkeepContract\",\"type\":\"address\"},{\"internalType\":\"uint32\",\"name\":\"gasLimit\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"adminAddress\",\"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\"},{\"internalType\":\"uint96\",\"name\":\"amount\",\"type\":\"uint96\"}],\"internalType\":\"structAutomationRegistrar2_2.RegistrationParams\",\"name\":\"requestParams\",\"type\":\"tuple\"}],\"name\":\"registerUpkeep\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"senderAddress\",\"type\":\"address\"},{\"internalType\":\"bool\",\"name\":\"allowed\",\"type\":\"bool\"}],\"name\":\"setAutoApproveAllowedSender\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"AutomationRegistry\",\"type\":\"address\"},{\"internalType\":\"uint96\",\"name\":\"minLINKJuels\",\"type\":\"uint96\"}],\"name\":\"setConfig\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint8\",\"name\":\"triggerType\",\"type\":\"uint8\"},{\"internalType\":\"enumAutomationRegistrar2_2.AutoApproveType\",\"name\":\"autoApproveType\",\"type\":\"uint8\"},{\"internalType\":\"uint32\",\"name\":\"autoApproveMaxAllowed\",\"type\":\"uint32\"}],\"name\":\"setTriggerConfig\",\"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\"}]", + Bin: "0x60a06040523480156200001157600080fd5b5060405162002d8238038062002d8283398101604081905262000034916200043b565b33806000816200008b5760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b0384811691909117909155811615620000be57620000be816200017a565b5050506001600160a01b038416608052620000da838362000225565b60005b81518110156200016f576200015a82828151811062000100576200010062000598565b60200260200101516000015183838151811062000121576200012162000598565b60200260200101516020015184848151811062000142576200014262000598565b6020026020010151604001516200029e60201b60201c565b806200016681620005ae565b915050620000dd565b50505050506200062f565b336001600160a01b03821603620001d45760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c66000000000000000000604482015260640162000082565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b6200022f6200034c565b6040805180820182526001600160a01b0384168082526001600160601b0384166020928301819052600160a01b810282176004558351918252918101919091527f39ce5d867555f0b0183e358fce5b158e7ca4fecd7c01cb7e0e19f1e23285838a910160405180910390a15050565b620002a86200034c565b60ff83166000908152600360205260409020805483919060ff19166001836002811115620002da57620002da620005d6565b021790555060ff831660009081526003602052604090819020805464ffffffff00191661010063ffffffff851602179055517f830a6d06a4e2caac67eba04323de22bdb04f032dd8b3d6a0c52b503d9a7036a3906200033f90859085908590620005ec565b60405180910390a1505050565b6000546001600160a01b03163314620003a85760405162461bcd60e51b815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e657200000000000000000000604482015260640162000082565b565b80516001600160a01b0381168114620003c257600080fd5b919050565b634e487b7160e01b600052604160045260246000fd5b604051606081016001600160401b0381118282101715620004025762000402620003c7565b60405290565b604051601f8201601f191681016001600160401b0381118282101715620004335762000433620003c7565b604052919050565b600080600080608085870312156200045257600080fd5b6200045d85620003aa565b935060206200046e818701620003aa565b604087810151919550906001600160601b03811681146200048e57600080fd5b606088810151919550906001600160401b0380821115620004ae57600080fd5b818a0191508a601f830112620004c357600080fd5b815181811115620004d857620004d8620003c7565b620004e8868260051b0162000408565b818152868101925090840283018601908c8211156200050657600080fd5b928601925b81841015620005875784848e031215620005255760008081fd5b6200052f620003dd565b845160ff81168114620005425760008081fd5b81528488015160038110620005575760008081fd5b818901528487015163ffffffff81168114620005735760008081fd5b81880152835292840192918601916200050b565b999c989b5096995050505050505050565b634e487b7160e01b600052603260045260246000fd5b600060018201620005cf57634e487b7160e01b600052601160045260246000fd5b5060010190565b634e487b7160e01b600052602160045260246000fd5b60ff8416815260608101600384106200061557634e487b7160e01b600052602160045260246000fd5b83602083015263ffffffff83166040830152949350505050565b6080516127146200066e60003960008181610177015281816105d601528181610887015281816109bd01528181610f0e015261171b01526127146000f3fe608060405234801561001057600080fd5b506004361061011b5760003560e01c8063856853e6116100b2578063b5ff5b4111610081578063c4d252f511610066578063c4d252f5146103e3578063e8d4070d146103f6578063f2fde38b1461040957600080fd5b8063b5ff5b4114610369578063c3f909d41461037c57600080fd5b8063856853e61461027857806388b12d551461028b5780638da5cb5b14610338578063a4c0ed361461035657600080fd5b80633f678e11116100ee5780633f678e11146101f35780636c4cdfc31461021457806379ba5097146102275780637e776f7f1461022f57600080fd5b8063181f5a77146101205780631b6b6d2314610172578063212d0884146101be578063367b9b4f146101de575b600080fd5b61015c6040518060400160405280601981526020017f4175746f6d6174696f6e52656769737472617220322e312e300000000000000081525081565b6040516101699190611a74565b60405180910390f35b6101997f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610169565b6101d16101cc366004611aa4565b61041c565b6040516101699190611b29565b6101f16101ec366004611b9d565b6104a9565b005b610206610201366004611bd6565b61053b565b604051908152602001610169565b6101f1610222366004611c2e565b6106d3565b6101f161076d565b61026861023d366004611c63565b73ffffffffffffffffffffffffffffffffffffffff1660009081526005602052604090205460ff1690565b6040519015158152602001610169565b6101f1610286366004611de1565b61086f565b6102ff610299366004611f40565b60009081526002602090815260409182902082518084019093525473ffffffffffffffffffffffffffffffffffffffff8116808452740100000000000000000000000000000000000000009091046bffffffffffffffffffffffff169290910182905291565b6040805173ffffffffffffffffffffffffffffffffffffffff90931683526bffffffffffffffffffffffff909116602083015201610169565b60005473ffffffffffffffffffffffffffffffffffffffff16610199565b6101f1610364366004611f59565b6109a5565b6101f1610377366004611fb5565b610ce3565b60408051808201825260045473ffffffffffffffffffffffffffffffffffffffff8116808352740100000000000000000000000000000000000000009091046bffffffffffffffffffffffff16602092830181905283519182529181019190915201610169565b6101f16103f1366004611f40565b610dc2565b6101f1610404366004611ffe565b61104c565b6101f1610417366004611c63565b6112d9565b60408051606080820183526000808352602080840182905283850182905260ff86811683526003909152908490208451928301909452835492939192839116600281111561046c5761046c611abf565b600281111561047d5761047d611abf565b8152905463ffffffff610100820481166020840152650100000000009091041660409091015292915050565b6104b16112ed565b73ffffffffffffffffffffffffffffffffffffffff821660008181526005602090815260409182902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001685151590811790915591519182527f20c6237dac83526a849285a9f79d08a483291bdd3a056a0ef9ae94ecee1ad356910160405180910390a25050565b6004546000907401000000000000000000000000000000000000000090046bffffffffffffffffffffffff1661057961014084016101208501612109565b6bffffffffffffffffffffffff1610156105bf576040517fcd1c886700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000166323b872dd333061060f61014087016101208801612109565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e086901b16815273ffffffffffffffffffffffffffffffffffffffff93841660048201529290911660248301526bffffffffffffffffffffffff1660448201526064016020604051808303816000875af1158015610696573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106ba9190612124565b506106cd6106c783612141565b33611370565b92915050565b6106db6112ed565b60408051808201825273ffffffffffffffffffffffffffffffffffffffff84168082526bffffffffffffffffffffffff8416602092830181905274010000000000000000000000000000000000000000810282176004558351918252918101919091527f39ce5d867555f0b0183e358fce5b158e7ca4fecd7c01cb7e0e19f1e23285838a910160405180910390a15050565b60015473ffffffffffffffffffffffffffffffffffffffff1633146107f3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e65720000000000000000000060448201526064015b60405180910390fd5b60008054337fffffffffffffffffffffffff00000000000000000000000000000000000000008083168217845560018054909116905560405173ffffffffffffffffffffffffffffffffffffffff90921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b3373ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016146108de576040517f018d10be00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6109966040518061014001604052808e81526020018d8d8080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525050509082525073ffffffffffffffffffffffffffffffffffffffff808d16602083015263ffffffff8c1660408301528a16606082015260ff8916608082015260a0810188905260c0810187905260e081018690526bffffffffffffffffffffffff85166101009091015282611370565b50505050505050505050505050565b3373ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001614610a14576040517f018d10be00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b81818080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525050505060208101517fffffffff0000000000000000000000000000000000000000000000000000000081167f856853e60000000000000000000000000000000000000000000000000000000014610aca576040517fe3d6792100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8484846000610adc8260048186612276565b810190610ae991906122a0565b509950505050505050505050806bffffffffffffffffffffffff168414610b3c576040517f55e97b0d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8988886000610b4e8260048186612276565b810190610b5b91906122a0565b9a50505050505050505050508073ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff1614610bcc576040517ff8c5638e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6004547401000000000000000000000000000000000000000090046bffffffffffffffffffffffff168d1015610c2e576040517fcd1c886700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60003073ffffffffffffffffffffffffffffffffffffffff168d8d604051610c579291906123dd565b600060405180830381855af49150503d8060008114610c92576040519150601f19603f3d011682016040523d82523d6000602084013e610c97565b606091505b5050905080610cd2576040517f649bf81000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b505050505050505050505050505050565b610ceb6112ed565b60ff8316600090815260036020526040902080548391907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001836002811115610d3857610d38611abf565b021790555060ff83166000908152600360205260409081902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffff00000000ff1661010063ffffffff851602179055517f830a6d06a4e2caac67eba04323de22bdb04f032dd8b3d6a0c52b503d9a7036a390610db5908590859085906123ed565b60405180910390a1505050565b60008181526002602090815260409182902082518084019093525473ffffffffffffffffffffffffffffffffffffffff8116808452740100000000000000000000000000000000000000009091046bffffffffffffffffffffffff1691830191909152331480610e49575060005473ffffffffffffffffffffffffffffffffffffffff1633145b610e7f576040517f61685c2b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b805173ffffffffffffffffffffffffffffffffffffffff16610ecd576040517f4b13b31e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600082815260026020908152604080832083905583519184015190517fa9059cbb0000000000000000000000000000000000000000000000000000000081527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff169263a9059cbb92610f859260040173ffffffffffffffffffffffffffffffffffffffff9290921682526bffffffffffffffffffffffff16602082015260400190565b6020604051808303816000875af1158015610fa4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610fc89190612124565b90508061101c5781516040517fc2e4dce800000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff90911660048201526024016107ea565b60405183907f3663fb28ebc87645eb972c9dad8521bf665c623f287e79f1c56f1eb374b82a2290600090a2505050565b6110546112ed565b60008181526002602090815260409182902082518084019093525473ffffffffffffffffffffffffffffffffffffffff8116808452740100000000000000000000000000000000000000009091046bffffffffffffffffffffffff16918301919091526110ed576040517f4b13b31e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008b8b8b8b8b8b8b8b8b60405160200161111099989796959493929190612461565b604051602081830303815290604052805190602001209050808314611161576040517f3f4d605300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60026000848152602001908152602001600020600080820160006101000a81549073ffffffffffffffffffffffffffffffffffffffff02191690556000820160146101000a8154906bffffffffffffffffffffffff021916905550506112c96040518061014001604052808f81526020016040518060200160405280600081525081526020018e73ffffffffffffffffffffffffffffffffffffffff1681526020018d63ffffffff1681526020018c73ffffffffffffffffffffffffffffffffffffffff1681526020018b60ff1681526020018a8a8080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525050509082525060208082018a905260408051601f8a0183900483028101830182528981529201919089908990819084018382808284376000920191909152505050908252506020858101516bffffffffffffffffffffffff1691015282611647565b5050505050505050505050505050565b6112e16112ed565b6112ea81611876565b50565b60005473ffffffffffffffffffffffffffffffffffffffff16331461136e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e65720000000000000000000060448201526064016107ea565b565b608082015160009073ffffffffffffffffffffffffffffffffffffffff166113c4576040517f05bb467c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008360400151846060015185608001518660a001518760c001518860e0015189610100015160405160200161140097969594939291906124e7565b604051602081830303815290604052805190602001209050836040015173ffffffffffffffffffffffffffffffffffffffff16817f7684390ebb103102f7f48c71439c2408713f8d437782a6fab2756acc0e42c1b786600001518760200151886060015189608001518a60a001518b60e001518c61010001518d60c001518e610120015160405161149999989796959493929190612569565b60405180910390a360a084015160ff9081166000908152600360205260408082208151606081019092528054929361151c9383911660028111156114df576114df611abf565b60028111156114f0576114f0611abf565b8152905463ffffffff61010082048116602084015265010000000000909104166040909101528561196b565b156115845760a085015160ff166000908152600360205260409020805465010000000000900463ffffffff1690600561155483612653565b91906101000a81548163ffffffff021916908363ffffffff1602179055505061157d8583611647565b905061163f565b61012085015160008381526002602052604081205490916115ca917401000000000000000000000000000000000000000090046bffffffffffffffffffffffff16612676565b604080518082018252608089015173ffffffffffffffffffffffffffffffffffffffff90811682526bffffffffffffffffffffffff9384166020808401918252600089815260029091529390932091519251909316740100000000000000000000000000000000000000000291909216179055505b949350505050565b600480546040808501516060860151608087015160a088015160c089015160e08a01516101008b015196517f28f32f3800000000000000000000000000000000000000000000000000000000815260009973ffffffffffffffffffffffffffffffffffffffff909916988a988a986328f32f38986116d29891979096919590949193909291016124e7565b6020604051808303816000875af11580156116f1573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061171591906126a2565b905060007f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16634000aea0848861012001518560405160200161176f91815260200190565b6040516020818303038152906040526040518463ffffffff1660e01b815260040161179c939291906126bb565b6020604051808303816000875af11580156117bb573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117df9190612124565b905080611830576040517fc2e4dce800000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff841660048201526024016107ea565b81857fb9a292fb7e3edd920cd2d2829a3615a640c43fd7de0a0820aa0668feb4c37d4b88600001516040516118659190611a74565b60405180910390a350949350505050565b3373ffffffffffffffffffffffffffffffffffffffff8216036118f5576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c6600000000000000000060448201526064016107ea565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b6000808351600281111561198157611981611abf565b0361198e575060006106cd565b6001835160028111156119a3576119a3611abf565b1480156119d6575073ffffffffffffffffffffffffffffffffffffffff821660009081526005602052604090205460ff16155b156119e3575060006106cd565b826020015163ffffffff16836040015163ffffffff161015611a07575060016106cd565b50600092915050565b6000815180845260005b81811015611a3657602081850181015186830182015201611a1a565b5060006020828601015260207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f83011685010191505092915050565b602081526000611a876020830184611a10565b9392505050565b803560ff81168114611a9f57600080fd5b919050565b600060208284031215611ab657600080fd5b611a8782611a8e565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b60038110611b25577f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b9052565b6000606082019050611b3c828451611aee565b602083015163ffffffff8082166020850152806040860151166040850152505092915050565b73ffffffffffffffffffffffffffffffffffffffff811681146112ea57600080fd5b8035611a9f81611b62565b80151581146112ea57600080fd5b60008060408385031215611bb057600080fd5b8235611bbb81611b62565b91506020830135611bcb81611b8f565b809150509250929050565b600060208284031215611be857600080fd5b813567ffffffffffffffff811115611bff57600080fd5b82016101408185031215611a8757600080fd5b80356bffffffffffffffffffffffff81168114611a9f57600080fd5b60008060408385031215611c4157600080fd5b8235611c4c81611b62565b9150611c5a60208401611c12565b90509250929050565b600060208284031215611c7557600080fd5b8135611a8781611b62565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051610140810167ffffffffffffffff81118282101715611cd357611cd3611c80565b60405290565b600082601f830112611cea57600080fd5b813567ffffffffffffffff80821115611d0557611d05611c80565b604051601f83017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f01168101908282118183101715611d4b57611d4b611c80565b81604052838152866020858801011115611d6457600080fd5b836020870160208301376000602085830101528094505050505092915050565b60008083601f840112611d9657600080fd5b50813567ffffffffffffffff811115611dae57600080fd5b602083019150836020828501011115611dc657600080fd5b9250929050565b803563ffffffff81168114611a9f57600080fd5b6000806000806000806000806000806000806101608d8f031215611e0457600080fd5b67ffffffffffffffff8d351115611e1a57600080fd5b611e278e8e358f01611cd9565b9b5067ffffffffffffffff60208e01351115611e4257600080fd5b611e528e60208f01358f01611d84565b909b509950611e6360408e01611b84565b9850611e7160608e01611dcd565b9750611e7f60808e01611b84565b9650611e8d60a08e01611a8e565b955067ffffffffffffffff60c08e01351115611ea857600080fd5b611eb88e60c08f01358f01611cd9565b945067ffffffffffffffff60e08e01351115611ed357600080fd5b611ee38e60e08f01358f01611cd9565b935067ffffffffffffffff6101008e01351115611eff57600080fd5b611f108e6101008f01358f01611cd9565b9250611f1f6101208e01611c12565b9150611f2e6101408e01611b84565b90509295989b509295989b509295989b565b600060208284031215611f5257600080fd5b5035919050565b60008060008060608587031215611f6f57600080fd5b8435611f7a81611b62565b935060208501359250604085013567ffffffffffffffff811115611f9d57600080fd5b611fa987828801611d84565b95989497509550505050565b600080600060608486031215611fca57600080fd5b611fd384611a8e565b9250602084013560038110611fe757600080fd5b9150611ff560408501611dcd565b90509250925092565b60008060008060008060008060008060006101208c8e03121561202057600080fd5b67ffffffffffffffff808d35111561203757600080fd5b6120448e8e358f01611cd9565b9b5061205260208e01611b84565b9a5061206060408e01611dcd565b995061206e60608e01611b84565b985061207c60808e01611a8e565b97508060a08e0135111561208f57600080fd5b61209f8e60a08f01358f01611d84565b909750955060c08d01358110156120b557600080fd5b6120c58e60c08f01358f01611cd9565b94508060e08e013511156120d857600080fd5b506120e98d60e08e01358e01611d84565b81945080935050506101008c013590509295989b509295989b9093969950565b60006020828403121561211b57600080fd5b611a8782611c12565b60006020828403121561213657600080fd5b8151611a8781611b8f565b6000610140823603121561215457600080fd5b61215c611caf565b823567ffffffffffffffff8082111561217457600080fd5b61218036838701611cd9565b8352602085013591508082111561219657600080fd5b6121a236838701611cd9565b60208401526121b360408601611b84565b60408401526121c460608601611dcd565b60608401526121d560808601611b84565b60808401526121e660a08601611a8e565b60a084015260c08501359150808211156121ff57600080fd5b61220b36838701611cd9565b60c084015260e085013591508082111561222457600080fd5b61223036838701611cd9565b60e08401526101009150818501358181111561224b57600080fd5b61225736828801611cd9565b8385015250505061012061226c818501611c12565b9082015292915050565b6000808585111561228657600080fd5b8386111561229357600080fd5b5050820193919092039150565b60008060008060008060008060008060006101608c8e0312156122c257600080fd5b67ffffffffffffffff808d3511156122d957600080fd5b6122e68e8e358f01611cd9565b9b508060208e013511156122f957600080fd5b6123098e60208f01358f01611cd9565b9a5061231760408e01611b84565b995061232560608e01611dcd565b985061233360808e01611b84565b975061234160a08e01611a8e565b96508060c08e0135111561235457600080fd5b6123648e60c08f01358f01611cd9565b95508060e08e0135111561237757600080fd5b6123878e60e08f01358f01611cd9565b9450806101008e0135111561239b57600080fd5b506123ad8d6101008e01358e01611cd9565b92506123bc6101208d01611c12565b91506123cb6101408d01611b84565b90509295989b509295989b9093969950565b8183823760009101908152919050565b60ff84168152606081016124046020830185611aee565b63ffffffff83166040830152949350505050565b8183528181602085013750600060208284010152600060207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f840116840101905092915050565b600073ffffffffffffffffffffffffffffffffffffffff808c16835263ffffffff8b166020840152808a1660408401525060ff8816606083015260e060808301526124b060e083018789612418565b82810360a08401526124c28187611a10565b905082810360c08401526124d7818587612418565b9c9b505050505050505050505050565b600073ffffffffffffffffffffffffffffffffffffffff808a16835263ffffffff8916602084015280881660408401525060ff8616606083015260e0608083015261253560e0830186611a10565b82810360a08401526125478186611a10565b905082810360c084015261255b8185611a10565b9a9950505050505050505050565b600061012080835261257d8184018d611a10565b90508281036020840152612591818c611a10565b905063ffffffff8a16604084015273ffffffffffffffffffffffffffffffffffffffff8916606084015260ff8816608084015282810360a08401526125d68188611a10565b905082810360c08401526125ea8187611a10565b905082810360e08401526125fe8186611a10565b9150506bffffffffffffffffffffffff83166101008301529a9950505050505050505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b600063ffffffff80831681810361266c5761266c612624565b6001019392505050565b6bffffffffffffffffffffffff81811683821601908082111561269b5761269b612624565b5092915050565b6000602082840312156126b457600080fd5b5051919050565b73ffffffffffffffffffffffffffffffffffffffff841681526bffffffffffffffffffffffff831660208201526060604082015260006126fe6060830184611a10565b9594505050505056fea164736f6c6343000810000a", +} + +var AutomationRegistrarABI = AutomationRegistrarMetaData.ABI + +var AutomationRegistrarBin = AutomationRegistrarMetaData.Bin + +func DeployAutomationRegistrar(auth *bind.TransactOpts, backend bind.ContractBackend, LINKAddress common.Address, AutomationRegistry common.Address, minLINKJuels *big.Int, triggerConfigs []AutomationRegistrar22InitialTriggerConfig) (common.Address, *types.Transaction, *AutomationRegistrar, error) { + parsed, err := AutomationRegistrarMetaData.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(AutomationRegistrarBin), backend, LINKAddress, AutomationRegistry, minLINKJuels, triggerConfigs) + if err != nil { + return common.Address{}, nil, nil, err + } + return address, tx, &AutomationRegistrar{address: address, abi: *parsed, AutomationRegistrarCaller: AutomationRegistrarCaller{contract: contract}, AutomationRegistrarTransactor: AutomationRegistrarTransactor{contract: contract}, AutomationRegistrarFilterer: AutomationRegistrarFilterer{contract: contract}}, nil +} + +type AutomationRegistrar struct { + address common.Address + abi abi.ABI + AutomationRegistrarCaller + AutomationRegistrarTransactor + AutomationRegistrarFilterer +} + +type AutomationRegistrarCaller struct { + contract *bind.BoundContract +} + +type AutomationRegistrarTransactor struct { + contract *bind.BoundContract +} + +type AutomationRegistrarFilterer struct { + contract *bind.BoundContract +} + +type AutomationRegistrarSession struct { + Contract *AutomationRegistrar + CallOpts bind.CallOpts + TransactOpts bind.TransactOpts +} + +type AutomationRegistrarCallerSession struct { + Contract *AutomationRegistrarCaller + CallOpts bind.CallOpts +} + +type AutomationRegistrarTransactorSession struct { + Contract *AutomationRegistrarTransactor + TransactOpts bind.TransactOpts +} + +type AutomationRegistrarRaw struct { + Contract *AutomationRegistrar +} + +type AutomationRegistrarCallerRaw struct { + Contract *AutomationRegistrarCaller +} + +type AutomationRegistrarTransactorRaw struct { + Contract *AutomationRegistrarTransactor +} + +func NewAutomationRegistrar(address common.Address, backend bind.ContractBackend) (*AutomationRegistrar, error) { + abi, err := abi.JSON(strings.NewReader(AutomationRegistrarABI)) + if err != nil { + return nil, err + } + contract, err := bindAutomationRegistrar(address, backend, backend, backend) + if err != nil { + return nil, err + } + return &AutomationRegistrar{address: address, abi: abi, AutomationRegistrarCaller: AutomationRegistrarCaller{contract: contract}, AutomationRegistrarTransactor: AutomationRegistrarTransactor{contract: contract}, AutomationRegistrarFilterer: AutomationRegistrarFilterer{contract: contract}}, nil +} + +func NewAutomationRegistrarCaller(address common.Address, caller bind.ContractCaller) (*AutomationRegistrarCaller, error) { + contract, err := bindAutomationRegistrar(address, caller, nil, nil) + if err != nil { + return nil, err + } + return &AutomationRegistrarCaller{contract: contract}, nil +} + +func NewAutomationRegistrarTransactor(address common.Address, transactor bind.ContractTransactor) (*AutomationRegistrarTransactor, error) { + contract, err := bindAutomationRegistrar(address, nil, transactor, nil) + if err != nil { + return nil, err + } + return &AutomationRegistrarTransactor{contract: contract}, nil +} + +func NewAutomationRegistrarFilterer(address common.Address, filterer bind.ContractFilterer) (*AutomationRegistrarFilterer, error) { + contract, err := bindAutomationRegistrar(address, nil, nil, filterer) + if err != nil { + return nil, err + } + return &AutomationRegistrarFilterer{contract: contract}, nil +} + +func bindAutomationRegistrar(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) { + parsed, err := AutomationRegistrarMetaData.GetAbi() + if err != nil { + return nil, err + } + return bind.NewBoundContract(address, *parsed, caller, transactor, filterer), nil +} + +func (_AutomationRegistrar *AutomationRegistrarRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _AutomationRegistrar.Contract.AutomationRegistrarCaller.contract.Call(opts, result, method, params...) +} + +func (_AutomationRegistrar *AutomationRegistrarRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _AutomationRegistrar.Contract.AutomationRegistrarTransactor.contract.Transfer(opts) +} + +func (_AutomationRegistrar *AutomationRegistrarRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _AutomationRegistrar.Contract.AutomationRegistrarTransactor.contract.Transact(opts, method, params...) +} + +func (_AutomationRegistrar *AutomationRegistrarCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _AutomationRegistrar.Contract.contract.Call(opts, result, method, params...) +} + +func (_AutomationRegistrar *AutomationRegistrarTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _AutomationRegistrar.Contract.contract.Transfer(opts) +} + +func (_AutomationRegistrar *AutomationRegistrarTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _AutomationRegistrar.Contract.contract.Transact(opts, method, params...) +} + +func (_AutomationRegistrar *AutomationRegistrarCaller) LINK(opts *bind.CallOpts) (common.Address, error) { + var out []interface{} + err := _AutomationRegistrar.contract.Call(opts, &out, "LINK") + + if err != nil { + return *new(common.Address), err + } + + out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) + + return out0, err + +} + +func (_AutomationRegistrar *AutomationRegistrarSession) LINK() (common.Address, error) { + return _AutomationRegistrar.Contract.LINK(&_AutomationRegistrar.CallOpts) +} + +func (_AutomationRegistrar *AutomationRegistrarCallerSession) LINK() (common.Address, error) { + return _AutomationRegistrar.Contract.LINK(&_AutomationRegistrar.CallOpts) +} + +func (_AutomationRegistrar *AutomationRegistrarCaller) GetAutoApproveAllowedSender(opts *bind.CallOpts, senderAddress common.Address) (bool, error) { + var out []interface{} + err := _AutomationRegistrar.contract.Call(opts, &out, "getAutoApproveAllowedSender", senderAddress) + + if err != nil { + return *new(bool), err + } + + out0 := *abi.ConvertType(out[0], new(bool)).(*bool) + + return out0, err + +} + +func (_AutomationRegistrar *AutomationRegistrarSession) GetAutoApproveAllowedSender(senderAddress common.Address) (bool, error) { + return _AutomationRegistrar.Contract.GetAutoApproveAllowedSender(&_AutomationRegistrar.CallOpts, senderAddress) +} + +func (_AutomationRegistrar *AutomationRegistrarCallerSession) GetAutoApproveAllowedSender(senderAddress common.Address) (bool, error) { + return _AutomationRegistrar.Contract.GetAutoApproveAllowedSender(&_AutomationRegistrar.CallOpts, senderAddress) +} + +func (_AutomationRegistrar *AutomationRegistrarCaller) GetConfig(opts *bind.CallOpts) (GetConfig, + + error) { + var out []interface{} + err := _AutomationRegistrar.contract.Call(opts, &out, "getConfig") + + outstruct := new(GetConfig) + if err != nil { + return *outstruct, err + } + + outstruct.AutomationRegistry = *abi.ConvertType(out[0], new(common.Address)).(*common.Address) + outstruct.MinLINKJuels = *abi.ConvertType(out[1], new(*big.Int)).(**big.Int) + + return *outstruct, err + +} + +func (_AutomationRegistrar *AutomationRegistrarSession) GetConfig() (GetConfig, + + error) { + return _AutomationRegistrar.Contract.GetConfig(&_AutomationRegistrar.CallOpts) +} + +func (_AutomationRegistrar *AutomationRegistrarCallerSession) GetConfig() (GetConfig, + + error) { + return _AutomationRegistrar.Contract.GetConfig(&_AutomationRegistrar.CallOpts) +} + +func (_AutomationRegistrar *AutomationRegistrarCaller) GetPendingRequest(opts *bind.CallOpts, hash [32]byte) (common.Address, *big.Int, error) { + var out []interface{} + err := _AutomationRegistrar.contract.Call(opts, &out, "getPendingRequest", hash) + + if err != nil { + return *new(common.Address), *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) + out1 := *abi.ConvertType(out[1], new(*big.Int)).(**big.Int) + + return out0, out1, err + +} + +func (_AutomationRegistrar *AutomationRegistrarSession) GetPendingRequest(hash [32]byte) (common.Address, *big.Int, error) { + return _AutomationRegistrar.Contract.GetPendingRequest(&_AutomationRegistrar.CallOpts, hash) +} + +func (_AutomationRegistrar *AutomationRegistrarCallerSession) GetPendingRequest(hash [32]byte) (common.Address, *big.Int, error) { + return _AutomationRegistrar.Contract.GetPendingRequest(&_AutomationRegistrar.CallOpts, hash) +} + +func (_AutomationRegistrar *AutomationRegistrarCaller) GetTriggerRegistrationDetails(opts *bind.CallOpts, triggerType uint8) (AutomationRegistrar22TriggerRegistrationStorage, error) { + var out []interface{} + err := _AutomationRegistrar.contract.Call(opts, &out, "getTriggerRegistrationDetails", triggerType) + + if err != nil { + return *new(AutomationRegistrar22TriggerRegistrationStorage), err + } + + out0 := *abi.ConvertType(out[0], new(AutomationRegistrar22TriggerRegistrationStorage)).(*AutomationRegistrar22TriggerRegistrationStorage) + + return out0, err + +} + +func (_AutomationRegistrar *AutomationRegistrarSession) GetTriggerRegistrationDetails(triggerType uint8) (AutomationRegistrar22TriggerRegistrationStorage, error) { + return _AutomationRegistrar.Contract.GetTriggerRegistrationDetails(&_AutomationRegistrar.CallOpts, triggerType) +} + +func (_AutomationRegistrar *AutomationRegistrarCallerSession) GetTriggerRegistrationDetails(triggerType uint8) (AutomationRegistrar22TriggerRegistrationStorage, error) { + return _AutomationRegistrar.Contract.GetTriggerRegistrationDetails(&_AutomationRegistrar.CallOpts, triggerType) +} + +func (_AutomationRegistrar *AutomationRegistrarCaller) Owner(opts *bind.CallOpts) (common.Address, error) { + var out []interface{} + err := _AutomationRegistrar.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 (_AutomationRegistrar *AutomationRegistrarSession) Owner() (common.Address, error) { + return _AutomationRegistrar.Contract.Owner(&_AutomationRegistrar.CallOpts) +} + +func (_AutomationRegistrar *AutomationRegistrarCallerSession) Owner() (common.Address, error) { + return _AutomationRegistrar.Contract.Owner(&_AutomationRegistrar.CallOpts) +} + +func (_AutomationRegistrar *AutomationRegistrarCaller) TypeAndVersion(opts *bind.CallOpts) (string, error) { + var out []interface{} + err := _AutomationRegistrar.contract.Call(opts, &out, "typeAndVersion") + + if err != nil { + return *new(string), err + } + + out0 := *abi.ConvertType(out[0], new(string)).(*string) + + return out0, err + +} + +func (_AutomationRegistrar *AutomationRegistrarSession) TypeAndVersion() (string, error) { + return _AutomationRegistrar.Contract.TypeAndVersion(&_AutomationRegistrar.CallOpts) +} + +func (_AutomationRegistrar *AutomationRegistrarCallerSession) TypeAndVersion() (string, error) { + return _AutomationRegistrar.Contract.TypeAndVersion(&_AutomationRegistrar.CallOpts) +} + +func (_AutomationRegistrar *AutomationRegistrarTransactor) AcceptOwnership(opts *bind.TransactOpts) (*types.Transaction, error) { + return _AutomationRegistrar.contract.Transact(opts, "acceptOwnership") +} + +func (_AutomationRegistrar *AutomationRegistrarSession) AcceptOwnership() (*types.Transaction, error) { + return _AutomationRegistrar.Contract.AcceptOwnership(&_AutomationRegistrar.TransactOpts) +} + +func (_AutomationRegistrar *AutomationRegistrarTransactorSession) AcceptOwnership() (*types.Transaction, error) { + return _AutomationRegistrar.Contract.AcceptOwnership(&_AutomationRegistrar.TransactOpts) +} + +func (_AutomationRegistrar *AutomationRegistrarTransactor) Approve(opts *bind.TransactOpts, name string, upkeepContract common.Address, gasLimit uint32, adminAddress common.Address, triggerType uint8, checkData []byte, triggerConfig []byte, offchainConfig []byte, hash [32]byte) (*types.Transaction, error) { + return _AutomationRegistrar.contract.Transact(opts, "approve", name, upkeepContract, gasLimit, adminAddress, triggerType, checkData, triggerConfig, offchainConfig, hash) +} + +func (_AutomationRegistrar *AutomationRegistrarSession) Approve(name string, upkeepContract common.Address, gasLimit uint32, adminAddress common.Address, triggerType uint8, checkData []byte, triggerConfig []byte, offchainConfig []byte, hash [32]byte) (*types.Transaction, error) { + return _AutomationRegistrar.Contract.Approve(&_AutomationRegistrar.TransactOpts, name, upkeepContract, gasLimit, adminAddress, triggerType, checkData, triggerConfig, offchainConfig, hash) +} + +func (_AutomationRegistrar *AutomationRegistrarTransactorSession) Approve(name string, upkeepContract common.Address, gasLimit uint32, adminAddress common.Address, triggerType uint8, checkData []byte, triggerConfig []byte, offchainConfig []byte, hash [32]byte) (*types.Transaction, error) { + return _AutomationRegistrar.Contract.Approve(&_AutomationRegistrar.TransactOpts, name, upkeepContract, gasLimit, adminAddress, triggerType, checkData, triggerConfig, offchainConfig, hash) +} + +func (_AutomationRegistrar *AutomationRegistrarTransactor) Cancel(opts *bind.TransactOpts, hash [32]byte) (*types.Transaction, error) { + return _AutomationRegistrar.contract.Transact(opts, "cancel", hash) +} + +func (_AutomationRegistrar *AutomationRegistrarSession) Cancel(hash [32]byte) (*types.Transaction, error) { + return _AutomationRegistrar.Contract.Cancel(&_AutomationRegistrar.TransactOpts, hash) +} + +func (_AutomationRegistrar *AutomationRegistrarTransactorSession) Cancel(hash [32]byte) (*types.Transaction, error) { + return _AutomationRegistrar.Contract.Cancel(&_AutomationRegistrar.TransactOpts, hash) +} + +func (_AutomationRegistrar *AutomationRegistrarTransactor) OnTokenTransfer(opts *bind.TransactOpts, sender common.Address, amount *big.Int, data []byte) (*types.Transaction, error) { + return _AutomationRegistrar.contract.Transact(opts, "onTokenTransfer", sender, amount, data) +} + +func (_AutomationRegistrar *AutomationRegistrarSession) OnTokenTransfer(sender common.Address, amount *big.Int, data []byte) (*types.Transaction, error) { + return _AutomationRegistrar.Contract.OnTokenTransfer(&_AutomationRegistrar.TransactOpts, sender, amount, data) +} + +func (_AutomationRegistrar *AutomationRegistrarTransactorSession) OnTokenTransfer(sender common.Address, amount *big.Int, data []byte) (*types.Transaction, error) { + return _AutomationRegistrar.Contract.OnTokenTransfer(&_AutomationRegistrar.TransactOpts, sender, amount, data) +} + +func (_AutomationRegistrar *AutomationRegistrarTransactor) Register(opts *bind.TransactOpts, name string, encryptedEmail []byte, upkeepContract common.Address, gasLimit uint32, adminAddress common.Address, triggerType uint8, checkData []byte, triggerConfig []byte, offchainConfig []byte, amount *big.Int, sender common.Address) (*types.Transaction, error) { + return _AutomationRegistrar.contract.Transact(opts, "register", name, encryptedEmail, upkeepContract, gasLimit, adminAddress, triggerType, checkData, triggerConfig, offchainConfig, amount, sender) +} + +func (_AutomationRegistrar *AutomationRegistrarSession) Register(name string, encryptedEmail []byte, upkeepContract common.Address, gasLimit uint32, adminAddress common.Address, triggerType uint8, checkData []byte, triggerConfig []byte, offchainConfig []byte, amount *big.Int, sender common.Address) (*types.Transaction, error) { + return _AutomationRegistrar.Contract.Register(&_AutomationRegistrar.TransactOpts, name, encryptedEmail, upkeepContract, gasLimit, adminAddress, triggerType, checkData, triggerConfig, offchainConfig, amount, sender) +} + +func (_AutomationRegistrar *AutomationRegistrarTransactorSession) Register(name string, encryptedEmail []byte, upkeepContract common.Address, gasLimit uint32, adminAddress common.Address, triggerType uint8, checkData []byte, triggerConfig []byte, offchainConfig []byte, amount *big.Int, sender common.Address) (*types.Transaction, error) { + return _AutomationRegistrar.Contract.Register(&_AutomationRegistrar.TransactOpts, name, encryptedEmail, upkeepContract, gasLimit, adminAddress, triggerType, checkData, triggerConfig, offchainConfig, amount, sender) +} + +func (_AutomationRegistrar *AutomationRegistrarTransactor) RegisterUpkeep(opts *bind.TransactOpts, requestParams AutomationRegistrar22RegistrationParams) (*types.Transaction, error) { + return _AutomationRegistrar.contract.Transact(opts, "registerUpkeep", requestParams) +} + +func (_AutomationRegistrar *AutomationRegistrarSession) RegisterUpkeep(requestParams AutomationRegistrar22RegistrationParams) (*types.Transaction, error) { + return _AutomationRegistrar.Contract.RegisterUpkeep(&_AutomationRegistrar.TransactOpts, requestParams) +} + +func (_AutomationRegistrar *AutomationRegistrarTransactorSession) RegisterUpkeep(requestParams AutomationRegistrar22RegistrationParams) (*types.Transaction, error) { + return _AutomationRegistrar.Contract.RegisterUpkeep(&_AutomationRegistrar.TransactOpts, requestParams) +} + +func (_AutomationRegistrar *AutomationRegistrarTransactor) SetAutoApproveAllowedSender(opts *bind.TransactOpts, senderAddress common.Address, allowed bool) (*types.Transaction, error) { + return _AutomationRegistrar.contract.Transact(opts, "setAutoApproveAllowedSender", senderAddress, allowed) +} + +func (_AutomationRegistrar *AutomationRegistrarSession) SetAutoApproveAllowedSender(senderAddress common.Address, allowed bool) (*types.Transaction, error) { + return _AutomationRegistrar.Contract.SetAutoApproveAllowedSender(&_AutomationRegistrar.TransactOpts, senderAddress, allowed) +} + +func (_AutomationRegistrar *AutomationRegistrarTransactorSession) SetAutoApproveAllowedSender(senderAddress common.Address, allowed bool) (*types.Transaction, error) { + return _AutomationRegistrar.Contract.SetAutoApproveAllowedSender(&_AutomationRegistrar.TransactOpts, senderAddress, allowed) +} + +func (_AutomationRegistrar *AutomationRegistrarTransactor) SetConfig(opts *bind.TransactOpts, AutomationRegistry common.Address, minLINKJuels *big.Int) (*types.Transaction, error) { + return _AutomationRegistrar.contract.Transact(opts, "setConfig", AutomationRegistry, minLINKJuels) +} + +func (_AutomationRegistrar *AutomationRegistrarSession) SetConfig(AutomationRegistry common.Address, minLINKJuels *big.Int) (*types.Transaction, error) { + return _AutomationRegistrar.Contract.SetConfig(&_AutomationRegistrar.TransactOpts, AutomationRegistry, minLINKJuels) +} + +func (_AutomationRegistrar *AutomationRegistrarTransactorSession) SetConfig(AutomationRegistry common.Address, minLINKJuels *big.Int) (*types.Transaction, error) { + return _AutomationRegistrar.Contract.SetConfig(&_AutomationRegistrar.TransactOpts, AutomationRegistry, minLINKJuels) +} + +func (_AutomationRegistrar *AutomationRegistrarTransactor) SetTriggerConfig(opts *bind.TransactOpts, triggerType uint8, autoApproveType uint8, autoApproveMaxAllowed uint32) (*types.Transaction, error) { + return _AutomationRegistrar.contract.Transact(opts, "setTriggerConfig", triggerType, autoApproveType, autoApproveMaxAllowed) +} + +func (_AutomationRegistrar *AutomationRegistrarSession) SetTriggerConfig(triggerType uint8, autoApproveType uint8, autoApproveMaxAllowed uint32) (*types.Transaction, error) { + return _AutomationRegistrar.Contract.SetTriggerConfig(&_AutomationRegistrar.TransactOpts, triggerType, autoApproveType, autoApproveMaxAllowed) +} + +func (_AutomationRegistrar *AutomationRegistrarTransactorSession) SetTriggerConfig(triggerType uint8, autoApproveType uint8, autoApproveMaxAllowed uint32) (*types.Transaction, error) { + return _AutomationRegistrar.Contract.SetTriggerConfig(&_AutomationRegistrar.TransactOpts, triggerType, autoApproveType, autoApproveMaxAllowed) +} + +func (_AutomationRegistrar *AutomationRegistrarTransactor) TransferOwnership(opts *bind.TransactOpts, to common.Address) (*types.Transaction, error) { + return _AutomationRegistrar.contract.Transact(opts, "transferOwnership", to) +} + +func (_AutomationRegistrar *AutomationRegistrarSession) TransferOwnership(to common.Address) (*types.Transaction, error) { + return _AutomationRegistrar.Contract.TransferOwnership(&_AutomationRegistrar.TransactOpts, to) +} + +func (_AutomationRegistrar *AutomationRegistrarTransactorSession) TransferOwnership(to common.Address) (*types.Transaction, error) { + return _AutomationRegistrar.Contract.TransferOwnership(&_AutomationRegistrar.TransactOpts, to) +} + +type AutomationRegistrarAutoApproveAllowedSenderSetIterator struct { + Event *AutomationRegistrarAutoApproveAllowedSenderSet + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *AutomationRegistrarAutoApproveAllowedSenderSetIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(AutomationRegistrarAutoApproveAllowedSenderSet) + 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(AutomationRegistrarAutoApproveAllowedSenderSet) + 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 *AutomationRegistrarAutoApproveAllowedSenderSetIterator) Error() error { + return it.fail +} + +func (it *AutomationRegistrarAutoApproveAllowedSenderSetIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type AutomationRegistrarAutoApproveAllowedSenderSet struct { + SenderAddress common.Address + Allowed bool + Raw types.Log +} + +func (_AutomationRegistrar *AutomationRegistrarFilterer) FilterAutoApproveAllowedSenderSet(opts *bind.FilterOpts, senderAddress []common.Address) (*AutomationRegistrarAutoApproveAllowedSenderSetIterator, error) { + + var senderAddressRule []interface{} + for _, senderAddressItem := range senderAddress { + senderAddressRule = append(senderAddressRule, senderAddressItem) + } + + logs, sub, err := _AutomationRegistrar.contract.FilterLogs(opts, "AutoApproveAllowedSenderSet", senderAddressRule) + if err != nil { + return nil, err + } + return &AutomationRegistrarAutoApproveAllowedSenderSetIterator{contract: _AutomationRegistrar.contract, event: "AutoApproveAllowedSenderSet", logs: logs, sub: sub}, nil +} + +func (_AutomationRegistrar *AutomationRegistrarFilterer) WatchAutoApproveAllowedSenderSet(opts *bind.WatchOpts, sink chan<- *AutomationRegistrarAutoApproveAllowedSenderSet, senderAddress []common.Address) (event.Subscription, error) { + + var senderAddressRule []interface{} + for _, senderAddressItem := range senderAddress { + senderAddressRule = append(senderAddressRule, senderAddressItem) + } + + logs, sub, err := _AutomationRegistrar.contract.WatchLogs(opts, "AutoApproveAllowedSenderSet", senderAddressRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(AutomationRegistrarAutoApproveAllowedSenderSet) + if err := _AutomationRegistrar.contract.UnpackLog(event, "AutoApproveAllowedSenderSet", 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 (_AutomationRegistrar *AutomationRegistrarFilterer) ParseAutoApproveAllowedSenderSet(log types.Log) (*AutomationRegistrarAutoApproveAllowedSenderSet, error) { + event := new(AutomationRegistrarAutoApproveAllowedSenderSet) + if err := _AutomationRegistrar.contract.UnpackLog(event, "AutoApproveAllowedSenderSet", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type AutomationRegistrarConfigChangedIterator struct { + Event *AutomationRegistrarConfigChanged + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *AutomationRegistrarConfigChangedIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(AutomationRegistrarConfigChanged) + 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(AutomationRegistrarConfigChanged) + 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 *AutomationRegistrarConfigChangedIterator) Error() error { + return it.fail +} + +func (it *AutomationRegistrarConfigChangedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type AutomationRegistrarConfigChanged struct { + AutomationRegistry common.Address + MinLINKJuels *big.Int + Raw types.Log +} + +func (_AutomationRegistrar *AutomationRegistrarFilterer) FilterConfigChanged(opts *bind.FilterOpts) (*AutomationRegistrarConfigChangedIterator, error) { + + logs, sub, err := _AutomationRegistrar.contract.FilterLogs(opts, "ConfigChanged") + if err != nil { + return nil, err + } + return &AutomationRegistrarConfigChangedIterator{contract: _AutomationRegistrar.contract, event: "ConfigChanged", logs: logs, sub: sub}, nil +} + +func (_AutomationRegistrar *AutomationRegistrarFilterer) WatchConfigChanged(opts *bind.WatchOpts, sink chan<- *AutomationRegistrarConfigChanged) (event.Subscription, error) { + + logs, sub, err := _AutomationRegistrar.contract.WatchLogs(opts, "ConfigChanged") + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(AutomationRegistrarConfigChanged) + if err := _AutomationRegistrar.contract.UnpackLog(event, "ConfigChanged", 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 (_AutomationRegistrar *AutomationRegistrarFilterer) ParseConfigChanged(log types.Log) (*AutomationRegistrarConfigChanged, error) { + event := new(AutomationRegistrarConfigChanged) + if err := _AutomationRegistrar.contract.UnpackLog(event, "ConfigChanged", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type AutomationRegistrarOwnershipTransferRequestedIterator struct { + Event *AutomationRegistrarOwnershipTransferRequested + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *AutomationRegistrarOwnershipTransferRequestedIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(AutomationRegistrarOwnershipTransferRequested) + 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(AutomationRegistrarOwnershipTransferRequested) + 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 *AutomationRegistrarOwnershipTransferRequestedIterator) Error() error { + return it.fail +} + +func (it *AutomationRegistrarOwnershipTransferRequestedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type AutomationRegistrarOwnershipTransferRequested struct { + From common.Address + To common.Address + Raw types.Log +} + +func (_AutomationRegistrar *AutomationRegistrarFilterer) FilterOwnershipTransferRequested(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*AutomationRegistrarOwnershipTransferRequestedIterator, 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 := _AutomationRegistrar.contract.FilterLogs(opts, "OwnershipTransferRequested", fromRule, toRule) + if err != nil { + return nil, err + } + return &AutomationRegistrarOwnershipTransferRequestedIterator{contract: _AutomationRegistrar.contract, event: "OwnershipTransferRequested", logs: logs, sub: sub}, nil +} + +func (_AutomationRegistrar *AutomationRegistrarFilterer) WatchOwnershipTransferRequested(opts *bind.WatchOpts, sink chan<- *AutomationRegistrarOwnershipTransferRequested, 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 := _AutomationRegistrar.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(AutomationRegistrarOwnershipTransferRequested) + if err := _AutomationRegistrar.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 (_AutomationRegistrar *AutomationRegistrarFilterer) ParseOwnershipTransferRequested(log types.Log) (*AutomationRegistrarOwnershipTransferRequested, error) { + event := new(AutomationRegistrarOwnershipTransferRequested) + if err := _AutomationRegistrar.contract.UnpackLog(event, "OwnershipTransferRequested", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type AutomationRegistrarOwnershipTransferredIterator struct { + Event *AutomationRegistrarOwnershipTransferred + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *AutomationRegistrarOwnershipTransferredIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(AutomationRegistrarOwnershipTransferred) + 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(AutomationRegistrarOwnershipTransferred) + 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 *AutomationRegistrarOwnershipTransferredIterator) Error() error { + return it.fail +} + +func (it *AutomationRegistrarOwnershipTransferredIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type AutomationRegistrarOwnershipTransferred struct { + From common.Address + To common.Address + Raw types.Log +} + +func (_AutomationRegistrar *AutomationRegistrarFilterer) FilterOwnershipTransferred(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*AutomationRegistrarOwnershipTransferredIterator, 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 := _AutomationRegistrar.contract.FilterLogs(opts, "OwnershipTransferred", fromRule, toRule) + if err != nil { + return nil, err + } + return &AutomationRegistrarOwnershipTransferredIterator{contract: _AutomationRegistrar.contract, event: "OwnershipTransferred", logs: logs, sub: sub}, nil +} + +func (_AutomationRegistrar *AutomationRegistrarFilterer) WatchOwnershipTransferred(opts *bind.WatchOpts, sink chan<- *AutomationRegistrarOwnershipTransferred, 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 := _AutomationRegistrar.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(AutomationRegistrarOwnershipTransferred) + if err := _AutomationRegistrar.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 (_AutomationRegistrar *AutomationRegistrarFilterer) ParseOwnershipTransferred(log types.Log) (*AutomationRegistrarOwnershipTransferred, error) { + event := new(AutomationRegistrarOwnershipTransferred) + if err := _AutomationRegistrar.contract.UnpackLog(event, "OwnershipTransferred", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type AutomationRegistrarRegistrationApprovedIterator struct { + Event *AutomationRegistrarRegistrationApproved + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *AutomationRegistrarRegistrationApprovedIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(AutomationRegistrarRegistrationApproved) + 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(AutomationRegistrarRegistrationApproved) + 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 *AutomationRegistrarRegistrationApprovedIterator) Error() error { + return it.fail +} + +func (it *AutomationRegistrarRegistrationApprovedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type AutomationRegistrarRegistrationApproved struct { + Hash [32]byte + DisplayName string + UpkeepId *big.Int + Raw types.Log +} + +func (_AutomationRegistrar *AutomationRegistrarFilterer) FilterRegistrationApproved(opts *bind.FilterOpts, hash [][32]byte, upkeepId []*big.Int) (*AutomationRegistrarRegistrationApprovedIterator, error) { + + var hashRule []interface{} + for _, hashItem := range hash { + hashRule = append(hashRule, hashItem) + } + + var upkeepIdRule []interface{} + for _, upkeepIdItem := range upkeepId { + upkeepIdRule = append(upkeepIdRule, upkeepIdItem) + } + + logs, sub, err := _AutomationRegistrar.contract.FilterLogs(opts, "RegistrationApproved", hashRule, upkeepIdRule) + if err != nil { + return nil, err + } + return &AutomationRegistrarRegistrationApprovedIterator{contract: _AutomationRegistrar.contract, event: "RegistrationApproved", logs: logs, sub: sub}, nil +} + +func (_AutomationRegistrar *AutomationRegistrarFilterer) WatchRegistrationApproved(opts *bind.WatchOpts, sink chan<- *AutomationRegistrarRegistrationApproved, hash [][32]byte, upkeepId []*big.Int) (event.Subscription, error) { + + var hashRule []interface{} + for _, hashItem := range hash { + hashRule = append(hashRule, hashItem) + } + + var upkeepIdRule []interface{} + for _, upkeepIdItem := range upkeepId { + upkeepIdRule = append(upkeepIdRule, upkeepIdItem) + } + + logs, sub, err := _AutomationRegistrar.contract.WatchLogs(opts, "RegistrationApproved", hashRule, upkeepIdRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(AutomationRegistrarRegistrationApproved) + if err := _AutomationRegistrar.contract.UnpackLog(event, "RegistrationApproved", 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 (_AutomationRegistrar *AutomationRegistrarFilterer) ParseRegistrationApproved(log types.Log) (*AutomationRegistrarRegistrationApproved, error) { + event := new(AutomationRegistrarRegistrationApproved) + if err := _AutomationRegistrar.contract.UnpackLog(event, "RegistrationApproved", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type AutomationRegistrarRegistrationRejectedIterator struct { + Event *AutomationRegistrarRegistrationRejected + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *AutomationRegistrarRegistrationRejectedIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(AutomationRegistrarRegistrationRejected) + 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(AutomationRegistrarRegistrationRejected) + 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 *AutomationRegistrarRegistrationRejectedIterator) Error() error { + return it.fail +} + +func (it *AutomationRegistrarRegistrationRejectedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type AutomationRegistrarRegistrationRejected struct { + Hash [32]byte + Raw types.Log +} + +func (_AutomationRegistrar *AutomationRegistrarFilterer) FilterRegistrationRejected(opts *bind.FilterOpts, hash [][32]byte) (*AutomationRegistrarRegistrationRejectedIterator, error) { + + var hashRule []interface{} + for _, hashItem := range hash { + hashRule = append(hashRule, hashItem) + } + + logs, sub, err := _AutomationRegistrar.contract.FilterLogs(opts, "RegistrationRejected", hashRule) + if err != nil { + return nil, err + } + return &AutomationRegistrarRegistrationRejectedIterator{contract: _AutomationRegistrar.contract, event: "RegistrationRejected", logs: logs, sub: sub}, nil +} + +func (_AutomationRegistrar *AutomationRegistrarFilterer) WatchRegistrationRejected(opts *bind.WatchOpts, sink chan<- *AutomationRegistrarRegistrationRejected, hash [][32]byte) (event.Subscription, error) { + + var hashRule []interface{} + for _, hashItem := range hash { + hashRule = append(hashRule, hashItem) + } + + logs, sub, err := _AutomationRegistrar.contract.WatchLogs(opts, "RegistrationRejected", hashRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(AutomationRegistrarRegistrationRejected) + if err := _AutomationRegistrar.contract.UnpackLog(event, "RegistrationRejected", 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 (_AutomationRegistrar *AutomationRegistrarFilterer) ParseRegistrationRejected(log types.Log) (*AutomationRegistrarRegistrationRejected, error) { + event := new(AutomationRegistrarRegistrationRejected) + if err := _AutomationRegistrar.contract.UnpackLog(event, "RegistrationRejected", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type AutomationRegistrarRegistrationRequestedIterator struct { + Event *AutomationRegistrarRegistrationRequested + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *AutomationRegistrarRegistrationRequestedIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(AutomationRegistrarRegistrationRequested) + 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(AutomationRegistrarRegistrationRequested) + 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 *AutomationRegistrarRegistrationRequestedIterator) Error() error { + return it.fail +} + +func (it *AutomationRegistrarRegistrationRequestedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type AutomationRegistrarRegistrationRequested struct { + Hash [32]byte + Name string + EncryptedEmail []byte + UpkeepContract common.Address + GasLimit uint32 + AdminAddress common.Address + TriggerType uint8 + TriggerConfig []byte + OffchainConfig []byte + CheckData []byte + Amount *big.Int + Raw types.Log +} + +func (_AutomationRegistrar *AutomationRegistrarFilterer) FilterRegistrationRequested(opts *bind.FilterOpts, hash [][32]byte, upkeepContract []common.Address) (*AutomationRegistrarRegistrationRequestedIterator, error) { + + var hashRule []interface{} + for _, hashItem := range hash { + hashRule = append(hashRule, hashItem) + } + + var upkeepContractRule []interface{} + for _, upkeepContractItem := range upkeepContract { + upkeepContractRule = append(upkeepContractRule, upkeepContractItem) + } + + logs, sub, err := _AutomationRegistrar.contract.FilterLogs(opts, "RegistrationRequested", hashRule, upkeepContractRule) + if err != nil { + return nil, err + } + return &AutomationRegistrarRegistrationRequestedIterator{contract: _AutomationRegistrar.contract, event: "RegistrationRequested", logs: logs, sub: sub}, nil +} + +func (_AutomationRegistrar *AutomationRegistrarFilterer) WatchRegistrationRequested(opts *bind.WatchOpts, sink chan<- *AutomationRegistrarRegistrationRequested, hash [][32]byte, upkeepContract []common.Address) (event.Subscription, error) { + + var hashRule []interface{} + for _, hashItem := range hash { + hashRule = append(hashRule, hashItem) + } + + var upkeepContractRule []interface{} + for _, upkeepContractItem := range upkeepContract { + upkeepContractRule = append(upkeepContractRule, upkeepContractItem) + } + + logs, sub, err := _AutomationRegistrar.contract.WatchLogs(opts, "RegistrationRequested", hashRule, upkeepContractRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(AutomationRegistrarRegistrationRequested) + if err := _AutomationRegistrar.contract.UnpackLog(event, "RegistrationRequested", 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 (_AutomationRegistrar *AutomationRegistrarFilterer) ParseRegistrationRequested(log types.Log) (*AutomationRegistrarRegistrationRequested, error) { + event := new(AutomationRegistrarRegistrationRequested) + if err := _AutomationRegistrar.contract.UnpackLog(event, "RegistrationRequested", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type AutomationRegistrarTriggerConfigSetIterator struct { + Event *AutomationRegistrarTriggerConfigSet + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *AutomationRegistrarTriggerConfigSetIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(AutomationRegistrarTriggerConfigSet) + 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(AutomationRegistrarTriggerConfigSet) + 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 *AutomationRegistrarTriggerConfigSetIterator) Error() error { + return it.fail +} + +func (it *AutomationRegistrarTriggerConfigSetIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type AutomationRegistrarTriggerConfigSet struct { + TriggerType uint8 + AutoApproveType uint8 + AutoApproveMaxAllowed uint32 + Raw types.Log +} + +func (_AutomationRegistrar *AutomationRegistrarFilterer) FilterTriggerConfigSet(opts *bind.FilterOpts) (*AutomationRegistrarTriggerConfigSetIterator, error) { + + logs, sub, err := _AutomationRegistrar.contract.FilterLogs(opts, "TriggerConfigSet") + if err != nil { + return nil, err + } + return &AutomationRegistrarTriggerConfigSetIterator{contract: _AutomationRegistrar.contract, event: "TriggerConfigSet", logs: logs, sub: sub}, nil +} + +func (_AutomationRegistrar *AutomationRegistrarFilterer) WatchTriggerConfigSet(opts *bind.WatchOpts, sink chan<- *AutomationRegistrarTriggerConfigSet) (event.Subscription, error) { + + logs, sub, err := _AutomationRegistrar.contract.WatchLogs(opts, "TriggerConfigSet") + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(AutomationRegistrarTriggerConfigSet) + if err := _AutomationRegistrar.contract.UnpackLog(event, "TriggerConfigSet", 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 (_AutomationRegistrar *AutomationRegistrarFilterer) ParseTriggerConfigSet(log types.Log) (*AutomationRegistrarTriggerConfigSet, error) { + event := new(AutomationRegistrarTriggerConfigSet) + if err := _AutomationRegistrar.contract.UnpackLog(event, "TriggerConfigSet", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type GetConfig struct { + AutomationRegistry common.Address + MinLINKJuels *big.Int +} + +func (_AutomationRegistrar *AutomationRegistrar) ParseLog(log types.Log) (generated.AbigenLog, error) { + switch log.Topics[0] { + case _AutomationRegistrar.abi.Events["AutoApproveAllowedSenderSet"].ID: + return _AutomationRegistrar.ParseAutoApproveAllowedSenderSet(log) + case _AutomationRegistrar.abi.Events["ConfigChanged"].ID: + return _AutomationRegistrar.ParseConfigChanged(log) + case _AutomationRegistrar.abi.Events["OwnershipTransferRequested"].ID: + return _AutomationRegistrar.ParseOwnershipTransferRequested(log) + case _AutomationRegistrar.abi.Events["OwnershipTransferred"].ID: + return _AutomationRegistrar.ParseOwnershipTransferred(log) + case _AutomationRegistrar.abi.Events["RegistrationApproved"].ID: + return _AutomationRegistrar.ParseRegistrationApproved(log) + case _AutomationRegistrar.abi.Events["RegistrationRejected"].ID: + return _AutomationRegistrar.ParseRegistrationRejected(log) + case _AutomationRegistrar.abi.Events["RegistrationRequested"].ID: + return _AutomationRegistrar.ParseRegistrationRequested(log) + case _AutomationRegistrar.abi.Events["TriggerConfigSet"].ID: + return _AutomationRegistrar.ParseTriggerConfigSet(log) + + default: + return nil, fmt.Errorf("abigen wrapper received unknown log topic: %v", log.Topics[0]) + } +} + +func (AutomationRegistrarAutoApproveAllowedSenderSet) Topic() common.Hash { + return common.HexToHash("0x20c6237dac83526a849285a9f79d08a483291bdd3a056a0ef9ae94ecee1ad356") +} + +func (AutomationRegistrarConfigChanged) Topic() common.Hash { + return common.HexToHash("0x39ce5d867555f0b0183e358fce5b158e7ca4fecd7c01cb7e0e19f1e23285838a") +} + +func (AutomationRegistrarOwnershipTransferRequested) Topic() common.Hash { + return common.HexToHash("0xed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae1278") +} + +func (AutomationRegistrarOwnershipTransferred) Topic() common.Hash { + return common.HexToHash("0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0") +} + +func (AutomationRegistrarRegistrationApproved) Topic() common.Hash { + return common.HexToHash("0xb9a292fb7e3edd920cd2d2829a3615a640c43fd7de0a0820aa0668feb4c37d4b") +} + +func (AutomationRegistrarRegistrationRejected) Topic() common.Hash { + return common.HexToHash("0x3663fb28ebc87645eb972c9dad8521bf665c623f287e79f1c56f1eb374b82a22") +} + +func (AutomationRegistrarRegistrationRequested) Topic() common.Hash { + return common.HexToHash("0x7684390ebb103102f7f48c71439c2408713f8d437782a6fab2756acc0e42c1b7") +} + +func (AutomationRegistrarTriggerConfigSet) Topic() common.Hash { + return common.HexToHash("0x830a6d06a4e2caac67eba04323de22bdb04f032dd8b3d6a0c52b503d9a7036a3") +} + +func (_AutomationRegistrar *AutomationRegistrar) Address() common.Address { + return _AutomationRegistrar.address +} + +type AutomationRegistrarInterface interface { + LINK(opts *bind.CallOpts) (common.Address, error) + + GetAutoApproveAllowedSender(opts *bind.CallOpts, senderAddress common.Address) (bool, error) + + GetConfig(opts *bind.CallOpts) (GetConfig, + + error) + + GetPendingRequest(opts *bind.CallOpts, hash [32]byte) (common.Address, *big.Int, error) + + GetTriggerRegistrationDetails(opts *bind.CallOpts, triggerType uint8) (AutomationRegistrar22TriggerRegistrationStorage, error) + + Owner(opts *bind.CallOpts) (common.Address, error) + + TypeAndVersion(opts *bind.CallOpts) (string, error) + + AcceptOwnership(opts *bind.TransactOpts) (*types.Transaction, error) + + Approve(opts *bind.TransactOpts, name string, upkeepContract common.Address, gasLimit uint32, adminAddress common.Address, triggerType uint8, checkData []byte, triggerConfig []byte, offchainConfig []byte, hash [32]byte) (*types.Transaction, error) + + Cancel(opts *bind.TransactOpts, hash [32]byte) (*types.Transaction, error) + + OnTokenTransfer(opts *bind.TransactOpts, sender common.Address, amount *big.Int, data []byte) (*types.Transaction, error) + + Register(opts *bind.TransactOpts, name string, encryptedEmail []byte, upkeepContract common.Address, gasLimit uint32, adminAddress common.Address, triggerType uint8, checkData []byte, triggerConfig []byte, offchainConfig []byte, amount *big.Int, sender common.Address) (*types.Transaction, error) + + RegisterUpkeep(opts *bind.TransactOpts, requestParams AutomationRegistrar22RegistrationParams) (*types.Transaction, error) + + SetAutoApproveAllowedSender(opts *bind.TransactOpts, senderAddress common.Address, allowed bool) (*types.Transaction, error) + + SetConfig(opts *bind.TransactOpts, AutomationRegistry common.Address, minLINKJuels *big.Int) (*types.Transaction, error) + + SetTriggerConfig(opts *bind.TransactOpts, triggerType uint8, autoApproveType uint8, autoApproveMaxAllowed uint32) (*types.Transaction, error) + + TransferOwnership(opts *bind.TransactOpts, to common.Address) (*types.Transaction, error) + + FilterAutoApproveAllowedSenderSet(opts *bind.FilterOpts, senderAddress []common.Address) (*AutomationRegistrarAutoApproveAllowedSenderSetIterator, error) + + WatchAutoApproveAllowedSenderSet(opts *bind.WatchOpts, sink chan<- *AutomationRegistrarAutoApproveAllowedSenderSet, senderAddress []common.Address) (event.Subscription, error) + + ParseAutoApproveAllowedSenderSet(log types.Log) (*AutomationRegistrarAutoApproveAllowedSenderSet, error) + + FilterConfigChanged(opts *bind.FilterOpts) (*AutomationRegistrarConfigChangedIterator, error) + + WatchConfigChanged(opts *bind.WatchOpts, sink chan<- *AutomationRegistrarConfigChanged) (event.Subscription, error) + + ParseConfigChanged(log types.Log) (*AutomationRegistrarConfigChanged, error) + + FilterOwnershipTransferRequested(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*AutomationRegistrarOwnershipTransferRequestedIterator, error) + + WatchOwnershipTransferRequested(opts *bind.WatchOpts, sink chan<- *AutomationRegistrarOwnershipTransferRequested, from []common.Address, to []common.Address) (event.Subscription, error) + + ParseOwnershipTransferRequested(log types.Log) (*AutomationRegistrarOwnershipTransferRequested, error) + + FilterOwnershipTransferred(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*AutomationRegistrarOwnershipTransferredIterator, error) + + WatchOwnershipTransferred(opts *bind.WatchOpts, sink chan<- *AutomationRegistrarOwnershipTransferred, from []common.Address, to []common.Address) (event.Subscription, error) + + ParseOwnershipTransferred(log types.Log) (*AutomationRegistrarOwnershipTransferred, error) + + FilterRegistrationApproved(opts *bind.FilterOpts, hash [][32]byte, upkeepId []*big.Int) (*AutomationRegistrarRegistrationApprovedIterator, error) + + WatchRegistrationApproved(opts *bind.WatchOpts, sink chan<- *AutomationRegistrarRegistrationApproved, hash [][32]byte, upkeepId []*big.Int) (event.Subscription, error) + + ParseRegistrationApproved(log types.Log) (*AutomationRegistrarRegistrationApproved, error) + + FilterRegistrationRejected(opts *bind.FilterOpts, hash [][32]byte) (*AutomationRegistrarRegistrationRejectedIterator, error) + + WatchRegistrationRejected(opts *bind.WatchOpts, sink chan<- *AutomationRegistrarRegistrationRejected, hash [][32]byte) (event.Subscription, error) + + ParseRegistrationRejected(log types.Log) (*AutomationRegistrarRegistrationRejected, error) + + FilterRegistrationRequested(opts *bind.FilterOpts, hash [][32]byte, upkeepContract []common.Address) (*AutomationRegistrarRegistrationRequestedIterator, error) + + WatchRegistrationRequested(opts *bind.WatchOpts, sink chan<- *AutomationRegistrarRegistrationRequested, hash [][32]byte, upkeepContract []common.Address) (event.Subscription, error) + + ParseRegistrationRequested(log types.Log) (*AutomationRegistrarRegistrationRequested, error) + + FilterTriggerConfigSet(opts *bind.FilterOpts) (*AutomationRegistrarTriggerConfigSetIterator, error) + + WatchTriggerConfigSet(opts *bind.WatchOpts, sink chan<- *AutomationRegistrarTriggerConfigSet) (event.Subscription, error) + + ParseTriggerConfigSet(log types.Log) (*AutomationRegistrarTriggerConfigSet, error) + + ParseLog(log types.Log) (generated.AbigenLog, error) + + Address() common.Address +} diff --git a/core/gethwrappers/generated/automation_utils_2_2/automation_utils_2_2.go b/core/gethwrappers/generated/automation_utils_2_2/automation_utils_2_2.go new file mode 100644 index 0000000000..5eb6411024 --- /dev/null +++ b/core/gethwrappers/generated/automation_utils_2_2/automation_utils_2_2.go @@ -0,0 +1,322 @@ +// Code generated - DO NOT EDIT. +// This file is a generated binding and any manual changes will be lost. + +package automation_utils_2_2 + +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 +) + +type AutomationRegistryBase22ConditionalTrigger struct { + BlockNum uint32 + BlockHash [32]byte +} + +type AutomationRegistryBase22LogTrigger struct { + LogBlockHash [32]byte + TxHash [32]byte + LogIndex uint32 + BlockNum uint32 + BlockHash [32]byte +} + +type AutomationRegistryBase22OnchainConfig struct { + PaymentPremiumPPB uint32 + FlatFeeMicroLink uint32 + CheckGasLimit uint32 + StalenessSeconds *big.Int + GasCeilingMultiplier uint16 + MinUpkeepSpend *big.Int + MaxPerformGas uint32 + MaxCheckDataSize uint32 + MaxPerformDataSize uint32 + MaxRevertDataSize uint32 + FallbackGasPrice *big.Int + FallbackLinkPrice *big.Int + Transcoder common.Address + Registrars []common.Address + UpkeepPrivilegeManager common.Address +} + +type AutomationRegistryBase22Report struct { + FastGasWei *big.Int + LinkNative *big.Int + UpkeepIds []*big.Int + GasLimits []*big.Int + Triggers [][]byte + PerformDatas [][]byte +} + +type Log struct { + Index *big.Int + Timestamp *big.Int + TxHash [32]byte + BlockNumber *big.Int + BlockHash [32]byte + Source common.Address + Topics [][32]byte + Data []byte +} + +type LogTriggerConfig struct { + ContractAddress common.Address + FilterSelector uint8 + Topic0 [32]byte + Topic1 [32]byte + Topic2 [32]byte + Topic3 [32]byte +} + +var AutomationUtilsMetaData = &bind.MetaData{ + ABI: "[{\"inputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"blockNum\",\"type\":\"uint32\"},{\"internalType\":\"bytes32\",\"name\":\"blockHash\",\"type\":\"bytes32\"}],\"internalType\":\"structAutomationRegistryBase2_2.ConditionalTrigger\",\"name\":\"\",\"type\":\"tuple\"}],\"name\":\"_conditionalTrigger\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"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\":\"\",\"type\":\"tuple\"}],\"name\":\"_log\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"bytes32\",\"name\":\"logBlockHash\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"txHash\",\"type\":\"bytes32\"},{\"internalType\":\"uint32\",\"name\":\"logIndex\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"blockNum\",\"type\":\"uint32\"},{\"internalType\":\"bytes32\",\"name\":\"blockHash\",\"type\":\"bytes32\"}],\"internalType\":\"structAutomationRegistryBase2_2.LogTrigger\",\"name\":\"\",\"type\":\"tuple\"}],\"name\":\"_logTrigger\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"contractAddress\",\"type\":\"address\"},{\"internalType\":\"uint8\",\"name\":\"filterSelector\",\"type\":\"uint8\"},{\"internalType\":\"bytes32\",\"name\":\"topic0\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"topic1\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"topic2\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"topic3\",\"type\":\"bytes32\"}],\"internalType\":\"structLogTriggerConfig\",\"name\":\"\",\"type\":\"tuple\"}],\"name\":\"_logTriggerConfig\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"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\":\"structAutomationRegistryBase2_2.OnchainConfig\",\"name\":\"\",\"type\":\"tuple\"}],\"name\":\"_onChainConfig\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint256\",\"name\":\"fastGasWei\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"linkNative\",\"type\":\"uint256\"},{\"internalType\":\"uint256[]\",\"name\":\"upkeepIds\",\"type\":\"uint256[]\"},{\"internalType\":\"uint256[]\",\"name\":\"gasLimits\",\"type\":\"uint256[]\"},{\"internalType\":\"bytes[]\",\"name\":\"triggers\",\"type\":\"bytes[]\"},{\"internalType\":\"bytes[]\",\"name\":\"performDatas\",\"type\":\"bytes[]\"}],\"internalType\":\"structAutomationRegistryBase2_2.Report\",\"name\":\"\",\"type\":\"tuple\"}],\"name\":\"_report\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", + Bin: "0x608060405234801561001057600080fd5b506108ca806100206000396000f3fe608060405234801561001057600080fd5b50600436106100725760003560e01c8063776f306111610050578063776f3061146100a6578063e65d6546146100b4578063e9720a49146100c257600080fd5b806321f373d7146100775780632ff92a811461008a5780634b6df29414610098575b600080fd5b6100886100853660046101e8565b50565b005b610088610085366004610363565b6100886100853660046104bd565b610088610085366004610514565b6100886100853660046106fb565b6100886100853660046107e8565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6040516101e0810167ffffffffffffffff81118282101715610123576101236100d0565b60405290565b60405160c0810167ffffffffffffffff81118282101715610123576101236100d0565b604051610100810167ffffffffffffffff81118282101715610123576101236100d0565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff811182821017156101b7576101b76100d0565b604052919050565b803573ffffffffffffffffffffffffffffffffffffffff811681146101e357600080fd5b919050565b600060c082840312156101fa57600080fd5b60405160c0810181811067ffffffffffffffff8211171561021d5761021d6100d0565b604052610229836101bf565b8152602083013560ff8116811461023f57600080fd5b8060208301525060408301356040820152606083013560608201526080830135608082015260a083013560a08201528091505092915050565b803563ffffffff811681146101e357600080fd5b803562ffffff811681146101e357600080fd5b803561ffff811681146101e357600080fd5b80356bffffffffffffffffffffffff811681146101e357600080fd5b600067ffffffffffffffff8211156102e7576102e76100d0565b5060051b60200190565b600082601f83011261030257600080fd5b81356020610317610312836102cd565b610170565b82815260059290921b8401810191818101908684111561033657600080fd5b8286015b848110156103585761034b816101bf565b835291830191830161033a565b509695505050505050565b60006020828403121561037557600080fd5b813567ffffffffffffffff8082111561038d57600080fd5b908301906101e082860312156103a257600080fd5b6103aa6100ff565b6103b383610278565b81526103c160208401610278565b60208201526103d260408401610278565b60408201526103e36060840161028c565b60608201526103f46080840161029f565b608082015261040560a084016102b1565b60a082015261041660c08401610278565b60c082015261042760e08401610278565b60e082015261010061043a818501610278565b9082015261012061044c848201610278565b90820152610140838101359082015261016080840135908201526101806104748185016101bf565b908201526101a0838101358381111561048c57600080fd5b610498888287016102f1565b8284015250506101c091506104ae8284016101bf565b91810191909152949350505050565b6000604082840312156104cf57600080fd5b6040516040810181811067ffffffffffffffff821117156104f2576104f26100d0565b6040526104fe83610278565b8152602083013560208201528091505092915050565b600060a0828403121561052657600080fd5b60405160a0810181811067ffffffffffffffff82111715610549576105496100d0565b8060405250823581526020830135602082015261056860408401610278565b604082015261057960608401610278565b6060820152608083013560808201528091505092915050565b600082601f8301126105a357600080fd5b813560206105b3610312836102cd565b82815260059290921b840181019181810190868411156105d257600080fd5b8286015b8481101561035857803583529183019183016105d6565b600082601f8301126105fe57600080fd5b813567ffffffffffffffff811115610618576106186100d0565b61064960207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f84011601610170565b81815284602083860101111561065e57600080fd5b816020850160208301376000918101602001919091529392505050565b600082601f83011261068c57600080fd5b8135602061069c610312836102cd565b82815260059290921b840181019181810190868411156106bb57600080fd5b8286015b8481101561035857803567ffffffffffffffff8111156106df5760008081fd5b6106ed8986838b01016105ed565b8452509183019183016106bf565b60006020828403121561070d57600080fd5b813567ffffffffffffffff8082111561072557600080fd5b9083019060c0828603121561073957600080fd5b610741610129565b823581526020830135602082015260408301358281111561076157600080fd5b61076d87828601610592565b60408301525060608301358281111561078557600080fd5b61079187828601610592565b6060830152506080830135828111156107a957600080fd5b6107b58782860161067b565b60808301525060a0830135828111156107cd57600080fd5b6107d98782860161067b565b60a08301525095945050505050565b6000602082840312156107fa57600080fd5b813567ffffffffffffffff8082111561081257600080fd5b90830190610100828603121561082757600080fd5b61082f61014c565b823581526020830135602082015260408301356040820152606083013560608201526080830135608082015261086760a084016101bf565b60a082015260c08301358281111561087e57600080fd5b61088a87828601610592565b60c08301525060e0830135828111156108a257600080fd5b6108ae878286016105ed565b60e0830152509594505050505056fea164736f6c6343000810000a", +} + +var AutomationUtilsABI = AutomationUtilsMetaData.ABI + +var AutomationUtilsBin = AutomationUtilsMetaData.Bin + +func DeployAutomationUtils(auth *bind.TransactOpts, backend bind.ContractBackend) (common.Address, *types.Transaction, *AutomationUtils, error) { + parsed, err := AutomationUtilsMetaData.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(AutomationUtilsBin), backend) + if err != nil { + return common.Address{}, nil, nil, err + } + return address, tx, &AutomationUtils{address: address, abi: *parsed, AutomationUtilsCaller: AutomationUtilsCaller{contract: contract}, AutomationUtilsTransactor: AutomationUtilsTransactor{contract: contract}, AutomationUtilsFilterer: AutomationUtilsFilterer{contract: contract}}, nil +} + +type AutomationUtils struct { + address common.Address + abi abi.ABI + AutomationUtilsCaller + AutomationUtilsTransactor + AutomationUtilsFilterer +} + +type AutomationUtilsCaller struct { + contract *bind.BoundContract +} + +type AutomationUtilsTransactor struct { + contract *bind.BoundContract +} + +type AutomationUtilsFilterer struct { + contract *bind.BoundContract +} + +type AutomationUtilsSession struct { + Contract *AutomationUtils + CallOpts bind.CallOpts + TransactOpts bind.TransactOpts +} + +type AutomationUtilsCallerSession struct { + Contract *AutomationUtilsCaller + CallOpts bind.CallOpts +} + +type AutomationUtilsTransactorSession struct { + Contract *AutomationUtilsTransactor + TransactOpts bind.TransactOpts +} + +type AutomationUtilsRaw struct { + Contract *AutomationUtils +} + +type AutomationUtilsCallerRaw struct { + Contract *AutomationUtilsCaller +} + +type AutomationUtilsTransactorRaw struct { + Contract *AutomationUtilsTransactor +} + +func NewAutomationUtils(address common.Address, backend bind.ContractBackend) (*AutomationUtils, error) { + abi, err := abi.JSON(strings.NewReader(AutomationUtilsABI)) + if err != nil { + return nil, err + } + contract, err := bindAutomationUtils(address, backend, backend, backend) + if err != nil { + return nil, err + } + return &AutomationUtils{address: address, abi: abi, AutomationUtilsCaller: AutomationUtilsCaller{contract: contract}, AutomationUtilsTransactor: AutomationUtilsTransactor{contract: contract}, AutomationUtilsFilterer: AutomationUtilsFilterer{contract: contract}}, nil +} + +func NewAutomationUtilsCaller(address common.Address, caller bind.ContractCaller) (*AutomationUtilsCaller, error) { + contract, err := bindAutomationUtils(address, caller, nil, nil) + if err != nil { + return nil, err + } + return &AutomationUtilsCaller{contract: contract}, nil +} + +func NewAutomationUtilsTransactor(address common.Address, transactor bind.ContractTransactor) (*AutomationUtilsTransactor, error) { + contract, err := bindAutomationUtils(address, nil, transactor, nil) + if err != nil { + return nil, err + } + return &AutomationUtilsTransactor{contract: contract}, nil +} + +func NewAutomationUtilsFilterer(address common.Address, filterer bind.ContractFilterer) (*AutomationUtilsFilterer, error) { + contract, err := bindAutomationUtils(address, nil, nil, filterer) + if err != nil { + return nil, err + } + return &AutomationUtilsFilterer{contract: contract}, nil +} + +func bindAutomationUtils(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) { + parsed, err := AutomationUtilsMetaData.GetAbi() + if err != nil { + return nil, err + } + return bind.NewBoundContract(address, *parsed, caller, transactor, filterer), nil +} + +func (_AutomationUtils *AutomationUtilsRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _AutomationUtils.Contract.AutomationUtilsCaller.contract.Call(opts, result, method, params...) +} + +func (_AutomationUtils *AutomationUtilsRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _AutomationUtils.Contract.AutomationUtilsTransactor.contract.Transfer(opts) +} + +func (_AutomationUtils *AutomationUtilsRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _AutomationUtils.Contract.AutomationUtilsTransactor.contract.Transact(opts, method, params...) +} + +func (_AutomationUtils *AutomationUtilsCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _AutomationUtils.Contract.contract.Call(opts, result, method, params...) +} + +func (_AutomationUtils *AutomationUtilsTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _AutomationUtils.Contract.contract.Transfer(opts) +} + +func (_AutomationUtils *AutomationUtilsTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _AutomationUtils.Contract.contract.Transact(opts, method, params...) +} + +func (_AutomationUtils *AutomationUtilsTransactor) ConditionalTrigger(opts *bind.TransactOpts, arg0 AutomationRegistryBase22ConditionalTrigger) (*types.Transaction, error) { + return _AutomationUtils.contract.Transact(opts, "_conditionalTrigger", arg0) +} + +func (_AutomationUtils *AutomationUtilsSession) ConditionalTrigger(arg0 AutomationRegistryBase22ConditionalTrigger) (*types.Transaction, error) { + return _AutomationUtils.Contract.ConditionalTrigger(&_AutomationUtils.TransactOpts, arg0) +} + +func (_AutomationUtils *AutomationUtilsTransactorSession) ConditionalTrigger(arg0 AutomationRegistryBase22ConditionalTrigger) (*types.Transaction, error) { + return _AutomationUtils.Contract.ConditionalTrigger(&_AutomationUtils.TransactOpts, arg0) +} + +func (_AutomationUtils *AutomationUtilsTransactor) Log(opts *bind.TransactOpts, arg0 Log) (*types.Transaction, error) { + return _AutomationUtils.contract.Transact(opts, "_log", arg0) +} + +func (_AutomationUtils *AutomationUtilsSession) Log(arg0 Log) (*types.Transaction, error) { + return _AutomationUtils.Contract.Log(&_AutomationUtils.TransactOpts, arg0) +} + +func (_AutomationUtils *AutomationUtilsTransactorSession) Log(arg0 Log) (*types.Transaction, error) { + return _AutomationUtils.Contract.Log(&_AutomationUtils.TransactOpts, arg0) +} + +func (_AutomationUtils *AutomationUtilsTransactor) LogTrigger(opts *bind.TransactOpts, arg0 AutomationRegistryBase22LogTrigger) (*types.Transaction, error) { + return _AutomationUtils.contract.Transact(opts, "_logTrigger", arg0) +} + +func (_AutomationUtils *AutomationUtilsSession) LogTrigger(arg0 AutomationRegistryBase22LogTrigger) (*types.Transaction, error) { + return _AutomationUtils.Contract.LogTrigger(&_AutomationUtils.TransactOpts, arg0) +} + +func (_AutomationUtils *AutomationUtilsTransactorSession) LogTrigger(arg0 AutomationRegistryBase22LogTrigger) (*types.Transaction, error) { + return _AutomationUtils.Contract.LogTrigger(&_AutomationUtils.TransactOpts, arg0) +} + +func (_AutomationUtils *AutomationUtilsTransactor) LogTriggerConfig(opts *bind.TransactOpts, arg0 LogTriggerConfig) (*types.Transaction, error) { + return _AutomationUtils.contract.Transact(opts, "_logTriggerConfig", arg0) +} + +func (_AutomationUtils *AutomationUtilsSession) LogTriggerConfig(arg0 LogTriggerConfig) (*types.Transaction, error) { + return _AutomationUtils.Contract.LogTriggerConfig(&_AutomationUtils.TransactOpts, arg0) +} + +func (_AutomationUtils *AutomationUtilsTransactorSession) LogTriggerConfig(arg0 LogTriggerConfig) (*types.Transaction, error) { + return _AutomationUtils.Contract.LogTriggerConfig(&_AutomationUtils.TransactOpts, arg0) +} + +func (_AutomationUtils *AutomationUtilsTransactor) OnChainConfig(opts *bind.TransactOpts, arg0 AutomationRegistryBase22OnchainConfig) (*types.Transaction, error) { + return _AutomationUtils.contract.Transact(opts, "_onChainConfig", arg0) +} + +func (_AutomationUtils *AutomationUtilsSession) OnChainConfig(arg0 AutomationRegistryBase22OnchainConfig) (*types.Transaction, error) { + return _AutomationUtils.Contract.OnChainConfig(&_AutomationUtils.TransactOpts, arg0) +} + +func (_AutomationUtils *AutomationUtilsTransactorSession) OnChainConfig(arg0 AutomationRegistryBase22OnchainConfig) (*types.Transaction, error) { + return _AutomationUtils.Contract.OnChainConfig(&_AutomationUtils.TransactOpts, arg0) +} + +func (_AutomationUtils *AutomationUtilsTransactor) Report(opts *bind.TransactOpts, arg0 AutomationRegistryBase22Report) (*types.Transaction, error) { + return _AutomationUtils.contract.Transact(opts, "_report", arg0) +} + +func (_AutomationUtils *AutomationUtilsSession) Report(arg0 AutomationRegistryBase22Report) (*types.Transaction, error) { + return _AutomationUtils.Contract.Report(&_AutomationUtils.TransactOpts, arg0) +} + +func (_AutomationUtils *AutomationUtilsTransactorSession) Report(arg0 AutomationRegistryBase22Report) (*types.Transaction, error) { + return _AutomationUtils.Contract.Report(&_AutomationUtils.TransactOpts, arg0) +} + +func (_AutomationUtils *AutomationUtils) Address() common.Address { + return _AutomationUtils.address +} + +type AutomationUtilsInterface interface { + ConditionalTrigger(opts *bind.TransactOpts, arg0 AutomationRegistryBase22ConditionalTrigger) (*types.Transaction, error) + + Log(opts *bind.TransactOpts, arg0 Log) (*types.Transaction, error) + + LogTrigger(opts *bind.TransactOpts, arg0 AutomationRegistryBase22LogTrigger) (*types.Transaction, error) + + LogTriggerConfig(opts *bind.TransactOpts, arg0 LogTriggerConfig) (*types.Transaction, error) + + OnChainConfig(opts *bind.TransactOpts, arg0 AutomationRegistryBase22OnchainConfig) (*types.Transaction, error) + + Report(opts *bind.TransactOpts, arg0 AutomationRegistryBase22Report) (*types.Transaction, error) + + Address() common.Address +} diff --git a/core/gethwrappers/generated/chain_reader_example/chain_reader_example.go b/core/gethwrappers/generated/chain_reader_example/chain_reader_example.go new file mode 100644 index 0000000000..f6dce0bb6c --- /dev/null +++ b/core/gethwrappers/generated/chain_reader_example/chain_reader_example.go @@ -0,0 +1,830 @@ +// Code generated - DO NOT EDIT. +// This file is a generated binding and any manual changes will be lost. + +package chain_reader_example + +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 +) + +type InnerTestStruct struct { + IntVal int64 + S string +} + +type MidLevelTestStruct struct { + FixedBytes [2]byte + Inner InnerTestStruct +} + +type TestStruct struct { + Field int32 + DifferentField string + OracleId uint8 + OracleIds [32]uint8 + Account common.Address + Accounts []common.Address + BigField *big.Int + NestedStruct MidLevelTestStruct +} + +var LatestValueHolderMetaData = &bind.MetaData{ + ABI: "[{\"inputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"int32\",\"name\":\"field\",\"type\":\"int32\"},{\"indexed\":false,\"internalType\":\"string\",\"name\":\"differentField\",\"type\":\"string\"},{\"indexed\":false,\"internalType\":\"uint8\",\"name\":\"oracleId\",\"type\":\"uint8\"},{\"indexed\":false,\"internalType\":\"uint8[32]\",\"name\":\"oracleIds\",\"type\":\"uint8[32]\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"Account\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"Accounts\",\"type\":\"address[]\"},{\"indexed\":false,\"internalType\":\"int192\",\"name\":\"bigField\",\"type\":\"int192\"},{\"components\":[{\"internalType\":\"bytes2\",\"name\":\"FixedBytes\",\"type\":\"bytes2\"},{\"components\":[{\"internalType\":\"int64\",\"name\":\"IntVal\",\"type\":\"int64\"},{\"internalType\":\"string\",\"name\":\"S\",\"type\":\"string\"}],\"internalType\":\"structInnerTestStruct\",\"name\":\"Inner\",\"type\":\"tuple\"}],\"indexed\":false,\"internalType\":\"structMidLevelTestStruct\",\"name\":\"nestedStruct\",\"type\":\"tuple\"}],\"name\":\"Triggered\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"string\",\"name\":\"fieldHash\",\"type\":\"string\"},{\"indexed\":false,\"internalType\":\"string\",\"name\":\"field\",\"type\":\"string\"}],\"name\":\"TriggeredEventWithDynamicTopic\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"int32\",\"name\":\"field1\",\"type\":\"int32\"},{\"indexed\":true,\"internalType\":\"int32\",\"name\":\"field2\",\"type\":\"int32\"},{\"indexed\":true,\"internalType\":\"int32\",\"name\":\"field3\",\"type\":\"int32\"}],\"name\":\"TriggeredWithFourTopics\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"int32\",\"name\":\"field\",\"type\":\"int32\"},{\"internalType\":\"string\",\"name\":\"differentField\",\"type\":\"string\"},{\"internalType\":\"uint8\",\"name\":\"oracleId\",\"type\":\"uint8\"},{\"internalType\":\"uint8[32]\",\"name\":\"oracleIds\",\"type\":\"uint8[32]\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"internalType\":\"address[]\",\"name\":\"accounts\",\"type\":\"address[]\"},{\"internalType\":\"int192\",\"name\":\"bigField\",\"type\":\"int192\"},{\"components\":[{\"internalType\":\"bytes2\",\"name\":\"FixedBytes\",\"type\":\"bytes2\"},{\"components\":[{\"internalType\":\"int64\",\"name\":\"IntVal\",\"type\":\"int64\"},{\"internalType\":\"string\",\"name\":\"S\",\"type\":\"string\"}],\"internalType\":\"structInnerTestStruct\",\"name\":\"Inner\",\"type\":\"tuple\"}],\"internalType\":\"structMidLevelTestStruct\",\"name\":\"nestedStruct\",\"type\":\"tuple\"}],\"name\":\"addTestStruct\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getDifferentPrimitiveValue\",\"outputs\":[{\"internalType\":\"uint64\",\"name\":\"\",\"type\":\"uint64\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"i\",\"type\":\"uint256\"}],\"name\":\"getElementAtIndex\",\"outputs\":[{\"components\":[{\"internalType\":\"int32\",\"name\":\"Field\",\"type\":\"int32\"},{\"internalType\":\"string\",\"name\":\"DifferentField\",\"type\":\"string\"},{\"internalType\":\"uint8\",\"name\":\"OracleId\",\"type\":\"uint8\"},{\"internalType\":\"uint8[32]\",\"name\":\"OracleIds\",\"type\":\"uint8[32]\"},{\"internalType\":\"address\",\"name\":\"Account\",\"type\":\"address\"},{\"internalType\":\"address[]\",\"name\":\"Accounts\",\"type\":\"address[]\"},{\"internalType\":\"int192\",\"name\":\"BigField\",\"type\":\"int192\"},{\"components\":[{\"internalType\":\"bytes2\",\"name\":\"FixedBytes\",\"type\":\"bytes2\"},{\"components\":[{\"internalType\":\"int64\",\"name\":\"IntVal\",\"type\":\"int64\"},{\"internalType\":\"string\",\"name\":\"S\",\"type\":\"string\"}],\"internalType\":\"structInnerTestStruct\",\"name\":\"Inner\",\"type\":\"tuple\"}],\"internalType\":\"structMidLevelTestStruct\",\"name\":\"NestedStruct\",\"type\":\"tuple\"}],\"internalType\":\"structTestStruct\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getPrimitiveValue\",\"outputs\":[{\"internalType\":\"uint64\",\"name\":\"\",\"type\":\"uint64\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getSliceValue\",\"outputs\":[{\"internalType\":\"uint64[]\",\"name\":\"\",\"type\":\"uint64[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"int32\",\"name\":\"field\",\"type\":\"int32\"},{\"internalType\":\"string\",\"name\":\"differentField\",\"type\":\"string\"},{\"internalType\":\"uint8\",\"name\":\"oracleId\",\"type\":\"uint8\"},{\"internalType\":\"uint8[32]\",\"name\":\"oracleIds\",\"type\":\"uint8[32]\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"internalType\":\"address[]\",\"name\":\"accounts\",\"type\":\"address[]\"},{\"internalType\":\"int192\",\"name\":\"bigField\",\"type\":\"int192\"},{\"components\":[{\"internalType\":\"bytes2\",\"name\":\"FixedBytes\",\"type\":\"bytes2\"},{\"components\":[{\"internalType\":\"int64\",\"name\":\"IntVal\",\"type\":\"int64\"},{\"internalType\":\"string\",\"name\":\"S\",\"type\":\"string\"}],\"internalType\":\"structInnerTestStruct\",\"name\":\"Inner\",\"type\":\"tuple\"}],\"internalType\":\"structMidLevelTestStruct\",\"name\":\"nestedStruct\",\"type\":\"tuple\"}],\"name\":\"returnSeen\",\"outputs\":[{\"components\":[{\"internalType\":\"int32\",\"name\":\"Field\",\"type\":\"int32\"},{\"internalType\":\"string\",\"name\":\"DifferentField\",\"type\":\"string\"},{\"internalType\":\"uint8\",\"name\":\"OracleId\",\"type\":\"uint8\"},{\"internalType\":\"uint8[32]\",\"name\":\"OracleIds\",\"type\":\"uint8[32]\"},{\"internalType\":\"address\",\"name\":\"Account\",\"type\":\"address\"},{\"internalType\":\"address[]\",\"name\":\"Accounts\",\"type\":\"address[]\"},{\"internalType\":\"int192\",\"name\":\"BigField\",\"type\":\"int192\"},{\"components\":[{\"internalType\":\"bytes2\",\"name\":\"FixedBytes\",\"type\":\"bytes2\"},{\"components\":[{\"internalType\":\"int64\",\"name\":\"IntVal\",\"type\":\"int64\"},{\"internalType\":\"string\",\"name\":\"S\",\"type\":\"string\"}],\"internalType\":\"structInnerTestStruct\",\"name\":\"Inner\",\"type\":\"tuple\"}],\"internalType\":\"structMidLevelTestStruct\",\"name\":\"NestedStruct\",\"type\":\"tuple\"}],\"internalType\":\"structTestStruct\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"int32\",\"name\":\"field\",\"type\":\"int32\"},{\"internalType\":\"string\",\"name\":\"differentField\",\"type\":\"string\"},{\"internalType\":\"uint8\",\"name\":\"oracleId\",\"type\":\"uint8\"},{\"internalType\":\"uint8[32]\",\"name\":\"oracleIds\",\"type\":\"uint8[32]\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"internalType\":\"address[]\",\"name\":\"accounts\",\"type\":\"address[]\"},{\"internalType\":\"int192\",\"name\":\"bigField\",\"type\":\"int192\"},{\"components\":[{\"internalType\":\"bytes2\",\"name\":\"FixedBytes\",\"type\":\"bytes2\"},{\"components\":[{\"internalType\":\"int64\",\"name\":\"IntVal\",\"type\":\"int64\"},{\"internalType\":\"string\",\"name\":\"S\",\"type\":\"string\"}],\"internalType\":\"structInnerTestStruct\",\"name\":\"Inner\",\"type\":\"tuple\"}],\"internalType\":\"structMidLevelTestStruct\",\"name\":\"nestedStruct\",\"type\":\"tuple\"}],\"name\":\"triggerEvent\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"field\",\"type\":\"string\"}],\"name\":\"triggerEventWithDynamicTopic\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"int32\",\"name\":\"field1\",\"type\":\"int32\"},{\"internalType\":\"int32\",\"name\":\"field2\",\"type\":\"int32\"},{\"internalType\":\"int32\",\"name\":\"field3\",\"type\":\"int32\"}],\"name\":\"triggerWithFourTopics\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", + Bin: "0x608060405234801561001057600080fd5b50600180548082018255600082905260048082047fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6908101805460086003958616810261010090810a8088026001600160401b0391820219909416939093179093558654808801909755848704909301805496909516909202900a91820291021990921691909117905561176c806100a96000396000f3fe608060405234801561001057600080fd5b50600436106100a35760003560e01c80637f002d6711610076578063dbfd73321161005b578063dbfd73321461013e578063ef4e1ced14610151578063f6f871c81461015857600080fd5b80637f002d671461010e578063ab5e0b381461012157600080fd5b80632c45576f146100a85780633272b66c146100d157806349eac2ac146100e6578063679004a4146100f9575b600080fd5b6100bb6100b6366004610baa565b61016b565b6040516100c89190610d09565b60405180910390f35b6100e46100df366004610e48565b610446565b005b6100e46100f4366004610f5d565b61049b565b61010161079e565b6040516100c8919061104f565b6100e461011c366004610f5d565b61082a565b6107c65b60405167ffffffffffffffff90911681526020016100c8565b6100e461014c36600461109d565b610881565b6003610125565b6100bb610166366004610f5d565b6108be565b6101736109c7565b60006101806001846110e0565b815481106101905761019061111a565b6000918252602091829020604080516101008101909152600a90920201805460030b825260018101805492939192918401916101cb90611149565b80601f01602080910402602001604051908101604052809291908181526020018280546101f790611149565b80156102445780601f1061021957610100808354040283529160200191610244565b820191906000526020600020905b81548152906001019060200180831161022757829003601f168201915b5050509183525050600282015460ff166020808301919091526040805161040081018083529190930192916003850191826000855b825461010083900a900460ff1681526020600192830181810494850194909303909202910180841161027957505050928452505050600482015473ffffffffffffffffffffffffffffffffffffffff16602080830191909152600583018054604080518285028101850182528281529401939283018282801561033257602002820191906000526020600020905b815473ffffffffffffffffffffffffffffffffffffffff168152600190910190602001808311610307575b5050509183525050600682015460170b6020808301919091526040805180820182526007808601805460f01b7fffff0000000000000000000000000000000000000000000000000000000000001683528351808501855260088801805490930b815260098801805495909701969395919486830194919392840191906103b790611149565b80601f01602080910402602001604051908101604052809291908181526020018280546103e390611149565b80156104305780601f1061040557610100808354040283529160200191610430565b820191906000526020600020905b81548152906001019060200180831161041357829003601f168201915b5050509190925250505090525090525092915050565b8181604051610456929190611196565b60405180910390207f3d969732b1bbbb9f1d7eb9f3f14e4cb50a74d950b3ef916a397b85dfbab93c67838360405161048f9291906111ef565b60405180910390a25050565b60006040518061010001604052808c60030b81526020018b8b8080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525050509082525060ff8a166020808301919091526040805161040081810183529190930192918b9183908390808284376000920191909152505050815273ffffffffffffffffffffffffffffffffffffffff8816602080830191909152604080518883028181018401835289825291909301929189918991829190850190849080828437600092019190915250505090825250601785900b602082015260400161058d846112ec565b905281546001808201845560009384526020938490208351600a9093020180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000001663ffffffff9093169290921782559282015191929091908201906105f39082611446565b5060408201516002820180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660ff90921691909117905560608201516106419060038301906020610a16565b5060808201516004820180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff90921691909117905560a082015180516106a8916005840191602090910190610aa9565b5060c08201516006820180547fffffffffffffffff0000000000000000000000000000000000000000000000001677ffffffffffffffffffffffffffffffffffffffffffffffff90921691909117905560e082015180516007830180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00001660f09290921c91909117815560208083015180516008860180547fffffffffffffffffffffffffffffffffffffffffffffffff00000000000000001667ffffffffffffffff90921691909117815591810151909190600986019061078b9082611446565b5050505050505050505050505050505050565b6060600180548060200260200160405190810160405280929190818152602001828054801561082057602002820191906000526020600020906000905b82829054906101000a900467ffffffffffffffff1667ffffffffffffffff16815260200190600801906020826007010492830192600103820291508084116107db5790505b5050505050905090565b8960030b7f7188419dcd8b51877b71766f075f3626586c0ff190e7d056aa65ce9acb649a3d8a8a8a8a8a8a8a8a8a60405161086d999897969594939291906116a5565b60405180910390a250505050505050505050565b8060030b8260030b8460030b7f91c80dc390f3d041b3a04b0099b19634499541ea26972250986ee4b24a12fac560405160405180910390a4505050565b6108c66109c7565b6040518061010001604052808c60030b81526020018b8b8080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525050509082525060ff8a166020808301919091526040805161040081810183529190930192918b9183908390808284376000920191909152505050815273ffffffffffffffffffffffffffffffffffffffff8816602080830191909152604080518883028181018401835289825291909301929189918991829190850190849080828437600092019190915250505090825250601785900b60208201526040016109b6846112ec565b90529b9a5050505050505050505050565b60408051610100810182526000808252606060208301819052928201529081016109ef610b23565b8152600060208201819052606060408301819052820152608001610a11610b42565b905290565b600183019183908215610a995791602002820160005b83821115610a6a57835183826101000a81548160ff021916908360ff1602179055509260200192600101602081600001049283019260010302610a2c565b8015610a975782816101000a81549060ff0219169055600101602081600001049283019260010302610a6a565b505b50610aa5929150610b95565b5090565b828054828255906000526020600020908101928215610a99579160200282015b82811115610a9957825182547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff909116178255602090920191600190910190610ac9565b6040518061040001604052806020906020820280368337509192915050565b604051806040016040528060007dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff19168152602001610a116040518060400160405280600060070b8152602001606081525090565b5b80821115610aa55760008155600101610b96565b600060208284031215610bbc57600080fd5b5035919050565b6000815180845260005b81811015610be957602081850181015186830182015201610bcd565b5060006020828601015260207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f83011685010191505092915050565b8060005b6020808210610c3a5750610c51565b825160ff1685529384019390910190600101610c2b565b50505050565b600081518084526020808501945080840160005b83811015610c9d57815173ffffffffffffffffffffffffffffffffffffffff1687529582019590820190600101610c6b565b509495945050505050565b7fffff00000000000000000000000000000000000000000000000000000000000081511682526000602082015160406020850152805160070b60408501526020810151905060406060850152610d016080850182610bc3565b949350505050565b60208152610d1d60208201835160030b9052565b600060208301516104e0806040850152610d3b610500850183610bc3565b91506040850151610d51606086018260ff169052565b506060850151610d646080860182610c27565b50608085015173ffffffffffffffffffffffffffffffffffffffff1661048085015260a08501517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe085840381016104a0870152610dc18483610c57565b935060c08701519150610dda6104c087018360170b9052565b60e0870151915080868503018387015250610df58382610ca8565b9695505050505050565b60008083601f840112610e1157600080fd5b50813567ffffffffffffffff811115610e2957600080fd5b602083019150836020828501011115610e4157600080fd5b9250929050565b60008060208385031215610e5b57600080fd5b823567ffffffffffffffff811115610e7257600080fd5b610e7e85828601610dff565b90969095509350505050565b8035600381900b8114610e9c57600080fd5b919050565b803560ff81168114610e9c57600080fd5b806104008101831015610ec457600080fd5b92915050565b803573ffffffffffffffffffffffffffffffffffffffff81168114610e9c57600080fd5b60008083601f840112610f0057600080fd5b50813567ffffffffffffffff811115610f1857600080fd5b6020830191508360208260051b8501011115610e4157600080fd5b8035601781900b8114610e9c57600080fd5b600060408284031215610f5757600080fd5b50919050565b6000806000806000806000806000806104e08b8d031215610f7d57600080fd5b610f868b610e8a565b995060208b013567ffffffffffffffff80821115610fa357600080fd5b610faf8e838f01610dff565b909b509950899150610fc360408e01610ea1565b9850610fd28e60608f01610eb2565b9750610fe16104608e01610eca565b96506104808d0135915080821115610ff857600080fd5b6110048e838f01610eee565b90965094508491506110196104a08e01610f33565b93506104c08d013591508082111561103057600080fd5b5061103d8d828e01610f45565b9150509295989b9194979a5092959850565b6020808252825182820181905260009190848201906040850190845b8181101561109157835167ffffffffffffffff168352928401929184019160010161106b565b50909695505050505050565b6000806000606084860312156110b257600080fd5b6110bb84610e8a565b92506110c960208501610e8a565b91506110d760408501610e8a565b90509250925092565b81810381811115610ec4577f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b600181811c9082168061115d57607f821691505b602082108103610f57577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b8183823760009101908152919050565b8183528181602085013750600060208284010152600060207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f840116840101905092915050565b602081526000610d016020830184866111a6565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6040805190810167ffffffffffffffff8111828210171561125557611255611203565b60405290565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff811182821017156112a2576112a2611203565b604052919050565b80357fffff00000000000000000000000000000000000000000000000000000000000081168114610e9c57600080fd5b8035600781900b8114610e9c57600080fd5b6000604082360312156112fe57600080fd5b611306611232565b61130f836112aa565b815260208084013567ffffffffffffffff8082111561132d57600080fd5b81860191506040823603121561134257600080fd5b61134a611232565b611353836112da565b8152838301358281111561136657600080fd5b929092019136601f84011261137a57600080fd5b82358281111561138c5761138c611203565b6113bc857fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8401160161125b565b925080835236858286010111156113d257600080fd5b8085850186850137600090830185015280840191909152918301919091525092915050565b601f82111561144157600081815260208120601f850160051c8101602086101561141e5750805b601f850160051c820191505b8181101561143d5782815560010161142a565b5050505b505050565b815167ffffffffffffffff81111561146057611460611203565b6114748161146e8454611149565b846113f7565b602080601f8311600181146114c757600084156114915750858301515b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600386901b1c1916600185901b17855561143d565b6000858152602081207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08616915b82811015611514578886015182559484019460019091019084016114f5565b508582101561155057878501517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600388901b60f8161c191681555b5050505050600190811b01905550565b8183526000602080850194508260005b85811015610c9d5773ffffffffffffffffffffffffffffffffffffffff61159683610eca565b1687529582019590820190600101611570565b7fffff0000000000000000000000000000000000000000000000000000000000006115d3826112aa565b168252600060208201357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc183360301811261160d57600080fd5b60406020850152820161161f816112da565b60070b604085015260208101357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe182360301811261165c57600080fd5b0160208101903567ffffffffffffffff81111561167857600080fd5b80360382131561168757600080fd5b6040606086015261169c6080860182846111a6565b95945050505050565b60006104c08083526116ba8184018c8e6111a6565b9050602060ff808c1682860152604085018b60005b848110156116f457836116e183610ea1565b16835291840191908401906001016116cf565b505050505073ffffffffffffffffffffffffffffffffffffffff881661044084015282810361046084015261172a818789611560565b905061173c61048084018660170b9052565b8281036104a084015261174f81856115a9565b9c9b50505050505050505050505056fea164736f6c6343000813000a", +} + +var LatestValueHolderABI = LatestValueHolderMetaData.ABI + +var LatestValueHolderBin = LatestValueHolderMetaData.Bin + +func DeployLatestValueHolder(auth *bind.TransactOpts, backend bind.ContractBackend) (common.Address, *types.Transaction, *LatestValueHolder, error) { + parsed, err := LatestValueHolderMetaData.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(LatestValueHolderBin), backend) + if err != nil { + return common.Address{}, nil, nil, err + } + return address, tx, &LatestValueHolder{address: address, abi: *parsed, LatestValueHolderCaller: LatestValueHolderCaller{contract: contract}, LatestValueHolderTransactor: LatestValueHolderTransactor{contract: contract}, LatestValueHolderFilterer: LatestValueHolderFilterer{contract: contract}}, nil +} + +type LatestValueHolder struct { + address common.Address + abi abi.ABI + LatestValueHolderCaller + LatestValueHolderTransactor + LatestValueHolderFilterer +} + +type LatestValueHolderCaller struct { + contract *bind.BoundContract +} + +type LatestValueHolderTransactor struct { + contract *bind.BoundContract +} + +type LatestValueHolderFilterer struct { + contract *bind.BoundContract +} + +type LatestValueHolderSession struct { + Contract *LatestValueHolder + CallOpts bind.CallOpts + TransactOpts bind.TransactOpts +} + +type LatestValueHolderCallerSession struct { + Contract *LatestValueHolderCaller + CallOpts bind.CallOpts +} + +type LatestValueHolderTransactorSession struct { + Contract *LatestValueHolderTransactor + TransactOpts bind.TransactOpts +} + +type LatestValueHolderRaw struct { + Contract *LatestValueHolder +} + +type LatestValueHolderCallerRaw struct { + Contract *LatestValueHolderCaller +} + +type LatestValueHolderTransactorRaw struct { + Contract *LatestValueHolderTransactor +} + +func NewLatestValueHolder(address common.Address, backend bind.ContractBackend) (*LatestValueHolder, error) { + abi, err := abi.JSON(strings.NewReader(LatestValueHolderABI)) + if err != nil { + return nil, err + } + contract, err := bindLatestValueHolder(address, backend, backend, backend) + if err != nil { + return nil, err + } + return &LatestValueHolder{address: address, abi: abi, LatestValueHolderCaller: LatestValueHolderCaller{contract: contract}, LatestValueHolderTransactor: LatestValueHolderTransactor{contract: contract}, LatestValueHolderFilterer: LatestValueHolderFilterer{contract: contract}}, nil +} + +func NewLatestValueHolderCaller(address common.Address, caller bind.ContractCaller) (*LatestValueHolderCaller, error) { + contract, err := bindLatestValueHolder(address, caller, nil, nil) + if err != nil { + return nil, err + } + return &LatestValueHolderCaller{contract: contract}, nil +} + +func NewLatestValueHolderTransactor(address common.Address, transactor bind.ContractTransactor) (*LatestValueHolderTransactor, error) { + contract, err := bindLatestValueHolder(address, nil, transactor, nil) + if err != nil { + return nil, err + } + return &LatestValueHolderTransactor{contract: contract}, nil +} + +func NewLatestValueHolderFilterer(address common.Address, filterer bind.ContractFilterer) (*LatestValueHolderFilterer, error) { + contract, err := bindLatestValueHolder(address, nil, nil, filterer) + if err != nil { + return nil, err + } + return &LatestValueHolderFilterer{contract: contract}, nil +} + +func bindLatestValueHolder(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) { + parsed, err := LatestValueHolderMetaData.GetAbi() + if err != nil { + return nil, err + } + return bind.NewBoundContract(address, *parsed, caller, transactor, filterer), nil +} + +func (_LatestValueHolder *LatestValueHolderRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _LatestValueHolder.Contract.LatestValueHolderCaller.contract.Call(opts, result, method, params...) +} + +func (_LatestValueHolder *LatestValueHolderRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _LatestValueHolder.Contract.LatestValueHolderTransactor.contract.Transfer(opts) +} + +func (_LatestValueHolder *LatestValueHolderRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _LatestValueHolder.Contract.LatestValueHolderTransactor.contract.Transact(opts, method, params...) +} + +func (_LatestValueHolder *LatestValueHolderCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _LatestValueHolder.Contract.contract.Call(opts, result, method, params...) +} + +func (_LatestValueHolder *LatestValueHolderTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _LatestValueHolder.Contract.contract.Transfer(opts) +} + +func (_LatestValueHolder *LatestValueHolderTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _LatestValueHolder.Contract.contract.Transact(opts, method, params...) +} + +func (_LatestValueHolder *LatestValueHolderCaller) GetDifferentPrimitiveValue(opts *bind.CallOpts) (uint64, error) { + var out []interface{} + err := _LatestValueHolder.contract.Call(opts, &out, "getDifferentPrimitiveValue") + + if err != nil { + return *new(uint64), err + } + + out0 := *abi.ConvertType(out[0], new(uint64)).(*uint64) + + return out0, err + +} + +func (_LatestValueHolder *LatestValueHolderSession) GetDifferentPrimitiveValue() (uint64, error) { + return _LatestValueHolder.Contract.GetDifferentPrimitiveValue(&_LatestValueHolder.CallOpts) +} + +func (_LatestValueHolder *LatestValueHolderCallerSession) GetDifferentPrimitiveValue() (uint64, error) { + return _LatestValueHolder.Contract.GetDifferentPrimitiveValue(&_LatestValueHolder.CallOpts) +} + +func (_LatestValueHolder *LatestValueHolderCaller) GetElementAtIndex(opts *bind.CallOpts, i *big.Int) (TestStruct, error) { + var out []interface{} + err := _LatestValueHolder.contract.Call(opts, &out, "getElementAtIndex", i) + + if err != nil { + return *new(TestStruct), err + } + + out0 := *abi.ConvertType(out[0], new(TestStruct)).(*TestStruct) + + return out0, err + +} + +func (_LatestValueHolder *LatestValueHolderSession) GetElementAtIndex(i *big.Int) (TestStruct, error) { + return _LatestValueHolder.Contract.GetElementAtIndex(&_LatestValueHolder.CallOpts, i) +} + +func (_LatestValueHolder *LatestValueHolderCallerSession) GetElementAtIndex(i *big.Int) (TestStruct, error) { + return _LatestValueHolder.Contract.GetElementAtIndex(&_LatestValueHolder.CallOpts, i) +} + +func (_LatestValueHolder *LatestValueHolderCaller) GetPrimitiveValue(opts *bind.CallOpts) (uint64, error) { + var out []interface{} + err := _LatestValueHolder.contract.Call(opts, &out, "getPrimitiveValue") + + if err != nil { + return *new(uint64), err + } + + out0 := *abi.ConvertType(out[0], new(uint64)).(*uint64) + + return out0, err + +} + +func (_LatestValueHolder *LatestValueHolderSession) GetPrimitiveValue() (uint64, error) { + return _LatestValueHolder.Contract.GetPrimitiveValue(&_LatestValueHolder.CallOpts) +} + +func (_LatestValueHolder *LatestValueHolderCallerSession) GetPrimitiveValue() (uint64, error) { + return _LatestValueHolder.Contract.GetPrimitiveValue(&_LatestValueHolder.CallOpts) +} + +func (_LatestValueHolder *LatestValueHolderCaller) GetSliceValue(opts *bind.CallOpts) ([]uint64, error) { + var out []interface{} + err := _LatestValueHolder.contract.Call(opts, &out, "getSliceValue") + + if err != nil { + return *new([]uint64), err + } + + out0 := *abi.ConvertType(out[0], new([]uint64)).(*[]uint64) + + return out0, err + +} + +func (_LatestValueHolder *LatestValueHolderSession) GetSliceValue() ([]uint64, error) { + return _LatestValueHolder.Contract.GetSliceValue(&_LatestValueHolder.CallOpts) +} + +func (_LatestValueHolder *LatestValueHolderCallerSession) GetSliceValue() ([]uint64, error) { + return _LatestValueHolder.Contract.GetSliceValue(&_LatestValueHolder.CallOpts) +} + +func (_LatestValueHolder *LatestValueHolderCaller) ReturnSeen(opts *bind.CallOpts, field int32, differentField string, oracleId uint8, oracleIds [32]uint8, account common.Address, accounts []common.Address, bigField *big.Int, nestedStruct MidLevelTestStruct) (TestStruct, error) { + var out []interface{} + err := _LatestValueHolder.contract.Call(opts, &out, "returnSeen", field, differentField, oracleId, oracleIds, account, accounts, bigField, nestedStruct) + + if err != nil { + return *new(TestStruct), err + } + + out0 := *abi.ConvertType(out[0], new(TestStruct)).(*TestStruct) + + return out0, err + +} + +func (_LatestValueHolder *LatestValueHolderSession) ReturnSeen(field int32, differentField string, oracleId uint8, oracleIds [32]uint8, account common.Address, accounts []common.Address, bigField *big.Int, nestedStruct MidLevelTestStruct) (TestStruct, error) { + return _LatestValueHolder.Contract.ReturnSeen(&_LatestValueHolder.CallOpts, field, differentField, oracleId, oracleIds, account, accounts, bigField, nestedStruct) +} + +func (_LatestValueHolder *LatestValueHolderCallerSession) ReturnSeen(field int32, differentField string, oracleId uint8, oracleIds [32]uint8, account common.Address, accounts []common.Address, bigField *big.Int, nestedStruct MidLevelTestStruct) (TestStruct, error) { + return _LatestValueHolder.Contract.ReturnSeen(&_LatestValueHolder.CallOpts, field, differentField, oracleId, oracleIds, account, accounts, bigField, nestedStruct) +} + +func (_LatestValueHolder *LatestValueHolderTransactor) AddTestStruct(opts *bind.TransactOpts, field int32, differentField string, oracleId uint8, oracleIds [32]uint8, account common.Address, accounts []common.Address, bigField *big.Int, nestedStruct MidLevelTestStruct) (*types.Transaction, error) { + return _LatestValueHolder.contract.Transact(opts, "addTestStruct", field, differentField, oracleId, oracleIds, account, accounts, bigField, nestedStruct) +} + +func (_LatestValueHolder *LatestValueHolderSession) AddTestStruct(field int32, differentField string, oracleId uint8, oracleIds [32]uint8, account common.Address, accounts []common.Address, bigField *big.Int, nestedStruct MidLevelTestStruct) (*types.Transaction, error) { + return _LatestValueHolder.Contract.AddTestStruct(&_LatestValueHolder.TransactOpts, field, differentField, oracleId, oracleIds, account, accounts, bigField, nestedStruct) +} + +func (_LatestValueHolder *LatestValueHolderTransactorSession) AddTestStruct(field int32, differentField string, oracleId uint8, oracleIds [32]uint8, account common.Address, accounts []common.Address, bigField *big.Int, nestedStruct MidLevelTestStruct) (*types.Transaction, error) { + return _LatestValueHolder.Contract.AddTestStruct(&_LatestValueHolder.TransactOpts, field, differentField, oracleId, oracleIds, account, accounts, bigField, nestedStruct) +} + +func (_LatestValueHolder *LatestValueHolderTransactor) TriggerEvent(opts *bind.TransactOpts, field int32, differentField string, oracleId uint8, oracleIds [32]uint8, account common.Address, accounts []common.Address, bigField *big.Int, nestedStruct MidLevelTestStruct) (*types.Transaction, error) { + return _LatestValueHolder.contract.Transact(opts, "triggerEvent", field, differentField, oracleId, oracleIds, account, accounts, bigField, nestedStruct) +} + +func (_LatestValueHolder *LatestValueHolderSession) TriggerEvent(field int32, differentField string, oracleId uint8, oracleIds [32]uint8, account common.Address, accounts []common.Address, bigField *big.Int, nestedStruct MidLevelTestStruct) (*types.Transaction, error) { + return _LatestValueHolder.Contract.TriggerEvent(&_LatestValueHolder.TransactOpts, field, differentField, oracleId, oracleIds, account, accounts, bigField, nestedStruct) +} + +func (_LatestValueHolder *LatestValueHolderTransactorSession) TriggerEvent(field int32, differentField string, oracleId uint8, oracleIds [32]uint8, account common.Address, accounts []common.Address, bigField *big.Int, nestedStruct MidLevelTestStruct) (*types.Transaction, error) { + return _LatestValueHolder.Contract.TriggerEvent(&_LatestValueHolder.TransactOpts, field, differentField, oracleId, oracleIds, account, accounts, bigField, nestedStruct) +} + +func (_LatestValueHolder *LatestValueHolderTransactor) TriggerEventWithDynamicTopic(opts *bind.TransactOpts, field string) (*types.Transaction, error) { + return _LatestValueHolder.contract.Transact(opts, "triggerEventWithDynamicTopic", field) +} + +func (_LatestValueHolder *LatestValueHolderSession) TriggerEventWithDynamicTopic(field string) (*types.Transaction, error) { + return _LatestValueHolder.Contract.TriggerEventWithDynamicTopic(&_LatestValueHolder.TransactOpts, field) +} + +func (_LatestValueHolder *LatestValueHolderTransactorSession) TriggerEventWithDynamicTopic(field string) (*types.Transaction, error) { + return _LatestValueHolder.Contract.TriggerEventWithDynamicTopic(&_LatestValueHolder.TransactOpts, field) +} + +func (_LatestValueHolder *LatestValueHolderTransactor) TriggerWithFourTopics(opts *bind.TransactOpts, field1 int32, field2 int32, field3 int32) (*types.Transaction, error) { + return _LatestValueHolder.contract.Transact(opts, "triggerWithFourTopics", field1, field2, field3) +} + +func (_LatestValueHolder *LatestValueHolderSession) TriggerWithFourTopics(field1 int32, field2 int32, field3 int32) (*types.Transaction, error) { + return _LatestValueHolder.Contract.TriggerWithFourTopics(&_LatestValueHolder.TransactOpts, field1, field2, field3) +} + +func (_LatestValueHolder *LatestValueHolderTransactorSession) TriggerWithFourTopics(field1 int32, field2 int32, field3 int32) (*types.Transaction, error) { + return _LatestValueHolder.Contract.TriggerWithFourTopics(&_LatestValueHolder.TransactOpts, field1, field2, field3) +} + +type LatestValueHolderTriggeredIterator struct { + Event *LatestValueHolderTriggered + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *LatestValueHolderTriggeredIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(LatestValueHolderTriggered) + 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(LatestValueHolderTriggered) + 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 *LatestValueHolderTriggeredIterator) Error() error { + return it.fail +} + +func (it *LatestValueHolderTriggeredIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type LatestValueHolderTriggered struct { + Field int32 + DifferentField string + OracleId uint8 + OracleIds [32]uint8 + Account common.Address + Accounts []common.Address + BigField *big.Int + NestedStruct MidLevelTestStruct + Raw types.Log +} + +func (_LatestValueHolder *LatestValueHolderFilterer) FilterTriggered(opts *bind.FilterOpts, field []int32) (*LatestValueHolderTriggeredIterator, error) { + + var fieldRule []interface{} + for _, fieldItem := range field { + fieldRule = append(fieldRule, fieldItem) + } + + logs, sub, err := _LatestValueHolder.contract.FilterLogs(opts, "Triggered", fieldRule) + if err != nil { + return nil, err + } + return &LatestValueHolderTriggeredIterator{contract: _LatestValueHolder.contract, event: "Triggered", logs: logs, sub: sub}, nil +} + +func (_LatestValueHolder *LatestValueHolderFilterer) WatchTriggered(opts *bind.WatchOpts, sink chan<- *LatestValueHolderTriggered, field []int32) (event.Subscription, error) { + + var fieldRule []interface{} + for _, fieldItem := range field { + fieldRule = append(fieldRule, fieldItem) + } + + logs, sub, err := _LatestValueHolder.contract.WatchLogs(opts, "Triggered", fieldRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(LatestValueHolderTriggered) + if err := _LatestValueHolder.contract.UnpackLog(event, "Triggered", 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 (_LatestValueHolder *LatestValueHolderFilterer) ParseTriggered(log types.Log) (*LatestValueHolderTriggered, error) { + event := new(LatestValueHolderTriggered) + if err := _LatestValueHolder.contract.UnpackLog(event, "Triggered", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type LatestValueHolderTriggeredEventWithDynamicTopicIterator struct { + Event *LatestValueHolderTriggeredEventWithDynamicTopic + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *LatestValueHolderTriggeredEventWithDynamicTopicIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(LatestValueHolderTriggeredEventWithDynamicTopic) + 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(LatestValueHolderTriggeredEventWithDynamicTopic) + 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 *LatestValueHolderTriggeredEventWithDynamicTopicIterator) Error() error { + return it.fail +} + +func (it *LatestValueHolderTriggeredEventWithDynamicTopicIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type LatestValueHolderTriggeredEventWithDynamicTopic struct { + FieldHash common.Hash + Field string + Raw types.Log +} + +func (_LatestValueHolder *LatestValueHolderFilterer) FilterTriggeredEventWithDynamicTopic(opts *bind.FilterOpts, fieldHash []string) (*LatestValueHolderTriggeredEventWithDynamicTopicIterator, error) { + + var fieldHashRule []interface{} + for _, fieldHashItem := range fieldHash { + fieldHashRule = append(fieldHashRule, fieldHashItem) + } + + logs, sub, err := _LatestValueHolder.contract.FilterLogs(opts, "TriggeredEventWithDynamicTopic", fieldHashRule) + if err != nil { + return nil, err + } + return &LatestValueHolderTriggeredEventWithDynamicTopicIterator{contract: _LatestValueHolder.contract, event: "TriggeredEventWithDynamicTopic", logs: logs, sub: sub}, nil +} + +func (_LatestValueHolder *LatestValueHolderFilterer) WatchTriggeredEventWithDynamicTopic(opts *bind.WatchOpts, sink chan<- *LatestValueHolderTriggeredEventWithDynamicTopic, fieldHash []string) (event.Subscription, error) { + + var fieldHashRule []interface{} + for _, fieldHashItem := range fieldHash { + fieldHashRule = append(fieldHashRule, fieldHashItem) + } + + logs, sub, err := _LatestValueHolder.contract.WatchLogs(opts, "TriggeredEventWithDynamicTopic", fieldHashRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(LatestValueHolderTriggeredEventWithDynamicTopic) + if err := _LatestValueHolder.contract.UnpackLog(event, "TriggeredEventWithDynamicTopic", 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 (_LatestValueHolder *LatestValueHolderFilterer) ParseTriggeredEventWithDynamicTopic(log types.Log) (*LatestValueHolderTriggeredEventWithDynamicTopic, error) { + event := new(LatestValueHolderTriggeredEventWithDynamicTopic) + if err := _LatestValueHolder.contract.UnpackLog(event, "TriggeredEventWithDynamicTopic", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type LatestValueHolderTriggeredWithFourTopicsIterator struct { + Event *LatestValueHolderTriggeredWithFourTopics + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *LatestValueHolderTriggeredWithFourTopicsIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(LatestValueHolderTriggeredWithFourTopics) + 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(LatestValueHolderTriggeredWithFourTopics) + 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 *LatestValueHolderTriggeredWithFourTopicsIterator) Error() error { + return it.fail +} + +func (it *LatestValueHolderTriggeredWithFourTopicsIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type LatestValueHolderTriggeredWithFourTopics struct { + Field1 int32 + Field2 int32 + Field3 int32 + Raw types.Log +} + +func (_LatestValueHolder *LatestValueHolderFilterer) FilterTriggeredWithFourTopics(opts *bind.FilterOpts, field1 []int32, field2 []int32, field3 []int32) (*LatestValueHolderTriggeredWithFourTopicsIterator, error) { + + var field1Rule []interface{} + for _, field1Item := range field1 { + field1Rule = append(field1Rule, field1Item) + } + var field2Rule []interface{} + for _, field2Item := range field2 { + field2Rule = append(field2Rule, field2Item) + } + var field3Rule []interface{} + for _, field3Item := range field3 { + field3Rule = append(field3Rule, field3Item) + } + + logs, sub, err := _LatestValueHolder.contract.FilterLogs(opts, "TriggeredWithFourTopics", field1Rule, field2Rule, field3Rule) + if err != nil { + return nil, err + } + return &LatestValueHolderTriggeredWithFourTopicsIterator{contract: _LatestValueHolder.contract, event: "TriggeredWithFourTopics", logs: logs, sub: sub}, nil +} + +func (_LatestValueHolder *LatestValueHolderFilterer) WatchTriggeredWithFourTopics(opts *bind.WatchOpts, sink chan<- *LatestValueHolderTriggeredWithFourTopics, field1 []int32, field2 []int32, field3 []int32) (event.Subscription, error) { + + var field1Rule []interface{} + for _, field1Item := range field1 { + field1Rule = append(field1Rule, field1Item) + } + var field2Rule []interface{} + for _, field2Item := range field2 { + field2Rule = append(field2Rule, field2Item) + } + var field3Rule []interface{} + for _, field3Item := range field3 { + field3Rule = append(field3Rule, field3Item) + } + + logs, sub, err := _LatestValueHolder.contract.WatchLogs(opts, "TriggeredWithFourTopics", field1Rule, field2Rule, field3Rule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(LatestValueHolderTriggeredWithFourTopics) + if err := _LatestValueHolder.contract.UnpackLog(event, "TriggeredWithFourTopics", 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 (_LatestValueHolder *LatestValueHolderFilterer) ParseTriggeredWithFourTopics(log types.Log) (*LatestValueHolderTriggeredWithFourTopics, error) { + event := new(LatestValueHolderTriggeredWithFourTopics) + if err := _LatestValueHolder.contract.UnpackLog(event, "TriggeredWithFourTopics", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +func (_LatestValueHolder *LatestValueHolder) ParseLog(log types.Log) (generated.AbigenLog, error) { + switch log.Topics[0] { + case _LatestValueHolder.abi.Events["Triggered"].ID: + return _LatestValueHolder.ParseTriggered(log) + case _LatestValueHolder.abi.Events["TriggeredEventWithDynamicTopic"].ID: + return _LatestValueHolder.ParseTriggeredEventWithDynamicTopic(log) + case _LatestValueHolder.abi.Events["TriggeredWithFourTopics"].ID: + return _LatestValueHolder.ParseTriggeredWithFourTopics(log) + + default: + return nil, fmt.Errorf("abigen wrapper received unknown log topic: %v", log.Topics[0]) + } +} + +func (LatestValueHolderTriggered) Topic() common.Hash { + return common.HexToHash("0x7188419dcd8b51877b71766f075f3626586c0ff190e7d056aa65ce9acb649a3d") +} + +func (LatestValueHolderTriggeredEventWithDynamicTopic) Topic() common.Hash { + return common.HexToHash("0x3d969732b1bbbb9f1d7eb9f3f14e4cb50a74d950b3ef916a397b85dfbab93c67") +} + +func (LatestValueHolderTriggeredWithFourTopics) Topic() common.Hash { + return common.HexToHash("0x91c80dc390f3d041b3a04b0099b19634499541ea26972250986ee4b24a12fac5") +} + +func (_LatestValueHolder *LatestValueHolder) Address() common.Address { + return _LatestValueHolder.address +} + +type LatestValueHolderInterface interface { + GetDifferentPrimitiveValue(opts *bind.CallOpts) (uint64, error) + + GetElementAtIndex(opts *bind.CallOpts, i *big.Int) (TestStruct, error) + + GetPrimitiveValue(opts *bind.CallOpts) (uint64, error) + + GetSliceValue(opts *bind.CallOpts) ([]uint64, error) + + ReturnSeen(opts *bind.CallOpts, field int32, differentField string, oracleId uint8, oracleIds [32]uint8, account common.Address, accounts []common.Address, bigField *big.Int, nestedStruct MidLevelTestStruct) (TestStruct, error) + + AddTestStruct(opts *bind.TransactOpts, field int32, differentField string, oracleId uint8, oracleIds [32]uint8, account common.Address, accounts []common.Address, bigField *big.Int, nestedStruct MidLevelTestStruct) (*types.Transaction, error) + + TriggerEvent(opts *bind.TransactOpts, field int32, differentField string, oracleId uint8, oracleIds [32]uint8, account common.Address, accounts []common.Address, bigField *big.Int, nestedStruct MidLevelTestStruct) (*types.Transaction, error) + + TriggerEventWithDynamicTopic(opts *bind.TransactOpts, field string) (*types.Transaction, error) + + TriggerWithFourTopics(opts *bind.TransactOpts, field1 int32, field2 int32, field3 int32) (*types.Transaction, error) + + FilterTriggered(opts *bind.FilterOpts, field []int32) (*LatestValueHolderTriggeredIterator, error) + + WatchTriggered(opts *bind.WatchOpts, sink chan<- *LatestValueHolderTriggered, field []int32) (event.Subscription, error) + + ParseTriggered(log types.Log) (*LatestValueHolderTriggered, error) + + FilterTriggeredEventWithDynamicTopic(opts *bind.FilterOpts, fieldHash []string) (*LatestValueHolderTriggeredEventWithDynamicTopicIterator, error) + + WatchTriggeredEventWithDynamicTopic(opts *bind.WatchOpts, sink chan<- *LatestValueHolderTriggeredEventWithDynamicTopic, fieldHash []string) (event.Subscription, error) + + ParseTriggeredEventWithDynamicTopic(log types.Log) (*LatestValueHolderTriggeredEventWithDynamicTopic, error) + + FilterTriggeredWithFourTopics(opts *bind.FilterOpts, field1 []int32, field2 []int32, field3 []int32) (*LatestValueHolderTriggeredWithFourTopicsIterator, error) + + WatchTriggeredWithFourTopics(opts *bind.WatchOpts, sink chan<- *LatestValueHolderTriggeredWithFourTopics, field1 []int32, field2 []int32, field3 []int32) (event.Subscription, error) + + ParseTriggeredWithFourTopics(log types.Log) (*LatestValueHolderTriggeredWithFourTopics, error) + + ParseLog(log types.Log) (generated.AbigenLog, error) + + Address() common.Address +} diff --git a/core/gethwrappers/generated/i_keeper_registry_master_wrapper_2_2/i_keeper_registry_master_wrapper_2_2.go b/core/gethwrappers/generated/i_keeper_registry_master_wrapper_2_2/i_keeper_registry_master_wrapper_2_2.go new file mode 100644 index 0000000000..964e54f189 --- /dev/null +++ b/core/gethwrappers/generated/i_keeper_registry_master_wrapper_2_2/i_keeper_registry_master_wrapper_2_2.go @@ -0,0 +1,6442 @@ +// Code generated - DO NOT EDIT. +// This file is a generated binding and any manual changes will be lost. + +package i_keeper_registry_master_wrapper_2_2 + +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 +) + +type AutomationRegistryBase22OnchainConfig struct { + PaymentPremiumPPB uint32 + FlatFeeMicroLink uint32 + CheckGasLimit uint32 + StalenessSeconds *big.Int + GasCeilingMultiplier uint16 + MinUpkeepSpend *big.Int + MaxPerformGas uint32 + MaxCheckDataSize uint32 + MaxPerformDataSize uint32 + MaxRevertDataSize uint32 + FallbackGasPrice *big.Int + FallbackLinkPrice *big.Int + Transcoder common.Address + Registrars []common.Address + UpkeepPrivilegeManager common.Address +} + +type AutomationRegistryBase22State struct { + Nonce uint32 + OwnerLinkBalance *big.Int + ExpectedLinkBalance *big.Int + TotalPremium *big.Int + NumUpkeeps *big.Int + ConfigCount uint32 + LatestConfigBlockNumber uint32 + LatestConfigDigest [32]byte + LatestEpoch uint32 + Paused bool +} + +type AutomationRegistryBase22UpkeepInfo struct { + Target common.Address + PerformGas uint32 + CheckData []byte + Balance *big.Int + Admin common.Address + MaxValidBlocknumber uint64 + LastPerformedBlockNumber uint32 + AmountSpent *big.Int + Paused bool + OffchainConfig []byte +} + +var IAutomationRegistryMasterMetaData = &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\":\"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\":\"structAutomationRegistryBase2_2.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\":\"structAutomationRegistryBase2_2.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\":\"structAutomationRegistryBase2_2.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\":\"structAutomationRegistryBase2_2.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 IAutomationRegistryMasterABI = IAutomationRegistryMasterMetaData.ABI + +type IAutomationRegistryMaster struct { + address common.Address + abi abi.ABI + IAutomationRegistryMasterCaller + IAutomationRegistryMasterTransactor + IAutomationRegistryMasterFilterer +} + +type IAutomationRegistryMasterCaller struct { + contract *bind.BoundContract +} + +type IAutomationRegistryMasterTransactor struct { + contract *bind.BoundContract +} + +type IAutomationRegistryMasterFilterer struct { + contract *bind.BoundContract +} + +type IAutomationRegistryMasterSession struct { + Contract *IAutomationRegistryMaster + CallOpts bind.CallOpts + TransactOpts bind.TransactOpts +} + +type IAutomationRegistryMasterCallerSession struct { + Contract *IAutomationRegistryMasterCaller + CallOpts bind.CallOpts +} + +type IAutomationRegistryMasterTransactorSession struct { + Contract *IAutomationRegistryMasterTransactor + TransactOpts bind.TransactOpts +} + +type IAutomationRegistryMasterRaw struct { + Contract *IAutomationRegistryMaster +} + +type IAutomationRegistryMasterCallerRaw struct { + Contract *IAutomationRegistryMasterCaller +} + +type IAutomationRegistryMasterTransactorRaw struct { + Contract *IAutomationRegistryMasterTransactor +} + +func NewIAutomationRegistryMaster(address common.Address, backend bind.ContractBackend) (*IAutomationRegistryMaster, error) { + abi, err := abi.JSON(strings.NewReader(IAutomationRegistryMasterABI)) + if err != nil { + return nil, err + } + contract, err := bindIAutomationRegistryMaster(address, backend, backend, backend) + if err != nil { + return nil, err + } + return &IAutomationRegistryMaster{address: address, abi: abi, IAutomationRegistryMasterCaller: IAutomationRegistryMasterCaller{contract: contract}, IAutomationRegistryMasterTransactor: IAutomationRegistryMasterTransactor{contract: contract}, IAutomationRegistryMasterFilterer: IAutomationRegistryMasterFilterer{contract: contract}}, nil +} + +func NewIAutomationRegistryMasterCaller(address common.Address, caller bind.ContractCaller) (*IAutomationRegistryMasterCaller, error) { + contract, err := bindIAutomationRegistryMaster(address, caller, nil, nil) + if err != nil { + return nil, err + } + return &IAutomationRegistryMasterCaller{contract: contract}, nil +} + +func NewIAutomationRegistryMasterTransactor(address common.Address, transactor bind.ContractTransactor) (*IAutomationRegistryMasterTransactor, error) { + contract, err := bindIAutomationRegistryMaster(address, nil, transactor, nil) + if err != nil { + return nil, err + } + return &IAutomationRegistryMasterTransactor{contract: contract}, nil +} + +func NewIAutomationRegistryMasterFilterer(address common.Address, filterer bind.ContractFilterer) (*IAutomationRegistryMasterFilterer, error) { + contract, err := bindIAutomationRegistryMaster(address, nil, nil, filterer) + if err != nil { + return nil, err + } + return &IAutomationRegistryMasterFilterer{contract: contract}, nil +} + +func bindIAutomationRegistryMaster(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) { + parsed, err := IAutomationRegistryMasterMetaData.GetAbi() + if err != nil { + return nil, err + } + return bind.NewBoundContract(address, *parsed, caller, transactor, filterer), nil +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _IAutomationRegistryMaster.Contract.IAutomationRegistryMasterCaller.contract.Call(opts, result, method, params...) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _IAutomationRegistryMaster.Contract.IAutomationRegistryMasterTransactor.contract.Transfer(opts) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _IAutomationRegistryMaster.Contract.IAutomationRegistryMasterTransactor.contract.Transact(opts, method, params...) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _IAutomationRegistryMaster.Contract.contract.Call(opts, result, method, params...) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _IAutomationRegistryMaster.Contract.contract.Transfer(opts) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _IAutomationRegistryMaster.Contract.contract.Transact(opts, method, params...) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterCaller) CheckCallback(opts *bind.CallOpts, id *big.Int, values [][]byte, extraData []byte) (CheckCallback, + + error) { + var out []interface{} + err := _IAutomationRegistryMaster.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 (_IAutomationRegistryMaster *IAutomationRegistryMasterSession) CheckCallback(id *big.Int, values [][]byte, extraData []byte) (CheckCallback, + + error) { + return _IAutomationRegistryMaster.Contract.CheckCallback(&_IAutomationRegistryMaster.CallOpts, id, values, extraData) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterCallerSession) CheckCallback(id *big.Int, values [][]byte, extraData []byte) (CheckCallback, + + error) { + return _IAutomationRegistryMaster.Contract.CheckCallback(&_IAutomationRegistryMaster.CallOpts, id, values, extraData) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterCaller) CheckUpkeep(opts *bind.CallOpts, id *big.Int, triggerData []byte) (CheckUpkeep, + + error) { + var out []interface{} + err := _IAutomationRegistryMaster.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 (_IAutomationRegistryMaster *IAutomationRegistryMasterSession) CheckUpkeep(id *big.Int, triggerData []byte) (CheckUpkeep, + + error) { + return _IAutomationRegistryMaster.Contract.CheckUpkeep(&_IAutomationRegistryMaster.CallOpts, id, triggerData) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterCallerSession) CheckUpkeep(id *big.Int, triggerData []byte) (CheckUpkeep, + + error) { + return _IAutomationRegistryMaster.Contract.CheckUpkeep(&_IAutomationRegistryMaster.CallOpts, id, triggerData) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterCaller) CheckUpkeep0(opts *bind.CallOpts, id *big.Int) (CheckUpkeep0, + + error) { + var out []interface{} + err := _IAutomationRegistryMaster.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 (_IAutomationRegistryMaster *IAutomationRegistryMasterSession) CheckUpkeep0(id *big.Int) (CheckUpkeep0, + + error) { + return _IAutomationRegistryMaster.Contract.CheckUpkeep0(&_IAutomationRegistryMaster.CallOpts, id) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterCallerSession) CheckUpkeep0(id *big.Int) (CheckUpkeep0, + + error) { + return _IAutomationRegistryMaster.Contract.CheckUpkeep0(&_IAutomationRegistryMaster.CallOpts, id) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterCaller) FallbackTo(opts *bind.CallOpts) (common.Address, error) { + var out []interface{} + err := _IAutomationRegistryMaster.contract.Call(opts, &out, "fallbackTo") + + if err != nil { + return *new(common.Address), err + } + + out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) + + return out0, err + +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterSession) FallbackTo() (common.Address, error) { + return _IAutomationRegistryMaster.Contract.FallbackTo(&_IAutomationRegistryMaster.CallOpts) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterCallerSession) FallbackTo() (common.Address, error) { + return _IAutomationRegistryMaster.Contract.FallbackTo(&_IAutomationRegistryMaster.CallOpts) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterCaller) GetActiveUpkeepIDs(opts *bind.CallOpts, startIndex *big.Int, maxCount *big.Int) ([]*big.Int, error) { + var out []interface{} + err := _IAutomationRegistryMaster.contract.Call(opts, &out, "getActiveUpkeepIDs", startIndex, maxCount) + + if err != nil { + return *new([]*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new([]*big.Int)).(*[]*big.Int) + + return out0, err + +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterSession) GetActiveUpkeepIDs(startIndex *big.Int, maxCount *big.Int) ([]*big.Int, error) { + return _IAutomationRegistryMaster.Contract.GetActiveUpkeepIDs(&_IAutomationRegistryMaster.CallOpts, startIndex, maxCount) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterCallerSession) GetActiveUpkeepIDs(startIndex *big.Int, maxCount *big.Int) ([]*big.Int, error) { + return _IAutomationRegistryMaster.Contract.GetActiveUpkeepIDs(&_IAutomationRegistryMaster.CallOpts, startIndex, maxCount) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterCaller) GetAdminPrivilegeConfig(opts *bind.CallOpts, admin common.Address) ([]byte, error) { + var out []interface{} + err := _IAutomationRegistryMaster.contract.Call(opts, &out, "getAdminPrivilegeConfig", admin) + + if err != nil { + return *new([]byte), err + } + + out0 := *abi.ConvertType(out[0], new([]byte)).(*[]byte) + + return out0, err + +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterSession) GetAdminPrivilegeConfig(admin common.Address) ([]byte, error) { + return _IAutomationRegistryMaster.Contract.GetAdminPrivilegeConfig(&_IAutomationRegistryMaster.CallOpts, admin) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterCallerSession) GetAdminPrivilegeConfig(admin common.Address) ([]byte, error) { + return _IAutomationRegistryMaster.Contract.GetAdminPrivilegeConfig(&_IAutomationRegistryMaster.CallOpts, admin) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterCaller) GetAutomationForwarderLogic(opts *bind.CallOpts) (common.Address, error) { + var out []interface{} + err := _IAutomationRegistryMaster.contract.Call(opts, &out, "getAutomationForwarderLogic") + + if err != nil { + return *new(common.Address), err + } + + out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) + + return out0, err + +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterSession) GetAutomationForwarderLogic() (common.Address, error) { + return _IAutomationRegistryMaster.Contract.GetAutomationForwarderLogic(&_IAutomationRegistryMaster.CallOpts) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterCallerSession) GetAutomationForwarderLogic() (common.Address, error) { + return _IAutomationRegistryMaster.Contract.GetAutomationForwarderLogic(&_IAutomationRegistryMaster.CallOpts) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterCaller) GetBalance(opts *bind.CallOpts, id *big.Int) (*big.Int, error) { + var out []interface{} + err := _IAutomationRegistryMaster.contract.Call(opts, &out, "getBalance", id) + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterSession) GetBalance(id *big.Int) (*big.Int, error) { + return _IAutomationRegistryMaster.Contract.GetBalance(&_IAutomationRegistryMaster.CallOpts, id) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterCallerSession) GetBalance(id *big.Int) (*big.Int, error) { + return _IAutomationRegistryMaster.Contract.GetBalance(&_IAutomationRegistryMaster.CallOpts, id) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterCaller) GetCancellationDelay(opts *bind.CallOpts) (*big.Int, error) { + var out []interface{} + err := _IAutomationRegistryMaster.contract.Call(opts, &out, "getCancellationDelay") + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterSession) GetCancellationDelay() (*big.Int, error) { + return _IAutomationRegistryMaster.Contract.GetCancellationDelay(&_IAutomationRegistryMaster.CallOpts) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterCallerSession) GetCancellationDelay() (*big.Int, error) { + return _IAutomationRegistryMaster.Contract.GetCancellationDelay(&_IAutomationRegistryMaster.CallOpts) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterCaller) GetConditionalGasOverhead(opts *bind.CallOpts) (*big.Int, error) { + var out []interface{} + err := _IAutomationRegistryMaster.contract.Call(opts, &out, "getConditionalGasOverhead") + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterSession) GetConditionalGasOverhead() (*big.Int, error) { + return _IAutomationRegistryMaster.Contract.GetConditionalGasOverhead(&_IAutomationRegistryMaster.CallOpts) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterCallerSession) GetConditionalGasOverhead() (*big.Int, error) { + return _IAutomationRegistryMaster.Contract.GetConditionalGasOverhead(&_IAutomationRegistryMaster.CallOpts) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterCaller) GetFastGasFeedAddress(opts *bind.CallOpts) (common.Address, error) { + var out []interface{} + err := _IAutomationRegistryMaster.contract.Call(opts, &out, "getFastGasFeedAddress") + + if err != nil { + return *new(common.Address), err + } + + out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) + + return out0, err + +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterSession) GetFastGasFeedAddress() (common.Address, error) { + return _IAutomationRegistryMaster.Contract.GetFastGasFeedAddress(&_IAutomationRegistryMaster.CallOpts) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterCallerSession) GetFastGasFeedAddress() (common.Address, error) { + return _IAutomationRegistryMaster.Contract.GetFastGasFeedAddress(&_IAutomationRegistryMaster.CallOpts) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterCaller) GetForwarder(opts *bind.CallOpts, upkeepID *big.Int) (common.Address, error) { + var out []interface{} + err := _IAutomationRegistryMaster.contract.Call(opts, &out, "getForwarder", upkeepID) + + if err != nil { + return *new(common.Address), err + } + + out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) + + return out0, err + +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterSession) GetForwarder(upkeepID *big.Int) (common.Address, error) { + return _IAutomationRegistryMaster.Contract.GetForwarder(&_IAutomationRegistryMaster.CallOpts, upkeepID) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterCallerSession) GetForwarder(upkeepID *big.Int) (common.Address, error) { + return _IAutomationRegistryMaster.Contract.GetForwarder(&_IAutomationRegistryMaster.CallOpts, upkeepID) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterCaller) GetLinkAddress(opts *bind.CallOpts) (common.Address, error) { + var out []interface{} + err := _IAutomationRegistryMaster.contract.Call(opts, &out, "getLinkAddress") + + if err != nil { + return *new(common.Address), err + } + + out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) + + return out0, err + +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterSession) GetLinkAddress() (common.Address, error) { + return _IAutomationRegistryMaster.Contract.GetLinkAddress(&_IAutomationRegistryMaster.CallOpts) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterCallerSession) GetLinkAddress() (common.Address, error) { + return _IAutomationRegistryMaster.Contract.GetLinkAddress(&_IAutomationRegistryMaster.CallOpts) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterCaller) GetLinkNativeFeedAddress(opts *bind.CallOpts) (common.Address, error) { + var out []interface{} + err := _IAutomationRegistryMaster.contract.Call(opts, &out, "getLinkNativeFeedAddress") + + if err != nil { + return *new(common.Address), err + } + + out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) + + return out0, err + +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterSession) GetLinkNativeFeedAddress() (common.Address, error) { + return _IAutomationRegistryMaster.Contract.GetLinkNativeFeedAddress(&_IAutomationRegistryMaster.CallOpts) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterCallerSession) GetLinkNativeFeedAddress() (common.Address, error) { + return _IAutomationRegistryMaster.Contract.GetLinkNativeFeedAddress(&_IAutomationRegistryMaster.CallOpts) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterCaller) GetLogGasOverhead(opts *bind.CallOpts) (*big.Int, error) { + var out []interface{} + err := _IAutomationRegistryMaster.contract.Call(opts, &out, "getLogGasOverhead") + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterSession) GetLogGasOverhead() (*big.Int, error) { + return _IAutomationRegistryMaster.Contract.GetLogGasOverhead(&_IAutomationRegistryMaster.CallOpts) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterCallerSession) GetLogGasOverhead() (*big.Int, error) { + return _IAutomationRegistryMaster.Contract.GetLogGasOverhead(&_IAutomationRegistryMaster.CallOpts) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterCaller) GetMaxPaymentForGas(opts *bind.CallOpts, triggerType uint8, gasLimit uint32) (*big.Int, error) { + var out []interface{} + err := _IAutomationRegistryMaster.contract.Call(opts, &out, "getMaxPaymentForGas", triggerType, gasLimit) + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterSession) GetMaxPaymentForGas(triggerType uint8, gasLimit uint32) (*big.Int, error) { + return _IAutomationRegistryMaster.Contract.GetMaxPaymentForGas(&_IAutomationRegistryMaster.CallOpts, triggerType, gasLimit) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterCallerSession) GetMaxPaymentForGas(triggerType uint8, gasLimit uint32) (*big.Int, error) { + return _IAutomationRegistryMaster.Contract.GetMaxPaymentForGas(&_IAutomationRegistryMaster.CallOpts, triggerType, gasLimit) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterCaller) GetMinBalance(opts *bind.CallOpts, id *big.Int) (*big.Int, error) { + var out []interface{} + err := _IAutomationRegistryMaster.contract.Call(opts, &out, "getMinBalance", id) + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterSession) GetMinBalance(id *big.Int) (*big.Int, error) { + return _IAutomationRegistryMaster.Contract.GetMinBalance(&_IAutomationRegistryMaster.CallOpts, id) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterCallerSession) GetMinBalance(id *big.Int) (*big.Int, error) { + return _IAutomationRegistryMaster.Contract.GetMinBalance(&_IAutomationRegistryMaster.CallOpts, id) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterCaller) GetMinBalanceForUpkeep(opts *bind.CallOpts, id *big.Int) (*big.Int, error) { + var out []interface{} + err := _IAutomationRegistryMaster.contract.Call(opts, &out, "getMinBalanceForUpkeep", id) + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterSession) GetMinBalanceForUpkeep(id *big.Int) (*big.Int, error) { + return _IAutomationRegistryMaster.Contract.GetMinBalanceForUpkeep(&_IAutomationRegistryMaster.CallOpts, id) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterCallerSession) GetMinBalanceForUpkeep(id *big.Int) (*big.Int, error) { + return _IAutomationRegistryMaster.Contract.GetMinBalanceForUpkeep(&_IAutomationRegistryMaster.CallOpts, id) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterCaller) GetMode(opts *bind.CallOpts) (uint8, error) { + var out []interface{} + err := _IAutomationRegistryMaster.contract.Call(opts, &out, "getMode") + + if err != nil { + return *new(uint8), err + } + + out0 := *abi.ConvertType(out[0], new(uint8)).(*uint8) + + return out0, err + +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterSession) GetMode() (uint8, error) { + return _IAutomationRegistryMaster.Contract.GetMode(&_IAutomationRegistryMaster.CallOpts) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterCallerSession) GetMode() (uint8, error) { + return _IAutomationRegistryMaster.Contract.GetMode(&_IAutomationRegistryMaster.CallOpts) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterCaller) GetPeerRegistryMigrationPermission(opts *bind.CallOpts, peer common.Address) (uint8, error) { + var out []interface{} + err := _IAutomationRegistryMaster.contract.Call(opts, &out, "getPeerRegistryMigrationPermission", peer) + + if err != nil { + return *new(uint8), err + } + + out0 := *abi.ConvertType(out[0], new(uint8)).(*uint8) + + return out0, err + +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterSession) GetPeerRegistryMigrationPermission(peer common.Address) (uint8, error) { + return _IAutomationRegistryMaster.Contract.GetPeerRegistryMigrationPermission(&_IAutomationRegistryMaster.CallOpts, peer) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterCallerSession) GetPeerRegistryMigrationPermission(peer common.Address) (uint8, error) { + return _IAutomationRegistryMaster.Contract.GetPeerRegistryMigrationPermission(&_IAutomationRegistryMaster.CallOpts, peer) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterCaller) GetPerPerformByteGasOverhead(opts *bind.CallOpts) (*big.Int, error) { + var out []interface{} + err := _IAutomationRegistryMaster.contract.Call(opts, &out, "getPerPerformByteGasOverhead") + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterSession) GetPerPerformByteGasOverhead() (*big.Int, error) { + return _IAutomationRegistryMaster.Contract.GetPerPerformByteGasOverhead(&_IAutomationRegistryMaster.CallOpts) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterCallerSession) GetPerPerformByteGasOverhead() (*big.Int, error) { + return _IAutomationRegistryMaster.Contract.GetPerPerformByteGasOverhead(&_IAutomationRegistryMaster.CallOpts) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterCaller) GetPerSignerGasOverhead(opts *bind.CallOpts) (*big.Int, error) { + var out []interface{} + err := _IAutomationRegistryMaster.contract.Call(opts, &out, "getPerSignerGasOverhead") + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterSession) GetPerSignerGasOverhead() (*big.Int, error) { + return _IAutomationRegistryMaster.Contract.GetPerSignerGasOverhead(&_IAutomationRegistryMaster.CallOpts) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterCallerSession) GetPerSignerGasOverhead() (*big.Int, error) { + return _IAutomationRegistryMaster.Contract.GetPerSignerGasOverhead(&_IAutomationRegistryMaster.CallOpts) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterCaller) GetSignerInfo(opts *bind.CallOpts, query common.Address) (GetSignerInfo, + + error) { + var out []interface{} + err := _IAutomationRegistryMaster.contract.Call(opts, &out, "getSignerInfo", query) + + outstruct := new(GetSignerInfo) + if err != nil { + return *outstruct, err + } + + outstruct.Active = *abi.ConvertType(out[0], new(bool)).(*bool) + outstruct.Index = *abi.ConvertType(out[1], new(uint8)).(*uint8) + + return *outstruct, err + +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterSession) GetSignerInfo(query common.Address) (GetSignerInfo, + + error) { + return _IAutomationRegistryMaster.Contract.GetSignerInfo(&_IAutomationRegistryMaster.CallOpts, query) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterCallerSession) GetSignerInfo(query common.Address) (GetSignerInfo, + + error) { + return _IAutomationRegistryMaster.Contract.GetSignerInfo(&_IAutomationRegistryMaster.CallOpts, query) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterCaller) GetState(opts *bind.CallOpts) (GetState, + + error) { + var out []interface{} + err := _IAutomationRegistryMaster.contract.Call(opts, &out, "getState") + + outstruct := new(GetState) + if err != nil { + return *outstruct, err + } + + outstruct.State = *abi.ConvertType(out[0], new(AutomationRegistryBase22State)).(*AutomationRegistryBase22State) + outstruct.Config = *abi.ConvertType(out[1], new(AutomationRegistryBase22OnchainConfig)).(*AutomationRegistryBase22OnchainConfig) + outstruct.Signers = *abi.ConvertType(out[2], new([]common.Address)).(*[]common.Address) + outstruct.Transmitters = *abi.ConvertType(out[3], new([]common.Address)).(*[]common.Address) + outstruct.F = *abi.ConvertType(out[4], new(uint8)).(*uint8) + + return *outstruct, err + +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterSession) GetState() (GetState, + + error) { + return _IAutomationRegistryMaster.Contract.GetState(&_IAutomationRegistryMaster.CallOpts) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterCallerSession) GetState() (GetState, + + error) { + return _IAutomationRegistryMaster.Contract.GetState(&_IAutomationRegistryMaster.CallOpts) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterCaller) GetTransmitterInfo(opts *bind.CallOpts, query common.Address) (GetTransmitterInfo, + + error) { + var out []interface{} + err := _IAutomationRegistryMaster.contract.Call(opts, &out, "getTransmitterInfo", query) + + outstruct := new(GetTransmitterInfo) + if err != nil { + return *outstruct, err + } + + outstruct.Active = *abi.ConvertType(out[0], new(bool)).(*bool) + outstruct.Index = *abi.ConvertType(out[1], new(uint8)).(*uint8) + outstruct.Balance = *abi.ConvertType(out[2], new(*big.Int)).(**big.Int) + outstruct.LastCollected = *abi.ConvertType(out[3], new(*big.Int)).(**big.Int) + outstruct.Payee = *abi.ConvertType(out[4], new(common.Address)).(*common.Address) + + return *outstruct, err + +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterSession) GetTransmitterInfo(query common.Address) (GetTransmitterInfo, + + error) { + return _IAutomationRegistryMaster.Contract.GetTransmitterInfo(&_IAutomationRegistryMaster.CallOpts, query) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterCallerSession) GetTransmitterInfo(query common.Address) (GetTransmitterInfo, + + error) { + return _IAutomationRegistryMaster.Contract.GetTransmitterInfo(&_IAutomationRegistryMaster.CallOpts, query) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterCaller) GetTriggerType(opts *bind.CallOpts, upkeepId *big.Int) (uint8, error) { + var out []interface{} + err := _IAutomationRegistryMaster.contract.Call(opts, &out, "getTriggerType", upkeepId) + + if err != nil { + return *new(uint8), err + } + + out0 := *abi.ConvertType(out[0], new(uint8)).(*uint8) + + return out0, err + +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterSession) GetTriggerType(upkeepId *big.Int) (uint8, error) { + return _IAutomationRegistryMaster.Contract.GetTriggerType(&_IAutomationRegistryMaster.CallOpts, upkeepId) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterCallerSession) GetTriggerType(upkeepId *big.Int) (uint8, error) { + return _IAutomationRegistryMaster.Contract.GetTriggerType(&_IAutomationRegistryMaster.CallOpts, upkeepId) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterCaller) GetUpkeep(opts *bind.CallOpts, id *big.Int) (AutomationRegistryBase22UpkeepInfo, error) { + var out []interface{} + err := _IAutomationRegistryMaster.contract.Call(opts, &out, "getUpkeep", id) + + if err != nil { + return *new(AutomationRegistryBase22UpkeepInfo), err + } + + out0 := *abi.ConvertType(out[0], new(AutomationRegistryBase22UpkeepInfo)).(*AutomationRegistryBase22UpkeepInfo) + + return out0, err + +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterSession) GetUpkeep(id *big.Int) (AutomationRegistryBase22UpkeepInfo, error) { + return _IAutomationRegistryMaster.Contract.GetUpkeep(&_IAutomationRegistryMaster.CallOpts, id) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterCallerSession) GetUpkeep(id *big.Int) (AutomationRegistryBase22UpkeepInfo, error) { + return _IAutomationRegistryMaster.Contract.GetUpkeep(&_IAutomationRegistryMaster.CallOpts, id) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterCaller) GetUpkeepPrivilegeConfig(opts *bind.CallOpts, upkeepId *big.Int) ([]byte, error) { + var out []interface{} + err := _IAutomationRegistryMaster.contract.Call(opts, &out, "getUpkeepPrivilegeConfig", upkeepId) + + if err != nil { + return *new([]byte), err + } + + out0 := *abi.ConvertType(out[0], new([]byte)).(*[]byte) + + return out0, err + +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterSession) GetUpkeepPrivilegeConfig(upkeepId *big.Int) ([]byte, error) { + return _IAutomationRegistryMaster.Contract.GetUpkeepPrivilegeConfig(&_IAutomationRegistryMaster.CallOpts, upkeepId) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterCallerSession) GetUpkeepPrivilegeConfig(upkeepId *big.Int) ([]byte, error) { + return _IAutomationRegistryMaster.Contract.GetUpkeepPrivilegeConfig(&_IAutomationRegistryMaster.CallOpts, upkeepId) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterCaller) GetUpkeepTriggerConfig(opts *bind.CallOpts, upkeepId *big.Int) ([]byte, error) { + var out []interface{} + err := _IAutomationRegistryMaster.contract.Call(opts, &out, "getUpkeepTriggerConfig", upkeepId) + + if err != nil { + return *new([]byte), err + } + + out0 := *abi.ConvertType(out[0], new([]byte)).(*[]byte) + + return out0, err + +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterSession) GetUpkeepTriggerConfig(upkeepId *big.Int) ([]byte, error) { + return _IAutomationRegistryMaster.Contract.GetUpkeepTriggerConfig(&_IAutomationRegistryMaster.CallOpts, upkeepId) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterCallerSession) GetUpkeepTriggerConfig(upkeepId *big.Int) ([]byte, error) { + return _IAutomationRegistryMaster.Contract.GetUpkeepTriggerConfig(&_IAutomationRegistryMaster.CallOpts, upkeepId) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterCaller) HasDedupKey(opts *bind.CallOpts, dedupKey [32]byte) (bool, error) { + var out []interface{} + err := _IAutomationRegistryMaster.contract.Call(opts, &out, "hasDedupKey", dedupKey) + + if err != nil { + return *new(bool), err + } + + out0 := *abi.ConvertType(out[0], new(bool)).(*bool) + + return out0, err + +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterSession) HasDedupKey(dedupKey [32]byte) (bool, error) { + return _IAutomationRegistryMaster.Contract.HasDedupKey(&_IAutomationRegistryMaster.CallOpts, dedupKey) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterCallerSession) HasDedupKey(dedupKey [32]byte) (bool, error) { + return _IAutomationRegistryMaster.Contract.HasDedupKey(&_IAutomationRegistryMaster.CallOpts, dedupKey) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterCaller) LatestConfigDetails(opts *bind.CallOpts) (LatestConfigDetails, + + error) { + var out []interface{} + err := _IAutomationRegistryMaster.contract.Call(opts, &out, "latestConfigDetails") + + outstruct := new(LatestConfigDetails) + if err != nil { + return *outstruct, err + } + + outstruct.ConfigCount = *abi.ConvertType(out[0], new(uint32)).(*uint32) + outstruct.BlockNumber = *abi.ConvertType(out[1], new(uint32)).(*uint32) + outstruct.ConfigDigest = *abi.ConvertType(out[2], new([32]byte)).(*[32]byte) + + return *outstruct, err + +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterSession) LatestConfigDetails() (LatestConfigDetails, + + error) { + return _IAutomationRegistryMaster.Contract.LatestConfigDetails(&_IAutomationRegistryMaster.CallOpts) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterCallerSession) LatestConfigDetails() (LatestConfigDetails, + + error) { + return _IAutomationRegistryMaster.Contract.LatestConfigDetails(&_IAutomationRegistryMaster.CallOpts) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterCaller) LatestConfigDigestAndEpoch(opts *bind.CallOpts) (LatestConfigDigestAndEpoch, + + error) { + var out []interface{} + err := _IAutomationRegistryMaster.contract.Call(opts, &out, "latestConfigDigestAndEpoch") + + outstruct := new(LatestConfigDigestAndEpoch) + if err != nil { + return *outstruct, err + } + + outstruct.ScanLogs = *abi.ConvertType(out[0], new(bool)).(*bool) + outstruct.ConfigDigest = *abi.ConvertType(out[1], new([32]byte)).(*[32]byte) + outstruct.Epoch = *abi.ConvertType(out[2], new(uint32)).(*uint32) + + return *outstruct, err + +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterSession) LatestConfigDigestAndEpoch() (LatestConfigDigestAndEpoch, + + error) { + return _IAutomationRegistryMaster.Contract.LatestConfigDigestAndEpoch(&_IAutomationRegistryMaster.CallOpts) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterCallerSession) LatestConfigDigestAndEpoch() (LatestConfigDigestAndEpoch, + + error) { + return _IAutomationRegistryMaster.Contract.LatestConfigDigestAndEpoch(&_IAutomationRegistryMaster.CallOpts) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterCaller) Owner(opts *bind.CallOpts) (common.Address, error) { + var out []interface{} + err := _IAutomationRegistryMaster.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 (_IAutomationRegistryMaster *IAutomationRegistryMasterSession) Owner() (common.Address, error) { + return _IAutomationRegistryMaster.Contract.Owner(&_IAutomationRegistryMaster.CallOpts) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterCallerSession) Owner() (common.Address, error) { + return _IAutomationRegistryMaster.Contract.Owner(&_IAutomationRegistryMaster.CallOpts) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterCaller) SimulatePerformUpkeep(opts *bind.CallOpts, id *big.Int, performData []byte) (SimulatePerformUpkeep, + + error) { + var out []interface{} + err := _IAutomationRegistryMaster.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 (_IAutomationRegistryMaster *IAutomationRegistryMasterSession) SimulatePerformUpkeep(id *big.Int, performData []byte) (SimulatePerformUpkeep, + + error) { + return _IAutomationRegistryMaster.Contract.SimulatePerformUpkeep(&_IAutomationRegistryMaster.CallOpts, id, performData) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterCallerSession) SimulatePerformUpkeep(id *big.Int, performData []byte) (SimulatePerformUpkeep, + + error) { + return _IAutomationRegistryMaster.Contract.SimulatePerformUpkeep(&_IAutomationRegistryMaster.CallOpts, id, performData) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterCaller) TypeAndVersion(opts *bind.CallOpts) (string, error) { + var out []interface{} + err := _IAutomationRegistryMaster.contract.Call(opts, &out, "typeAndVersion") + + if err != nil { + return *new(string), err + } + + out0 := *abi.ConvertType(out[0], new(string)).(*string) + + return out0, err + +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterSession) TypeAndVersion() (string, error) { + return _IAutomationRegistryMaster.Contract.TypeAndVersion(&_IAutomationRegistryMaster.CallOpts) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterCallerSession) TypeAndVersion() (string, error) { + return _IAutomationRegistryMaster.Contract.TypeAndVersion(&_IAutomationRegistryMaster.CallOpts) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterCaller) UpkeepTranscoderVersion(opts *bind.CallOpts) (uint8, error) { + var out []interface{} + err := _IAutomationRegistryMaster.contract.Call(opts, &out, "upkeepTranscoderVersion") + + if err != nil { + return *new(uint8), err + } + + out0 := *abi.ConvertType(out[0], new(uint8)).(*uint8) + + return out0, err + +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterSession) UpkeepTranscoderVersion() (uint8, error) { + return _IAutomationRegistryMaster.Contract.UpkeepTranscoderVersion(&_IAutomationRegistryMaster.CallOpts) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterCallerSession) UpkeepTranscoderVersion() (uint8, error) { + return _IAutomationRegistryMaster.Contract.UpkeepTranscoderVersion(&_IAutomationRegistryMaster.CallOpts) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterCaller) UpkeepVersion(opts *bind.CallOpts) (uint8, error) { + var out []interface{} + err := _IAutomationRegistryMaster.contract.Call(opts, &out, "upkeepVersion") + + if err != nil { + return *new(uint8), err + } + + out0 := *abi.ConvertType(out[0], new(uint8)).(*uint8) + + return out0, err + +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterSession) UpkeepVersion() (uint8, error) { + return _IAutomationRegistryMaster.Contract.UpkeepVersion(&_IAutomationRegistryMaster.CallOpts) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterCallerSession) UpkeepVersion() (uint8, error) { + return _IAutomationRegistryMaster.Contract.UpkeepVersion(&_IAutomationRegistryMaster.CallOpts) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterTransactor) AcceptOwnership(opts *bind.TransactOpts) (*types.Transaction, error) { + return _IAutomationRegistryMaster.contract.Transact(opts, "acceptOwnership") +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterSession) AcceptOwnership() (*types.Transaction, error) { + return _IAutomationRegistryMaster.Contract.AcceptOwnership(&_IAutomationRegistryMaster.TransactOpts) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterTransactorSession) AcceptOwnership() (*types.Transaction, error) { + return _IAutomationRegistryMaster.Contract.AcceptOwnership(&_IAutomationRegistryMaster.TransactOpts) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterTransactor) AcceptPayeeship(opts *bind.TransactOpts, transmitter common.Address) (*types.Transaction, error) { + return _IAutomationRegistryMaster.contract.Transact(opts, "acceptPayeeship", transmitter) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterSession) AcceptPayeeship(transmitter common.Address) (*types.Transaction, error) { + return _IAutomationRegistryMaster.Contract.AcceptPayeeship(&_IAutomationRegistryMaster.TransactOpts, transmitter) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterTransactorSession) AcceptPayeeship(transmitter common.Address) (*types.Transaction, error) { + return _IAutomationRegistryMaster.Contract.AcceptPayeeship(&_IAutomationRegistryMaster.TransactOpts, transmitter) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterTransactor) AcceptUpkeepAdmin(opts *bind.TransactOpts, id *big.Int) (*types.Transaction, error) { + return _IAutomationRegistryMaster.contract.Transact(opts, "acceptUpkeepAdmin", id) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterSession) AcceptUpkeepAdmin(id *big.Int) (*types.Transaction, error) { + return _IAutomationRegistryMaster.Contract.AcceptUpkeepAdmin(&_IAutomationRegistryMaster.TransactOpts, id) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterTransactorSession) AcceptUpkeepAdmin(id *big.Int) (*types.Transaction, error) { + return _IAutomationRegistryMaster.Contract.AcceptUpkeepAdmin(&_IAutomationRegistryMaster.TransactOpts, id) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterTransactor) AddFunds(opts *bind.TransactOpts, id *big.Int, amount *big.Int) (*types.Transaction, error) { + return _IAutomationRegistryMaster.contract.Transact(opts, "addFunds", id, amount) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterSession) AddFunds(id *big.Int, amount *big.Int) (*types.Transaction, error) { + return _IAutomationRegistryMaster.Contract.AddFunds(&_IAutomationRegistryMaster.TransactOpts, id, amount) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterTransactorSession) AddFunds(id *big.Int, amount *big.Int) (*types.Transaction, error) { + return _IAutomationRegistryMaster.Contract.AddFunds(&_IAutomationRegistryMaster.TransactOpts, id, amount) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterTransactor) CancelUpkeep(opts *bind.TransactOpts, id *big.Int) (*types.Transaction, error) { + return _IAutomationRegistryMaster.contract.Transact(opts, "cancelUpkeep", id) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterSession) CancelUpkeep(id *big.Int) (*types.Transaction, error) { + return _IAutomationRegistryMaster.Contract.CancelUpkeep(&_IAutomationRegistryMaster.TransactOpts, id) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterTransactorSession) CancelUpkeep(id *big.Int) (*types.Transaction, error) { + return _IAutomationRegistryMaster.Contract.CancelUpkeep(&_IAutomationRegistryMaster.TransactOpts, id) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterTransactor) ExecuteCallback(opts *bind.TransactOpts, id *big.Int, payload []byte) (*types.Transaction, error) { + return _IAutomationRegistryMaster.contract.Transact(opts, "executeCallback", id, payload) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterSession) ExecuteCallback(id *big.Int, payload []byte) (*types.Transaction, error) { + return _IAutomationRegistryMaster.Contract.ExecuteCallback(&_IAutomationRegistryMaster.TransactOpts, id, payload) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterTransactorSession) ExecuteCallback(id *big.Int, payload []byte) (*types.Transaction, error) { + return _IAutomationRegistryMaster.Contract.ExecuteCallback(&_IAutomationRegistryMaster.TransactOpts, id, payload) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterTransactor) MigrateUpkeeps(opts *bind.TransactOpts, ids []*big.Int, destination common.Address) (*types.Transaction, error) { + return _IAutomationRegistryMaster.contract.Transact(opts, "migrateUpkeeps", ids, destination) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterSession) MigrateUpkeeps(ids []*big.Int, destination common.Address) (*types.Transaction, error) { + return _IAutomationRegistryMaster.Contract.MigrateUpkeeps(&_IAutomationRegistryMaster.TransactOpts, ids, destination) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterTransactorSession) MigrateUpkeeps(ids []*big.Int, destination common.Address) (*types.Transaction, error) { + return _IAutomationRegistryMaster.Contract.MigrateUpkeeps(&_IAutomationRegistryMaster.TransactOpts, ids, destination) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterTransactor) OnTokenTransfer(opts *bind.TransactOpts, sender common.Address, amount *big.Int, data []byte) (*types.Transaction, error) { + return _IAutomationRegistryMaster.contract.Transact(opts, "onTokenTransfer", sender, amount, data) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterSession) OnTokenTransfer(sender common.Address, amount *big.Int, data []byte) (*types.Transaction, error) { + return _IAutomationRegistryMaster.Contract.OnTokenTransfer(&_IAutomationRegistryMaster.TransactOpts, sender, amount, data) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterTransactorSession) OnTokenTransfer(sender common.Address, amount *big.Int, data []byte) (*types.Transaction, error) { + return _IAutomationRegistryMaster.Contract.OnTokenTransfer(&_IAutomationRegistryMaster.TransactOpts, sender, amount, data) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterTransactor) Pause(opts *bind.TransactOpts) (*types.Transaction, error) { + return _IAutomationRegistryMaster.contract.Transact(opts, "pause") +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterSession) Pause() (*types.Transaction, error) { + return _IAutomationRegistryMaster.Contract.Pause(&_IAutomationRegistryMaster.TransactOpts) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterTransactorSession) Pause() (*types.Transaction, error) { + return _IAutomationRegistryMaster.Contract.Pause(&_IAutomationRegistryMaster.TransactOpts) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterTransactor) PauseUpkeep(opts *bind.TransactOpts, id *big.Int) (*types.Transaction, error) { + return _IAutomationRegistryMaster.contract.Transact(opts, "pauseUpkeep", id) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterSession) PauseUpkeep(id *big.Int) (*types.Transaction, error) { + return _IAutomationRegistryMaster.Contract.PauseUpkeep(&_IAutomationRegistryMaster.TransactOpts, id) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterTransactorSession) PauseUpkeep(id *big.Int) (*types.Transaction, error) { + return _IAutomationRegistryMaster.Contract.PauseUpkeep(&_IAutomationRegistryMaster.TransactOpts, id) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterTransactor) ReceiveUpkeeps(opts *bind.TransactOpts, encodedUpkeeps []byte) (*types.Transaction, error) { + return _IAutomationRegistryMaster.contract.Transact(opts, "receiveUpkeeps", encodedUpkeeps) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterSession) ReceiveUpkeeps(encodedUpkeeps []byte) (*types.Transaction, error) { + return _IAutomationRegistryMaster.Contract.ReceiveUpkeeps(&_IAutomationRegistryMaster.TransactOpts, encodedUpkeeps) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterTransactorSession) ReceiveUpkeeps(encodedUpkeeps []byte) (*types.Transaction, error) { + return _IAutomationRegistryMaster.Contract.ReceiveUpkeeps(&_IAutomationRegistryMaster.TransactOpts, encodedUpkeeps) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterTransactor) RecoverFunds(opts *bind.TransactOpts) (*types.Transaction, error) { + return _IAutomationRegistryMaster.contract.Transact(opts, "recoverFunds") +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterSession) RecoverFunds() (*types.Transaction, error) { + return _IAutomationRegistryMaster.Contract.RecoverFunds(&_IAutomationRegistryMaster.TransactOpts) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterTransactorSession) RecoverFunds() (*types.Transaction, error) { + return _IAutomationRegistryMaster.Contract.RecoverFunds(&_IAutomationRegistryMaster.TransactOpts) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterTransactor) RegisterUpkeep(opts *bind.TransactOpts, target common.Address, gasLimit uint32, admin common.Address, triggerType uint8, checkData []byte, triggerConfig []byte, offchainConfig []byte) (*types.Transaction, error) { + return _IAutomationRegistryMaster.contract.Transact(opts, "registerUpkeep", target, gasLimit, admin, triggerType, checkData, triggerConfig, offchainConfig) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterSession) RegisterUpkeep(target common.Address, gasLimit uint32, admin common.Address, triggerType uint8, checkData []byte, triggerConfig []byte, offchainConfig []byte) (*types.Transaction, error) { + return _IAutomationRegistryMaster.Contract.RegisterUpkeep(&_IAutomationRegistryMaster.TransactOpts, target, gasLimit, admin, triggerType, checkData, triggerConfig, offchainConfig) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterTransactorSession) RegisterUpkeep(target common.Address, gasLimit uint32, admin common.Address, triggerType uint8, checkData []byte, triggerConfig []byte, offchainConfig []byte) (*types.Transaction, error) { + return _IAutomationRegistryMaster.Contract.RegisterUpkeep(&_IAutomationRegistryMaster.TransactOpts, target, gasLimit, admin, triggerType, checkData, triggerConfig, offchainConfig) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterTransactor) RegisterUpkeep0(opts *bind.TransactOpts, target common.Address, gasLimit uint32, admin common.Address, checkData []byte, offchainConfig []byte) (*types.Transaction, error) { + return _IAutomationRegistryMaster.contract.Transact(opts, "registerUpkeep0", target, gasLimit, admin, checkData, offchainConfig) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterSession) RegisterUpkeep0(target common.Address, gasLimit uint32, admin common.Address, checkData []byte, offchainConfig []byte) (*types.Transaction, error) { + return _IAutomationRegistryMaster.Contract.RegisterUpkeep0(&_IAutomationRegistryMaster.TransactOpts, target, gasLimit, admin, checkData, offchainConfig) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterTransactorSession) RegisterUpkeep0(target common.Address, gasLimit uint32, admin common.Address, checkData []byte, offchainConfig []byte) (*types.Transaction, error) { + return _IAutomationRegistryMaster.Contract.RegisterUpkeep0(&_IAutomationRegistryMaster.TransactOpts, target, gasLimit, admin, checkData, offchainConfig) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterTransactor) SetAdminPrivilegeConfig(opts *bind.TransactOpts, admin common.Address, newPrivilegeConfig []byte) (*types.Transaction, error) { + return _IAutomationRegistryMaster.contract.Transact(opts, "setAdminPrivilegeConfig", admin, newPrivilegeConfig) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterSession) SetAdminPrivilegeConfig(admin common.Address, newPrivilegeConfig []byte) (*types.Transaction, error) { + return _IAutomationRegistryMaster.Contract.SetAdminPrivilegeConfig(&_IAutomationRegistryMaster.TransactOpts, admin, newPrivilegeConfig) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterTransactorSession) SetAdminPrivilegeConfig(admin common.Address, newPrivilegeConfig []byte) (*types.Transaction, error) { + return _IAutomationRegistryMaster.Contract.SetAdminPrivilegeConfig(&_IAutomationRegistryMaster.TransactOpts, admin, newPrivilegeConfig) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterTransactor) SetConfig(opts *bind.TransactOpts, signers []common.Address, transmitters []common.Address, f uint8, onchainConfigBytes []byte, offchainConfigVersion uint64, offchainConfig []byte) (*types.Transaction, error) { + return _IAutomationRegistryMaster.contract.Transact(opts, "setConfig", signers, transmitters, f, onchainConfigBytes, offchainConfigVersion, offchainConfig) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterSession) SetConfig(signers []common.Address, transmitters []common.Address, f uint8, onchainConfigBytes []byte, offchainConfigVersion uint64, offchainConfig []byte) (*types.Transaction, error) { + return _IAutomationRegistryMaster.Contract.SetConfig(&_IAutomationRegistryMaster.TransactOpts, signers, transmitters, f, onchainConfigBytes, offchainConfigVersion, offchainConfig) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterTransactorSession) SetConfig(signers []common.Address, transmitters []common.Address, f uint8, onchainConfigBytes []byte, offchainConfigVersion uint64, offchainConfig []byte) (*types.Transaction, error) { + return _IAutomationRegistryMaster.Contract.SetConfig(&_IAutomationRegistryMaster.TransactOpts, signers, transmitters, f, onchainConfigBytes, offchainConfigVersion, offchainConfig) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterTransactor) SetConfigTypeSafe(opts *bind.TransactOpts, signers []common.Address, transmitters []common.Address, f uint8, onchainConfig AutomationRegistryBase22OnchainConfig, offchainConfigVersion uint64, offchainConfig []byte) (*types.Transaction, error) { + return _IAutomationRegistryMaster.contract.Transact(opts, "setConfigTypeSafe", signers, transmitters, f, onchainConfig, offchainConfigVersion, offchainConfig) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterSession) SetConfigTypeSafe(signers []common.Address, transmitters []common.Address, f uint8, onchainConfig AutomationRegistryBase22OnchainConfig, offchainConfigVersion uint64, offchainConfig []byte) (*types.Transaction, error) { + return _IAutomationRegistryMaster.Contract.SetConfigTypeSafe(&_IAutomationRegistryMaster.TransactOpts, signers, transmitters, f, onchainConfig, offchainConfigVersion, offchainConfig) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterTransactorSession) SetConfigTypeSafe(signers []common.Address, transmitters []common.Address, f uint8, onchainConfig AutomationRegistryBase22OnchainConfig, offchainConfigVersion uint64, offchainConfig []byte) (*types.Transaction, error) { + return _IAutomationRegistryMaster.Contract.SetConfigTypeSafe(&_IAutomationRegistryMaster.TransactOpts, signers, transmitters, f, onchainConfig, offchainConfigVersion, offchainConfig) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterTransactor) SetPayees(opts *bind.TransactOpts, payees []common.Address) (*types.Transaction, error) { + return _IAutomationRegistryMaster.contract.Transact(opts, "setPayees", payees) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterSession) SetPayees(payees []common.Address) (*types.Transaction, error) { + return _IAutomationRegistryMaster.Contract.SetPayees(&_IAutomationRegistryMaster.TransactOpts, payees) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterTransactorSession) SetPayees(payees []common.Address) (*types.Transaction, error) { + return _IAutomationRegistryMaster.Contract.SetPayees(&_IAutomationRegistryMaster.TransactOpts, payees) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterTransactor) SetPeerRegistryMigrationPermission(opts *bind.TransactOpts, peer common.Address, permission uint8) (*types.Transaction, error) { + return _IAutomationRegistryMaster.contract.Transact(opts, "setPeerRegistryMigrationPermission", peer, permission) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterSession) SetPeerRegistryMigrationPermission(peer common.Address, permission uint8) (*types.Transaction, error) { + return _IAutomationRegistryMaster.Contract.SetPeerRegistryMigrationPermission(&_IAutomationRegistryMaster.TransactOpts, peer, permission) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterTransactorSession) SetPeerRegistryMigrationPermission(peer common.Address, permission uint8) (*types.Transaction, error) { + return _IAutomationRegistryMaster.Contract.SetPeerRegistryMigrationPermission(&_IAutomationRegistryMaster.TransactOpts, peer, permission) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterTransactor) SetUpkeepCheckData(opts *bind.TransactOpts, id *big.Int, newCheckData []byte) (*types.Transaction, error) { + return _IAutomationRegistryMaster.contract.Transact(opts, "setUpkeepCheckData", id, newCheckData) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterSession) SetUpkeepCheckData(id *big.Int, newCheckData []byte) (*types.Transaction, error) { + return _IAutomationRegistryMaster.Contract.SetUpkeepCheckData(&_IAutomationRegistryMaster.TransactOpts, id, newCheckData) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterTransactorSession) SetUpkeepCheckData(id *big.Int, newCheckData []byte) (*types.Transaction, error) { + return _IAutomationRegistryMaster.Contract.SetUpkeepCheckData(&_IAutomationRegistryMaster.TransactOpts, id, newCheckData) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterTransactor) SetUpkeepGasLimit(opts *bind.TransactOpts, id *big.Int, gasLimit uint32) (*types.Transaction, error) { + return _IAutomationRegistryMaster.contract.Transact(opts, "setUpkeepGasLimit", id, gasLimit) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterSession) SetUpkeepGasLimit(id *big.Int, gasLimit uint32) (*types.Transaction, error) { + return _IAutomationRegistryMaster.Contract.SetUpkeepGasLimit(&_IAutomationRegistryMaster.TransactOpts, id, gasLimit) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterTransactorSession) SetUpkeepGasLimit(id *big.Int, gasLimit uint32) (*types.Transaction, error) { + return _IAutomationRegistryMaster.Contract.SetUpkeepGasLimit(&_IAutomationRegistryMaster.TransactOpts, id, gasLimit) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterTransactor) SetUpkeepOffchainConfig(opts *bind.TransactOpts, id *big.Int, config []byte) (*types.Transaction, error) { + return _IAutomationRegistryMaster.contract.Transact(opts, "setUpkeepOffchainConfig", id, config) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterSession) SetUpkeepOffchainConfig(id *big.Int, config []byte) (*types.Transaction, error) { + return _IAutomationRegistryMaster.Contract.SetUpkeepOffchainConfig(&_IAutomationRegistryMaster.TransactOpts, id, config) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterTransactorSession) SetUpkeepOffchainConfig(id *big.Int, config []byte) (*types.Transaction, error) { + return _IAutomationRegistryMaster.Contract.SetUpkeepOffchainConfig(&_IAutomationRegistryMaster.TransactOpts, id, config) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterTransactor) SetUpkeepPrivilegeConfig(opts *bind.TransactOpts, upkeepId *big.Int, newPrivilegeConfig []byte) (*types.Transaction, error) { + return _IAutomationRegistryMaster.contract.Transact(opts, "setUpkeepPrivilegeConfig", upkeepId, newPrivilegeConfig) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterSession) SetUpkeepPrivilegeConfig(upkeepId *big.Int, newPrivilegeConfig []byte) (*types.Transaction, error) { + return _IAutomationRegistryMaster.Contract.SetUpkeepPrivilegeConfig(&_IAutomationRegistryMaster.TransactOpts, upkeepId, newPrivilegeConfig) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterTransactorSession) SetUpkeepPrivilegeConfig(upkeepId *big.Int, newPrivilegeConfig []byte) (*types.Transaction, error) { + return _IAutomationRegistryMaster.Contract.SetUpkeepPrivilegeConfig(&_IAutomationRegistryMaster.TransactOpts, upkeepId, newPrivilegeConfig) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterTransactor) SetUpkeepTriggerConfig(opts *bind.TransactOpts, id *big.Int, triggerConfig []byte) (*types.Transaction, error) { + return _IAutomationRegistryMaster.contract.Transact(opts, "setUpkeepTriggerConfig", id, triggerConfig) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterSession) SetUpkeepTriggerConfig(id *big.Int, triggerConfig []byte) (*types.Transaction, error) { + return _IAutomationRegistryMaster.Contract.SetUpkeepTriggerConfig(&_IAutomationRegistryMaster.TransactOpts, id, triggerConfig) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterTransactorSession) SetUpkeepTriggerConfig(id *big.Int, triggerConfig []byte) (*types.Transaction, error) { + return _IAutomationRegistryMaster.Contract.SetUpkeepTriggerConfig(&_IAutomationRegistryMaster.TransactOpts, id, triggerConfig) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterTransactor) TransferOwnership(opts *bind.TransactOpts, to common.Address) (*types.Transaction, error) { + return _IAutomationRegistryMaster.contract.Transact(opts, "transferOwnership", to) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterSession) TransferOwnership(to common.Address) (*types.Transaction, error) { + return _IAutomationRegistryMaster.Contract.TransferOwnership(&_IAutomationRegistryMaster.TransactOpts, to) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterTransactorSession) TransferOwnership(to common.Address) (*types.Transaction, error) { + return _IAutomationRegistryMaster.Contract.TransferOwnership(&_IAutomationRegistryMaster.TransactOpts, to) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterTransactor) TransferPayeeship(opts *bind.TransactOpts, transmitter common.Address, proposed common.Address) (*types.Transaction, error) { + return _IAutomationRegistryMaster.contract.Transact(opts, "transferPayeeship", transmitter, proposed) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterSession) TransferPayeeship(transmitter common.Address, proposed common.Address) (*types.Transaction, error) { + return _IAutomationRegistryMaster.Contract.TransferPayeeship(&_IAutomationRegistryMaster.TransactOpts, transmitter, proposed) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterTransactorSession) TransferPayeeship(transmitter common.Address, proposed common.Address) (*types.Transaction, error) { + return _IAutomationRegistryMaster.Contract.TransferPayeeship(&_IAutomationRegistryMaster.TransactOpts, transmitter, proposed) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterTransactor) TransferUpkeepAdmin(opts *bind.TransactOpts, id *big.Int, proposed common.Address) (*types.Transaction, error) { + return _IAutomationRegistryMaster.contract.Transact(opts, "transferUpkeepAdmin", id, proposed) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterSession) TransferUpkeepAdmin(id *big.Int, proposed common.Address) (*types.Transaction, error) { + return _IAutomationRegistryMaster.Contract.TransferUpkeepAdmin(&_IAutomationRegistryMaster.TransactOpts, id, proposed) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterTransactorSession) TransferUpkeepAdmin(id *big.Int, proposed common.Address) (*types.Transaction, error) { + return _IAutomationRegistryMaster.Contract.TransferUpkeepAdmin(&_IAutomationRegistryMaster.TransactOpts, id, proposed) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterTransactor) Transmit(opts *bind.TransactOpts, reportContext [3][32]byte, rawReport []byte, rs [][32]byte, ss [][32]byte, rawVs [32]byte) (*types.Transaction, error) { + return _IAutomationRegistryMaster.contract.Transact(opts, "transmit", reportContext, rawReport, rs, ss, rawVs) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterSession) Transmit(reportContext [3][32]byte, rawReport []byte, rs [][32]byte, ss [][32]byte, rawVs [32]byte) (*types.Transaction, error) { + return _IAutomationRegistryMaster.Contract.Transmit(&_IAutomationRegistryMaster.TransactOpts, reportContext, rawReport, rs, ss, rawVs) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterTransactorSession) Transmit(reportContext [3][32]byte, rawReport []byte, rs [][32]byte, ss [][32]byte, rawVs [32]byte) (*types.Transaction, error) { + return _IAutomationRegistryMaster.Contract.Transmit(&_IAutomationRegistryMaster.TransactOpts, reportContext, rawReport, rs, ss, rawVs) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterTransactor) Unpause(opts *bind.TransactOpts) (*types.Transaction, error) { + return _IAutomationRegistryMaster.contract.Transact(opts, "unpause") +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterSession) Unpause() (*types.Transaction, error) { + return _IAutomationRegistryMaster.Contract.Unpause(&_IAutomationRegistryMaster.TransactOpts) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterTransactorSession) Unpause() (*types.Transaction, error) { + return _IAutomationRegistryMaster.Contract.Unpause(&_IAutomationRegistryMaster.TransactOpts) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterTransactor) UnpauseUpkeep(opts *bind.TransactOpts, id *big.Int) (*types.Transaction, error) { + return _IAutomationRegistryMaster.contract.Transact(opts, "unpauseUpkeep", id) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterSession) UnpauseUpkeep(id *big.Int) (*types.Transaction, error) { + return _IAutomationRegistryMaster.Contract.UnpauseUpkeep(&_IAutomationRegistryMaster.TransactOpts, id) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterTransactorSession) UnpauseUpkeep(id *big.Int) (*types.Transaction, error) { + return _IAutomationRegistryMaster.Contract.UnpauseUpkeep(&_IAutomationRegistryMaster.TransactOpts, id) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterTransactor) WithdrawFunds(opts *bind.TransactOpts, id *big.Int, to common.Address) (*types.Transaction, error) { + return _IAutomationRegistryMaster.contract.Transact(opts, "withdrawFunds", id, to) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterSession) WithdrawFunds(id *big.Int, to common.Address) (*types.Transaction, error) { + return _IAutomationRegistryMaster.Contract.WithdrawFunds(&_IAutomationRegistryMaster.TransactOpts, id, to) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterTransactorSession) WithdrawFunds(id *big.Int, to common.Address) (*types.Transaction, error) { + return _IAutomationRegistryMaster.Contract.WithdrawFunds(&_IAutomationRegistryMaster.TransactOpts, id, to) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterTransactor) WithdrawOwnerFunds(opts *bind.TransactOpts) (*types.Transaction, error) { + return _IAutomationRegistryMaster.contract.Transact(opts, "withdrawOwnerFunds") +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterSession) WithdrawOwnerFunds() (*types.Transaction, error) { + return _IAutomationRegistryMaster.Contract.WithdrawOwnerFunds(&_IAutomationRegistryMaster.TransactOpts) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterTransactorSession) WithdrawOwnerFunds() (*types.Transaction, error) { + return _IAutomationRegistryMaster.Contract.WithdrawOwnerFunds(&_IAutomationRegistryMaster.TransactOpts) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterTransactor) WithdrawPayment(opts *bind.TransactOpts, from common.Address, to common.Address) (*types.Transaction, error) { + return _IAutomationRegistryMaster.contract.Transact(opts, "withdrawPayment", from, to) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterSession) WithdrawPayment(from common.Address, to common.Address) (*types.Transaction, error) { + return _IAutomationRegistryMaster.Contract.WithdrawPayment(&_IAutomationRegistryMaster.TransactOpts, from, to) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterTransactorSession) WithdrawPayment(from common.Address, to common.Address) (*types.Transaction, error) { + return _IAutomationRegistryMaster.Contract.WithdrawPayment(&_IAutomationRegistryMaster.TransactOpts, from, to) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterTransactor) Fallback(opts *bind.TransactOpts, calldata []byte) (*types.Transaction, error) { + return _IAutomationRegistryMaster.contract.RawTransact(opts, calldata) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterSession) Fallback(calldata []byte) (*types.Transaction, error) { + return _IAutomationRegistryMaster.Contract.Fallback(&_IAutomationRegistryMaster.TransactOpts, calldata) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterTransactorSession) Fallback(calldata []byte) (*types.Transaction, error) { + return _IAutomationRegistryMaster.Contract.Fallback(&_IAutomationRegistryMaster.TransactOpts, calldata) +} + +type IAutomationRegistryMasterAdminPrivilegeConfigSetIterator struct { + Event *IAutomationRegistryMasterAdminPrivilegeConfigSet + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *IAutomationRegistryMasterAdminPrivilegeConfigSetIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(IAutomationRegistryMasterAdminPrivilegeConfigSet) + 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(IAutomationRegistryMasterAdminPrivilegeConfigSet) + 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 *IAutomationRegistryMasterAdminPrivilegeConfigSetIterator) Error() error { + return it.fail +} + +func (it *IAutomationRegistryMasterAdminPrivilegeConfigSetIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type IAutomationRegistryMasterAdminPrivilegeConfigSet struct { + Admin common.Address + PrivilegeConfig []byte + Raw types.Log +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterFilterer) FilterAdminPrivilegeConfigSet(opts *bind.FilterOpts, admin []common.Address) (*IAutomationRegistryMasterAdminPrivilegeConfigSetIterator, error) { + + var adminRule []interface{} + for _, adminItem := range admin { + adminRule = append(adminRule, adminItem) + } + + logs, sub, err := _IAutomationRegistryMaster.contract.FilterLogs(opts, "AdminPrivilegeConfigSet", adminRule) + if err != nil { + return nil, err + } + return &IAutomationRegistryMasterAdminPrivilegeConfigSetIterator{contract: _IAutomationRegistryMaster.contract, event: "AdminPrivilegeConfigSet", logs: logs, sub: sub}, nil +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterFilterer) WatchAdminPrivilegeConfigSet(opts *bind.WatchOpts, sink chan<- *IAutomationRegistryMasterAdminPrivilegeConfigSet, admin []common.Address) (event.Subscription, error) { + + var adminRule []interface{} + for _, adminItem := range admin { + adminRule = append(adminRule, adminItem) + } + + logs, sub, err := _IAutomationRegistryMaster.contract.WatchLogs(opts, "AdminPrivilegeConfigSet", adminRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(IAutomationRegistryMasterAdminPrivilegeConfigSet) + if err := _IAutomationRegistryMaster.contract.UnpackLog(event, "AdminPrivilegeConfigSet", 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 (_IAutomationRegistryMaster *IAutomationRegistryMasterFilterer) ParseAdminPrivilegeConfigSet(log types.Log) (*IAutomationRegistryMasterAdminPrivilegeConfigSet, error) { + event := new(IAutomationRegistryMasterAdminPrivilegeConfigSet) + if err := _IAutomationRegistryMaster.contract.UnpackLog(event, "AdminPrivilegeConfigSet", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type IAutomationRegistryMasterCancelledUpkeepReportIterator struct { + Event *IAutomationRegistryMasterCancelledUpkeepReport + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *IAutomationRegistryMasterCancelledUpkeepReportIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(IAutomationRegistryMasterCancelledUpkeepReport) + 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(IAutomationRegistryMasterCancelledUpkeepReport) + 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 *IAutomationRegistryMasterCancelledUpkeepReportIterator) Error() error { + return it.fail +} + +func (it *IAutomationRegistryMasterCancelledUpkeepReportIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type IAutomationRegistryMasterCancelledUpkeepReport struct { + Id *big.Int + Trigger []byte + Raw types.Log +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterFilterer) FilterCancelledUpkeepReport(opts *bind.FilterOpts, id []*big.Int) (*IAutomationRegistryMasterCancelledUpkeepReportIterator, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + + logs, sub, err := _IAutomationRegistryMaster.contract.FilterLogs(opts, "CancelledUpkeepReport", idRule) + if err != nil { + return nil, err + } + return &IAutomationRegistryMasterCancelledUpkeepReportIterator{contract: _IAutomationRegistryMaster.contract, event: "CancelledUpkeepReport", logs: logs, sub: sub}, nil +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterFilterer) WatchCancelledUpkeepReport(opts *bind.WatchOpts, sink chan<- *IAutomationRegistryMasterCancelledUpkeepReport, id []*big.Int) (event.Subscription, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + + logs, sub, err := _IAutomationRegistryMaster.contract.WatchLogs(opts, "CancelledUpkeepReport", idRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(IAutomationRegistryMasterCancelledUpkeepReport) + if err := _IAutomationRegistryMaster.contract.UnpackLog(event, "CancelledUpkeepReport", 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 (_IAutomationRegistryMaster *IAutomationRegistryMasterFilterer) ParseCancelledUpkeepReport(log types.Log) (*IAutomationRegistryMasterCancelledUpkeepReport, error) { + event := new(IAutomationRegistryMasterCancelledUpkeepReport) + if err := _IAutomationRegistryMaster.contract.UnpackLog(event, "CancelledUpkeepReport", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type IAutomationRegistryMasterConfigSetIterator struct { + Event *IAutomationRegistryMasterConfigSet + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *IAutomationRegistryMasterConfigSetIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(IAutomationRegistryMasterConfigSet) + 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(IAutomationRegistryMasterConfigSet) + 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 *IAutomationRegistryMasterConfigSetIterator) Error() error { + return it.fail +} + +func (it *IAutomationRegistryMasterConfigSetIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type IAutomationRegistryMasterConfigSet struct { + PreviousConfigBlockNumber uint32 + ConfigDigest [32]byte + ConfigCount uint64 + Signers []common.Address + Transmitters []common.Address + F uint8 + OnchainConfig []byte + OffchainConfigVersion uint64 + OffchainConfig []byte + Raw types.Log +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterFilterer) FilterConfigSet(opts *bind.FilterOpts) (*IAutomationRegistryMasterConfigSetIterator, error) { + + logs, sub, err := _IAutomationRegistryMaster.contract.FilterLogs(opts, "ConfigSet") + if err != nil { + return nil, err + } + return &IAutomationRegistryMasterConfigSetIterator{contract: _IAutomationRegistryMaster.contract, event: "ConfigSet", logs: logs, sub: sub}, nil +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterFilterer) WatchConfigSet(opts *bind.WatchOpts, sink chan<- *IAutomationRegistryMasterConfigSet) (event.Subscription, error) { + + logs, sub, err := _IAutomationRegistryMaster.contract.WatchLogs(opts, "ConfigSet") + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(IAutomationRegistryMasterConfigSet) + if err := _IAutomationRegistryMaster.contract.UnpackLog(event, "ConfigSet", 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 (_IAutomationRegistryMaster *IAutomationRegistryMasterFilterer) ParseConfigSet(log types.Log) (*IAutomationRegistryMasterConfigSet, error) { + event := new(IAutomationRegistryMasterConfigSet) + if err := _IAutomationRegistryMaster.contract.UnpackLog(event, "ConfigSet", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type IAutomationRegistryMasterDedupKeyAddedIterator struct { + Event *IAutomationRegistryMasterDedupKeyAdded + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *IAutomationRegistryMasterDedupKeyAddedIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(IAutomationRegistryMasterDedupKeyAdded) + 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(IAutomationRegistryMasterDedupKeyAdded) + 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 *IAutomationRegistryMasterDedupKeyAddedIterator) Error() error { + return it.fail +} + +func (it *IAutomationRegistryMasterDedupKeyAddedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type IAutomationRegistryMasterDedupKeyAdded struct { + DedupKey [32]byte + Raw types.Log +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterFilterer) FilterDedupKeyAdded(opts *bind.FilterOpts, dedupKey [][32]byte) (*IAutomationRegistryMasterDedupKeyAddedIterator, error) { + + var dedupKeyRule []interface{} + for _, dedupKeyItem := range dedupKey { + dedupKeyRule = append(dedupKeyRule, dedupKeyItem) + } + + logs, sub, err := _IAutomationRegistryMaster.contract.FilterLogs(opts, "DedupKeyAdded", dedupKeyRule) + if err != nil { + return nil, err + } + return &IAutomationRegistryMasterDedupKeyAddedIterator{contract: _IAutomationRegistryMaster.contract, event: "DedupKeyAdded", logs: logs, sub: sub}, nil +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterFilterer) WatchDedupKeyAdded(opts *bind.WatchOpts, sink chan<- *IAutomationRegistryMasterDedupKeyAdded, dedupKey [][32]byte) (event.Subscription, error) { + + var dedupKeyRule []interface{} + for _, dedupKeyItem := range dedupKey { + dedupKeyRule = append(dedupKeyRule, dedupKeyItem) + } + + logs, sub, err := _IAutomationRegistryMaster.contract.WatchLogs(opts, "DedupKeyAdded", dedupKeyRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(IAutomationRegistryMasterDedupKeyAdded) + if err := _IAutomationRegistryMaster.contract.UnpackLog(event, "DedupKeyAdded", 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 (_IAutomationRegistryMaster *IAutomationRegistryMasterFilterer) ParseDedupKeyAdded(log types.Log) (*IAutomationRegistryMasterDedupKeyAdded, error) { + event := new(IAutomationRegistryMasterDedupKeyAdded) + if err := _IAutomationRegistryMaster.contract.UnpackLog(event, "DedupKeyAdded", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type IAutomationRegistryMasterFundsAddedIterator struct { + Event *IAutomationRegistryMasterFundsAdded + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *IAutomationRegistryMasterFundsAddedIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(IAutomationRegistryMasterFundsAdded) + 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(IAutomationRegistryMasterFundsAdded) + 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 *IAutomationRegistryMasterFundsAddedIterator) Error() error { + return it.fail +} + +func (it *IAutomationRegistryMasterFundsAddedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type IAutomationRegistryMasterFundsAdded struct { + Id *big.Int + From common.Address + Amount *big.Int + Raw types.Log +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterFilterer) FilterFundsAdded(opts *bind.FilterOpts, id []*big.Int, from []common.Address) (*IAutomationRegistryMasterFundsAddedIterator, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + var fromRule []interface{} + for _, fromItem := range from { + fromRule = append(fromRule, fromItem) + } + + logs, sub, err := _IAutomationRegistryMaster.contract.FilterLogs(opts, "FundsAdded", idRule, fromRule) + if err != nil { + return nil, err + } + return &IAutomationRegistryMasterFundsAddedIterator{contract: _IAutomationRegistryMaster.contract, event: "FundsAdded", logs: logs, sub: sub}, nil +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterFilterer) WatchFundsAdded(opts *bind.WatchOpts, sink chan<- *IAutomationRegistryMasterFundsAdded, id []*big.Int, from []common.Address) (event.Subscription, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + var fromRule []interface{} + for _, fromItem := range from { + fromRule = append(fromRule, fromItem) + } + + logs, sub, err := _IAutomationRegistryMaster.contract.WatchLogs(opts, "FundsAdded", idRule, fromRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(IAutomationRegistryMasterFundsAdded) + if err := _IAutomationRegistryMaster.contract.UnpackLog(event, "FundsAdded", 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 (_IAutomationRegistryMaster *IAutomationRegistryMasterFilterer) ParseFundsAdded(log types.Log) (*IAutomationRegistryMasterFundsAdded, error) { + event := new(IAutomationRegistryMasterFundsAdded) + if err := _IAutomationRegistryMaster.contract.UnpackLog(event, "FundsAdded", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type IAutomationRegistryMasterFundsWithdrawnIterator struct { + Event *IAutomationRegistryMasterFundsWithdrawn + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *IAutomationRegistryMasterFundsWithdrawnIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(IAutomationRegistryMasterFundsWithdrawn) + 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(IAutomationRegistryMasterFundsWithdrawn) + 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 *IAutomationRegistryMasterFundsWithdrawnIterator) Error() error { + return it.fail +} + +func (it *IAutomationRegistryMasterFundsWithdrawnIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type IAutomationRegistryMasterFundsWithdrawn struct { + Id *big.Int + Amount *big.Int + To common.Address + Raw types.Log +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterFilterer) FilterFundsWithdrawn(opts *bind.FilterOpts, id []*big.Int) (*IAutomationRegistryMasterFundsWithdrawnIterator, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + + logs, sub, err := _IAutomationRegistryMaster.contract.FilterLogs(opts, "FundsWithdrawn", idRule) + if err != nil { + return nil, err + } + return &IAutomationRegistryMasterFundsWithdrawnIterator{contract: _IAutomationRegistryMaster.contract, event: "FundsWithdrawn", logs: logs, sub: sub}, nil +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterFilterer) WatchFundsWithdrawn(opts *bind.WatchOpts, sink chan<- *IAutomationRegistryMasterFundsWithdrawn, id []*big.Int) (event.Subscription, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + + logs, sub, err := _IAutomationRegistryMaster.contract.WatchLogs(opts, "FundsWithdrawn", idRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(IAutomationRegistryMasterFundsWithdrawn) + if err := _IAutomationRegistryMaster.contract.UnpackLog(event, "FundsWithdrawn", 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 (_IAutomationRegistryMaster *IAutomationRegistryMasterFilterer) ParseFundsWithdrawn(log types.Log) (*IAutomationRegistryMasterFundsWithdrawn, error) { + event := new(IAutomationRegistryMasterFundsWithdrawn) + if err := _IAutomationRegistryMaster.contract.UnpackLog(event, "FundsWithdrawn", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type IAutomationRegistryMasterInsufficientFundsUpkeepReportIterator struct { + Event *IAutomationRegistryMasterInsufficientFundsUpkeepReport + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *IAutomationRegistryMasterInsufficientFundsUpkeepReportIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(IAutomationRegistryMasterInsufficientFundsUpkeepReport) + 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(IAutomationRegistryMasterInsufficientFundsUpkeepReport) + 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 *IAutomationRegistryMasterInsufficientFundsUpkeepReportIterator) Error() error { + return it.fail +} + +func (it *IAutomationRegistryMasterInsufficientFundsUpkeepReportIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type IAutomationRegistryMasterInsufficientFundsUpkeepReport struct { + Id *big.Int + Trigger []byte + Raw types.Log +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterFilterer) FilterInsufficientFundsUpkeepReport(opts *bind.FilterOpts, id []*big.Int) (*IAutomationRegistryMasterInsufficientFundsUpkeepReportIterator, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + + logs, sub, err := _IAutomationRegistryMaster.contract.FilterLogs(opts, "InsufficientFundsUpkeepReport", idRule) + if err != nil { + return nil, err + } + return &IAutomationRegistryMasterInsufficientFundsUpkeepReportIterator{contract: _IAutomationRegistryMaster.contract, event: "InsufficientFundsUpkeepReport", logs: logs, sub: sub}, nil +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterFilterer) WatchInsufficientFundsUpkeepReport(opts *bind.WatchOpts, sink chan<- *IAutomationRegistryMasterInsufficientFundsUpkeepReport, id []*big.Int) (event.Subscription, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + + logs, sub, err := _IAutomationRegistryMaster.contract.WatchLogs(opts, "InsufficientFundsUpkeepReport", idRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(IAutomationRegistryMasterInsufficientFundsUpkeepReport) + if err := _IAutomationRegistryMaster.contract.UnpackLog(event, "InsufficientFundsUpkeepReport", 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 (_IAutomationRegistryMaster *IAutomationRegistryMasterFilterer) ParseInsufficientFundsUpkeepReport(log types.Log) (*IAutomationRegistryMasterInsufficientFundsUpkeepReport, error) { + event := new(IAutomationRegistryMasterInsufficientFundsUpkeepReport) + if err := _IAutomationRegistryMaster.contract.UnpackLog(event, "InsufficientFundsUpkeepReport", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type IAutomationRegistryMasterOwnerFundsWithdrawnIterator struct { + Event *IAutomationRegistryMasterOwnerFundsWithdrawn + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *IAutomationRegistryMasterOwnerFundsWithdrawnIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(IAutomationRegistryMasterOwnerFundsWithdrawn) + 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(IAutomationRegistryMasterOwnerFundsWithdrawn) + 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 *IAutomationRegistryMasterOwnerFundsWithdrawnIterator) Error() error { + return it.fail +} + +func (it *IAutomationRegistryMasterOwnerFundsWithdrawnIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type IAutomationRegistryMasterOwnerFundsWithdrawn struct { + Amount *big.Int + Raw types.Log +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterFilterer) FilterOwnerFundsWithdrawn(opts *bind.FilterOpts) (*IAutomationRegistryMasterOwnerFundsWithdrawnIterator, error) { + + logs, sub, err := _IAutomationRegistryMaster.contract.FilterLogs(opts, "OwnerFundsWithdrawn") + if err != nil { + return nil, err + } + return &IAutomationRegistryMasterOwnerFundsWithdrawnIterator{contract: _IAutomationRegistryMaster.contract, event: "OwnerFundsWithdrawn", logs: logs, sub: sub}, nil +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterFilterer) WatchOwnerFundsWithdrawn(opts *bind.WatchOpts, sink chan<- *IAutomationRegistryMasterOwnerFundsWithdrawn) (event.Subscription, error) { + + logs, sub, err := _IAutomationRegistryMaster.contract.WatchLogs(opts, "OwnerFundsWithdrawn") + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(IAutomationRegistryMasterOwnerFundsWithdrawn) + if err := _IAutomationRegistryMaster.contract.UnpackLog(event, "OwnerFundsWithdrawn", 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 (_IAutomationRegistryMaster *IAutomationRegistryMasterFilterer) ParseOwnerFundsWithdrawn(log types.Log) (*IAutomationRegistryMasterOwnerFundsWithdrawn, error) { + event := new(IAutomationRegistryMasterOwnerFundsWithdrawn) + if err := _IAutomationRegistryMaster.contract.UnpackLog(event, "OwnerFundsWithdrawn", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type IAutomationRegistryMasterOwnershipTransferRequestedIterator struct { + Event *IAutomationRegistryMasterOwnershipTransferRequested + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *IAutomationRegistryMasterOwnershipTransferRequestedIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(IAutomationRegistryMasterOwnershipTransferRequested) + 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(IAutomationRegistryMasterOwnershipTransferRequested) + 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 *IAutomationRegistryMasterOwnershipTransferRequestedIterator) Error() error { + return it.fail +} + +func (it *IAutomationRegistryMasterOwnershipTransferRequestedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type IAutomationRegistryMasterOwnershipTransferRequested struct { + From common.Address + To common.Address + Raw types.Log +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterFilterer) FilterOwnershipTransferRequested(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*IAutomationRegistryMasterOwnershipTransferRequestedIterator, 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 := _IAutomationRegistryMaster.contract.FilterLogs(opts, "OwnershipTransferRequested", fromRule, toRule) + if err != nil { + return nil, err + } + return &IAutomationRegistryMasterOwnershipTransferRequestedIterator{contract: _IAutomationRegistryMaster.contract, event: "OwnershipTransferRequested", logs: logs, sub: sub}, nil +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterFilterer) WatchOwnershipTransferRequested(opts *bind.WatchOpts, sink chan<- *IAutomationRegistryMasterOwnershipTransferRequested, 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 := _IAutomationRegistryMaster.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(IAutomationRegistryMasterOwnershipTransferRequested) + if err := _IAutomationRegistryMaster.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 (_IAutomationRegistryMaster *IAutomationRegistryMasterFilterer) ParseOwnershipTransferRequested(log types.Log) (*IAutomationRegistryMasterOwnershipTransferRequested, error) { + event := new(IAutomationRegistryMasterOwnershipTransferRequested) + if err := _IAutomationRegistryMaster.contract.UnpackLog(event, "OwnershipTransferRequested", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type IAutomationRegistryMasterOwnershipTransferredIterator struct { + Event *IAutomationRegistryMasterOwnershipTransferred + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *IAutomationRegistryMasterOwnershipTransferredIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(IAutomationRegistryMasterOwnershipTransferred) + 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(IAutomationRegistryMasterOwnershipTransferred) + 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 *IAutomationRegistryMasterOwnershipTransferredIterator) Error() error { + return it.fail +} + +func (it *IAutomationRegistryMasterOwnershipTransferredIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type IAutomationRegistryMasterOwnershipTransferred struct { + From common.Address + To common.Address + Raw types.Log +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterFilterer) FilterOwnershipTransferred(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*IAutomationRegistryMasterOwnershipTransferredIterator, 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 := _IAutomationRegistryMaster.contract.FilterLogs(opts, "OwnershipTransferred", fromRule, toRule) + if err != nil { + return nil, err + } + return &IAutomationRegistryMasterOwnershipTransferredIterator{contract: _IAutomationRegistryMaster.contract, event: "OwnershipTransferred", logs: logs, sub: sub}, nil +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterFilterer) WatchOwnershipTransferred(opts *bind.WatchOpts, sink chan<- *IAutomationRegistryMasterOwnershipTransferred, 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 := _IAutomationRegistryMaster.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(IAutomationRegistryMasterOwnershipTransferred) + if err := _IAutomationRegistryMaster.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 (_IAutomationRegistryMaster *IAutomationRegistryMasterFilterer) ParseOwnershipTransferred(log types.Log) (*IAutomationRegistryMasterOwnershipTransferred, error) { + event := new(IAutomationRegistryMasterOwnershipTransferred) + if err := _IAutomationRegistryMaster.contract.UnpackLog(event, "OwnershipTransferred", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type IAutomationRegistryMasterPausedIterator struct { + Event *IAutomationRegistryMasterPaused + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *IAutomationRegistryMasterPausedIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(IAutomationRegistryMasterPaused) + 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(IAutomationRegistryMasterPaused) + 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 *IAutomationRegistryMasterPausedIterator) Error() error { + return it.fail +} + +func (it *IAutomationRegistryMasterPausedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type IAutomationRegistryMasterPaused struct { + Account common.Address + Raw types.Log +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterFilterer) FilterPaused(opts *bind.FilterOpts) (*IAutomationRegistryMasterPausedIterator, error) { + + logs, sub, err := _IAutomationRegistryMaster.contract.FilterLogs(opts, "Paused") + if err != nil { + return nil, err + } + return &IAutomationRegistryMasterPausedIterator{contract: _IAutomationRegistryMaster.contract, event: "Paused", logs: logs, sub: sub}, nil +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterFilterer) WatchPaused(opts *bind.WatchOpts, sink chan<- *IAutomationRegistryMasterPaused) (event.Subscription, error) { + + logs, sub, err := _IAutomationRegistryMaster.contract.WatchLogs(opts, "Paused") + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(IAutomationRegistryMasterPaused) + if err := _IAutomationRegistryMaster.contract.UnpackLog(event, "Paused", 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 (_IAutomationRegistryMaster *IAutomationRegistryMasterFilterer) ParsePaused(log types.Log) (*IAutomationRegistryMasterPaused, error) { + event := new(IAutomationRegistryMasterPaused) + if err := _IAutomationRegistryMaster.contract.UnpackLog(event, "Paused", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type IAutomationRegistryMasterPayeesUpdatedIterator struct { + Event *IAutomationRegistryMasterPayeesUpdated + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *IAutomationRegistryMasterPayeesUpdatedIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(IAutomationRegistryMasterPayeesUpdated) + 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(IAutomationRegistryMasterPayeesUpdated) + 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 *IAutomationRegistryMasterPayeesUpdatedIterator) Error() error { + return it.fail +} + +func (it *IAutomationRegistryMasterPayeesUpdatedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type IAutomationRegistryMasterPayeesUpdated struct { + Transmitters []common.Address + Payees []common.Address + Raw types.Log +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterFilterer) FilterPayeesUpdated(opts *bind.FilterOpts) (*IAutomationRegistryMasterPayeesUpdatedIterator, error) { + + logs, sub, err := _IAutomationRegistryMaster.contract.FilterLogs(opts, "PayeesUpdated") + if err != nil { + return nil, err + } + return &IAutomationRegistryMasterPayeesUpdatedIterator{contract: _IAutomationRegistryMaster.contract, event: "PayeesUpdated", logs: logs, sub: sub}, nil +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterFilterer) WatchPayeesUpdated(opts *bind.WatchOpts, sink chan<- *IAutomationRegistryMasterPayeesUpdated) (event.Subscription, error) { + + logs, sub, err := _IAutomationRegistryMaster.contract.WatchLogs(opts, "PayeesUpdated") + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(IAutomationRegistryMasterPayeesUpdated) + if err := _IAutomationRegistryMaster.contract.UnpackLog(event, "PayeesUpdated", 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 (_IAutomationRegistryMaster *IAutomationRegistryMasterFilterer) ParsePayeesUpdated(log types.Log) (*IAutomationRegistryMasterPayeesUpdated, error) { + event := new(IAutomationRegistryMasterPayeesUpdated) + if err := _IAutomationRegistryMaster.contract.UnpackLog(event, "PayeesUpdated", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type IAutomationRegistryMasterPayeeshipTransferRequestedIterator struct { + Event *IAutomationRegistryMasterPayeeshipTransferRequested + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *IAutomationRegistryMasterPayeeshipTransferRequestedIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(IAutomationRegistryMasterPayeeshipTransferRequested) + 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(IAutomationRegistryMasterPayeeshipTransferRequested) + 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 *IAutomationRegistryMasterPayeeshipTransferRequestedIterator) Error() error { + return it.fail +} + +func (it *IAutomationRegistryMasterPayeeshipTransferRequestedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type IAutomationRegistryMasterPayeeshipTransferRequested struct { + Transmitter common.Address + From common.Address + To common.Address + Raw types.Log +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterFilterer) FilterPayeeshipTransferRequested(opts *bind.FilterOpts, transmitter []common.Address, from []common.Address, to []common.Address) (*IAutomationRegistryMasterPayeeshipTransferRequestedIterator, error) { + + var transmitterRule []interface{} + for _, transmitterItem := range transmitter { + transmitterRule = append(transmitterRule, transmitterItem) + } + 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 := _IAutomationRegistryMaster.contract.FilterLogs(opts, "PayeeshipTransferRequested", transmitterRule, fromRule, toRule) + if err != nil { + return nil, err + } + return &IAutomationRegistryMasterPayeeshipTransferRequestedIterator{contract: _IAutomationRegistryMaster.contract, event: "PayeeshipTransferRequested", logs: logs, sub: sub}, nil +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterFilterer) WatchPayeeshipTransferRequested(opts *bind.WatchOpts, sink chan<- *IAutomationRegistryMasterPayeeshipTransferRequested, transmitter []common.Address, from []common.Address, to []common.Address) (event.Subscription, error) { + + var transmitterRule []interface{} + for _, transmitterItem := range transmitter { + transmitterRule = append(transmitterRule, transmitterItem) + } + 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 := _IAutomationRegistryMaster.contract.WatchLogs(opts, "PayeeshipTransferRequested", transmitterRule, 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(IAutomationRegistryMasterPayeeshipTransferRequested) + if err := _IAutomationRegistryMaster.contract.UnpackLog(event, "PayeeshipTransferRequested", 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 (_IAutomationRegistryMaster *IAutomationRegistryMasterFilterer) ParsePayeeshipTransferRequested(log types.Log) (*IAutomationRegistryMasterPayeeshipTransferRequested, error) { + event := new(IAutomationRegistryMasterPayeeshipTransferRequested) + if err := _IAutomationRegistryMaster.contract.UnpackLog(event, "PayeeshipTransferRequested", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type IAutomationRegistryMasterPayeeshipTransferredIterator struct { + Event *IAutomationRegistryMasterPayeeshipTransferred + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *IAutomationRegistryMasterPayeeshipTransferredIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(IAutomationRegistryMasterPayeeshipTransferred) + 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(IAutomationRegistryMasterPayeeshipTransferred) + 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 *IAutomationRegistryMasterPayeeshipTransferredIterator) Error() error { + return it.fail +} + +func (it *IAutomationRegistryMasterPayeeshipTransferredIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type IAutomationRegistryMasterPayeeshipTransferred struct { + Transmitter common.Address + From common.Address + To common.Address + Raw types.Log +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterFilterer) FilterPayeeshipTransferred(opts *bind.FilterOpts, transmitter []common.Address, from []common.Address, to []common.Address) (*IAutomationRegistryMasterPayeeshipTransferredIterator, error) { + + var transmitterRule []interface{} + for _, transmitterItem := range transmitter { + transmitterRule = append(transmitterRule, transmitterItem) + } + 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 := _IAutomationRegistryMaster.contract.FilterLogs(opts, "PayeeshipTransferred", transmitterRule, fromRule, toRule) + if err != nil { + return nil, err + } + return &IAutomationRegistryMasterPayeeshipTransferredIterator{contract: _IAutomationRegistryMaster.contract, event: "PayeeshipTransferred", logs: logs, sub: sub}, nil +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterFilterer) WatchPayeeshipTransferred(opts *bind.WatchOpts, sink chan<- *IAutomationRegistryMasterPayeeshipTransferred, transmitter []common.Address, from []common.Address, to []common.Address) (event.Subscription, error) { + + var transmitterRule []interface{} + for _, transmitterItem := range transmitter { + transmitterRule = append(transmitterRule, transmitterItem) + } + 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 := _IAutomationRegistryMaster.contract.WatchLogs(opts, "PayeeshipTransferred", transmitterRule, 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(IAutomationRegistryMasterPayeeshipTransferred) + if err := _IAutomationRegistryMaster.contract.UnpackLog(event, "PayeeshipTransferred", 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 (_IAutomationRegistryMaster *IAutomationRegistryMasterFilterer) ParsePayeeshipTransferred(log types.Log) (*IAutomationRegistryMasterPayeeshipTransferred, error) { + event := new(IAutomationRegistryMasterPayeeshipTransferred) + if err := _IAutomationRegistryMaster.contract.UnpackLog(event, "PayeeshipTransferred", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type IAutomationRegistryMasterPaymentWithdrawnIterator struct { + Event *IAutomationRegistryMasterPaymentWithdrawn + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *IAutomationRegistryMasterPaymentWithdrawnIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(IAutomationRegistryMasterPaymentWithdrawn) + 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(IAutomationRegistryMasterPaymentWithdrawn) + 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 *IAutomationRegistryMasterPaymentWithdrawnIterator) Error() error { + return it.fail +} + +func (it *IAutomationRegistryMasterPaymentWithdrawnIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type IAutomationRegistryMasterPaymentWithdrawn struct { + Transmitter common.Address + Amount *big.Int + To common.Address + Payee common.Address + Raw types.Log +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterFilterer) FilterPaymentWithdrawn(opts *bind.FilterOpts, transmitter []common.Address, amount []*big.Int, to []common.Address) (*IAutomationRegistryMasterPaymentWithdrawnIterator, error) { + + var transmitterRule []interface{} + for _, transmitterItem := range transmitter { + transmitterRule = append(transmitterRule, transmitterItem) + } + var amountRule []interface{} + for _, amountItem := range amount { + amountRule = append(amountRule, amountItem) + } + var toRule []interface{} + for _, toItem := range to { + toRule = append(toRule, toItem) + } + + logs, sub, err := _IAutomationRegistryMaster.contract.FilterLogs(opts, "PaymentWithdrawn", transmitterRule, amountRule, toRule) + if err != nil { + return nil, err + } + return &IAutomationRegistryMasterPaymentWithdrawnIterator{contract: _IAutomationRegistryMaster.contract, event: "PaymentWithdrawn", logs: logs, sub: sub}, nil +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterFilterer) WatchPaymentWithdrawn(opts *bind.WatchOpts, sink chan<- *IAutomationRegistryMasterPaymentWithdrawn, transmitter []common.Address, amount []*big.Int, to []common.Address) (event.Subscription, error) { + + var transmitterRule []interface{} + for _, transmitterItem := range transmitter { + transmitterRule = append(transmitterRule, transmitterItem) + } + var amountRule []interface{} + for _, amountItem := range amount { + amountRule = append(amountRule, amountItem) + } + var toRule []interface{} + for _, toItem := range to { + toRule = append(toRule, toItem) + } + + logs, sub, err := _IAutomationRegistryMaster.contract.WatchLogs(opts, "PaymentWithdrawn", transmitterRule, amountRule, 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(IAutomationRegistryMasterPaymentWithdrawn) + if err := _IAutomationRegistryMaster.contract.UnpackLog(event, "PaymentWithdrawn", 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 (_IAutomationRegistryMaster *IAutomationRegistryMasterFilterer) ParsePaymentWithdrawn(log types.Log) (*IAutomationRegistryMasterPaymentWithdrawn, error) { + event := new(IAutomationRegistryMasterPaymentWithdrawn) + if err := _IAutomationRegistryMaster.contract.UnpackLog(event, "PaymentWithdrawn", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type IAutomationRegistryMasterReorgedUpkeepReportIterator struct { + Event *IAutomationRegistryMasterReorgedUpkeepReport + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *IAutomationRegistryMasterReorgedUpkeepReportIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(IAutomationRegistryMasterReorgedUpkeepReport) + 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(IAutomationRegistryMasterReorgedUpkeepReport) + 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 *IAutomationRegistryMasterReorgedUpkeepReportIterator) Error() error { + return it.fail +} + +func (it *IAutomationRegistryMasterReorgedUpkeepReportIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type IAutomationRegistryMasterReorgedUpkeepReport struct { + Id *big.Int + Trigger []byte + Raw types.Log +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterFilterer) FilterReorgedUpkeepReport(opts *bind.FilterOpts, id []*big.Int) (*IAutomationRegistryMasterReorgedUpkeepReportIterator, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + + logs, sub, err := _IAutomationRegistryMaster.contract.FilterLogs(opts, "ReorgedUpkeepReport", idRule) + if err != nil { + return nil, err + } + return &IAutomationRegistryMasterReorgedUpkeepReportIterator{contract: _IAutomationRegistryMaster.contract, event: "ReorgedUpkeepReport", logs: logs, sub: sub}, nil +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterFilterer) WatchReorgedUpkeepReport(opts *bind.WatchOpts, sink chan<- *IAutomationRegistryMasterReorgedUpkeepReport, id []*big.Int) (event.Subscription, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + + logs, sub, err := _IAutomationRegistryMaster.contract.WatchLogs(opts, "ReorgedUpkeepReport", idRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(IAutomationRegistryMasterReorgedUpkeepReport) + if err := _IAutomationRegistryMaster.contract.UnpackLog(event, "ReorgedUpkeepReport", 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 (_IAutomationRegistryMaster *IAutomationRegistryMasterFilterer) ParseReorgedUpkeepReport(log types.Log) (*IAutomationRegistryMasterReorgedUpkeepReport, error) { + event := new(IAutomationRegistryMasterReorgedUpkeepReport) + if err := _IAutomationRegistryMaster.contract.UnpackLog(event, "ReorgedUpkeepReport", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type IAutomationRegistryMasterStaleUpkeepReportIterator struct { + Event *IAutomationRegistryMasterStaleUpkeepReport + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *IAutomationRegistryMasterStaleUpkeepReportIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(IAutomationRegistryMasterStaleUpkeepReport) + 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(IAutomationRegistryMasterStaleUpkeepReport) + 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 *IAutomationRegistryMasterStaleUpkeepReportIterator) Error() error { + return it.fail +} + +func (it *IAutomationRegistryMasterStaleUpkeepReportIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type IAutomationRegistryMasterStaleUpkeepReport struct { + Id *big.Int + Trigger []byte + Raw types.Log +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterFilterer) FilterStaleUpkeepReport(opts *bind.FilterOpts, id []*big.Int) (*IAutomationRegistryMasterStaleUpkeepReportIterator, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + + logs, sub, err := _IAutomationRegistryMaster.contract.FilterLogs(opts, "StaleUpkeepReport", idRule) + if err != nil { + return nil, err + } + return &IAutomationRegistryMasterStaleUpkeepReportIterator{contract: _IAutomationRegistryMaster.contract, event: "StaleUpkeepReport", logs: logs, sub: sub}, nil +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterFilterer) WatchStaleUpkeepReport(opts *bind.WatchOpts, sink chan<- *IAutomationRegistryMasterStaleUpkeepReport, id []*big.Int) (event.Subscription, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + + logs, sub, err := _IAutomationRegistryMaster.contract.WatchLogs(opts, "StaleUpkeepReport", idRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(IAutomationRegistryMasterStaleUpkeepReport) + if err := _IAutomationRegistryMaster.contract.UnpackLog(event, "StaleUpkeepReport", 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 (_IAutomationRegistryMaster *IAutomationRegistryMasterFilterer) ParseStaleUpkeepReport(log types.Log) (*IAutomationRegistryMasterStaleUpkeepReport, error) { + event := new(IAutomationRegistryMasterStaleUpkeepReport) + if err := _IAutomationRegistryMaster.contract.UnpackLog(event, "StaleUpkeepReport", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type IAutomationRegistryMasterTransmittedIterator struct { + Event *IAutomationRegistryMasterTransmitted + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *IAutomationRegistryMasterTransmittedIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(IAutomationRegistryMasterTransmitted) + 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(IAutomationRegistryMasterTransmitted) + 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 *IAutomationRegistryMasterTransmittedIterator) Error() error { + return it.fail +} + +func (it *IAutomationRegistryMasterTransmittedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type IAutomationRegistryMasterTransmitted struct { + ConfigDigest [32]byte + Epoch uint32 + Raw types.Log +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterFilterer) FilterTransmitted(opts *bind.FilterOpts) (*IAutomationRegistryMasterTransmittedIterator, error) { + + logs, sub, err := _IAutomationRegistryMaster.contract.FilterLogs(opts, "Transmitted") + if err != nil { + return nil, err + } + return &IAutomationRegistryMasterTransmittedIterator{contract: _IAutomationRegistryMaster.contract, event: "Transmitted", logs: logs, sub: sub}, nil +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterFilterer) WatchTransmitted(opts *bind.WatchOpts, sink chan<- *IAutomationRegistryMasterTransmitted) (event.Subscription, error) { + + logs, sub, err := _IAutomationRegistryMaster.contract.WatchLogs(opts, "Transmitted") + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(IAutomationRegistryMasterTransmitted) + if err := _IAutomationRegistryMaster.contract.UnpackLog(event, "Transmitted", 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 (_IAutomationRegistryMaster *IAutomationRegistryMasterFilterer) ParseTransmitted(log types.Log) (*IAutomationRegistryMasterTransmitted, error) { + event := new(IAutomationRegistryMasterTransmitted) + if err := _IAutomationRegistryMaster.contract.UnpackLog(event, "Transmitted", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type IAutomationRegistryMasterUnpausedIterator struct { + Event *IAutomationRegistryMasterUnpaused + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *IAutomationRegistryMasterUnpausedIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(IAutomationRegistryMasterUnpaused) + 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(IAutomationRegistryMasterUnpaused) + 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 *IAutomationRegistryMasterUnpausedIterator) Error() error { + return it.fail +} + +func (it *IAutomationRegistryMasterUnpausedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type IAutomationRegistryMasterUnpaused struct { + Account common.Address + Raw types.Log +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterFilterer) FilterUnpaused(opts *bind.FilterOpts) (*IAutomationRegistryMasterUnpausedIterator, error) { + + logs, sub, err := _IAutomationRegistryMaster.contract.FilterLogs(opts, "Unpaused") + if err != nil { + return nil, err + } + return &IAutomationRegistryMasterUnpausedIterator{contract: _IAutomationRegistryMaster.contract, event: "Unpaused", logs: logs, sub: sub}, nil +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterFilterer) WatchUnpaused(opts *bind.WatchOpts, sink chan<- *IAutomationRegistryMasterUnpaused) (event.Subscription, error) { + + logs, sub, err := _IAutomationRegistryMaster.contract.WatchLogs(opts, "Unpaused") + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(IAutomationRegistryMasterUnpaused) + if err := _IAutomationRegistryMaster.contract.UnpackLog(event, "Unpaused", 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 (_IAutomationRegistryMaster *IAutomationRegistryMasterFilterer) ParseUnpaused(log types.Log) (*IAutomationRegistryMasterUnpaused, error) { + event := new(IAutomationRegistryMasterUnpaused) + if err := _IAutomationRegistryMaster.contract.UnpackLog(event, "Unpaused", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type IAutomationRegistryMasterUpkeepAdminTransferRequestedIterator struct { + Event *IAutomationRegistryMasterUpkeepAdminTransferRequested + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *IAutomationRegistryMasterUpkeepAdminTransferRequestedIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(IAutomationRegistryMasterUpkeepAdminTransferRequested) + 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(IAutomationRegistryMasterUpkeepAdminTransferRequested) + 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 *IAutomationRegistryMasterUpkeepAdminTransferRequestedIterator) Error() error { + return it.fail +} + +func (it *IAutomationRegistryMasterUpkeepAdminTransferRequestedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type IAutomationRegistryMasterUpkeepAdminTransferRequested struct { + Id *big.Int + From common.Address + To common.Address + Raw types.Log +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterFilterer) FilterUpkeepAdminTransferRequested(opts *bind.FilterOpts, id []*big.Int, from []common.Address, to []common.Address) (*IAutomationRegistryMasterUpkeepAdminTransferRequestedIterator, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + 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 := _IAutomationRegistryMaster.contract.FilterLogs(opts, "UpkeepAdminTransferRequested", idRule, fromRule, toRule) + if err != nil { + return nil, err + } + return &IAutomationRegistryMasterUpkeepAdminTransferRequestedIterator{contract: _IAutomationRegistryMaster.contract, event: "UpkeepAdminTransferRequested", logs: logs, sub: sub}, nil +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterFilterer) WatchUpkeepAdminTransferRequested(opts *bind.WatchOpts, sink chan<- *IAutomationRegistryMasterUpkeepAdminTransferRequested, id []*big.Int, from []common.Address, to []common.Address) (event.Subscription, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + 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 := _IAutomationRegistryMaster.contract.WatchLogs(opts, "UpkeepAdminTransferRequested", idRule, 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(IAutomationRegistryMasterUpkeepAdminTransferRequested) + if err := _IAutomationRegistryMaster.contract.UnpackLog(event, "UpkeepAdminTransferRequested", 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 (_IAutomationRegistryMaster *IAutomationRegistryMasterFilterer) ParseUpkeepAdminTransferRequested(log types.Log) (*IAutomationRegistryMasterUpkeepAdminTransferRequested, error) { + event := new(IAutomationRegistryMasterUpkeepAdminTransferRequested) + if err := _IAutomationRegistryMaster.contract.UnpackLog(event, "UpkeepAdminTransferRequested", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type IAutomationRegistryMasterUpkeepAdminTransferredIterator struct { + Event *IAutomationRegistryMasterUpkeepAdminTransferred + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *IAutomationRegistryMasterUpkeepAdminTransferredIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(IAutomationRegistryMasterUpkeepAdminTransferred) + 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(IAutomationRegistryMasterUpkeepAdminTransferred) + 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 *IAutomationRegistryMasterUpkeepAdminTransferredIterator) Error() error { + return it.fail +} + +func (it *IAutomationRegistryMasterUpkeepAdminTransferredIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type IAutomationRegistryMasterUpkeepAdminTransferred struct { + Id *big.Int + From common.Address + To common.Address + Raw types.Log +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterFilterer) FilterUpkeepAdminTransferred(opts *bind.FilterOpts, id []*big.Int, from []common.Address, to []common.Address) (*IAutomationRegistryMasterUpkeepAdminTransferredIterator, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + 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 := _IAutomationRegistryMaster.contract.FilterLogs(opts, "UpkeepAdminTransferred", idRule, fromRule, toRule) + if err != nil { + return nil, err + } + return &IAutomationRegistryMasterUpkeepAdminTransferredIterator{contract: _IAutomationRegistryMaster.contract, event: "UpkeepAdminTransferred", logs: logs, sub: sub}, nil +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterFilterer) WatchUpkeepAdminTransferred(opts *bind.WatchOpts, sink chan<- *IAutomationRegistryMasterUpkeepAdminTransferred, id []*big.Int, from []common.Address, to []common.Address) (event.Subscription, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + 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 := _IAutomationRegistryMaster.contract.WatchLogs(opts, "UpkeepAdminTransferred", idRule, 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(IAutomationRegistryMasterUpkeepAdminTransferred) + if err := _IAutomationRegistryMaster.contract.UnpackLog(event, "UpkeepAdminTransferred", 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 (_IAutomationRegistryMaster *IAutomationRegistryMasterFilterer) ParseUpkeepAdminTransferred(log types.Log) (*IAutomationRegistryMasterUpkeepAdminTransferred, error) { + event := new(IAutomationRegistryMasterUpkeepAdminTransferred) + if err := _IAutomationRegistryMaster.contract.UnpackLog(event, "UpkeepAdminTransferred", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type IAutomationRegistryMasterUpkeepCanceledIterator struct { + Event *IAutomationRegistryMasterUpkeepCanceled + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *IAutomationRegistryMasterUpkeepCanceledIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(IAutomationRegistryMasterUpkeepCanceled) + 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(IAutomationRegistryMasterUpkeepCanceled) + 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 *IAutomationRegistryMasterUpkeepCanceledIterator) Error() error { + return it.fail +} + +func (it *IAutomationRegistryMasterUpkeepCanceledIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type IAutomationRegistryMasterUpkeepCanceled struct { + Id *big.Int + AtBlockHeight uint64 + Raw types.Log +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterFilterer) FilterUpkeepCanceled(opts *bind.FilterOpts, id []*big.Int, atBlockHeight []uint64) (*IAutomationRegistryMasterUpkeepCanceledIterator, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + var atBlockHeightRule []interface{} + for _, atBlockHeightItem := range atBlockHeight { + atBlockHeightRule = append(atBlockHeightRule, atBlockHeightItem) + } + + logs, sub, err := _IAutomationRegistryMaster.contract.FilterLogs(opts, "UpkeepCanceled", idRule, atBlockHeightRule) + if err != nil { + return nil, err + } + return &IAutomationRegistryMasterUpkeepCanceledIterator{contract: _IAutomationRegistryMaster.contract, event: "UpkeepCanceled", logs: logs, sub: sub}, nil +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterFilterer) WatchUpkeepCanceled(opts *bind.WatchOpts, sink chan<- *IAutomationRegistryMasterUpkeepCanceled, id []*big.Int, atBlockHeight []uint64) (event.Subscription, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + var atBlockHeightRule []interface{} + for _, atBlockHeightItem := range atBlockHeight { + atBlockHeightRule = append(atBlockHeightRule, atBlockHeightItem) + } + + logs, sub, err := _IAutomationRegistryMaster.contract.WatchLogs(opts, "UpkeepCanceled", idRule, atBlockHeightRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(IAutomationRegistryMasterUpkeepCanceled) + if err := _IAutomationRegistryMaster.contract.UnpackLog(event, "UpkeepCanceled", 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 (_IAutomationRegistryMaster *IAutomationRegistryMasterFilterer) ParseUpkeepCanceled(log types.Log) (*IAutomationRegistryMasterUpkeepCanceled, error) { + event := new(IAutomationRegistryMasterUpkeepCanceled) + if err := _IAutomationRegistryMaster.contract.UnpackLog(event, "UpkeepCanceled", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type IAutomationRegistryMasterUpkeepCheckDataSetIterator struct { + Event *IAutomationRegistryMasterUpkeepCheckDataSet + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *IAutomationRegistryMasterUpkeepCheckDataSetIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(IAutomationRegistryMasterUpkeepCheckDataSet) + 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(IAutomationRegistryMasterUpkeepCheckDataSet) + 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 *IAutomationRegistryMasterUpkeepCheckDataSetIterator) Error() error { + return it.fail +} + +func (it *IAutomationRegistryMasterUpkeepCheckDataSetIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type IAutomationRegistryMasterUpkeepCheckDataSet struct { + Id *big.Int + NewCheckData []byte + Raw types.Log +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterFilterer) FilterUpkeepCheckDataSet(opts *bind.FilterOpts, id []*big.Int) (*IAutomationRegistryMasterUpkeepCheckDataSetIterator, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + + logs, sub, err := _IAutomationRegistryMaster.contract.FilterLogs(opts, "UpkeepCheckDataSet", idRule) + if err != nil { + return nil, err + } + return &IAutomationRegistryMasterUpkeepCheckDataSetIterator{contract: _IAutomationRegistryMaster.contract, event: "UpkeepCheckDataSet", logs: logs, sub: sub}, nil +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterFilterer) WatchUpkeepCheckDataSet(opts *bind.WatchOpts, sink chan<- *IAutomationRegistryMasterUpkeepCheckDataSet, id []*big.Int) (event.Subscription, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + + logs, sub, err := _IAutomationRegistryMaster.contract.WatchLogs(opts, "UpkeepCheckDataSet", idRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(IAutomationRegistryMasterUpkeepCheckDataSet) + if err := _IAutomationRegistryMaster.contract.UnpackLog(event, "UpkeepCheckDataSet", 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 (_IAutomationRegistryMaster *IAutomationRegistryMasterFilterer) ParseUpkeepCheckDataSet(log types.Log) (*IAutomationRegistryMasterUpkeepCheckDataSet, error) { + event := new(IAutomationRegistryMasterUpkeepCheckDataSet) + if err := _IAutomationRegistryMaster.contract.UnpackLog(event, "UpkeepCheckDataSet", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type IAutomationRegistryMasterUpkeepGasLimitSetIterator struct { + Event *IAutomationRegistryMasterUpkeepGasLimitSet + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *IAutomationRegistryMasterUpkeepGasLimitSetIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(IAutomationRegistryMasterUpkeepGasLimitSet) + 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(IAutomationRegistryMasterUpkeepGasLimitSet) + 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 *IAutomationRegistryMasterUpkeepGasLimitSetIterator) Error() error { + return it.fail +} + +func (it *IAutomationRegistryMasterUpkeepGasLimitSetIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type IAutomationRegistryMasterUpkeepGasLimitSet struct { + Id *big.Int + GasLimit *big.Int + Raw types.Log +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterFilterer) FilterUpkeepGasLimitSet(opts *bind.FilterOpts, id []*big.Int) (*IAutomationRegistryMasterUpkeepGasLimitSetIterator, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + + logs, sub, err := _IAutomationRegistryMaster.contract.FilterLogs(opts, "UpkeepGasLimitSet", idRule) + if err != nil { + return nil, err + } + return &IAutomationRegistryMasterUpkeepGasLimitSetIterator{contract: _IAutomationRegistryMaster.contract, event: "UpkeepGasLimitSet", logs: logs, sub: sub}, nil +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterFilterer) WatchUpkeepGasLimitSet(opts *bind.WatchOpts, sink chan<- *IAutomationRegistryMasterUpkeepGasLimitSet, id []*big.Int) (event.Subscription, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + + logs, sub, err := _IAutomationRegistryMaster.contract.WatchLogs(opts, "UpkeepGasLimitSet", idRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(IAutomationRegistryMasterUpkeepGasLimitSet) + if err := _IAutomationRegistryMaster.contract.UnpackLog(event, "UpkeepGasLimitSet", 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 (_IAutomationRegistryMaster *IAutomationRegistryMasterFilterer) ParseUpkeepGasLimitSet(log types.Log) (*IAutomationRegistryMasterUpkeepGasLimitSet, error) { + event := new(IAutomationRegistryMasterUpkeepGasLimitSet) + if err := _IAutomationRegistryMaster.contract.UnpackLog(event, "UpkeepGasLimitSet", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type IAutomationRegistryMasterUpkeepMigratedIterator struct { + Event *IAutomationRegistryMasterUpkeepMigrated + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *IAutomationRegistryMasterUpkeepMigratedIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(IAutomationRegistryMasterUpkeepMigrated) + 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(IAutomationRegistryMasterUpkeepMigrated) + 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 *IAutomationRegistryMasterUpkeepMigratedIterator) Error() error { + return it.fail +} + +func (it *IAutomationRegistryMasterUpkeepMigratedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type IAutomationRegistryMasterUpkeepMigrated struct { + Id *big.Int + RemainingBalance *big.Int + Destination common.Address + Raw types.Log +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterFilterer) FilterUpkeepMigrated(opts *bind.FilterOpts, id []*big.Int) (*IAutomationRegistryMasterUpkeepMigratedIterator, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + + logs, sub, err := _IAutomationRegistryMaster.contract.FilterLogs(opts, "UpkeepMigrated", idRule) + if err != nil { + return nil, err + } + return &IAutomationRegistryMasterUpkeepMigratedIterator{contract: _IAutomationRegistryMaster.contract, event: "UpkeepMigrated", logs: logs, sub: sub}, nil +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterFilterer) WatchUpkeepMigrated(opts *bind.WatchOpts, sink chan<- *IAutomationRegistryMasterUpkeepMigrated, id []*big.Int) (event.Subscription, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + + logs, sub, err := _IAutomationRegistryMaster.contract.WatchLogs(opts, "UpkeepMigrated", idRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(IAutomationRegistryMasterUpkeepMigrated) + if err := _IAutomationRegistryMaster.contract.UnpackLog(event, "UpkeepMigrated", 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 (_IAutomationRegistryMaster *IAutomationRegistryMasterFilterer) ParseUpkeepMigrated(log types.Log) (*IAutomationRegistryMasterUpkeepMigrated, error) { + event := new(IAutomationRegistryMasterUpkeepMigrated) + if err := _IAutomationRegistryMaster.contract.UnpackLog(event, "UpkeepMigrated", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type IAutomationRegistryMasterUpkeepOffchainConfigSetIterator struct { + Event *IAutomationRegistryMasterUpkeepOffchainConfigSet + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *IAutomationRegistryMasterUpkeepOffchainConfigSetIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(IAutomationRegistryMasterUpkeepOffchainConfigSet) + 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(IAutomationRegistryMasterUpkeepOffchainConfigSet) + 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 *IAutomationRegistryMasterUpkeepOffchainConfigSetIterator) Error() error { + return it.fail +} + +func (it *IAutomationRegistryMasterUpkeepOffchainConfigSetIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type IAutomationRegistryMasterUpkeepOffchainConfigSet struct { + Id *big.Int + OffchainConfig []byte + Raw types.Log +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterFilterer) FilterUpkeepOffchainConfigSet(opts *bind.FilterOpts, id []*big.Int) (*IAutomationRegistryMasterUpkeepOffchainConfigSetIterator, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + + logs, sub, err := _IAutomationRegistryMaster.contract.FilterLogs(opts, "UpkeepOffchainConfigSet", idRule) + if err != nil { + return nil, err + } + return &IAutomationRegistryMasterUpkeepOffchainConfigSetIterator{contract: _IAutomationRegistryMaster.contract, event: "UpkeepOffchainConfigSet", logs: logs, sub: sub}, nil +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterFilterer) WatchUpkeepOffchainConfigSet(opts *bind.WatchOpts, sink chan<- *IAutomationRegistryMasterUpkeepOffchainConfigSet, id []*big.Int) (event.Subscription, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + + logs, sub, err := _IAutomationRegistryMaster.contract.WatchLogs(opts, "UpkeepOffchainConfigSet", idRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(IAutomationRegistryMasterUpkeepOffchainConfigSet) + if err := _IAutomationRegistryMaster.contract.UnpackLog(event, "UpkeepOffchainConfigSet", 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 (_IAutomationRegistryMaster *IAutomationRegistryMasterFilterer) ParseUpkeepOffchainConfigSet(log types.Log) (*IAutomationRegistryMasterUpkeepOffchainConfigSet, error) { + event := new(IAutomationRegistryMasterUpkeepOffchainConfigSet) + if err := _IAutomationRegistryMaster.contract.UnpackLog(event, "UpkeepOffchainConfigSet", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type IAutomationRegistryMasterUpkeepPausedIterator struct { + Event *IAutomationRegistryMasterUpkeepPaused + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *IAutomationRegistryMasterUpkeepPausedIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(IAutomationRegistryMasterUpkeepPaused) + 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(IAutomationRegistryMasterUpkeepPaused) + 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 *IAutomationRegistryMasterUpkeepPausedIterator) Error() error { + return it.fail +} + +func (it *IAutomationRegistryMasterUpkeepPausedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type IAutomationRegistryMasterUpkeepPaused struct { + Id *big.Int + Raw types.Log +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterFilterer) FilterUpkeepPaused(opts *bind.FilterOpts, id []*big.Int) (*IAutomationRegistryMasterUpkeepPausedIterator, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + + logs, sub, err := _IAutomationRegistryMaster.contract.FilterLogs(opts, "UpkeepPaused", idRule) + if err != nil { + return nil, err + } + return &IAutomationRegistryMasterUpkeepPausedIterator{contract: _IAutomationRegistryMaster.contract, event: "UpkeepPaused", logs: logs, sub: sub}, nil +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterFilterer) WatchUpkeepPaused(opts *bind.WatchOpts, sink chan<- *IAutomationRegistryMasterUpkeepPaused, id []*big.Int) (event.Subscription, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + + logs, sub, err := _IAutomationRegistryMaster.contract.WatchLogs(opts, "UpkeepPaused", idRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(IAutomationRegistryMasterUpkeepPaused) + if err := _IAutomationRegistryMaster.contract.UnpackLog(event, "UpkeepPaused", 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 (_IAutomationRegistryMaster *IAutomationRegistryMasterFilterer) ParseUpkeepPaused(log types.Log) (*IAutomationRegistryMasterUpkeepPaused, error) { + event := new(IAutomationRegistryMasterUpkeepPaused) + if err := _IAutomationRegistryMaster.contract.UnpackLog(event, "UpkeepPaused", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type IAutomationRegistryMasterUpkeepPerformedIterator struct { + Event *IAutomationRegistryMasterUpkeepPerformed + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *IAutomationRegistryMasterUpkeepPerformedIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(IAutomationRegistryMasterUpkeepPerformed) + 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(IAutomationRegistryMasterUpkeepPerformed) + 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 *IAutomationRegistryMasterUpkeepPerformedIterator) Error() error { + return it.fail +} + +func (it *IAutomationRegistryMasterUpkeepPerformedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type IAutomationRegistryMasterUpkeepPerformed struct { + Id *big.Int + Success bool + TotalPayment *big.Int + GasUsed *big.Int + GasOverhead *big.Int + Trigger []byte + Raw types.Log +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterFilterer) FilterUpkeepPerformed(opts *bind.FilterOpts, id []*big.Int, success []bool) (*IAutomationRegistryMasterUpkeepPerformedIterator, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + var successRule []interface{} + for _, successItem := range success { + successRule = append(successRule, successItem) + } + + logs, sub, err := _IAutomationRegistryMaster.contract.FilterLogs(opts, "UpkeepPerformed", idRule, successRule) + if err != nil { + return nil, err + } + return &IAutomationRegistryMasterUpkeepPerformedIterator{contract: _IAutomationRegistryMaster.contract, event: "UpkeepPerformed", logs: logs, sub: sub}, nil +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterFilterer) WatchUpkeepPerformed(opts *bind.WatchOpts, sink chan<- *IAutomationRegistryMasterUpkeepPerformed, id []*big.Int, success []bool) (event.Subscription, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + var successRule []interface{} + for _, successItem := range success { + successRule = append(successRule, successItem) + } + + logs, sub, err := _IAutomationRegistryMaster.contract.WatchLogs(opts, "UpkeepPerformed", idRule, successRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(IAutomationRegistryMasterUpkeepPerformed) + if err := _IAutomationRegistryMaster.contract.UnpackLog(event, "UpkeepPerformed", 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 (_IAutomationRegistryMaster *IAutomationRegistryMasterFilterer) ParseUpkeepPerformed(log types.Log) (*IAutomationRegistryMasterUpkeepPerformed, error) { + event := new(IAutomationRegistryMasterUpkeepPerformed) + if err := _IAutomationRegistryMaster.contract.UnpackLog(event, "UpkeepPerformed", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type IAutomationRegistryMasterUpkeepPrivilegeConfigSetIterator struct { + Event *IAutomationRegistryMasterUpkeepPrivilegeConfigSet + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *IAutomationRegistryMasterUpkeepPrivilegeConfigSetIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(IAutomationRegistryMasterUpkeepPrivilegeConfigSet) + 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(IAutomationRegistryMasterUpkeepPrivilegeConfigSet) + 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 *IAutomationRegistryMasterUpkeepPrivilegeConfigSetIterator) Error() error { + return it.fail +} + +func (it *IAutomationRegistryMasterUpkeepPrivilegeConfigSetIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type IAutomationRegistryMasterUpkeepPrivilegeConfigSet struct { + Id *big.Int + PrivilegeConfig []byte + Raw types.Log +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterFilterer) FilterUpkeepPrivilegeConfigSet(opts *bind.FilterOpts, id []*big.Int) (*IAutomationRegistryMasterUpkeepPrivilegeConfigSetIterator, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + + logs, sub, err := _IAutomationRegistryMaster.contract.FilterLogs(opts, "UpkeepPrivilegeConfigSet", idRule) + if err != nil { + return nil, err + } + return &IAutomationRegistryMasterUpkeepPrivilegeConfigSetIterator{contract: _IAutomationRegistryMaster.contract, event: "UpkeepPrivilegeConfigSet", logs: logs, sub: sub}, nil +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterFilterer) WatchUpkeepPrivilegeConfigSet(opts *bind.WatchOpts, sink chan<- *IAutomationRegistryMasterUpkeepPrivilegeConfigSet, id []*big.Int) (event.Subscription, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + + logs, sub, err := _IAutomationRegistryMaster.contract.WatchLogs(opts, "UpkeepPrivilegeConfigSet", idRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(IAutomationRegistryMasterUpkeepPrivilegeConfigSet) + if err := _IAutomationRegistryMaster.contract.UnpackLog(event, "UpkeepPrivilegeConfigSet", 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 (_IAutomationRegistryMaster *IAutomationRegistryMasterFilterer) ParseUpkeepPrivilegeConfigSet(log types.Log) (*IAutomationRegistryMasterUpkeepPrivilegeConfigSet, error) { + event := new(IAutomationRegistryMasterUpkeepPrivilegeConfigSet) + if err := _IAutomationRegistryMaster.contract.UnpackLog(event, "UpkeepPrivilegeConfigSet", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type IAutomationRegistryMasterUpkeepReceivedIterator struct { + Event *IAutomationRegistryMasterUpkeepReceived + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *IAutomationRegistryMasterUpkeepReceivedIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(IAutomationRegistryMasterUpkeepReceived) + 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(IAutomationRegistryMasterUpkeepReceived) + 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 *IAutomationRegistryMasterUpkeepReceivedIterator) Error() error { + return it.fail +} + +func (it *IAutomationRegistryMasterUpkeepReceivedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type IAutomationRegistryMasterUpkeepReceived struct { + Id *big.Int + StartingBalance *big.Int + ImportedFrom common.Address + Raw types.Log +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterFilterer) FilterUpkeepReceived(opts *bind.FilterOpts, id []*big.Int) (*IAutomationRegistryMasterUpkeepReceivedIterator, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + + logs, sub, err := _IAutomationRegistryMaster.contract.FilterLogs(opts, "UpkeepReceived", idRule) + if err != nil { + return nil, err + } + return &IAutomationRegistryMasterUpkeepReceivedIterator{contract: _IAutomationRegistryMaster.contract, event: "UpkeepReceived", logs: logs, sub: sub}, nil +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterFilterer) WatchUpkeepReceived(opts *bind.WatchOpts, sink chan<- *IAutomationRegistryMasterUpkeepReceived, id []*big.Int) (event.Subscription, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + + logs, sub, err := _IAutomationRegistryMaster.contract.WatchLogs(opts, "UpkeepReceived", idRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(IAutomationRegistryMasterUpkeepReceived) + if err := _IAutomationRegistryMaster.contract.UnpackLog(event, "UpkeepReceived", 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 (_IAutomationRegistryMaster *IAutomationRegistryMasterFilterer) ParseUpkeepReceived(log types.Log) (*IAutomationRegistryMasterUpkeepReceived, error) { + event := new(IAutomationRegistryMasterUpkeepReceived) + if err := _IAutomationRegistryMaster.contract.UnpackLog(event, "UpkeepReceived", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type IAutomationRegistryMasterUpkeepRegisteredIterator struct { + Event *IAutomationRegistryMasterUpkeepRegistered + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *IAutomationRegistryMasterUpkeepRegisteredIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(IAutomationRegistryMasterUpkeepRegistered) + 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(IAutomationRegistryMasterUpkeepRegistered) + 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 *IAutomationRegistryMasterUpkeepRegisteredIterator) Error() error { + return it.fail +} + +func (it *IAutomationRegistryMasterUpkeepRegisteredIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type IAutomationRegistryMasterUpkeepRegistered struct { + Id *big.Int + PerformGas uint32 + Admin common.Address + Raw types.Log +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterFilterer) FilterUpkeepRegistered(opts *bind.FilterOpts, id []*big.Int) (*IAutomationRegistryMasterUpkeepRegisteredIterator, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + + logs, sub, err := _IAutomationRegistryMaster.contract.FilterLogs(opts, "UpkeepRegistered", idRule) + if err != nil { + return nil, err + } + return &IAutomationRegistryMasterUpkeepRegisteredIterator{contract: _IAutomationRegistryMaster.contract, event: "UpkeepRegistered", logs: logs, sub: sub}, nil +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterFilterer) WatchUpkeepRegistered(opts *bind.WatchOpts, sink chan<- *IAutomationRegistryMasterUpkeepRegistered, id []*big.Int) (event.Subscription, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + + logs, sub, err := _IAutomationRegistryMaster.contract.WatchLogs(opts, "UpkeepRegistered", idRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(IAutomationRegistryMasterUpkeepRegistered) + if err := _IAutomationRegistryMaster.contract.UnpackLog(event, "UpkeepRegistered", 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 (_IAutomationRegistryMaster *IAutomationRegistryMasterFilterer) ParseUpkeepRegistered(log types.Log) (*IAutomationRegistryMasterUpkeepRegistered, error) { + event := new(IAutomationRegistryMasterUpkeepRegistered) + if err := _IAutomationRegistryMaster.contract.UnpackLog(event, "UpkeepRegistered", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type IAutomationRegistryMasterUpkeepTriggerConfigSetIterator struct { + Event *IAutomationRegistryMasterUpkeepTriggerConfigSet + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *IAutomationRegistryMasterUpkeepTriggerConfigSetIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(IAutomationRegistryMasterUpkeepTriggerConfigSet) + 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(IAutomationRegistryMasterUpkeepTriggerConfigSet) + 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 *IAutomationRegistryMasterUpkeepTriggerConfigSetIterator) Error() error { + return it.fail +} + +func (it *IAutomationRegistryMasterUpkeepTriggerConfigSetIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type IAutomationRegistryMasterUpkeepTriggerConfigSet struct { + Id *big.Int + TriggerConfig []byte + Raw types.Log +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterFilterer) FilterUpkeepTriggerConfigSet(opts *bind.FilterOpts, id []*big.Int) (*IAutomationRegistryMasterUpkeepTriggerConfigSetIterator, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + + logs, sub, err := _IAutomationRegistryMaster.contract.FilterLogs(opts, "UpkeepTriggerConfigSet", idRule) + if err != nil { + return nil, err + } + return &IAutomationRegistryMasterUpkeepTriggerConfigSetIterator{contract: _IAutomationRegistryMaster.contract, event: "UpkeepTriggerConfigSet", logs: logs, sub: sub}, nil +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterFilterer) WatchUpkeepTriggerConfigSet(opts *bind.WatchOpts, sink chan<- *IAutomationRegistryMasterUpkeepTriggerConfigSet, id []*big.Int) (event.Subscription, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + + logs, sub, err := _IAutomationRegistryMaster.contract.WatchLogs(opts, "UpkeepTriggerConfigSet", idRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(IAutomationRegistryMasterUpkeepTriggerConfigSet) + if err := _IAutomationRegistryMaster.contract.UnpackLog(event, "UpkeepTriggerConfigSet", 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 (_IAutomationRegistryMaster *IAutomationRegistryMasterFilterer) ParseUpkeepTriggerConfigSet(log types.Log) (*IAutomationRegistryMasterUpkeepTriggerConfigSet, error) { + event := new(IAutomationRegistryMasterUpkeepTriggerConfigSet) + if err := _IAutomationRegistryMaster.contract.UnpackLog(event, "UpkeepTriggerConfigSet", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type IAutomationRegistryMasterUpkeepUnpausedIterator struct { + Event *IAutomationRegistryMasterUpkeepUnpaused + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *IAutomationRegistryMasterUpkeepUnpausedIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(IAutomationRegistryMasterUpkeepUnpaused) + 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(IAutomationRegistryMasterUpkeepUnpaused) + 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 *IAutomationRegistryMasterUpkeepUnpausedIterator) Error() error { + return it.fail +} + +func (it *IAutomationRegistryMasterUpkeepUnpausedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type IAutomationRegistryMasterUpkeepUnpaused struct { + Id *big.Int + Raw types.Log +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterFilterer) FilterUpkeepUnpaused(opts *bind.FilterOpts, id []*big.Int) (*IAutomationRegistryMasterUpkeepUnpausedIterator, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + + logs, sub, err := _IAutomationRegistryMaster.contract.FilterLogs(opts, "UpkeepUnpaused", idRule) + if err != nil { + return nil, err + } + return &IAutomationRegistryMasterUpkeepUnpausedIterator{contract: _IAutomationRegistryMaster.contract, event: "UpkeepUnpaused", logs: logs, sub: sub}, nil +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterFilterer) WatchUpkeepUnpaused(opts *bind.WatchOpts, sink chan<- *IAutomationRegistryMasterUpkeepUnpaused, id []*big.Int) (event.Subscription, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + + logs, sub, err := _IAutomationRegistryMaster.contract.WatchLogs(opts, "UpkeepUnpaused", idRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(IAutomationRegistryMasterUpkeepUnpaused) + if err := _IAutomationRegistryMaster.contract.UnpackLog(event, "UpkeepUnpaused", 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 (_IAutomationRegistryMaster *IAutomationRegistryMasterFilterer) ParseUpkeepUnpaused(log types.Log) (*IAutomationRegistryMasterUpkeepUnpaused, error) { + event := new(IAutomationRegistryMasterUpkeepUnpaused) + if err := _IAutomationRegistryMaster.contract.UnpackLog(event, "UpkeepUnpaused", log); err != nil { + return nil, err + } + event.Raw = log + 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 +} +type GetState struct { + State AutomationRegistryBase22State + Config AutomationRegistryBase22OnchainConfig + Signers []common.Address + Transmitters []common.Address + F uint8 +} +type GetTransmitterInfo struct { + Active bool + Index uint8 + Balance *big.Int + LastCollected *big.Int + Payee common.Address +} +type LatestConfigDetails struct { + ConfigCount uint32 + BlockNumber uint32 + ConfigDigest [32]byte +} +type LatestConfigDigestAndEpoch struct { + ScanLogs bool + ConfigDigest [32]byte + Epoch uint32 +} +type SimulatePerformUpkeep struct { + Success bool + GasUsed *big.Int +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMaster) ParseLog(log types.Log) (generated.AbigenLog, error) { + switch log.Topics[0] { + case _IAutomationRegistryMaster.abi.Events["AdminPrivilegeConfigSet"].ID: + return _IAutomationRegistryMaster.ParseAdminPrivilegeConfigSet(log) + case _IAutomationRegistryMaster.abi.Events["CancelledUpkeepReport"].ID: + return _IAutomationRegistryMaster.ParseCancelledUpkeepReport(log) + case _IAutomationRegistryMaster.abi.Events["ConfigSet"].ID: + return _IAutomationRegistryMaster.ParseConfigSet(log) + case _IAutomationRegistryMaster.abi.Events["DedupKeyAdded"].ID: + return _IAutomationRegistryMaster.ParseDedupKeyAdded(log) + case _IAutomationRegistryMaster.abi.Events["FundsAdded"].ID: + return _IAutomationRegistryMaster.ParseFundsAdded(log) + case _IAutomationRegistryMaster.abi.Events["FundsWithdrawn"].ID: + return _IAutomationRegistryMaster.ParseFundsWithdrawn(log) + case _IAutomationRegistryMaster.abi.Events["InsufficientFundsUpkeepReport"].ID: + return _IAutomationRegistryMaster.ParseInsufficientFundsUpkeepReport(log) + case _IAutomationRegistryMaster.abi.Events["OwnerFundsWithdrawn"].ID: + return _IAutomationRegistryMaster.ParseOwnerFundsWithdrawn(log) + case _IAutomationRegistryMaster.abi.Events["OwnershipTransferRequested"].ID: + return _IAutomationRegistryMaster.ParseOwnershipTransferRequested(log) + case _IAutomationRegistryMaster.abi.Events["OwnershipTransferred"].ID: + return _IAutomationRegistryMaster.ParseOwnershipTransferred(log) + case _IAutomationRegistryMaster.abi.Events["Paused"].ID: + return _IAutomationRegistryMaster.ParsePaused(log) + case _IAutomationRegistryMaster.abi.Events["PayeesUpdated"].ID: + return _IAutomationRegistryMaster.ParsePayeesUpdated(log) + case _IAutomationRegistryMaster.abi.Events["PayeeshipTransferRequested"].ID: + return _IAutomationRegistryMaster.ParsePayeeshipTransferRequested(log) + case _IAutomationRegistryMaster.abi.Events["PayeeshipTransferred"].ID: + return _IAutomationRegistryMaster.ParsePayeeshipTransferred(log) + case _IAutomationRegistryMaster.abi.Events["PaymentWithdrawn"].ID: + return _IAutomationRegistryMaster.ParsePaymentWithdrawn(log) + case _IAutomationRegistryMaster.abi.Events["ReorgedUpkeepReport"].ID: + return _IAutomationRegistryMaster.ParseReorgedUpkeepReport(log) + case _IAutomationRegistryMaster.abi.Events["StaleUpkeepReport"].ID: + return _IAutomationRegistryMaster.ParseStaleUpkeepReport(log) + case _IAutomationRegistryMaster.abi.Events["Transmitted"].ID: + return _IAutomationRegistryMaster.ParseTransmitted(log) + case _IAutomationRegistryMaster.abi.Events["Unpaused"].ID: + return _IAutomationRegistryMaster.ParseUnpaused(log) + case _IAutomationRegistryMaster.abi.Events["UpkeepAdminTransferRequested"].ID: + return _IAutomationRegistryMaster.ParseUpkeepAdminTransferRequested(log) + case _IAutomationRegistryMaster.abi.Events["UpkeepAdminTransferred"].ID: + return _IAutomationRegistryMaster.ParseUpkeepAdminTransferred(log) + case _IAutomationRegistryMaster.abi.Events["UpkeepCanceled"].ID: + return _IAutomationRegistryMaster.ParseUpkeepCanceled(log) + case _IAutomationRegistryMaster.abi.Events["UpkeepCheckDataSet"].ID: + return _IAutomationRegistryMaster.ParseUpkeepCheckDataSet(log) + case _IAutomationRegistryMaster.abi.Events["UpkeepGasLimitSet"].ID: + return _IAutomationRegistryMaster.ParseUpkeepGasLimitSet(log) + case _IAutomationRegistryMaster.abi.Events["UpkeepMigrated"].ID: + return _IAutomationRegistryMaster.ParseUpkeepMigrated(log) + case _IAutomationRegistryMaster.abi.Events["UpkeepOffchainConfigSet"].ID: + return _IAutomationRegistryMaster.ParseUpkeepOffchainConfigSet(log) + case _IAutomationRegistryMaster.abi.Events["UpkeepPaused"].ID: + return _IAutomationRegistryMaster.ParseUpkeepPaused(log) + case _IAutomationRegistryMaster.abi.Events["UpkeepPerformed"].ID: + return _IAutomationRegistryMaster.ParseUpkeepPerformed(log) + case _IAutomationRegistryMaster.abi.Events["UpkeepPrivilegeConfigSet"].ID: + return _IAutomationRegistryMaster.ParseUpkeepPrivilegeConfigSet(log) + case _IAutomationRegistryMaster.abi.Events["UpkeepReceived"].ID: + return _IAutomationRegistryMaster.ParseUpkeepReceived(log) + case _IAutomationRegistryMaster.abi.Events["UpkeepRegistered"].ID: + return _IAutomationRegistryMaster.ParseUpkeepRegistered(log) + case _IAutomationRegistryMaster.abi.Events["UpkeepTriggerConfigSet"].ID: + return _IAutomationRegistryMaster.ParseUpkeepTriggerConfigSet(log) + case _IAutomationRegistryMaster.abi.Events["UpkeepUnpaused"].ID: + return _IAutomationRegistryMaster.ParseUpkeepUnpaused(log) + + default: + return nil, fmt.Errorf("abigen wrapper received unknown log topic: %v", log.Topics[0]) + } +} + +func (IAutomationRegistryMasterAdminPrivilegeConfigSet) Topic() common.Hash { + return common.HexToHash("0x7c44b4eb59ee7873514e7e43e7718c269d872965938b288aa143befca62f99d2") +} + +func (IAutomationRegistryMasterCancelledUpkeepReport) Topic() common.Hash { + return common.HexToHash("0xc3237c8807c467c1b39b8d0395eff077313e691bf0a7388106792564ebfd5636") +} + +func (IAutomationRegistryMasterConfigSet) Topic() common.Hash { + return common.HexToHash("0x1591690b8638f5fb2dbec82ac741805ac5da8b45dc5263f4875b0496fdce4e05") +} + +func (IAutomationRegistryMasterDedupKeyAdded) Topic() common.Hash { + return common.HexToHash("0xa4a4e334c0e330143f9437484fe516c13bc560b86b5b0daf58e7084aaac228f2") +} + +func (IAutomationRegistryMasterFundsAdded) Topic() common.Hash { + return common.HexToHash("0xafd24114486da8ebfc32f3626dada8863652e187461aa74d4bfa734891506203") +} + +func (IAutomationRegistryMasterFundsWithdrawn) Topic() common.Hash { + return common.HexToHash("0xf3b5906e5672f3e524854103bcafbbdba80dbdfeca2c35e116127b1060a68318") +} + +func (IAutomationRegistryMasterInsufficientFundsUpkeepReport) Topic() common.Hash { + return common.HexToHash("0x377c8b0c126ae5248d27aca1c76fac4608aff85673ee3caf09747e1044549e02") +} + +func (IAutomationRegistryMasterOwnerFundsWithdrawn) Topic() common.Hash { + return common.HexToHash("0x1d07d0b0be43d3e5fee41a80b579af370affee03fa595bf56d5d4c19328162f1") +} + +func (IAutomationRegistryMasterOwnershipTransferRequested) Topic() common.Hash { + return common.HexToHash("0xed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae1278") +} + +func (IAutomationRegistryMasterOwnershipTransferred) Topic() common.Hash { + return common.HexToHash("0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0") +} + +func (IAutomationRegistryMasterPaused) Topic() common.Hash { + return common.HexToHash("0x62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a258") +} + +func (IAutomationRegistryMasterPayeesUpdated) Topic() common.Hash { + return common.HexToHash("0xa46de38886467c59be07a0675f14781206a5477d871628af46c2443822fcb725") +} + +func (IAutomationRegistryMasterPayeeshipTransferRequested) Topic() common.Hash { + return common.HexToHash("0x84f7c7c80bb8ed2279b4aab5f61cd05e6374073d38f46d7f32de8c30e9e38367") +} + +func (IAutomationRegistryMasterPayeeshipTransferred) Topic() common.Hash { + return common.HexToHash("0x78af32efdcad432315431e9b03d27e6cd98fb79c405fdc5af7c1714d9c0f75b3") +} + +func (IAutomationRegistryMasterPaymentWithdrawn) Topic() common.Hash { + return common.HexToHash("0x9819093176a1851202c7bcfa46845809b4e47c261866550e94ed3775d2f40698") +} + +func (IAutomationRegistryMasterReorgedUpkeepReport) Topic() common.Hash { + return common.HexToHash("0x6aa7f60c176da7af894b384daea2249497448137f5943c1237ada8bc92bdc301") +} + +func (IAutomationRegistryMasterStaleUpkeepReport) Topic() common.Hash { + return common.HexToHash("0x405288ea7be309e16cfdf481367f90a413e1d4634fcdaf8966546db9b93012e8") +} + +func (IAutomationRegistryMasterTransmitted) Topic() common.Hash { + return common.HexToHash("0xb04e63db38c49950639fa09d29872f21f5d49d614f3a969d8adf3d4b52e41a62") +} + +func (IAutomationRegistryMasterUnpaused) Topic() common.Hash { + return common.HexToHash("0x5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa") +} + +func (IAutomationRegistryMasterUpkeepAdminTransferRequested) Topic() common.Hash { + return common.HexToHash("0xb1cbb2c4b8480034c27e06da5f096b8233a8fd4497028593a41ff6df79726b35") +} + +func (IAutomationRegistryMasterUpkeepAdminTransferred) Topic() common.Hash { + return common.HexToHash("0x5cff4db96bef051785e999f44bfcd21c18823e034fb92dd376e3db4ce0feeb2c") +} + +func (IAutomationRegistryMasterUpkeepCanceled) Topic() common.Hash { + return common.HexToHash("0x91cb3bb75cfbd718bbfccc56b7f53d92d7048ef4ca39a3b7b7c6d4af1f791181") +} + +func (IAutomationRegistryMasterUpkeepCheckDataSet) Topic() common.Hash { + return common.HexToHash("0xcba2d5723b2ee59e53a8e8a82a4a7caf4fdfe70e9f7c582950bf7e7a5c24e83d") +} + +func (IAutomationRegistryMasterUpkeepGasLimitSet) Topic() common.Hash { + return common.HexToHash("0xc24c07e655ce79fba8a589778987d3c015bc6af1632bb20cf9182e02a65d972c") +} + +func (IAutomationRegistryMasterUpkeepMigrated) Topic() common.Hash { + return common.HexToHash("0xb38647142fbb1ea4c000fc4569b37a4e9a9f6313317b84ee3e5326c1a6cd06ff") +} + +func (IAutomationRegistryMasterUpkeepOffchainConfigSet) Topic() common.Hash { + return common.HexToHash("0x3e8740446213c8a77d40e08f79136ce3f347d13ed270a6ebdf57159e0faf4850") +} + +func (IAutomationRegistryMasterUpkeepPaused) Topic() common.Hash { + return common.HexToHash("0x8ab10247ce168c27748e656ecf852b951fcaac790c18106b19aa0ae57a8b741f") +} + +func (IAutomationRegistryMasterUpkeepPerformed) Topic() common.Hash { + return common.HexToHash("0xad8cc9579b21dfe2c2f6ea35ba15b656e46b4f5b0cb424f52739b8ce5cac9c5b") +} + +func (IAutomationRegistryMasterUpkeepPrivilegeConfigSet) Topic() common.Hash { + return common.HexToHash("0x2fd8d70753a007014349d4591843cc031c2dd7a260d7dd82eca8253686ae7769") +} + +func (IAutomationRegistryMasterUpkeepReceived) Topic() common.Hash { + return common.HexToHash("0x74931a144e43a50694897f241d973aecb5024c0e910f9bb80a163ea3c1cf5a71") +} + +func (IAutomationRegistryMasterUpkeepRegistered) Topic() common.Hash { + return common.HexToHash("0xbae366358c023f887e791d7a62f2e4316f1026bd77f6fb49501a917b3bc5d012") +} + +func (IAutomationRegistryMasterUpkeepTriggerConfigSet) Topic() common.Hash { + return common.HexToHash("0x2b72ac786c97e68dbab71023ed6f2bdbfc80ad9bb7808941929229d71b7d5664") +} + +func (IAutomationRegistryMasterUpkeepUnpaused) Topic() common.Hash { + return common.HexToHash("0x7bada562044eb163f6b4003c4553e4e62825344c0418eea087bed5ee05a47456") +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMaster) Address() common.Address { + return _IAutomationRegistryMaster.address +} + +type IAutomationRegistryMasterInterface 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) + + GetAdminPrivilegeConfig(opts *bind.CallOpts, admin common.Address) ([]byte, error) + + GetAutomationForwarderLogic(opts *bind.CallOpts) (common.Address, error) + + GetBalance(opts *bind.CallOpts, id *big.Int) (*big.Int, error) + + GetCancellationDelay(opts *bind.CallOpts) (*big.Int, error) + + GetConditionalGasOverhead(opts *bind.CallOpts) (*big.Int, error) + + GetFastGasFeedAddress(opts *bind.CallOpts) (common.Address, error) + + GetForwarder(opts *bind.CallOpts, upkeepID *big.Int) (common.Address, error) + + GetLinkAddress(opts *bind.CallOpts) (common.Address, error) + + GetLinkNativeFeedAddress(opts *bind.CallOpts) (common.Address, error) + + GetLogGasOverhead(opts *bind.CallOpts) (*big.Int, error) + + GetMaxPaymentForGas(opts *bind.CallOpts, triggerType uint8, gasLimit uint32) (*big.Int, error) + + GetMinBalance(opts *bind.CallOpts, id *big.Int) (*big.Int, error) + + GetMinBalanceForUpkeep(opts *bind.CallOpts, id *big.Int) (*big.Int, error) + + GetMode(opts *bind.CallOpts) (uint8, error) + + GetPeerRegistryMigrationPermission(opts *bind.CallOpts, peer common.Address) (uint8, error) + + GetPerPerformByteGasOverhead(opts *bind.CallOpts) (*big.Int, error) + + GetPerSignerGasOverhead(opts *bind.CallOpts) (*big.Int, error) + + GetSignerInfo(opts *bind.CallOpts, query common.Address) (GetSignerInfo, + + error) + + GetState(opts *bind.CallOpts) (GetState, + + error) + + GetTransmitterInfo(opts *bind.CallOpts, query common.Address) (GetTransmitterInfo, + + error) + + GetTriggerType(opts *bind.CallOpts, upkeepId *big.Int) (uint8, error) + + GetUpkeep(opts *bind.CallOpts, id *big.Int) (AutomationRegistryBase22UpkeepInfo, error) + + GetUpkeepPrivilegeConfig(opts *bind.CallOpts, upkeepId *big.Int) ([]byte, error) + + GetUpkeepTriggerConfig(opts *bind.CallOpts, upkeepId *big.Int) ([]byte, error) + + HasDedupKey(opts *bind.CallOpts, dedupKey [32]byte) (bool, error) + + LatestConfigDetails(opts *bind.CallOpts) (LatestConfigDetails, + + error) + + LatestConfigDigestAndEpoch(opts *bind.CallOpts) (LatestConfigDigestAndEpoch, + + error) + + 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) + + UpkeepVersion(opts *bind.CallOpts) (uint8, error) + + AcceptOwnership(opts *bind.TransactOpts) (*types.Transaction, error) + + AcceptPayeeship(opts *bind.TransactOpts, transmitter common.Address) (*types.Transaction, error) + + AcceptUpkeepAdmin(opts *bind.TransactOpts, id *big.Int) (*types.Transaction, error) + + AddFunds(opts *bind.TransactOpts, id *big.Int, amount *big.Int) (*types.Transaction, error) + + CancelUpkeep(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) + + OnTokenTransfer(opts *bind.TransactOpts, sender common.Address, amount *big.Int, data []byte) (*types.Transaction, error) + + Pause(opts *bind.TransactOpts) (*types.Transaction, error) + + PauseUpkeep(opts *bind.TransactOpts, id *big.Int) (*types.Transaction, error) + + ReceiveUpkeeps(opts *bind.TransactOpts, encodedUpkeeps []byte) (*types.Transaction, error) + + RecoverFunds(opts *bind.TransactOpts) (*types.Transaction, error) + + RegisterUpkeep(opts *bind.TransactOpts, target common.Address, gasLimit uint32, admin common.Address, triggerType uint8, checkData []byte, triggerConfig []byte, offchainConfig []byte) (*types.Transaction, error) + + RegisterUpkeep0(opts *bind.TransactOpts, target common.Address, gasLimit uint32, admin common.Address, checkData []byte, offchainConfig []byte) (*types.Transaction, error) + + SetAdminPrivilegeConfig(opts *bind.TransactOpts, admin common.Address, newPrivilegeConfig []byte) (*types.Transaction, error) + + SetConfig(opts *bind.TransactOpts, signers []common.Address, transmitters []common.Address, f uint8, onchainConfigBytes []byte, offchainConfigVersion uint64, offchainConfig []byte) (*types.Transaction, error) + + SetConfigTypeSafe(opts *bind.TransactOpts, signers []common.Address, transmitters []common.Address, f uint8, onchainConfig AutomationRegistryBase22OnchainConfig, offchainConfigVersion uint64, offchainConfig []byte) (*types.Transaction, error) + + SetPayees(opts *bind.TransactOpts, payees []common.Address) (*types.Transaction, error) + + SetPeerRegistryMigrationPermission(opts *bind.TransactOpts, peer common.Address, permission uint8) (*types.Transaction, error) + + SetUpkeepCheckData(opts *bind.TransactOpts, id *big.Int, newCheckData []byte) (*types.Transaction, error) + + SetUpkeepGasLimit(opts *bind.TransactOpts, id *big.Int, gasLimit uint32) (*types.Transaction, error) + + SetUpkeepOffchainConfig(opts *bind.TransactOpts, id *big.Int, config []byte) (*types.Transaction, error) + + SetUpkeepPrivilegeConfig(opts *bind.TransactOpts, upkeepId *big.Int, newPrivilegeConfig []byte) (*types.Transaction, error) + + SetUpkeepTriggerConfig(opts *bind.TransactOpts, id *big.Int, triggerConfig []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) + + TransferUpkeepAdmin(opts *bind.TransactOpts, id *big.Int, proposed common.Address) (*types.Transaction, error) + + Transmit(opts *bind.TransactOpts, reportContext [3][32]byte, rawReport []byte, rs [][32]byte, ss [][32]byte, rawVs [32]byte) (*types.Transaction, error) + + Unpause(opts *bind.TransactOpts) (*types.Transaction, error) + + UnpauseUpkeep(opts *bind.TransactOpts, id *big.Int) (*types.Transaction, error) + + WithdrawFunds(opts *bind.TransactOpts, id *big.Int, to common.Address) (*types.Transaction, error) + + WithdrawOwnerFunds(opts *bind.TransactOpts) (*types.Transaction, error) + + WithdrawPayment(opts *bind.TransactOpts, from common.Address, to common.Address) (*types.Transaction, error) + + Fallback(opts *bind.TransactOpts, calldata []byte) (*types.Transaction, error) + + FilterAdminPrivilegeConfigSet(opts *bind.FilterOpts, admin []common.Address) (*IAutomationRegistryMasterAdminPrivilegeConfigSetIterator, error) + + WatchAdminPrivilegeConfigSet(opts *bind.WatchOpts, sink chan<- *IAutomationRegistryMasterAdminPrivilegeConfigSet, admin []common.Address) (event.Subscription, error) + + ParseAdminPrivilegeConfigSet(log types.Log) (*IAutomationRegistryMasterAdminPrivilegeConfigSet, error) + + FilterCancelledUpkeepReport(opts *bind.FilterOpts, id []*big.Int) (*IAutomationRegistryMasterCancelledUpkeepReportIterator, error) + + WatchCancelledUpkeepReport(opts *bind.WatchOpts, sink chan<- *IAutomationRegistryMasterCancelledUpkeepReport, id []*big.Int) (event.Subscription, error) + + ParseCancelledUpkeepReport(log types.Log) (*IAutomationRegistryMasterCancelledUpkeepReport, error) + + FilterConfigSet(opts *bind.FilterOpts) (*IAutomationRegistryMasterConfigSetIterator, error) + + WatchConfigSet(opts *bind.WatchOpts, sink chan<- *IAutomationRegistryMasterConfigSet) (event.Subscription, error) + + ParseConfigSet(log types.Log) (*IAutomationRegistryMasterConfigSet, error) + + FilterDedupKeyAdded(opts *bind.FilterOpts, dedupKey [][32]byte) (*IAutomationRegistryMasterDedupKeyAddedIterator, error) + + WatchDedupKeyAdded(opts *bind.WatchOpts, sink chan<- *IAutomationRegistryMasterDedupKeyAdded, dedupKey [][32]byte) (event.Subscription, error) + + ParseDedupKeyAdded(log types.Log) (*IAutomationRegistryMasterDedupKeyAdded, error) + + FilterFundsAdded(opts *bind.FilterOpts, id []*big.Int, from []common.Address) (*IAutomationRegistryMasterFundsAddedIterator, error) + + WatchFundsAdded(opts *bind.WatchOpts, sink chan<- *IAutomationRegistryMasterFundsAdded, id []*big.Int, from []common.Address) (event.Subscription, error) + + ParseFundsAdded(log types.Log) (*IAutomationRegistryMasterFundsAdded, error) + + FilterFundsWithdrawn(opts *bind.FilterOpts, id []*big.Int) (*IAutomationRegistryMasterFundsWithdrawnIterator, error) + + WatchFundsWithdrawn(opts *bind.WatchOpts, sink chan<- *IAutomationRegistryMasterFundsWithdrawn, id []*big.Int) (event.Subscription, error) + + ParseFundsWithdrawn(log types.Log) (*IAutomationRegistryMasterFundsWithdrawn, error) + + FilterInsufficientFundsUpkeepReport(opts *bind.FilterOpts, id []*big.Int) (*IAutomationRegistryMasterInsufficientFundsUpkeepReportIterator, error) + + WatchInsufficientFundsUpkeepReport(opts *bind.WatchOpts, sink chan<- *IAutomationRegistryMasterInsufficientFundsUpkeepReport, id []*big.Int) (event.Subscription, error) + + ParseInsufficientFundsUpkeepReport(log types.Log) (*IAutomationRegistryMasterInsufficientFundsUpkeepReport, error) + + FilterOwnerFundsWithdrawn(opts *bind.FilterOpts) (*IAutomationRegistryMasterOwnerFundsWithdrawnIterator, error) + + WatchOwnerFundsWithdrawn(opts *bind.WatchOpts, sink chan<- *IAutomationRegistryMasterOwnerFundsWithdrawn) (event.Subscription, error) + + ParseOwnerFundsWithdrawn(log types.Log) (*IAutomationRegistryMasterOwnerFundsWithdrawn, error) + + FilterOwnershipTransferRequested(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*IAutomationRegistryMasterOwnershipTransferRequestedIterator, error) + + WatchOwnershipTransferRequested(opts *bind.WatchOpts, sink chan<- *IAutomationRegistryMasterOwnershipTransferRequested, from []common.Address, to []common.Address) (event.Subscription, error) + + ParseOwnershipTransferRequested(log types.Log) (*IAutomationRegistryMasterOwnershipTransferRequested, error) + + FilterOwnershipTransferred(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*IAutomationRegistryMasterOwnershipTransferredIterator, error) + + WatchOwnershipTransferred(opts *bind.WatchOpts, sink chan<- *IAutomationRegistryMasterOwnershipTransferred, from []common.Address, to []common.Address) (event.Subscription, error) + + ParseOwnershipTransferred(log types.Log) (*IAutomationRegistryMasterOwnershipTransferred, error) + + FilterPaused(opts *bind.FilterOpts) (*IAutomationRegistryMasterPausedIterator, error) + + WatchPaused(opts *bind.WatchOpts, sink chan<- *IAutomationRegistryMasterPaused) (event.Subscription, error) + + ParsePaused(log types.Log) (*IAutomationRegistryMasterPaused, error) + + FilterPayeesUpdated(opts *bind.FilterOpts) (*IAutomationRegistryMasterPayeesUpdatedIterator, error) + + WatchPayeesUpdated(opts *bind.WatchOpts, sink chan<- *IAutomationRegistryMasterPayeesUpdated) (event.Subscription, error) + + ParsePayeesUpdated(log types.Log) (*IAutomationRegistryMasterPayeesUpdated, error) + + FilterPayeeshipTransferRequested(opts *bind.FilterOpts, transmitter []common.Address, from []common.Address, to []common.Address) (*IAutomationRegistryMasterPayeeshipTransferRequestedIterator, error) + + WatchPayeeshipTransferRequested(opts *bind.WatchOpts, sink chan<- *IAutomationRegistryMasterPayeeshipTransferRequested, transmitter []common.Address, from []common.Address, to []common.Address) (event.Subscription, error) + + ParsePayeeshipTransferRequested(log types.Log) (*IAutomationRegistryMasterPayeeshipTransferRequested, error) + + FilterPayeeshipTransferred(opts *bind.FilterOpts, transmitter []common.Address, from []common.Address, to []common.Address) (*IAutomationRegistryMasterPayeeshipTransferredIterator, error) + + WatchPayeeshipTransferred(opts *bind.WatchOpts, sink chan<- *IAutomationRegistryMasterPayeeshipTransferred, transmitter []common.Address, from []common.Address, to []common.Address) (event.Subscription, error) + + ParsePayeeshipTransferred(log types.Log) (*IAutomationRegistryMasterPayeeshipTransferred, error) + + FilterPaymentWithdrawn(opts *bind.FilterOpts, transmitter []common.Address, amount []*big.Int, to []common.Address) (*IAutomationRegistryMasterPaymentWithdrawnIterator, error) + + WatchPaymentWithdrawn(opts *bind.WatchOpts, sink chan<- *IAutomationRegistryMasterPaymentWithdrawn, transmitter []common.Address, amount []*big.Int, to []common.Address) (event.Subscription, error) + + ParsePaymentWithdrawn(log types.Log) (*IAutomationRegistryMasterPaymentWithdrawn, error) + + FilterReorgedUpkeepReport(opts *bind.FilterOpts, id []*big.Int) (*IAutomationRegistryMasterReorgedUpkeepReportIterator, error) + + WatchReorgedUpkeepReport(opts *bind.WatchOpts, sink chan<- *IAutomationRegistryMasterReorgedUpkeepReport, id []*big.Int) (event.Subscription, error) + + ParseReorgedUpkeepReport(log types.Log) (*IAutomationRegistryMasterReorgedUpkeepReport, error) + + FilterStaleUpkeepReport(opts *bind.FilterOpts, id []*big.Int) (*IAutomationRegistryMasterStaleUpkeepReportIterator, error) + + WatchStaleUpkeepReport(opts *bind.WatchOpts, sink chan<- *IAutomationRegistryMasterStaleUpkeepReport, id []*big.Int) (event.Subscription, error) + + ParseStaleUpkeepReport(log types.Log) (*IAutomationRegistryMasterStaleUpkeepReport, error) + + FilterTransmitted(opts *bind.FilterOpts) (*IAutomationRegistryMasterTransmittedIterator, error) + + WatchTransmitted(opts *bind.WatchOpts, sink chan<- *IAutomationRegistryMasterTransmitted) (event.Subscription, error) + + ParseTransmitted(log types.Log) (*IAutomationRegistryMasterTransmitted, error) + + FilterUnpaused(opts *bind.FilterOpts) (*IAutomationRegistryMasterUnpausedIterator, error) + + WatchUnpaused(opts *bind.WatchOpts, sink chan<- *IAutomationRegistryMasterUnpaused) (event.Subscription, error) + + ParseUnpaused(log types.Log) (*IAutomationRegistryMasterUnpaused, error) + + FilterUpkeepAdminTransferRequested(opts *bind.FilterOpts, id []*big.Int, from []common.Address, to []common.Address) (*IAutomationRegistryMasterUpkeepAdminTransferRequestedIterator, error) + + WatchUpkeepAdminTransferRequested(opts *bind.WatchOpts, sink chan<- *IAutomationRegistryMasterUpkeepAdminTransferRequested, id []*big.Int, from []common.Address, to []common.Address) (event.Subscription, error) + + ParseUpkeepAdminTransferRequested(log types.Log) (*IAutomationRegistryMasterUpkeepAdminTransferRequested, error) + + FilterUpkeepAdminTransferred(opts *bind.FilterOpts, id []*big.Int, from []common.Address, to []common.Address) (*IAutomationRegistryMasterUpkeepAdminTransferredIterator, error) + + WatchUpkeepAdminTransferred(opts *bind.WatchOpts, sink chan<- *IAutomationRegistryMasterUpkeepAdminTransferred, id []*big.Int, from []common.Address, to []common.Address) (event.Subscription, error) + + ParseUpkeepAdminTransferred(log types.Log) (*IAutomationRegistryMasterUpkeepAdminTransferred, error) + + FilterUpkeepCanceled(opts *bind.FilterOpts, id []*big.Int, atBlockHeight []uint64) (*IAutomationRegistryMasterUpkeepCanceledIterator, error) + + WatchUpkeepCanceled(opts *bind.WatchOpts, sink chan<- *IAutomationRegistryMasterUpkeepCanceled, id []*big.Int, atBlockHeight []uint64) (event.Subscription, error) + + ParseUpkeepCanceled(log types.Log) (*IAutomationRegistryMasterUpkeepCanceled, error) + + FilterUpkeepCheckDataSet(opts *bind.FilterOpts, id []*big.Int) (*IAutomationRegistryMasterUpkeepCheckDataSetIterator, error) + + WatchUpkeepCheckDataSet(opts *bind.WatchOpts, sink chan<- *IAutomationRegistryMasterUpkeepCheckDataSet, id []*big.Int) (event.Subscription, error) + + ParseUpkeepCheckDataSet(log types.Log) (*IAutomationRegistryMasterUpkeepCheckDataSet, error) + + FilterUpkeepGasLimitSet(opts *bind.FilterOpts, id []*big.Int) (*IAutomationRegistryMasterUpkeepGasLimitSetIterator, error) + + WatchUpkeepGasLimitSet(opts *bind.WatchOpts, sink chan<- *IAutomationRegistryMasterUpkeepGasLimitSet, id []*big.Int) (event.Subscription, error) + + ParseUpkeepGasLimitSet(log types.Log) (*IAutomationRegistryMasterUpkeepGasLimitSet, error) + + FilterUpkeepMigrated(opts *bind.FilterOpts, id []*big.Int) (*IAutomationRegistryMasterUpkeepMigratedIterator, error) + + WatchUpkeepMigrated(opts *bind.WatchOpts, sink chan<- *IAutomationRegistryMasterUpkeepMigrated, id []*big.Int) (event.Subscription, error) + + ParseUpkeepMigrated(log types.Log) (*IAutomationRegistryMasterUpkeepMigrated, error) + + FilterUpkeepOffchainConfigSet(opts *bind.FilterOpts, id []*big.Int) (*IAutomationRegistryMasterUpkeepOffchainConfigSetIterator, error) + + WatchUpkeepOffchainConfigSet(opts *bind.WatchOpts, sink chan<- *IAutomationRegistryMasterUpkeepOffchainConfigSet, id []*big.Int) (event.Subscription, error) + + ParseUpkeepOffchainConfigSet(log types.Log) (*IAutomationRegistryMasterUpkeepOffchainConfigSet, error) + + FilterUpkeepPaused(opts *bind.FilterOpts, id []*big.Int) (*IAutomationRegistryMasterUpkeepPausedIterator, error) + + WatchUpkeepPaused(opts *bind.WatchOpts, sink chan<- *IAutomationRegistryMasterUpkeepPaused, id []*big.Int) (event.Subscription, error) + + ParseUpkeepPaused(log types.Log) (*IAutomationRegistryMasterUpkeepPaused, error) + + FilterUpkeepPerformed(opts *bind.FilterOpts, id []*big.Int, success []bool) (*IAutomationRegistryMasterUpkeepPerformedIterator, error) + + WatchUpkeepPerformed(opts *bind.WatchOpts, sink chan<- *IAutomationRegistryMasterUpkeepPerformed, id []*big.Int, success []bool) (event.Subscription, error) + + ParseUpkeepPerformed(log types.Log) (*IAutomationRegistryMasterUpkeepPerformed, error) + + FilterUpkeepPrivilegeConfigSet(opts *bind.FilterOpts, id []*big.Int) (*IAutomationRegistryMasterUpkeepPrivilegeConfigSetIterator, error) + + WatchUpkeepPrivilegeConfigSet(opts *bind.WatchOpts, sink chan<- *IAutomationRegistryMasterUpkeepPrivilegeConfigSet, id []*big.Int) (event.Subscription, error) + + ParseUpkeepPrivilegeConfigSet(log types.Log) (*IAutomationRegistryMasterUpkeepPrivilegeConfigSet, error) + + FilterUpkeepReceived(opts *bind.FilterOpts, id []*big.Int) (*IAutomationRegistryMasterUpkeepReceivedIterator, error) + + WatchUpkeepReceived(opts *bind.WatchOpts, sink chan<- *IAutomationRegistryMasterUpkeepReceived, id []*big.Int) (event.Subscription, error) + + ParseUpkeepReceived(log types.Log) (*IAutomationRegistryMasterUpkeepReceived, error) + + FilterUpkeepRegistered(opts *bind.FilterOpts, id []*big.Int) (*IAutomationRegistryMasterUpkeepRegisteredIterator, error) + + WatchUpkeepRegistered(opts *bind.WatchOpts, sink chan<- *IAutomationRegistryMasterUpkeepRegistered, id []*big.Int) (event.Subscription, error) + + ParseUpkeepRegistered(log types.Log) (*IAutomationRegistryMasterUpkeepRegistered, error) + + FilterUpkeepTriggerConfigSet(opts *bind.FilterOpts, id []*big.Int) (*IAutomationRegistryMasterUpkeepTriggerConfigSetIterator, error) + + WatchUpkeepTriggerConfigSet(opts *bind.WatchOpts, sink chan<- *IAutomationRegistryMasterUpkeepTriggerConfigSet, id []*big.Int) (event.Subscription, error) + + ParseUpkeepTriggerConfigSet(log types.Log) (*IAutomationRegistryMasterUpkeepTriggerConfigSet, error) + + FilterUpkeepUnpaused(opts *bind.FilterOpts, id []*big.Int) (*IAutomationRegistryMasterUpkeepUnpausedIterator, error) + + WatchUpkeepUnpaused(opts *bind.WatchOpts, sink chan<- *IAutomationRegistryMasterUpkeepUnpaused, id []*big.Int) (event.Subscription, error) + + ParseUpkeepUnpaused(log types.Log) (*IAutomationRegistryMasterUpkeepUnpaused, error) + + ParseLog(log types.Log) (generated.AbigenLog, error) + + Address() common.Address +} diff --git a/core/gethwrappers/generated/keeper_registry_logic_a_wrapper_2_2/keeper_registry_logic_a_wrapper_2_2.go b/core/gethwrappers/generated/keeper_registry_logic_a_wrapper_2_2/keeper_registry_logic_a_wrapper_2_2.go new file mode 100644 index 0000000000..31aa106358 --- /dev/null +++ b/core/gethwrappers/generated/keeper_registry_logic_a_wrapper_2_2/keeper_registry_logic_a_wrapper_2_2.go @@ -0,0 +1,4863 @@ +// Code generated - DO NOT EDIT. +// This file is a generated binding and any manual changes will be lost. + +package keeper_registry_logic_a_wrapper_2_2 + +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 AutomationRegistryLogicAMetaData = &bind.MetaData{ + ABI: "[{\"inputs\":[{\"internalType\":\"contractAutomationRegistryLogicB2_2\",\"name\":\"logicB\",\"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\":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\":\"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\":\"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\":\"enumAutomationRegistryBase2_2.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\":\"enumAutomationRegistryBase2_2.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\":\"enumAutomationRegistryBase2_2.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\":\"enumAutomationRegistryBase2_2.UpkeepFailureReason\",\"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\":\"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\":[{\"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\":\"enumAutomationRegistryBase2_2.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\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", + Bin: "0x6101406040523480156200001257600080fd5b50604051620061d1380380620061d18339810160408190526200003591620003df565b80816001600160a01b0316634b4fd03b6040518163ffffffff1660e01b8152600401602060405180830381865afa15801562000075573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200009b919062000406565b826001600160a01b031663ca30e6036040518163ffffffff1660e01b8152600401602060405180830381865afa158015620000da573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620001009190620003df565b836001600160a01b031663b10b673c6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156200013f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620001659190620003df565b846001600160a01b0316636709d0e56040518163ffffffff1660e01b8152600401602060405180830381865afa158015620001a4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620001ca9190620003df565b856001600160a01b0316635425d8ac6040518163ffffffff1660e01b8152600401602060405180830381865afa15801562000209573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200022f9190620003df565b3380600081620002865760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b0384811691909117909155811615620002b957620002b9816200031b565b505050846002811115620002d157620002d162000429565b60e0816002811115620002e857620002e862000429565b9052506001600160a01b0393841660805291831660a052821660c0528116610100529190911661012052506200043f9050565b336001600160a01b03821603620003755760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c6600000000000000000060448201526064016200027d565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b6001600160a01b0381168114620003dc57600080fd5b50565b600060208284031215620003f257600080fd5b8151620003ff81620003c6565b9392505050565b6000602082840312156200041957600080fd5b815160038110620003ff57600080fd5b634e487b7160e01b600052602160045260246000fd5b60805160a05160c05160e0516101005161012051615d18620004b96000396000818161010e01526101a90152600081816103e10152611fa10152600081816135370152818161376d015281816139b50152613b5d015260006130e1015260006131c5015260008181611de301526123af0152615d186000f3fe60806040523480156200001157600080fd5b50600436106200010c5760003560e01c806385c1b0ba11620000a5578063c8048022116200006f578063c804802214620002b7578063ce7dc5b414620002ce578063f2fde38b14620002e5578063f7d334ba14620002fc576200010c565b806385c1b0ba14620002535780638da5cb5b146200026a5780638e86139b1462000289578063948108f714620002a0576200010c565b80634ee88d3511620000e75780634ee88d3514620001ef5780636ded9eae146200020657806371791aa0146200021d57806379ba50971462000249576200010c565b806328f32f38146200015457806329c5efad146200017e578063349e8cca14620001a7575b7f00000000000000000000000000000000000000000000000000000000000000003660008037600080366000845af43d6000803e8080156200014d573d6000f35b3d6000fd5b005b6200016b62000165366004620041ea565b62000313565b6040519081526020015b60405180910390f35b620001956200018f366004620042d0565b6200068c565b604051620001759493929190620043f8565b7f00000000000000000000000000000000000000000000000000000000000000005b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200162000175565b620001526200020036600462004435565b62000930565b6200016b6200021736600462004485565b62000998565b620002346200022e366004620042d0565b620009fe565b60405162000175979695949392919062004538565b62000152620010f0565b62000152620002643660046200458a565b620011f3565b60005473ffffffffffffffffffffffffffffffffffffffff16620001c9565b620001526200029a36600462004617565b62001e64565b62000152620002b13660046200467a565b620021ec565b62000152620002c8366004620046a9565b6200247f565b62000195620002df3660046200477f565b62002846565b62000152620002f6366004620047f6565b62002916565b620002346200030d366004620046a9565b6200292e565b6000805473ffffffffffffffffffffffffffffffffffffffff163314801590620003475750620003456009336200296c565b155b156200037f576040517fd48b678b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff89163b620003ce576040517f09ee12d500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b620003d986620029a0565b9050600089307f00000000000000000000000000000000000000000000000000000000000000006040516200040e9062003f7b565b73ffffffffffffffffffffffffffffffffffffffff938416815291831660208301529091166040820152606001604051809103906000f08015801562000458573d6000803e3d6000fd5b5090506200051f826040518060e001604052806000151581526020018c63ffffffff16815260200163ffffffff801681526020018473ffffffffffffffffffffffffffffffffffffffff16815260200160006bffffffffffffffffffffffff16815260200160006bffffffffffffffffffffffff168152602001600063ffffffff168152508a89898080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152508b92508a915062002b449050565b6014805474010000000000000000000000000000000000000000900463ffffffff1690806200054e8362004845565b91906101000a81548163ffffffff021916908363ffffffff16021790555050817fbae366358c023f887e791d7a62f2e4316f1026bd77f6fb49501a917b3bc5d0128a8a604051620005c792919063ffffffff92909216825273ffffffffffffffffffffffffffffffffffffffff16602082015260400190565b60405180910390a2817fcba2d5723b2ee59e53a8e8a82a4a7caf4fdfe70e9f7c582950bf7e7a5c24e83d878760405162000603929190620048b4565b60405180910390a2817f2b72ac786c97e68dbab71023ed6f2bdbfc80ad9bb7808941929229d71b7d5664856040516200063d9190620048ca565b60405180910390a2817f3e8740446213c8a77d40e08f79136ce3f347d13ed270a6ebdf57159e0faf485084604051620006779190620048ca565b60405180910390a25098975050505050505050565b600060606000806200069d62002f1f565b600086815260046020908152604091829020825160e081018452815460ff811615158252610100810463ffffffff90811694830194909452650100000000008104841694820194909452690100000000000000000090930473ffffffffffffffffffffffffffffffffffffffff166060840152600101546bffffffffffffffffffffffff80821660808501526c0100000000000000000000000082041660a0840152780100000000000000000000000000000000000000000000000090041660c08201525a9150600080826060015173ffffffffffffffffffffffffffffffffffffffff1663f00e6a2a6040518163ffffffff1660e01b8152600401602060405180830381865afa158015620007b7573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620007dd9190620048ec565b73ffffffffffffffffffffffffffffffffffffffff166013600101600c9054906101000a900463ffffffff1663ffffffff16896040516200081f91906200490c565b60006040518083038160008787f1925050503d80600081146200085f576040519150601f19603f3d011682016040523d82523d6000602084013e62000864565b606091505b50915091505a6200087690856200492a565b935081620008a157600060405180602001604052806000815250600796509650965050505062000927565b80806020019051810190620008b791906200499b565b909750955086620008e557600060405180602001604052806000815250600496509650965050505062000927565b601554865164010000000090910463ffffffff1610156200092357600060405180602001604052806000815250600596509650965050505062000927565b5050505b92959194509250565b6200093b8362002f5a565b6000838152601a602052604090206200095682848362004a90565b50827f2b72ac786c97e68dbab71023ed6f2bdbfc80ad9bb7808941929229d71b7d566483836040516200098b929190620048b4565b60405180910390a2505050565b6000620009f288888860008989604051806020016040528060008152508a8a8080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506200031392505050565b98975050505050505050565b60006060600080600080600062000a1462002f1f565b600062000a218a62003010565b905060006012604051806101200160405290816000820160009054906101000a900460ff1660ff1660ff1681526020016000820160019054906101000a900463ffffffff1663ffffffff1663ffffffff1681526020016000820160059054906101000a900463ffffffff1663ffffffff1663ffffffff1681526020016000820160099054906101000a900462ffffff1662ffffff1662ffffff16815260200160008201600c9054906101000a900461ffff1661ffff1661ffff16815260200160008201600e9054906101000a900460ff1615151515815260200160008201600f9054906101000a900460ff161515151581526020016000820160109054906101000a90046bffffffffffffffffffffffff166bffffffffffffffffffffffff166bffffffffffffffffffffffff16815260200160008201601c9054906101000a900463ffffffff1663ffffffff1663ffffffff168152505090506000600460008d81526020019081526020016000206040518060e00160405290816000820160009054906101000a900460ff161515151581526020016000820160019054906101000a900463ffffffff1663ffffffff1663ffffffff1681526020016000820160059054906101000a900463ffffffff1663ffffffff1663ffffffff1681526020016000820160099054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020016001820160009054906101000a90046bffffffffffffffffffffffff166bffffffffffffffffffffffff166bffffffffffffffffffffffff16815260200160018201600c9054906101000a90046bffffffffffffffffffffffff166bffffffffffffffffffffffff166bffffffffffffffffffffffff1681526020016001820160189054906101000a900463ffffffff1663ffffffff1663ffffffff168152505090508160a001511562000d45576000604051806020016040528060008152506009600084602001516000808263ffffffff1692509950995099509950995099509950505050620010e4565b604081015163ffffffff9081161462000d96576000604051806020016040528060008152506001600084602001516000808263ffffffff1692509950995099509950995099509950505050620010e4565b80511562000ddc576000604051806020016040528060008152506002600084602001516000808263ffffffff1692509950995099509950995099509950505050620010e4565b62000de782620030be565b602083015160155492975090955060009162000e19918591879190640100000000900463ffffffff168a8a87620032b0565b9050806bffffffffffffffffffffffff168260a001516bffffffffffffffffffffffff16101562000e83576000604051806020016040528060008152506006600085602001516000808263ffffffff1692509a509a509a509a509a509a509a5050505050620010e4565b600062000e928e868f62003301565b90505a9850600080846060015173ffffffffffffffffffffffffffffffffffffffff1663f00e6a2a6040518163ffffffff1660e01b8152600401602060405180830381865afa15801562000eea573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062000f109190620048ec565b73ffffffffffffffffffffffffffffffffffffffff166013600101600c9054906101000a900463ffffffff1663ffffffff168460405162000f5291906200490c565b60006040518083038160008787f1925050503d806000811462000f92576040519150601f19603f3d011682016040523d82523d6000602084013e62000f97565b606091505b50915091505a62000fa9908c6200492a565b9a5081620010295760155481516801000000000000000090910463ffffffff1610156200100657505060408051602080820190925260008082529490910151939c509a50600899505063ffffffff9091169550620010e492505050565b602090940151939b5060039a505063ffffffff9092169650620010e49350505050565b808060200190518101906200103f91906200499b565b909e509c508d6200108057505060408051602080820190925260008082529490910151939c509a50600499505063ffffffff9091169550620010e492505050565b6015548d5164010000000090910463ffffffff161015620010d157505060408051602080820190925260008082529490910151939c509a50600599505063ffffffff9091169550620010e492505050565b505050506020015163ffffffff16945050505b92959891949750929550565b60015473ffffffffffffffffffffffffffffffffffffffff16331462001177576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e65720000000000000000000060448201526064015b60405180910390fd5b60008054337fffffffffffffffffffffffff00000000000000000000000000000000000000008083168217845560018054909116905560405173ffffffffffffffffffffffffffffffffffffffff90921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b600173ffffffffffffffffffffffffffffffffffffffff821660009081526019602052604090205460ff1660038111156200123257620012326200438d565b141580156200127e5750600373ffffffffffffffffffffffffffffffffffffffff821660009081526019602052604090205460ff1660038111156200127b576200127b6200438d565b14155b15620012b6576040517f0ebeec3c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6013546c01000000000000000000000000900473ffffffffffffffffffffffffffffffffffffffff1662001316576040517fd12d7d8d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600082900362001352576040517f2c2fc94100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040805160e081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c081018290526000808567ffffffffffffffff811115620013a957620013a962004071565b604051908082528060200260200182016040528015620013d3578160200160208202803683370190505b50905060008667ffffffffffffffff811115620013f457620013f462004071565b6040519080825280602002602001820160405280156200147b57816020015b6040805160e08101825260008082526020808301829052928201819052606082018190526080820181905260a0820181905260c082015282527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff909201910181620014135790505b50905060008767ffffffffffffffff8111156200149c576200149c62004071565b604051908082528060200260200182016040528015620014d157816020015b6060815260200190600190039081620014bb5790505b50905060008867ffffffffffffffff811115620014f257620014f262004071565b6040519080825280602002602001820160405280156200152757816020015b6060815260200190600190039081620015115790505b50905060008967ffffffffffffffff81111562001548576200154862004071565b6040519080825280602002602001820160405280156200157d57816020015b6060815260200190600190039081620015675790505b50905060005b8a81101562001b61578b8b82818110620015a157620015a162004bb8565b60209081029290920135600081815260048452604090819020815160e081018352815460ff811615158252610100810463ffffffff90811697830197909752650100000000008104871693820193909352690100000000000000000090920473ffffffffffffffffffffffffffffffffffffffff166060830152600101546bffffffffffffffffffffffff80821660808401526c0100000000000000000000000082041660a08301527801000000000000000000000000000000000000000000000000900490931660c08401529a509098506200168090508962002f5a565b60608801516040517f1a5da6c800000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8c8116600483015290911690631a5da6c890602401600060405180830381600087803b158015620016f057600080fd5b505af115801562001705573d6000803e3d6000fd5b50505050878582815181106200171f576200171f62004bb8565b6020026020010181905250600560008a815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1686828151811062001773576200177362004bb8565b73ffffffffffffffffffffffffffffffffffffffff90921660209283029190910182015260008a81526007909152604090208054620017b290620049e8565b80601f0160208091040260200160405190810160405280929190818152602001828054620017e090620049e8565b8015620018315780601f10620018055761010080835404028352916020019162001831565b820191906000526020600020905b8154815290600101906020018083116200181357829003601f168201915b50505050508482815181106200184b576200184b62004bb8565b6020026020010181905250601a60008a815260200190815260200160002080546200187690620049e8565b80601f0160208091040260200160405190810160405280929190818152602001828054620018a490620049e8565b8015620018f55780601f10620018c957610100808354040283529160200191620018f5565b820191906000526020600020905b815481529060010190602001808311620018d757829003601f168201915b50505050508382815181106200190f576200190f62004bb8565b6020026020010181905250601b60008a815260200190815260200160002080546200193a90620049e8565b80601f01602080910402602001604051908101604052809291908181526020018280546200196890620049e8565b8015620019b95780601f106200198d57610100808354040283529160200191620019b9565b820191906000526020600020905b8154815290600101906020018083116200199b57829003601f168201915b5050505050828281518110620019d357620019d362004bb8565b60200260200101819052508760a001516bffffffffffffffffffffffff1687620019fe919062004be7565b60008a815260046020908152604080832080547fffffff000000000000000000000000000000000000000000000000000000000016815560010180547fffffffff000000000000000000000000000000000000000000000000000000001690556007909152812091985062001a74919062003f89565b6000898152601a6020526040812062001a8d9162003f89565b6000898152601b6020526040812062001aa69162003f89565b600089815260066020526040902080547fffffffffffffffffffffffff000000000000000000000000000000000000000016905562001ae760028a62003523565b5060a0880151604080516bffffffffffffffffffffffff909216825273ffffffffffffffffffffffffffffffffffffffff8c1660208301528a917fb38647142fbb1ea4c000fc4569b37a4e9a9f6313317b84ee3e5326c1a6cd06ff910160405180910390a28062001b588162004bfd565b91505062001583565b508560185462001b7291906200492a565b60185560008b8b868167ffffffffffffffff81111562001b965762001b9662004071565b60405190808252806020026020018201604052801562001bc0578160200160208202803683370190505b508988888860405160200162001bde98979695949392919062004da3565b60405160208183030381529060405290508973ffffffffffffffffffffffffffffffffffffffff16638e86139b6013600001600c9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663c71249ab60038e73ffffffffffffffffffffffffffffffffffffffff1663aab9edd66040518163ffffffff1660e01b8152600401602060405180830381865afa15801562001c9a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062001cc0919062004e73565b866040518463ffffffff1660e01b815260040162001ce19392919062004e98565b600060405180830381865afa15801562001cff573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016820160405262001d47919081019062004ebf565b6040518263ffffffff1660e01b815260040162001d659190620048ca565b600060405180830381600087803b15801562001d8057600080fd5b505af115801562001d95573d6000803e3d6000fd5b50506040517fa9059cbb00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8d81166004830152602482018b90527f000000000000000000000000000000000000000000000000000000000000000016925063a9059cbb91506044016020604051808303816000875af115801562001e2f573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062001e55919062004ef8565b50505050505050505050505050565b60023360009081526019602052604090205460ff16600381111562001e8d5762001e8d6200438d565b1415801562001ec3575060033360009081526019602052604090205460ff16600381111562001ec05762001ec06200438d565b14155b1562001efb576040517f0ebeec3c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600080808080808062001f11888a018a620050f0565b965096509650965096509650965060005b8751811015620021e057600073ffffffffffffffffffffffffffffffffffffffff1687828151811062001f595762001f5962004bb8565b60200260200101516060015173ffffffffffffffffffffffffffffffffffffffff16036200206d5785818151811062001f965762001f9662004bb8565b6020026020010151307f000000000000000000000000000000000000000000000000000000000000000060405162001fce9062003f7b565b73ffffffffffffffffffffffffffffffffffffffff938416815291831660208301529091166040820152606001604051809103906000f08015801562002018573d6000803e3d6000fd5b508782815181106200202e576200202e62004bb8565b60200260200101516060019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff16815250505b6200212588828151811062002086576200208662004bb8565b6020026020010151888381518110620020a357620020a362004bb8565b6020026020010151878481518110620020c057620020c062004bb8565b6020026020010151878581518110620020dd57620020dd62004bb8565b6020026020010151878681518110620020fa57620020fa62004bb8565b602002602001015187878151811062002117576200211762004bb8565b602002602001015162002b44565b8781815181106200213a576200213a62004bb8565b60200260200101517f74931a144e43a50694897f241d973aecb5024c0e910f9bb80a163ea3c1cf5a7188838151811062002178576200217862004bb8565b602002602001015160a0015133604051620021c39291906bffffffffffffffffffffffff92909216825273ffffffffffffffffffffffffffffffffffffffff16602082015260400190565b60405180910390a280620021d78162004bfd565b91505062001f22565b50505050505050505050565b600082815260046020908152604091829020825160e081018452815460ff81161515825263ffffffff6101008204811694830194909452650100000000008104841694820185905273ffffffffffffffffffffffffffffffffffffffff69010000000000000000009091041660608201526001909101546bffffffffffffffffffffffff80821660808401526c0100000000000000000000000082041660a083015278010000000000000000000000000000000000000000000000009004821660c08201529114620022ea576040517f9c0083a200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b818160a00151620022fc919062005221565b600084815260046020526040902060010180547fffffffffffffffff000000000000000000000000ffffffffffffffffffffffff166c010000000000000000000000006bffffffffffffffffffffffff93841602179055601854620023649184169062004be7565b6018556040517f23b872dd0000000000000000000000000000000000000000000000000000000081523360048201523060248201526bffffffffffffffffffffffff831660448201527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16906323b872dd906064016020604051808303816000875af11580156200240e573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062002434919062004ef8565b506040516bffffffffffffffffffffffff83168152339084907fafd24114486da8ebfc32f3626dada8863652e187461aa74d4bfa7348915062039060200160405180910390a3505050565b6000818152600460209081526040808320815160e081018352815460ff81161515825263ffffffff6101008204811695830195909552650100000000008104851693820184905273ffffffffffffffffffffffffffffffffffffffff69010000000000000000009091041660608201526001909101546bffffffffffffffffffffffff80821660808401526c0100000000000000000000000082041660a083015278010000000000000000000000000000000000000000000000009004831660c082015292911415906200256860005473ffffffffffffffffffffffffffffffffffffffff1690565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16149050818015620025c35750808015620025c15750620025b462003531565b836040015163ffffffff16115b155b15620025fb576040517ffbc0357800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b801580156200262e575060008481526005602052604090205473ffffffffffffffffffffffffffffffffffffffff163314155b1562002666576040517ffbdb8e5600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60006200267262003531565b9050816200268a576200268760328262004be7565b90505b6000858152600460205260409020805463ffffffff80841665010000000000027fffffffffffffffffffffffffffffffffffffffffffffff00000000ffffffffff90921691909117909155620026e69060029087906200352316565b5060135460808501516bffffffffffffffffffffffff91821691600091168211156200274f5760808601516200271d908362005249565b90508560a001516bffffffffffffffffffffffff16816bffffffffffffffffffffffff1611156200274f575060a08501515b808660a0015162002761919062005249565b600088815260046020526040902060010180547fffffffffffffffff000000000000000000000000ffffffffffffffffffffffff166c010000000000000000000000006bffffffffffffffffffffffff93841602179055601454620027c99183911662005221565b601480547fffffffffffffffffffffffffffffffffffffffff000000000000000000000000166bffffffffffffffffffffffff9290921691909117905560405167ffffffffffffffff84169088907f91cb3bb75cfbd718bbfccc56b7f53d92d7048ef4ca39a3b7b7c6d4af1f79118190600090a350505050505050565b600060606000806200285762002f1f565b6000634b56a42e60e01b888888604051602401620028789392919062005271565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff000000000000000000000000000000000000000000000000000000009093169290921790915290506200290389826200068c565b929c919b50995090975095505050505050565b62002920620035ed565b6200292b8162003670565b50565b600060606000806000806000620029558860405180602001604052806000815250620009fe565b959e949d50929b5090995097509550909350915050565b73ffffffffffffffffffffffffffffffffffffffff8116600090815260018301602052604081205415155b90505b92915050565b6000806000620029c76001620029b562003531565b620029c191906200492a565b62003767565b601454604080516020810193909352309083015274010000000000000000000000000000000000000000900463ffffffff166060820152608001604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081840301815282825280516020918201209083015201604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152919052905060045b600f81101562002ad3578282828151811062002a8f5762002a8f62004bb8565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053508062002aca8162004bfd565b91505062002a6f565b5083600181111562002ae95762002ae96200438d565b60f81b81600f8151811062002b025762002b0262004bb8565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a90535062002b3c81620052a5565b949350505050565b6012546e010000000000000000000000000000900460ff161562002b94576040517f24522f3400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b601554835163ffffffff909116101562002bda576040517fae7235df00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6108fc856020015163ffffffff16108062002c185750601454602086015163ffffffff70010000000000000000000000000000000090920482169116115b1562002c50576040517f14c237fb00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000868152600460205260409020546901000000000000000000900473ffffffffffffffffffffffffffffffffffffffff161562002cba576040517f6e3b930b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000868152600460209081526040808320885181548a8501518b85015160608d01517fffffffffffffffffffffffffffffffffffffffffffffffffffffff00000000009093169315157fffffffffffffffffffffffffffffffffffffffffffffffffffffff00000000ff169390931761010063ffffffff92831602177fffffff000000000000000000000000000000000000000000000000ffffffffff1665010000000000938216939093027fffffff0000000000000000000000000000000000000000ffffffffffffffffff1692909217690100000000000000000073ffffffffffffffffffffffffffffffffffffffff9283160217835560808b01516001909301805460a08d015160c08e01516bffffffffffffffffffffffff9687167fffffffffffffffff000000000000000000000000000000000000000000000000909316929092176c010000000000000000000000009690911695909502949094177fffffffff00000000ffffffffffffffffffffffffffffffffffffffffffffffff1678010000000000000000000000000000000000000000000000009490931693909302919091179091556005835281842080547fffffffffffffffffffffffff0000000000000000000000000000000000000000169189169190911790556007909152902062002ead8482620052e8565b508460a001516bffffffffffffffffffffffff1660185462002ed0919062004be7565b6018556000868152601a6020526040902062002eed8382620052e8565b506000868152601b6020526040902062002f088282620052e8565b5062002f16600287620038cf565b50505050505050565b321562002f58576040517fb60ac5db00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b565b60008181526005602052604090205473ffffffffffffffffffffffffffffffffffffffff16331462002fb8576040517fa47c170600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008181526004602052604090205465010000000000900463ffffffff908116146200292b576040517f9c0083a200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000818160045b600f811015620030a5577fff00000000000000000000000000000000000000000000000000000000000000821683826020811062003059576200305962004bb8565b1a60f81b7effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916146200309057506000949350505050565b806200309c8162004bfd565b91505062003017565b5081600f1a600181111562002b3c5762002b3c6200438d565b6000806000836060015162ffffff1690506000808263ffffffff161190506000807f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663feaf968c6040518163ffffffff1660e01b815260040160a060405180830381865afa1580156200314b573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200317191906200542a565b50945090925050506000811315806200318957508142105b80620031ae5750828015620031ae5750620031a582426200492a565b8463ffffffff16105b15620031bf576016549550620031c3565b8095505b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663feaf968c6040518163ffffffff1660e01b815260040160a060405180830381865afa1580156200322f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200325591906200542a565b50945090925050506000811315806200326d57508142105b806200329257508280156200329257506200328982426200492a565b8463ffffffff16105b15620032a3576017549450620032a7565b8094505b50505050915091565b600080620032c488878b60000151620038dd565b9050600080620032e18b8a63ffffffff16858a8a60018b6200397c565b9092509050620032f2818362005221565b9b9a5050505050505050505050565b606060008360018111156200331a576200331a6200438d565b03620033e7576000848152600760205260409081902090517f6e04ff0d0000000000000000000000000000000000000000000000000000000091620033629160240162005522565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff000000000000000000000000000000000000000000000000000000009093169290921790915290506200351c565b6001836001811115620033fe57620033fe6200438d565b03620034ea576000828060200190518101906200341c919062005599565b6000868152600760205260409081902090519192507f40691db4000000000000000000000000000000000000000000000000000000009162003463918491602401620056ad565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff000000000000000000000000000000000000000000000000000000009093169290921790915291506200351c9050565b6040517ff2b2d41200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b9392505050565b600062002997838362003e1e565b600060017f000000000000000000000000000000000000000000000000000000000000000060028111156200356a576200356a6200438d565b03620035e857606473ffffffffffffffffffffffffffffffffffffffff1663a3b1b31d6040518163ffffffff1660e01b8152600401602060405180830381865afa158015620035bd573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620035e3919062005775565b905090565b504390565b60005473ffffffffffffffffffffffffffffffffffffffff16331462002f58576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e65720000000000000000000060448201526064016200116e565b3373ffffffffffffffffffffffffffffffffffffffff821603620036f1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c6600000000000000000060448201526064016200116e565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b600060017f00000000000000000000000000000000000000000000000000000000000000006002811115620037a057620037a06200438d565b03620038c5576000606473ffffffffffffffffffffffffffffffffffffffff1663a3b1b31d6040518163ffffffff1660e01b8152600401602060405180830381865afa158015620037f5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200381b919062005775565b905080831015806200383957506101006200383784836200492a565b115b15620038485750600092915050565b6040517f2b407a8200000000000000000000000000000000000000000000000000000000815260048101849052606490632b407a8290602401602060405180830381865afa1580156200389f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200351c919062005775565b504090565b919050565b600062002997838362003f29565b60008080856001811115620038f657620038f66200438d565b0362003907575062015f906200392a565b60018560018111156200391e576200391e6200438d565b03620034ea57506201adb05b6200393d63ffffffff851660146200578f565b6200394a846001620057cf565b6200395b9060ff16611d4c6200578f565b62003967908362004be7565b62003973919062004be7565b95945050505050565b6000806000896080015161ffff16876200399791906200578f565b9050838015620039a65750803a105b15620039af57503a5b600060027f00000000000000000000000000000000000000000000000000000000000000006002811115620039e857620039e86200438d565b0362003b5957604080516000815260208101909152851562003a4c5760003660405180608001604052806048815260200162005cc46048913960405160200162003a3593929190620057eb565b604051602081830303815290604052905062003aba565b60155462003a6a90640100000000900463ffffffff16600462005814565b63ffffffff1667ffffffffffffffff81111562003a8b5762003a8b62004071565b6040519080825280601f01601f19166020018201604052801562003ab6576020820181803683370190505b5090505b6040517f49948e0e00000000000000000000000000000000000000000000000000000000815273420000000000000000000000000000000000000f906349948e0e9062003b0c908490600401620048ca565b602060405180830381865afa15801562003b2a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062003b50919062005775565b91505062003cc3565b60017f0000000000000000000000000000000000000000000000000000000000000000600281111562003b905762003b906200438d565b0362003cc357841562003c1857606c73ffffffffffffffffffffffffffffffffffffffff1663c6f7de0e6040518163ffffffff1660e01b8152600401602060405180830381865afa15801562003bea573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062003c10919062005775565b905062003cc3565b6000606c73ffffffffffffffffffffffffffffffffffffffff166341b247a86040518163ffffffff1660e01b815260040160c060405180830381865afa15801562003c67573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062003c8d919062005843565b505060155492945062003cb293505050640100000000900463ffffffff16826200578f565b62003cbf9060106200578f565b9150505b8462003ce257808b6080015161ffff1662003cdf91906200578f565b90505b62003cf261ffff8716826200588e565b90506000878262003d048c8e62004be7565b62003d1090866200578f565b62003d1c919062004be7565b62003d3090670de0b6b3a76400006200578f565b62003d3c91906200588e565b905060008c6040015163ffffffff1664e8d4a5100062003d5d91906200578f565b898e6020015163ffffffff16858f8862003d7891906200578f565b62003d84919062004be7565b62003d9490633b9aca006200578f565b62003da091906200578f565b62003dac91906200588e565b62003db8919062004be7565b90506b033b2e3c9fd0803ce800000062003dd3828462004be7565b111562003e0c576040517f2ad7547a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b909c909b509950505050505050505050565b6000818152600183016020526040812054801562003f1757600062003e456001836200492a565b855490915060009062003e5b906001906200492a565b905081811462003ec757600086600001828154811062003e7f5762003e7f62004bb8565b906000526020600020015490508087600001848154811062003ea55762003ea562004bb8565b6000918252602080832090910192909255918252600188019052604090208390555b855486908062003edb5762003edb620058ca565b6001900381819060005260206000200160009055905585600101600086815260200190815260200160002060009055600193505050506200299a565b60009150506200299a565b5092915050565b600081815260018301602052604081205462003f72575081546001818101845560008481526020808220909301849055845484825282860190935260409020919091556200299a565b5060006200299a565b6103ca80620058fa83390190565b50805462003f9790620049e8565b6000825580601f1062003fa8575050565b601f0160209004906000526020600020908101906200292b91905b8082111562003fd9576000815560010162003fc3565b5090565b73ffffffffffffffffffffffffffffffffffffffff811681146200292b57600080fd5b803563ffffffff81168114620038ca57600080fd5b803560028110620038ca57600080fd5b60008083601f8401126200403857600080fd5b50813567ffffffffffffffff8111156200405157600080fd5b6020830191508360208285010111156200406a57600080fd5b9250929050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b60405160e0810167ffffffffffffffff81118282101715620040c657620040c662004071565b60405290565b604051610100810167ffffffffffffffff81118282101715620040c657620040c662004071565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff811182821017156200413d576200413d62004071565b604052919050565b600067ffffffffffffffff82111562004162576200416262004071565b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b600082601f830112620041a057600080fd5b8135620041b7620041b18262004145565b620040f3565b818152846020838601011115620041cd57600080fd5b816020850160208301376000918101602001919091529392505050565b60008060008060008060008060e0898b0312156200420757600080fd5b8835620042148162003fdd565b97506200422460208a0162004000565b96506040890135620042368162003fdd565b95506200424660608a0162004015565b9450608089013567ffffffffffffffff808211156200426457600080fd5b620042728c838d0162004025565b909650945060a08b01359150808211156200428c57600080fd5b6200429a8c838d016200418e565b935060c08b0135915080821115620042b157600080fd5b50620042c08b828c016200418e565b9150509295985092959890939650565b60008060408385031215620042e457600080fd5b82359150602083013567ffffffffffffffff8111156200430357600080fd5b62004311858286016200418e565b9150509250929050565b60005b83811015620043385781810151838201526020016200431e565b50506000910152565b600081518084526200435b8160208601602086016200431b565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b600a8110620043f4577f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b9052565b841515815260806020820152600062004415608083018662004341565b9050620044266040830185620043bc565b82606083015295945050505050565b6000806000604084860312156200444b57600080fd5b83359250602084013567ffffffffffffffff8111156200446a57600080fd5b620044788682870162004025565b9497909650939450505050565b600080600080600080600060a0888a031215620044a157600080fd5b8735620044ae8162003fdd565b9650620044be6020890162004000565b95506040880135620044d08162003fdd565b9450606088013567ffffffffffffffff80821115620044ee57600080fd5b620044fc8b838c0162004025565b909650945060808a01359150808211156200451657600080fd5b50620045258a828b0162004025565b989b979a50959850939692959293505050565b871515815260e0602082015260006200455560e083018962004341565b9050620045666040830188620043bc565b8560608301528460808301528360a08301528260c083015298975050505050505050565b600080600060408486031215620045a057600080fd5b833567ffffffffffffffff80821115620045b957600080fd5b818601915086601f830112620045ce57600080fd5b813581811115620045de57600080fd5b8760208260051b8501011115620045f457600080fd5b602092830195509350508401356200460c8162003fdd565b809150509250925092565b600080602083850312156200462b57600080fd5b823567ffffffffffffffff8111156200464357600080fd5b620046518582860162004025565b90969095509350505050565b80356bffffffffffffffffffffffff81168114620038ca57600080fd5b600080604083850312156200468e57600080fd5b82359150620046a0602084016200465d565b90509250929050565b600060208284031215620046bc57600080fd5b5035919050565b600067ffffffffffffffff821115620046e057620046e062004071565b5060051b60200190565b600082601f830112620046fc57600080fd5b813560206200470f620041b183620046c3565b82815260059290921b840181019181810190868411156200472f57600080fd5b8286015b848110156200477457803567ffffffffffffffff811115620047555760008081fd5b620047658986838b01016200418e565b84525091830191830162004733565b509695505050505050565b600080600080606085870312156200479657600080fd5b84359350602085013567ffffffffffffffff80821115620047b657600080fd5b620047c488838901620046ea565b94506040870135915080821115620047db57600080fd5b50620047ea8782880162004025565b95989497509550505050565b6000602082840312156200480957600080fd5b81356200351c8162003fdd565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b600063ffffffff80831681810362004861576200486162004816565b6001019392505050565b8183528181602085013750600060208284010152600060207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f840116840101905092915050565b60208152600062002b3c6020830184866200486b565b60208152600062002997602083018462004341565b8051620038ca8162003fdd565b600060208284031215620048ff57600080fd5b81516200351c8162003fdd565b60008251620049208184602087016200431b565b9190910192915050565b818103818111156200299a576200299a62004816565b80151581146200292b57600080fd5b600082601f8301126200496157600080fd5b815162004972620041b18262004145565b8181528460208386010111156200498857600080fd5b62002b3c8260208301602087016200431b565b60008060408385031215620049af57600080fd5b8251620049bc8162004940565b602084015190925067ffffffffffffffff811115620049da57600080fd5b62004311858286016200494f565b600181811c90821680620049fd57607f821691505b60208210810362004a37577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b50919050565b601f82111562004a8b57600081815260208120601f850160051c8101602086101562004a665750805b601f850160051c820191505b8181101562004a875782815560010162004a72565b5050505b505050565b67ffffffffffffffff83111562004aab5762004aab62004071565b62004ac38362004abc8354620049e8565b8362004a3d565b6000601f84116001811462004b18576000851562004ae15750838201355b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600387901b1c1916600186901b17835562004bb1565b6000838152602090207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0861690835b8281101562004b69578685013582556020948501946001909201910162004b47565b508682101562004ba5577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60f88860031b161c19848701351681555b505060018560011b0183555b5050505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b808201808211156200299a576200299a62004816565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff820362004c315762004c3162004816565b5060010190565b600081518084526020808501945080840160005b8381101562004cf75781518051151588528381015163ffffffff908116858a01526040808301519091169089015260608082015173ffffffffffffffffffffffffffffffffffffffff16908901526080808201516bffffffffffffffffffffffff169089015260a08082015162004cd2828b01826bffffffffffffffffffffffff169052565b505060c09081015163ffffffff169088015260e0909601959082019060010162004c4c565b509495945050505050565b600081518084526020808501945080840160005b8381101562004cf757815173ffffffffffffffffffffffffffffffffffffffff168752958201959082019060010162004d16565b600081518084526020808501808196508360051b8101915082860160005b8581101562004d9657828403895262004d8384835162004341565b9885019893509084019060010162004d68565b5091979650505050505050565b60e081528760e082015260006101007f07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8a111562004de057600080fd5b8960051b808c8386013783018381038201602085015262004e048282018b62004c38565b915050828103604084015262004e1b818962004d02565b9050828103606084015262004e31818862004d02565b9050828103608084015262004e47818762004d4a565b905082810360a084015262004e5d818662004d4a565b905082810360c0840152620032f2818562004d4a565b60006020828403121562004e8657600080fd5b815160ff811681146200351c57600080fd5b60ff8416815260ff8316602082015260606040820152600062003973606083018462004341565b60006020828403121562004ed257600080fd5b815167ffffffffffffffff81111562004eea57600080fd5b62002b3c848285016200494f565b60006020828403121562004f0b57600080fd5b81516200351c8162004940565b600082601f83011262004f2a57600080fd5b8135602062004f3d620041b183620046c3565b82815260059290921b8401810191818101908684111562004f5d57600080fd5b8286015b8481101562004774578035835291830191830162004f61565b600082601f83011262004f8c57600080fd5b8135602062004f9f620041b183620046c3565b82815260e0928302850182019282820191908785111562004fbf57600080fd5b8387015b85811015620050765781818a03121562004fdd5760008081fd5b62004fe7620040a0565b813562004ff48162004940565b81526200500382870162004000565b8682015260406200501681840162004000565b908201526060828101356200502b8162003fdd565b9082015260806200503e8382016200465d565b9082015260a0620050518382016200465d565b9082015260c06200506483820162004000565b90820152845292840192810162004fc3565b5090979650505050505050565b600082601f8301126200509557600080fd5b81356020620050a8620041b183620046c3565b82815260059290921b84018101918181019086841115620050c857600080fd5b8286015b8481101562004774578035620050e28162003fdd565b8352918301918301620050cc565b600080600080600080600060e0888a0312156200510c57600080fd5b873567ffffffffffffffff808211156200512557600080fd5b620051338b838c0162004f18565b985060208a01359150808211156200514a57600080fd5b620051588b838c0162004f7a565b975060408a01359150808211156200516f57600080fd5b6200517d8b838c0162005083565b965060608a01359150808211156200519457600080fd5b620051a28b838c0162005083565b955060808a0135915080821115620051b957600080fd5b620051c78b838c01620046ea565b945060a08a0135915080821115620051de57600080fd5b620051ec8b838c01620046ea565b935060c08a01359150808211156200520357600080fd5b50620052128a828b01620046ea565b91505092959891949750929550565b6bffffffffffffffffffffffff81811683821601908082111562003f225762003f2262004816565b6bffffffffffffffffffffffff82811682821603908082111562003f225762003f2262004816565b60408152600062005286604083018662004d4a565b82810360208401526200529b8185876200486b565b9695505050505050565b8051602080830151919081101562004a37577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60209190910360031b1b16919050565b815167ffffffffffffffff81111562005305576200530562004071565b6200531d81620053168454620049e8565b8462004a3d565b602080601f8311600181146200537357600084156200533c5750858301515b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600386901b1c1916600185901b17855562004a87565b6000858152602081207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08616915b82811015620053c257888601518255948401946001909101908401620053a1565b5085821015620053ff57878501517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600388901b60f8161c191681555b5050505050600190811b01905550565b805169ffffffffffffffffffff81168114620038ca57600080fd5b600080600080600060a086880312156200544357600080fd5b6200544e866200540f565b945060208601519350604086015192506060860151915062005473608087016200540f565b90509295509295909350565b600081546200548e81620049e8565b808552602060018381168015620054ae5760018114620054e75762005517565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff008516838901528284151560051b890101955062005517565b866000528260002060005b858110156200550f5781548a8201860152908301908401620054f2565b890184019650505b505050505092915050565b6020815260006200299760208301846200547f565b600082601f8301126200554957600080fd5b815160206200555c620041b183620046c3565b82815260059290921b840181019181810190868411156200557c57600080fd5b8286015b8481101562004774578051835291830191830162005580565b600060208284031215620055ac57600080fd5b815167ffffffffffffffff80821115620055c557600080fd5b908301906101008286031215620055db57600080fd5b620055e5620040cc565b82518152602083015160208201526040830151604082015260608301516060820152608083015160808201526200561f60a08401620048df565b60a082015260c0830151828111156200563757600080fd5b620056458782860162005537565b60c08301525060e0830151828111156200565e57600080fd5b6200566c878286016200494f565b60e08301525095945050505050565b600081518084526020808501945080840160005b8381101562004cf7578151875295820195908201906001016200568f565b60408152825160408201526020830151606082015260408301516080820152606083015160a0820152608083015160c082015273ffffffffffffffffffffffffffffffffffffffff60a08401511660e0820152600060c0840151610100808185015250620057206101408401826200567b565b905060e08501517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc0848303016101208501526200575e828262004341565b91505082810360208401526200397381856200547f565b6000602082840312156200578857600080fd5b5051919050565b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0483118215151615620057ca57620057ca62004816565b500290565b60ff81811683821601908111156200299a576200299a62004816565b8284823760008382016000815283516200580a8183602088016200431b565b0195945050505050565b600063ffffffff808316818516818304811182151516156200583a576200583a62004816565b02949350505050565b60008060008060008060c087890312156200585d57600080fd5b865195506020870151945060408701519350606087015192506080870151915060a087015190509295509295509295565b600082620058c5577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500490565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fdfe60c060405234801561001057600080fd5b506040516103ca3803806103ca83398101604081905261002f91610076565b600080546001600160a01b0319166001600160a01b039384161790559181166080521660a0526100b9565b80516001600160a01b038116811461007157600080fd5b919050565b60008060006060848603121561008b57600080fd5b6100948461005a565b92506100a26020850161005a565b91506100b06040850161005a565b90509250925092565b60805160a0516102e76100e36000396000603801526000818160c4015261011701526102e76000f3fe608060405234801561001057600080fd5b50600436106100365760003560e01c806379188d161461007b578063f00e6a2a146100aa575b7f00000000000000000000000000000000000000000000000000000000000000003660008037600080366000845af43d6000803e808015610076573d6000f35b3d6000fd5b61008e6100893660046101c1565b6100ee565b6040805192151583526020830191909152015b60405180910390f35b60405173ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001681526020016100a1565b60008054819073ffffffffffffffffffffffffffffffffffffffff16331461011557600080fd5b7f00000000000000000000000000000000000000000000000000000000000000005a91505a61138881101561014957600080fd5b61138881039050856040820482031161016157600080fd5b50803b61016d57600080fd5b6000808551602087016000858af192505a610188908361029a565b9150509250929050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b600080604083850312156101d457600080fd5b82359150602083013567ffffffffffffffff808211156101f357600080fd5b818501915085601f83011261020757600080fd5b81358181111561021957610219610192565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f0116810190838211818310171561025f5761025f610192565b8160405282815288602084870101111561027857600080fd5b8260208601602083013760006020848301015280955050505050509250929050565b818103818111156102d4577f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b9291505056fea164736f6c6343000810000a307866666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666a164736f6c6343000810000a", +} + +var AutomationRegistryLogicAABI = AutomationRegistryLogicAMetaData.ABI + +var AutomationRegistryLogicABin = AutomationRegistryLogicAMetaData.Bin + +func DeployAutomationRegistryLogicA(auth *bind.TransactOpts, backend bind.ContractBackend, logicB common.Address) (common.Address, *types.Transaction, *AutomationRegistryLogicA, error) { + parsed, err := AutomationRegistryLogicAMetaData.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(AutomationRegistryLogicABin), backend, logicB) + if err != nil { + return common.Address{}, nil, nil, err + } + return address, tx, &AutomationRegistryLogicA{address: address, abi: *parsed, AutomationRegistryLogicACaller: AutomationRegistryLogicACaller{contract: contract}, AutomationRegistryLogicATransactor: AutomationRegistryLogicATransactor{contract: contract}, AutomationRegistryLogicAFilterer: AutomationRegistryLogicAFilterer{contract: contract}}, nil +} + +type AutomationRegistryLogicA struct { + address common.Address + abi abi.ABI + AutomationRegistryLogicACaller + AutomationRegistryLogicATransactor + AutomationRegistryLogicAFilterer +} + +type AutomationRegistryLogicACaller struct { + contract *bind.BoundContract +} + +type AutomationRegistryLogicATransactor struct { + contract *bind.BoundContract +} + +type AutomationRegistryLogicAFilterer struct { + contract *bind.BoundContract +} + +type AutomationRegistryLogicASession struct { + Contract *AutomationRegistryLogicA + CallOpts bind.CallOpts + TransactOpts bind.TransactOpts +} + +type AutomationRegistryLogicACallerSession struct { + Contract *AutomationRegistryLogicACaller + CallOpts bind.CallOpts +} + +type AutomationRegistryLogicATransactorSession struct { + Contract *AutomationRegistryLogicATransactor + TransactOpts bind.TransactOpts +} + +type AutomationRegistryLogicARaw struct { + Contract *AutomationRegistryLogicA +} + +type AutomationRegistryLogicACallerRaw struct { + Contract *AutomationRegistryLogicACaller +} + +type AutomationRegistryLogicATransactorRaw struct { + Contract *AutomationRegistryLogicATransactor +} + +func NewAutomationRegistryLogicA(address common.Address, backend bind.ContractBackend) (*AutomationRegistryLogicA, error) { + abi, err := abi.JSON(strings.NewReader(AutomationRegistryLogicAABI)) + if err != nil { + return nil, err + } + contract, err := bindAutomationRegistryLogicA(address, backend, backend, backend) + if err != nil { + return nil, err + } + return &AutomationRegistryLogicA{address: address, abi: abi, AutomationRegistryLogicACaller: AutomationRegistryLogicACaller{contract: contract}, AutomationRegistryLogicATransactor: AutomationRegistryLogicATransactor{contract: contract}, AutomationRegistryLogicAFilterer: AutomationRegistryLogicAFilterer{contract: contract}}, nil +} + +func NewAutomationRegistryLogicACaller(address common.Address, caller bind.ContractCaller) (*AutomationRegistryLogicACaller, error) { + contract, err := bindAutomationRegistryLogicA(address, caller, nil, nil) + if err != nil { + return nil, err + } + return &AutomationRegistryLogicACaller{contract: contract}, nil +} + +func NewAutomationRegistryLogicATransactor(address common.Address, transactor bind.ContractTransactor) (*AutomationRegistryLogicATransactor, error) { + contract, err := bindAutomationRegistryLogicA(address, nil, transactor, nil) + if err != nil { + return nil, err + } + return &AutomationRegistryLogicATransactor{contract: contract}, nil +} + +func NewAutomationRegistryLogicAFilterer(address common.Address, filterer bind.ContractFilterer) (*AutomationRegistryLogicAFilterer, error) { + contract, err := bindAutomationRegistryLogicA(address, nil, nil, filterer) + if err != nil { + return nil, err + } + return &AutomationRegistryLogicAFilterer{contract: contract}, nil +} + +func bindAutomationRegistryLogicA(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) { + parsed, err := AutomationRegistryLogicAMetaData.GetAbi() + if err != nil { + return nil, err + } + return bind.NewBoundContract(address, *parsed, caller, transactor, filterer), nil +} + +func (_AutomationRegistryLogicA *AutomationRegistryLogicARaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _AutomationRegistryLogicA.Contract.AutomationRegistryLogicACaller.contract.Call(opts, result, method, params...) +} + +func (_AutomationRegistryLogicA *AutomationRegistryLogicARaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _AutomationRegistryLogicA.Contract.AutomationRegistryLogicATransactor.contract.Transfer(opts) +} + +func (_AutomationRegistryLogicA *AutomationRegistryLogicARaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _AutomationRegistryLogicA.Contract.AutomationRegistryLogicATransactor.contract.Transact(opts, method, params...) +} + +func (_AutomationRegistryLogicA *AutomationRegistryLogicACallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _AutomationRegistryLogicA.Contract.contract.Call(opts, result, method, params...) +} + +func (_AutomationRegistryLogicA *AutomationRegistryLogicATransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _AutomationRegistryLogicA.Contract.contract.Transfer(opts) +} + +func (_AutomationRegistryLogicA *AutomationRegistryLogicATransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _AutomationRegistryLogicA.Contract.contract.Transact(opts, method, params...) +} + +func (_AutomationRegistryLogicA *AutomationRegistryLogicACaller) FallbackTo(opts *bind.CallOpts) (common.Address, error) { + var out []interface{} + err := _AutomationRegistryLogicA.contract.Call(opts, &out, "fallbackTo") + + if err != nil { + return *new(common.Address), err + } + + out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) + + return out0, err + +} + +func (_AutomationRegistryLogicA *AutomationRegistryLogicASession) FallbackTo() (common.Address, error) { + return _AutomationRegistryLogicA.Contract.FallbackTo(&_AutomationRegistryLogicA.CallOpts) +} + +func (_AutomationRegistryLogicA *AutomationRegistryLogicACallerSession) FallbackTo() (common.Address, error) { + return _AutomationRegistryLogicA.Contract.FallbackTo(&_AutomationRegistryLogicA.CallOpts) +} + +func (_AutomationRegistryLogicA *AutomationRegistryLogicACaller) Owner(opts *bind.CallOpts) (common.Address, error) { + var out []interface{} + err := _AutomationRegistryLogicA.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 (_AutomationRegistryLogicA *AutomationRegistryLogicASession) Owner() (common.Address, error) { + return _AutomationRegistryLogicA.Contract.Owner(&_AutomationRegistryLogicA.CallOpts) +} + +func (_AutomationRegistryLogicA *AutomationRegistryLogicACallerSession) Owner() (common.Address, error) { + return _AutomationRegistryLogicA.Contract.Owner(&_AutomationRegistryLogicA.CallOpts) +} + +func (_AutomationRegistryLogicA *AutomationRegistryLogicATransactor) AcceptOwnership(opts *bind.TransactOpts) (*types.Transaction, error) { + return _AutomationRegistryLogicA.contract.Transact(opts, "acceptOwnership") +} + +func (_AutomationRegistryLogicA *AutomationRegistryLogicASession) AcceptOwnership() (*types.Transaction, error) { + return _AutomationRegistryLogicA.Contract.AcceptOwnership(&_AutomationRegistryLogicA.TransactOpts) +} + +func (_AutomationRegistryLogicA *AutomationRegistryLogicATransactorSession) AcceptOwnership() (*types.Transaction, error) { + return _AutomationRegistryLogicA.Contract.AcceptOwnership(&_AutomationRegistryLogicA.TransactOpts) +} + +func (_AutomationRegistryLogicA *AutomationRegistryLogicATransactor) AddFunds(opts *bind.TransactOpts, id *big.Int, amount *big.Int) (*types.Transaction, error) { + return _AutomationRegistryLogicA.contract.Transact(opts, "addFunds", id, amount) +} + +func (_AutomationRegistryLogicA *AutomationRegistryLogicASession) AddFunds(id *big.Int, amount *big.Int) (*types.Transaction, error) { + return _AutomationRegistryLogicA.Contract.AddFunds(&_AutomationRegistryLogicA.TransactOpts, id, amount) +} + +func (_AutomationRegistryLogicA *AutomationRegistryLogicATransactorSession) AddFunds(id *big.Int, amount *big.Int) (*types.Transaction, error) { + return _AutomationRegistryLogicA.Contract.AddFunds(&_AutomationRegistryLogicA.TransactOpts, id, amount) +} + +func (_AutomationRegistryLogicA *AutomationRegistryLogicATransactor) CancelUpkeep(opts *bind.TransactOpts, id *big.Int) (*types.Transaction, error) { + return _AutomationRegistryLogicA.contract.Transact(opts, "cancelUpkeep", id) +} + +func (_AutomationRegistryLogicA *AutomationRegistryLogicASession) CancelUpkeep(id *big.Int) (*types.Transaction, error) { + return _AutomationRegistryLogicA.Contract.CancelUpkeep(&_AutomationRegistryLogicA.TransactOpts, id) +} + +func (_AutomationRegistryLogicA *AutomationRegistryLogicATransactorSession) CancelUpkeep(id *big.Int) (*types.Transaction, error) { + return _AutomationRegistryLogicA.Contract.CancelUpkeep(&_AutomationRegistryLogicA.TransactOpts, id) +} + +func (_AutomationRegistryLogicA *AutomationRegistryLogicATransactor) CheckCallback(opts *bind.TransactOpts, id *big.Int, values [][]byte, extraData []byte) (*types.Transaction, error) { + return _AutomationRegistryLogicA.contract.Transact(opts, "checkCallback", id, values, extraData) +} + +func (_AutomationRegistryLogicA *AutomationRegistryLogicASession) CheckCallback(id *big.Int, values [][]byte, extraData []byte) (*types.Transaction, error) { + return _AutomationRegistryLogicA.Contract.CheckCallback(&_AutomationRegistryLogicA.TransactOpts, id, values, extraData) +} + +func (_AutomationRegistryLogicA *AutomationRegistryLogicATransactorSession) CheckCallback(id *big.Int, values [][]byte, extraData []byte) (*types.Transaction, error) { + return _AutomationRegistryLogicA.Contract.CheckCallback(&_AutomationRegistryLogicA.TransactOpts, id, values, extraData) +} + +func (_AutomationRegistryLogicA *AutomationRegistryLogicATransactor) CheckUpkeep(opts *bind.TransactOpts, id *big.Int, triggerData []byte) (*types.Transaction, error) { + return _AutomationRegistryLogicA.contract.Transact(opts, "checkUpkeep", id, triggerData) +} + +func (_AutomationRegistryLogicA *AutomationRegistryLogicASession) CheckUpkeep(id *big.Int, triggerData []byte) (*types.Transaction, error) { + return _AutomationRegistryLogicA.Contract.CheckUpkeep(&_AutomationRegistryLogicA.TransactOpts, id, triggerData) +} + +func (_AutomationRegistryLogicA *AutomationRegistryLogicATransactorSession) CheckUpkeep(id *big.Int, triggerData []byte) (*types.Transaction, error) { + return _AutomationRegistryLogicA.Contract.CheckUpkeep(&_AutomationRegistryLogicA.TransactOpts, id, triggerData) +} + +func (_AutomationRegistryLogicA *AutomationRegistryLogicATransactor) CheckUpkeep0(opts *bind.TransactOpts, id *big.Int) (*types.Transaction, error) { + return _AutomationRegistryLogicA.contract.Transact(opts, "checkUpkeep0", id) +} + +func (_AutomationRegistryLogicA *AutomationRegistryLogicASession) CheckUpkeep0(id *big.Int) (*types.Transaction, error) { + return _AutomationRegistryLogicA.Contract.CheckUpkeep0(&_AutomationRegistryLogicA.TransactOpts, id) +} + +func (_AutomationRegistryLogicA *AutomationRegistryLogicATransactorSession) CheckUpkeep0(id *big.Int) (*types.Transaction, error) { + return _AutomationRegistryLogicA.Contract.CheckUpkeep0(&_AutomationRegistryLogicA.TransactOpts, id) +} + +func (_AutomationRegistryLogicA *AutomationRegistryLogicATransactor) ExecuteCallback(opts *bind.TransactOpts, id *big.Int, payload []byte) (*types.Transaction, error) { + return _AutomationRegistryLogicA.contract.Transact(opts, "executeCallback", id, payload) +} + +func (_AutomationRegistryLogicA *AutomationRegistryLogicASession) ExecuteCallback(id *big.Int, payload []byte) (*types.Transaction, error) { + return _AutomationRegistryLogicA.Contract.ExecuteCallback(&_AutomationRegistryLogicA.TransactOpts, id, payload) +} + +func (_AutomationRegistryLogicA *AutomationRegistryLogicATransactorSession) ExecuteCallback(id *big.Int, payload []byte) (*types.Transaction, error) { + return _AutomationRegistryLogicA.Contract.ExecuteCallback(&_AutomationRegistryLogicA.TransactOpts, id, payload) +} + +func (_AutomationRegistryLogicA *AutomationRegistryLogicATransactor) MigrateUpkeeps(opts *bind.TransactOpts, ids []*big.Int, destination common.Address) (*types.Transaction, error) { + return _AutomationRegistryLogicA.contract.Transact(opts, "migrateUpkeeps", ids, destination) +} + +func (_AutomationRegistryLogicA *AutomationRegistryLogicASession) MigrateUpkeeps(ids []*big.Int, destination common.Address) (*types.Transaction, error) { + return _AutomationRegistryLogicA.Contract.MigrateUpkeeps(&_AutomationRegistryLogicA.TransactOpts, ids, destination) +} + +func (_AutomationRegistryLogicA *AutomationRegistryLogicATransactorSession) MigrateUpkeeps(ids []*big.Int, destination common.Address) (*types.Transaction, error) { + return _AutomationRegistryLogicA.Contract.MigrateUpkeeps(&_AutomationRegistryLogicA.TransactOpts, ids, destination) +} + +func (_AutomationRegistryLogicA *AutomationRegistryLogicATransactor) ReceiveUpkeeps(opts *bind.TransactOpts, encodedUpkeeps []byte) (*types.Transaction, error) { + return _AutomationRegistryLogicA.contract.Transact(opts, "receiveUpkeeps", encodedUpkeeps) +} + +func (_AutomationRegistryLogicA *AutomationRegistryLogicASession) ReceiveUpkeeps(encodedUpkeeps []byte) (*types.Transaction, error) { + return _AutomationRegistryLogicA.Contract.ReceiveUpkeeps(&_AutomationRegistryLogicA.TransactOpts, encodedUpkeeps) +} + +func (_AutomationRegistryLogicA *AutomationRegistryLogicATransactorSession) ReceiveUpkeeps(encodedUpkeeps []byte) (*types.Transaction, error) { + return _AutomationRegistryLogicA.Contract.ReceiveUpkeeps(&_AutomationRegistryLogicA.TransactOpts, encodedUpkeeps) +} + +func (_AutomationRegistryLogicA *AutomationRegistryLogicATransactor) RegisterUpkeep(opts *bind.TransactOpts, target common.Address, gasLimit uint32, admin common.Address, triggerType uint8, checkData []byte, triggerConfig []byte, offchainConfig []byte) (*types.Transaction, error) { + return _AutomationRegistryLogicA.contract.Transact(opts, "registerUpkeep", target, gasLimit, admin, triggerType, checkData, triggerConfig, offchainConfig) +} + +func (_AutomationRegistryLogicA *AutomationRegistryLogicASession) RegisterUpkeep(target common.Address, gasLimit uint32, admin common.Address, triggerType uint8, checkData []byte, triggerConfig []byte, offchainConfig []byte) (*types.Transaction, error) { + return _AutomationRegistryLogicA.Contract.RegisterUpkeep(&_AutomationRegistryLogicA.TransactOpts, target, gasLimit, admin, triggerType, checkData, triggerConfig, offchainConfig) +} + +func (_AutomationRegistryLogicA *AutomationRegistryLogicATransactorSession) RegisterUpkeep(target common.Address, gasLimit uint32, admin common.Address, triggerType uint8, checkData []byte, triggerConfig []byte, offchainConfig []byte) (*types.Transaction, error) { + return _AutomationRegistryLogicA.Contract.RegisterUpkeep(&_AutomationRegistryLogicA.TransactOpts, target, gasLimit, admin, triggerType, checkData, triggerConfig, offchainConfig) +} + +func (_AutomationRegistryLogicA *AutomationRegistryLogicATransactor) RegisterUpkeep0(opts *bind.TransactOpts, target common.Address, gasLimit uint32, admin common.Address, checkData []byte, offchainConfig []byte) (*types.Transaction, error) { + return _AutomationRegistryLogicA.contract.Transact(opts, "registerUpkeep0", target, gasLimit, admin, checkData, offchainConfig) +} + +func (_AutomationRegistryLogicA *AutomationRegistryLogicASession) RegisterUpkeep0(target common.Address, gasLimit uint32, admin common.Address, checkData []byte, offchainConfig []byte) (*types.Transaction, error) { + return _AutomationRegistryLogicA.Contract.RegisterUpkeep0(&_AutomationRegistryLogicA.TransactOpts, target, gasLimit, admin, checkData, offchainConfig) +} + +func (_AutomationRegistryLogicA *AutomationRegistryLogicATransactorSession) RegisterUpkeep0(target common.Address, gasLimit uint32, admin common.Address, checkData []byte, offchainConfig []byte) (*types.Transaction, error) { + return _AutomationRegistryLogicA.Contract.RegisterUpkeep0(&_AutomationRegistryLogicA.TransactOpts, target, gasLimit, admin, checkData, offchainConfig) +} + +func (_AutomationRegistryLogicA *AutomationRegistryLogicATransactor) SetUpkeepTriggerConfig(opts *bind.TransactOpts, id *big.Int, triggerConfig []byte) (*types.Transaction, error) { + return _AutomationRegistryLogicA.contract.Transact(opts, "setUpkeepTriggerConfig", id, triggerConfig) +} + +func (_AutomationRegistryLogicA *AutomationRegistryLogicASession) SetUpkeepTriggerConfig(id *big.Int, triggerConfig []byte) (*types.Transaction, error) { + return _AutomationRegistryLogicA.Contract.SetUpkeepTriggerConfig(&_AutomationRegistryLogicA.TransactOpts, id, triggerConfig) +} + +func (_AutomationRegistryLogicA *AutomationRegistryLogicATransactorSession) SetUpkeepTriggerConfig(id *big.Int, triggerConfig []byte) (*types.Transaction, error) { + return _AutomationRegistryLogicA.Contract.SetUpkeepTriggerConfig(&_AutomationRegistryLogicA.TransactOpts, id, triggerConfig) +} + +func (_AutomationRegistryLogicA *AutomationRegistryLogicATransactor) TransferOwnership(opts *bind.TransactOpts, to common.Address) (*types.Transaction, error) { + return _AutomationRegistryLogicA.contract.Transact(opts, "transferOwnership", to) +} + +func (_AutomationRegistryLogicA *AutomationRegistryLogicASession) TransferOwnership(to common.Address) (*types.Transaction, error) { + return _AutomationRegistryLogicA.Contract.TransferOwnership(&_AutomationRegistryLogicA.TransactOpts, to) +} + +func (_AutomationRegistryLogicA *AutomationRegistryLogicATransactorSession) TransferOwnership(to common.Address) (*types.Transaction, error) { + return _AutomationRegistryLogicA.Contract.TransferOwnership(&_AutomationRegistryLogicA.TransactOpts, to) +} + +func (_AutomationRegistryLogicA *AutomationRegistryLogicATransactor) Fallback(opts *bind.TransactOpts, calldata []byte) (*types.Transaction, error) { + return _AutomationRegistryLogicA.contract.RawTransact(opts, calldata) +} + +func (_AutomationRegistryLogicA *AutomationRegistryLogicASession) Fallback(calldata []byte) (*types.Transaction, error) { + return _AutomationRegistryLogicA.Contract.Fallback(&_AutomationRegistryLogicA.TransactOpts, calldata) +} + +func (_AutomationRegistryLogicA *AutomationRegistryLogicATransactorSession) Fallback(calldata []byte) (*types.Transaction, error) { + return _AutomationRegistryLogicA.Contract.Fallback(&_AutomationRegistryLogicA.TransactOpts, calldata) +} + +type AutomationRegistryLogicAAdminPrivilegeConfigSetIterator struct { + Event *AutomationRegistryLogicAAdminPrivilegeConfigSet + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *AutomationRegistryLogicAAdminPrivilegeConfigSetIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(AutomationRegistryLogicAAdminPrivilegeConfigSet) + 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(AutomationRegistryLogicAAdminPrivilegeConfigSet) + 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 *AutomationRegistryLogicAAdminPrivilegeConfigSetIterator) Error() error { + return it.fail +} + +func (it *AutomationRegistryLogicAAdminPrivilegeConfigSetIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type AutomationRegistryLogicAAdminPrivilegeConfigSet struct { + Admin common.Address + PrivilegeConfig []byte + Raw types.Log +} + +func (_AutomationRegistryLogicA *AutomationRegistryLogicAFilterer) FilterAdminPrivilegeConfigSet(opts *bind.FilterOpts, admin []common.Address) (*AutomationRegistryLogicAAdminPrivilegeConfigSetIterator, error) { + + var adminRule []interface{} + for _, adminItem := range admin { + adminRule = append(adminRule, adminItem) + } + + logs, sub, err := _AutomationRegistryLogicA.contract.FilterLogs(opts, "AdminPrivilegeConfigSet", adminRule) + if err != nil { + return nil, err + } + return &AutomationRegistryLogicAAdminPrivilegeConfigSetIterator{contract: _AutomationRegistryLogicA.contract, event: "AdminPrivilegeConfigSet", logs: logs, sub: sub}, nil +} + +func (_AutomationRegistryLogicA *AutomationRegistryLogicAFilterer) WatchAdminPrivilegeConfigSet(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicAAdminPrivilegeConfigSet, admin []common.Address) (event.Subscription, error) { + + var adminRule []interface{} + for _, adminItem := range admin { + adminRule = append(adminRule, adminItem) + } + + logs, sub, err := _AutomationRegistryLogicA.contract.WatchLogs(opts, "AdminPrivilegeConfigSet", adminRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(AutomationRegistryLogicAAdminPrivilegeConfigSet) + if err := _AutomationRegistryLogicA.contract.UnpackLog(event, "AdminPrivilegeConfigSet", 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 (_AutomationRegistryLogicA *AutomationRegistryLogicAFilterer) ParseAdminPrivilegeConfigSet(log types.Log) (*AutomationRegistryLogicAAdminPrivilegeConfigSet, error) { + event := new(AutomationRegistryLogicAAdminPrivilegeConfigSet) + if err := _AutomationRegistryLogicA.contract.UnpackLog(event, "AdminPrivilegeConfigSet", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type AutomationRegistryLogicACancelledUpkeepReportIterator struct { + Event *AutomationRegistryLogicACancelledUpkeepReport + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *AutomationRegistryLogicACancelledUpkeepReportIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(AutomationRegistryLogicACancelledUpkeepReport) + 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(AutomationRegistryLogicACancelledUpkeepReport) + 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 *AutomationRegistryLogicACancelledUpkeepReportIterator) Error() error { + return it.fail +} + +func (it *AutomationRegistryLogicACancelledUpkeepReportIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type AutomationRegistryLogicACancelledUpkeepReport struct { + Id *big.Int + Trigger []byte + Raw types.Log +} + +func (_AutomationRegistryLogicA *AutomationRegistryLogicAFilterer) FilterCancelledUpkeepReport(opts *bind.FilterOpts, id []*big.Int) (*AutomationRegistryLogicACancelledUpkeepReportIterator, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + + logs, sub, err := _AutomationRegistryLogicA.contract.FilterLogs(opts, "CancelledUpkeepReport", idRule) + if err != nil { + return nil, err + } + return &AutomationRegistryLogicACancelledUpkeepReportIterator{contract: _AutomationRegistryLogicA.contract, event: "CancelledUpkeepReport", logs: logs, sub: sub}, nil +} + +func (_AutomationRegistryLogicA *AutomationRegistryLogicAFilterer) WatchCancelledUpkeepReport(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicACancelledUpkeepReport, id []*big.Int) (event.Subscription, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + + logs, sub, err := _AutomationRegistryLogicA.contract.WatchLogs(opts, "CancelledUpkeepReport", idRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(AutomationRegistryLogicACancelledUpkeepReport) + if err := _AutomationRegistryLogicA.contract.UnpackLog(event, "CancelledUpkeepReport", 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 (_AutomationRegistryLogicA *AutomationRegistryLogicAFilterer) ParseCancelledUpkeepReport(log types.Log) (*AutomationRegistryLogicACancelledUpkeepReport, error) { + event := new(AutomationRegistryLogicACancelledUpkeepReport) + if err := _AutomationRegistryLogicA.contract.UnpackLog(event, "CancelledUpkeepReport", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type AutomationRegistryLogicADedupKeyAddedIterator struct { + Event *AutomationRegistryLogicADedupKeyAdded + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *AutomationRegistryLogicADedupKeyAddedIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(AutomationRegistryLogicADedupKeyAdded) + 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(AutomationRegistryLogicADedupKeyAdded) + 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 *AutomationRegistryLogicADedupKeyAddedIterator) Error() error { + return it.fail +} + +func (it *AutomationRegistryLogicADedupKeyAddedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type AutomationRegistryLogicADedupKeyAdded struct { + DedupKey [32]byte + Raw types.Log +} + +func (_AutomationRegistryLogicA *AutomationRegistryLogicAFilterer) FilterDedupKeyAdded(opts *bind.FilterOpts, dedupKey [][32]byte) (*AutomationRegistryLogicADedupKeyAddedIterator, error) { + + var dedupKeyRule []interface{} + for _, dedupKeyItem := range dedupKey { + dedupKeyRule = append(dedupKeyRule, dedupKeyItem) + } + + logs, sub, err := _AutomationRegistryLogicA.contract.FilterLogs(opts, "DedupKeyAdded", dedupKeyRule) + if err != nil { + return nil, err + } + return &AutomationRegistryLogicADedupKeyAddedIterator{contract: _AutomationRegistryLogicA.contract, event: "DedupKeyAdded", logs: logs, sub: sub}, nil +} + +func (_AutomationRegistryLogicA *AutomationRegistryLogicAFilterer) WatchDedupKeyAdded(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicADedupKeyAdded, dedupKey [][32]byte) (event.Subscription, error) { + + var dedupKeyRule []interface{} + for _, dedupKeyItem := range dedupKey { + dedupKeyRule = append(dedupKeyRule, dedupKeyItem) + } + + logs, sub, err := _AutomationRegistryLogicA.contract.WatchLogs(opts, "DedupKeyAdded", dedupKeyRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(AutomationRegistryLogicADedupKeyAdded) + if err := _AutomationRegistryLogicA.contract.UnpackLog(event, "DedupKeyAdded", 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 (_AutomationRegistryLogicA *AutomationRegistryLogicAFilterer) ParseDedupKeyAdded(log types.Log) (*AutomationRegistryLogicADedupKeyAdded, error) { + event := new(AutomationRegistryLogicADedupKeyAdded) + if err := _AutomationRegistryLogicA.contract.UnpackLog(event, "DedupKeyAdded", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type AutomationRegistryLogicAFundsAddedIterator struct { + Event *AutomationRegistryLogicAFundsAdded + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *AutomationRegistryLogicAFundsAddedIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(AutomationRegistryLogicAFundsAdded) + 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(AutomationRegistryLogicAFundsAdded) + 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 *AutomationRegistryLogicAFundsAddedIterator) Error() error { + return it.fail +} + +func (it *AutomationRegistryLogicAFundsAddedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type AutomationRegistryLogicAFundsAdded struct { + Id *big.Int + From common.Address + Amount *big.Int + Raw types.Log +} + +func (_AutomationRegistryLogicA *AutomationRegistryLogicAFilterer) FilterFundsAdded(opts *bind.FilterOpts, id []*big.Int, from []common.Address) (*AutomationRegistryLogicAFundsAddedIterator, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + var fromRule []interface{} + for _, fromItem := range from { + fromRule = append(fromRule, fromItem) + } + + logs, sub, err := _AutomationRegistryLogicA.contract.FilterLogs(opts, "FundsAdded", idRule, fromRule) + if err != nil { + return nil, err + } + return &AutomationRegistryLogicAFundsAddedIterator{contract: _AutomationRegistryLogicA.contract, event: "FundsAdded", logs: logs, sub: sub}, nil +} + +func (_AutomationRegistryLogicA *AutomationRegistryLogicAFilterer) WatchFundsAdded(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicAFundsAdded, id []*big.Int, from []common.Address) (event.Subscription, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + var fromRule []interface{} + for _, fromItem := range from { + fromRule = append(fromRule, fromItem) + } + + logs, sub, err := _AutomationRegistryLogicA.contract.WatchLogs(opts, "FundsAdded", idRule, fromRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(AutomationRegistryLogicAFundsAdded) + if err := _AutomationRegistryLogicA.contract.UnpackLog(event, "FundsAdded", 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 (_AutomationRegistryLogicA *AutomationRegistryLogicAFilterer) ParseFundsAdded(log types.Log) (*AutomationRegistryLogicAFundsAdded, error) { + event := new(AutomationRegistryLogicAFundsAdded) + if err := _AutomationRegistryLogicA.contract.UnpackLog(event, "FundsAdded", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type AutomationRegistryLogicAFundsWithdrawnIterator struct { + Event *AutomationRegistryLogicAFundsWithdrawn + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *AutomationRegistryLogicAFundsWithdrawnIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(AutomationRegistryLogicAFundsWithdrawn) + 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(AutomationRegistryLogicAFundsWithdrawn) + 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 *AutomationRegistryLogicAFundsWithdrawnIterator) Error() error { + return it.fail +} + +func (it *AutomationRegistryLogicAFundsWithdrawnIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type AutomationRegistryLogicAFundsWithdrawn struct { + Id *big.Int + Amount *big.Int + To common.Address + Raw types.Log +} + +func (_AutomationRegistryLogicA *AutomationRegistryLogicAFilterer) FilterFundsWithdrawn(opts *bind.FilterOpts, id []*big.Int) (*AutomationRegistryLogicAFundsWithdrawnIterator, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + + logs, sub, err := _AutomationRegistryLogicA.contract.FilterLogs(opts, "FundsWithdrawn", idRule) + if err != nil { + return nil, err + } + return &AutomationRegistryLogicAFundsWithdrawnIterator{contract: _AutomationRegistryLogicA.contract, event: "FundsWithdrawn", logs: logs, sub: sub}, nil +} + +func (_AutomationRegistryLogicA *AutomationRegistryLogicAFilterer) WatchFundsWithdrawn(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicAFundsWithdrawn, id []*big.Int) (event.Subscription, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + + logs, sub, err := _AutomationRegistryLogicA.contract.WatchLogs(opts, "FundsWithdrawn", idRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(AutomationRegistryLogicAFundsWithdrawn) + if err := _AutomationRegistryLogicA.contract.UnpackLog(event, "FundsWithdrawn", 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 (_AutomationRegistryLogicA *AutomationRegistryLogicAFilterer) ParseFundsWithdrawn(log types.Log) (*AutomationRegistryLogicAFundsWithdrawn, error) { + event := new(AutomationRegistryLogicAFundsWithdrawn) + if err := _AutomationRegistryLogicA.contract.UnpackLog(event, "FundsWithdrawn", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type AutomationRegistryLogicAInsufficientFundsUpkeepReportIterator struct { + Event *AutomationRegistryLogicAInsufficientFundsUpkeepReport + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *AutomationRegistryLogicAInsufficientFundsUpkeepReportIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(AutomationRegistryLogicAInsufficientFundsUpkeepReport) + 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(AutomationRegistryLogicAInsufficientFundsUpkeepReport) + 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 *AutomationRegistryLogicAInsufficientFundsUpkeepReportIterator) Error() error { + return it.fail +} + +func (it *AutomationRegistryLogicAInsufficientFundsUpkeepReportIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type AutomationRegistryLogicAInsufficientFundsUpkeepReport struct { + Id *big.Int + Trigger []byte + Raw types.Log +} + +func (_AutomationRegistryLogicA *AutomationRegistryLogicAFilterer) FilterInsufficientFundsUpkeepReport(opts *bind.FilterOpts, id []*big.Int) (*AutomationRegistryLogicAInsufficientFundsUpkeepReportIterator, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + + logs, sub, err := _AutomationRegistryLogicA.contract.FilterLogs(opts, "InsufficientFundsUpkeepReport", idRule) + if err != nil { + return nil, err + } + return &AutomationRegistryLogicAInsufficientFundsUpkeepReportIterator{contract: _AutomationRegistryLogicA.contract, event: "InsufficientFundsUpkeepReport", logs: logs, sub: sub}, nil +} + +func (_AutomationRegistryLogicA *AutomationRegistryLogicAFilterer) WatchInsufficientFundsUpkeepReport(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicAInsufficientFundsUpkeepReport, id []*big.Int) (event.Subscription, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + + logs, sub, err := _AutomationRegistryLogicA.contract.WatchLogs(opts, "InsufficientFundsUpkeepReport", idRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(AutomationRegistryLogicAInsufficientFundsUpkeepReport) + if err := _AutomationRegistryLogicA.contract.UnpackLog(event, "InsufficientFundsUpkeepReport", 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 (_AutomationRegistryLogicA *AutomationRegistryLogicAFilterer) ParseInsufficientFundsUpkeepReport(log types.Log) (*AutomationRegistryLogicAInsufficientFundsUpkeepReport, error) { + event := new(AutomationRegistryLogicAInsufficientFundsUpkeepReport) + if err := _AutomationRegistryLogicA.contract.UnpackLog(event, "InsufficientFundsUpkeepReport", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type AutomationRegistryLogicAOwnerFundsWithdrawnIterator struct { + Event *AutomationRegistryLogicAOwnerFundsWithdrawn + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *AutomationRegistryLogicAOwnerFundsWithdrawnIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(AutomationRegistryLogicAOwnerFundsWithdrawn) + 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(AutomationRegistryLogicAOwnerFundsWithdrawn) + 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 *AutomationRegistryLogicAOwnerFundsWithdrawnIterator) Error() error { + return it.fail +} + +func (it *AutomationRegistryLogicAOwnerFundsWithdrawnIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type AutomationRegistryLogicAOwnerFundsWithdrawn struct { + Amount *big.Int + Raw types.Log +} + +func (_AutomationRegistryLogicA *AutomationRegistryLogicAFilterer) FilterOwnerFundsWithdrawn(opts *bind.FilterOpts) (*AutomationRegistryLogicAOwnerFundsWithdrawnIterator, error) { + + logs, sub, err := _AutomationRegistryLogicA.contract.FilterLogs(opts, "OwnerFundsWithdrawn") + if err != nil { + return nil, err + } + return &AutomationRegistryLogicAOwnerFundsWithdrawnIterator{contract: _AutomationRegistryLogicA.contract, event: "OwnerFundsWithdrawn", logs: logs, sub: sub}, nil +} + +func (_AutomationRegistryLogicA *AutomationRegistryLogicAFilterer) WatchOwnerFundsWithdrawn(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicAOwnerFundsWithdrawn) (event.Subscription, error) { + + logs, sub, err := _AutomationRegistryLogicA.contract.WatchLogs(opts, "OwnerFundsWithdrawn") + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(AutomationRegistryLogicAOwnerFundsWithdrawn) + if err := _AutomationRegistryLogicA.contract.UnpackLog(event, "OwnerFundsWithdrawn", 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 (_AutomationRegistryLogicA *AutomationRegistryLogicAFilterer) ParseOwnerFundsWithdrawn(log types.Log) (*AutomationRegistryLogicAOwnerFundsWithdrawn, error) { + event := new(AutomationRegistryLogicAOwnerFundsWithdrawn) + if err := _AutomationRegistryLogicA.contract.UnpackLog(event, "OwnerFundsWithdrawn", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type AutomationRegistryLogicAOwnershipTransferRequestedIterator struct { + Event *AutomationRegistryLogicAOwnershipTransferRequested + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *AutomationRegistryLogicAOwnershipTransferRequestedIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(AutomationRegistryLogicAOwnershipTransferRequested) + 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(AutomationRegistryLogicAOwnershipTransferRequested) + 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 *AutomationRegistryLogicAOwnershipTransferRequestedIterator) Error() error { + return it.fail +} + +func (it *AutomationRegistryLogicAOwnershipTransferRequestedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type AutomationRegistryLogicAOwnershipTransferRequested struct { + From common.Address + To common.Address + Raw types.Log +} + +func (_AutomationRegistryLogicA *AutomationRegistryLogicAFilterer) FilterOwnershipTransferRequested(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*AutomationRegistryLogicAOwnershipTransferRequestedIterator, 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 := _AutomationRegistryLogicA.contract.FilterLogs(opts, "OwnershipTransferRequested", fromRule, toRule) + if err != nil { + return nil, err + } + return &AutomationRegistryLogicAOwnershipTransferRequestedIterator{contract: _AutomationRegistryLogicA.contract, event: "OwnershipTransferRequested", logs: logs, sub: sub}, nil +} + +func (_AutomationRegistryLogicA *AutomationRegistryLogicAFilterer) WatchOwnershipTransferRequested(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicAOwnershipTransferRequested, 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 := _AutomationRegistryLogicA.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(AutomationRegistryLogicAOwnershipTransferRequested) + if err := _AutomationRegistryLogicA.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 (_AutomationRegistryLogicA *AutomationRegistryLogicAFilterer) ParseOwnershipTransferRequested(log types.Log) (*AutomationRegistryLogicAOwnershipTransferRequested, error) { + event := new(AutomationRegistryLogicAOwnershipTransferRequested) + if err := _AutomationRegistryLogicA.contract.UnpackLog(event, "OwnershipTransferRequested", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type AutomationRegistryLogicAOwnershipTransferredIterator struct { + Event *AutomationRegistryLogicAOwnershipTransferred + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *AutomationRegistryLogicAOwnershipTransferredIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(AutomationRegistryLogicAOwnershipTransferred) + 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(AutomationRegistryLogicAOwnershipTransferred) + 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 *AutomationRegistryLogicAOwnershipTransferredIterator) Error() error { + return it.fail +} + +func (it *AutomationRegistryLogicAOwnershipTransferredIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type AutomationRegistryLogicAOwnershipTransferred struct { + From common.Address + To common.Address + Raw types.Log +} + +func (_AutomationRegistryLogicA *AutomationRegistryLogicAFilterer) FilterOwnershipTransferred(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*AutomationRegistryLogicAOwnershipTransferredIterator, 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 := _AutomationRegistryLogicA.contract.FilterLogs(opts, "OwnershipTransferred", fromRule, toRule) + if err != nil { + return nil, err + } + return &AutomationRegistryLogicAOwnershipTransferredIterator{contract: _AutomationRegistryLogicA.contract, event: "OwnershipTransferred", logs: logs, sub: sub}, nil +} + +func (_AutomationRegistryLogicA *AutomationRegistryLogicAFilterer) WatchOwnershipTransferred(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicAOwnershipTransferred, 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 := _AutomationRegistryLogicA.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(AutomationRegistryLogicAOwnershipTransferred) + if err := _AutomationRegistryLogicA.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 (_AutomationRegistryLogicA *AutomationRegistryLogicAFilterer) ParseOwnershipTransferred(log types.Log) (*AutomationRegistryLogicAOwnershipTransferred, error) { + event := new(AutomationRegistryLogicAOwnershipTransferred) + if err := _AutomationRegistryLogicA.contract.UnpackLog(event, "OwnershipTransferred", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type AutomationRegistryLogicAPausedIterator struct { + Event *AutomationRegistryLogicAPaused + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *AutomationRegistryLogicAPausedIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(AutomationRegistryLogicAPaused) + 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(AutomationRegistryLogicAPaused) + 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 *AutomationRegistryLogicAPausedIterator) Error() error { + return it.fail +} + +func (it *AutomationRegistryLogicAPausedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type AutomationRegistryLogicAPaused struct { + Account common.Address + Raw types.Log +} + +func (_AutomationRegistryLogicA *AutomationRegistryLogicAFilterer) FilterPaused(opts *bind.FilterOpts) (*AutomationRegistryLogicAPausedIterator, error) { + + logs, sub, err := _AutomationRegistryLogicA.contract.FilterLogs(opts, "Paused") + if err != nil { + return nil, err + } + return &AutomationRegistryLogicAPausedIterator{contract: _AutomationRegistryLogicA.contract, event: "Paused", logs: logs, sub: sub}, nil +} + +func (_AutomationRegistryLogicA *AutomationRegistryLogicAFilterer) WatchPaused(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicAPaused) (event.Subscription, error) { + + logs, sub, err := _AutomationRegistryLogicA.contract.WatchLogs(opts, "Paused") + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(AutomationRegistryLogicAPaused) + if err := _AutomationRegistryLogicA.contract.UnpackLog(event, "Paused", 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 (_AutomationRegistryLogicA *AutomationRegistryLogicAFilterer) ParsePaused(log types.Log) (*AutomationRegistryLogicAPaused, error) { + event := new(AutomationRegistryLogicAPaused) + if err := _AutomationRegistryLogicA.contract.UnpackLog(event, "Paused", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type AutomationRegistryLogicAPayeesUpdatedIterator struct { + Event *AutomationRegistryLogicAPayeesUpdated + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *AutomationRegistryLogicAPayeesUpdatedIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(AutomationRegistryLogicAPayeesUpdated) + 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(AutomationRegistryLogicAPayeesUpdated) + 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 *AutomationRegistryLogicAPayeesUpdatedIterator) Error() error { + return it.fail +} + +func (it *AutomationRegistryLogicAPayeesUpdatedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type AutomationRegistryLogicAPayeesUpdated struct { + Transmitters []common.Address + Payees []common.Address + Raw types.Log +} + +func (_AutomationRegistryLogicA *AutomationRegistryLogicAFilterer) FilterPayeesUpdated(opts *bind.FilterOpts) (*AutomationRegistryLogicAPayeesUpdatedIterator, error) { + + logs, sub, err := _AutomationRegistryLogicA.contract.FilterLogs(opts, "PayeesUpdated") + if err != nil { + return nil, err + } + return &AutomationRegistryLogicAPayeesUpdatedIterator{contract: _AutomationRegistryLogicA.contract, event: "PayeesUpdated", logs: logs, sub: sub}, nil +} + +func (_AutomationRegistryLogicA *AutomationRegistryLogicAFilterer) WatchPayeesUpdated(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicAPayeesUpdated) (event.Subscription, error) { + + logs, sub, err := _AutomationRegistryLogicA.contract.WatchLogs(opts, "PayeesUpdated") + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(AutomationRegistryLogicAPayeesUpdated) + if err := _AutomationRegistryLogicA.contract.UnpackLog(event, "PayeesUpdated", 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 (_AutomationRegistryLogicA *AutomationRegistryLogicAFilterer) ParsePayeesUpdated(log types.Log) (*AutomationRegistryLogicAPayeesUpdated, error) { + event := new(AutomationRegistryLogicAPayeesUpdated) + if err := _AutomationRegistryLogicA.contract.UnpackLog(event, "PayeesUpdated", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type AutomationRegistryLogicAPayeeshipTransferRequestedIterator struct { + Event *AutomationRegistryLogicAPayeeshipTransferRequested + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *AutomationRegistryLogicAPayeeshipTransferRequestedIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(AutomationRegistryLogicAPayeeshipTransferRequested) + 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(AutomationRegistryLogicAPayeeshipTransferRequested) + 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 *AutomationRegistryLogicAPayeeshipTransferRequestedIterator) Error() error { + return it.fail +} + +func (it *AutomationRegistryLogicAPayeeshipTransferRequestedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type AutomationRegistryLogicAPayeeshipTransferRequested struct { + Transmitter common.Address + From common.Address + To common.Address + Raw types.Log +} + +func (_AutomationRegistryLogicA *AutomationRegistryLogicAFilterer) FilterPayeeshipTransferRequested(opts *bind.FilterOpts, transmitter []common.Address, from []common.Address, to []common.Address) (*AutomationRegistryLogicAPayeeshipTransferRequestedIterator, error) { + + var transmitterRule []interface{} + for _, transmitterItem := range transmitter { + transmitterRule = append(transmitterRule, transmitterItem) + } + 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 := _AutomationRegistryLogicA.contract.FilterLogs(opts, "PayeeshipTransferRequested", transmitterRule, fromRule, toRule) + if err != nil { + return nil, err + } + return &AutomationRegistryLogicAPayeeshipTransferRequestedIterator{contract: _AutomationRegistryLogicA.contract, event: "PayeeshipTransferRequested", logs: logs, sub: sub}, nil +} + +func (_AutomationRegistryLogicA *AutomationRegistryLogicAFilterer) WatchPayeeshipTransferRequested(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicAPayeeshipTransferRequested, transmitter []common.Address, from []common.Address, to []common.Address) (event.Subscription, error) { + + var transmitterRule []interface{} + for _, transmitterItem := range transmitter { + transmitterRule = append(transmitterRule, transmitterItem) + } + 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 := _AutomationRegistryLogicA.contract.WatchLogs(opts, "PayeeshipTransferRequested", transmitterRule, 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(AutomationRegistryLogicAPayeeshipTransferRequested) + if err := _AutomationRegistryLogicA.contract.UnpackLog(event, "PayeeshipTransferRequested", 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 (_AutomationRegistryLogicA *AutomationRegistryLogicAFilterer) ParsePayeeshipTransferRequested(log types.Log) (*AutomationRegistryLogicAPayeeshipTransferRequested, error) { + event := new(AutomationRegistryLogicAPayeeshipTransferRequested) + if err := _AutomationRegistryLogicA.contract.UnpackLog(event, "PayeeshipTransferRequested", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type AutomationRegistryLogicAPayeeshipTransferredIterator struct { + Event *AutomationRegistryLogicAPayeeshipTransferred + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *AutomationRegistryLogicAPayeeshipTransferredIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(AutomationRegistryLogicAPayeeshipTransferred) + 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(AutomationRegistryLogicAPayeeshipTransferred) + 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 *AutomationRegistryLogicAPayeeshipTransferredIterator) Error() error { + return it.fail +} + +func (it *AutomationRegistryLogicAPayeeshipTransferredIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type AutomationRegistryLogicAPayeeshipTransferred struct { + Transmitter common.Address + From common.Address + To common.Address + Raw types.Log +} + +func (_AutomationRegistryLogicA *AutomationRegistryLogicAFilterer) FilterPayeeshipTransferred(opts *bind.FilterOpts, transmitter []common.Address, from []common.Address, to []common.Address) (*AutomationRegistryLogicAPayeeshipTransferredIterator, error) { + + var transmitterRule []interface{} + for _, transmitterItem := range transmitter { + transmitterRule = append(transmitterRule, transmitterItem) + } + 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 := _AutomationRegistryLogicA.contract.FilterLogs(opts, "PayeeshipTransferred", transmitterRule, fromRule, toRule) + if err != nil { + return nil, err + } + return &AutomationRegistryLogicAPayeeshipTransferredIterator{contract: _AutomationRegistryLogicA.contract, event: "PayeeshipTransferred", logs: logs, sub: sub}, nil +} + +func (_AutomationRegistryLogicA *AutomationRegistryLogicAFilterer) WatchPayeeshipTransferred(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicAPayeeshipTransferred, transmitter []common.Address, from []common.Address, to []common.Address) (event.Subscription, error) { + + var transmitterRule []interface{} + for _, transmitterItem := range transmitter { + transmitterRule = append(transmitterRule, transmitterItem) + } + 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 := _AutomationRegistryLogicA.contract.WatchLogs(opts, "PayeeshipTransferred", transmitterRule, 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(AutomationRegistryLogicAPayeeshipTransferred) + if err := _AutomationRegistryLogicA.contract.UnpackLog(event, "PayeeshipTransferred", 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 (_AutomationRegistryLogicA *AutomationRegistryLogicAFilterer) ParsePayeeshipTransferred(log types.Log) (*AutomationRegistryLogicAPayeeshipTransferred, error) { + event := new(AutomationRegistryLogicAPayeeshipTransferred) + if err := _AutomationRegistryLogicA.contract.UnpackLog(event, "PayeeshipTransferred", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type AutomationRegistryLogicAPaymentWithdrawnIterator struct { + Event *AutomationRegistryLogicAPaymentWithdrawn + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *AutomationRegistryLogicAPaymentWithdrawnIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(AutomationRegistryLogicAPaymentWithdrawn) + 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(AutomationRegistryLogicAPaymentWithdrawn) + 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 *AutomationRegistryLogicAPaymentWithdrawnIterator) Error() error { + return it.fail +} + +func (it *AutomationRegistryLogicAPaymentWithdrawnIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type AutomationRegistryLogicAPaymentWithdrawn struct { + Transmitter common.Address + Amount *big.Int + To common.Address + Payee common.Address + Raw types.Log +} + +func (_AutomationRegistryLogicA *AutomationRegistryLogicAFilterer) FilterPaymentWithdrawn(opts *bind.FilterOpts, transmitter []common.Address, amount []*big.Int, to []common.Address) (*AutomationRegistryLogicAPaymentWithdrawnIterator, error) { + + var transmitterRule []interface{} + for _, transmitterItem := range transmitter { + transmitterRule = append(transmitterRule, transmitterItem) + } + var amountRule []interface{} + for _, amountItem := range amount { + amountRule = append(amountRule, amountItem) + } + var toRule []interface{} + for _, toItem := range to { + toRule = append(toRule, toItem) + } + + logs, sub, err := _AutomationRegistryLogicA.contract.FilterLogs(opts, "PaymentWithdrawn", transmitterRule, amountRule, toRule) + if err != nil { + return nil, err + } + return &AutomationRegistryLogicAPaymentWithdrawnIterator{contract: _AutomationRegistryLogicA.contract, event: "PaymentWithdrawn", logs: logs, sub: sub}, nil +} + +func (_AutomationRegistryLogicA *AutomationRegistryLogicAFilterer) WatchPaymentWithdrawn(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicAPaymentWithdrawn, transmitter []common.Address, amount []*big.Int, to []common.Address) (event.Subscription, error) { + + var transmitterRule []interface{} + for _, transmitterItem := range transmitter { + transmitterRule = append(transmitterRule, transmitterItem) + } + var amountRule []interface{} + for _, amountItem := range amount { + amountRule = append(amountRule, amountItem) + } + var toRule []interface{} + for _, toItem := range to { + toRule = append(toRule, toItem) + } + + logs, sub, err := _AutomationRegistryLogicA.contract.WatchLogs(opts, "PaymentWithdrawn", transmitterRule, amountRule, 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(AutomationRegistryLogicAPaymentWithdrawn) + if err := _AutomationRegistryLogicA.contract.UnpackLog(event, "PaymentWithdrawn", 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 (_AutomationRegistryLogicA *AutomationRegistryLogicAFilterer) ParsePaymentWithdrawn(log types.Log) (*AutomationRegistryLogicAPaymentWithdrawn, error) { + event := new(AutomationRegistryLogicAPaymentWithdrawn) + if err := _AutomationRegistryLogicA.contract.UnpackLog(event, "PaymentWithdrawn", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type AutomationRegistryLogicAReorgedUpkeepReportIterator struct { + Event *AutomationRegistryLogicAReorgedUpkeepReport + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *AutomationRegistryLogicAReorgedUpkeepReportIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(AutomationRegistryLogicAReorgedUpkeepReport) + 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(AutomationRegistryLogicAReorgedUpkeepReport) + 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 *AutomationRegistryLogicAReorgedUpkeepReportIterator) Error() error { + return it.fail +} + +func (it *AutomationRegistryLogicAReorgedUpkeepReportIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type AutomationRegistryLogicAReorgedUpkeepReport struct { + Id *big.Int + Trigger []byte + Raw types.Log +} + +func (_AutomationRegistryLogicA *AutomationRegistryLogicAFilterer) FilterReorgedUpkeepReport(opts *bind.FilterOpts, id []*big.Int) (*AutomationRegistryLogicAReorgedUpkeepReportIterator, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + + logs, sub, err := _AutomationRegistryLogicA.contract.FilterLogs(opts, "ReorgedUpkeepReport", idRule) + if err != nil { + return nil, err + } + return &AutomationRegistryLogicAReorgedUpkeepReportIterator{contract: _AutomationRegistryLogicA.contract, event: "ReorgedUpkeepReport", logs: logs, sub: sub}, nil +} + +func (_AutomationRegistryLogicA *AutomationRegistryLogicAFilterer) WatchReorgedUpkeepReport(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicAReorgedUpkeepReport, id []*big.Int) (event.Subscription, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + + logs, sub, err := _AutomationRegistryLogicA.contract.WatchLogs(opts, "ReorgedUpkeepReport", idRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(AutomationRegistryLogicAReorgedUpkeepReport) + if err := _AutomationRegistryLogicA.contract.UnpackLog(event, "ReorgedUpkeepReport", 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 (_AutomationRegistryLogicA *AutomationRegistryLogicAFilterer) ParseReorgedUpkeepReport(log types.Log) (*AutomationRegistryLogicAReorgedUpkeepReport, error) { + event := new(AutomationRegistryLogicAReorgedUpkeepReport) + if err := _AutomationRegistryLogicA.contract.UnpackLog(event, "ReorgedUpkeepReport", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type AutomationRegistryLogicAStaleUpkeepReportIterator struct { + Event *AutomationRegistryLogicAStaleUpkeepReport + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *AutomationRegistryLogicAStaleUpkeepReportIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(AutomationRegistryLogicAStaleUpkeepReport) + 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(AutomationRegistryLogicAStaleUpkeepReport) + 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 *AutomationRegistryLogicAStaleUpkeepReportIterator) Error() error { + return it.fail +} + +func (it *AutomationRegistryLogicAStaleUpkeepReportIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type AutomationRegistryLogicAStaleUpkeepReport struct { + Id *big.Int + Trigger []byte + Raw types.Log +} + +func (_AutomationRegistryLogicA *AutomationRegistryLogicAFilterer) FilterStaleUpkeepReport(opts *bind.FilterOpts, id []*big.Int) (*AutomationRegistryLogicAStaleUpkeepReportIterator, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + + logs, sub, err := _AutomationRegistryLogicA.contract.FilterLogs(opts, "StaleUpkeepReport", idRule) + if err != nil { + return nil, err + } + return &AutomationRegistryLogicAStaleUpkeepReportIterator{contract: _AutomationRegistryLogicA.contract, event: "StaleUpkeepReport", logs: logs, sub: sub}, nil +} + +func (_AutomationRegistryLogicA *AutomationRegistryLogicAFilterer) WatchStaleUpkeepReport(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicAStaleUpkeepReport, id []*big.Int) (event.Subscription, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + + logs, sub, err := _AutomationRegistryLogicA.contract.WatchLogs(opts, "StaleUpkeepReport", idRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(AutomationRegistryLogicAStaleUpkeepReport) + if err := _AutomationRegistryLogicA.contract.UnpackLog(event, "StaleUpkeepReport", 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 (_AutomationRegistryLogicA *AutomationRegistryLogicAFilterer) ParseStaleUpkeepReport(log types.Log) (*AutomationRegistryLogicAStaleUpkeepReport, error) { + event := new(AutomationRegistryLogicAStaleUpkeepReport) + if err := _AutomationRegistryLogicA.contract.UnpackLog(event, "StaleUpkeepReport", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type AutomationRegistryLogicAUnpausedIterator struct { + Event *AutomationRegistryLogicAUnpaused + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *AutomationRegistryLogicAUnpausedIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(AutomationRegistryLogicAUnpaused) + 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(AutomationRegistryLogicAUnpaused) + 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 *AutomationRegistryLogicAUnpausedIterator) Error() error { + return it.fail +} + +func (it *AutomationRegistryLogicAUnpausedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type AutomationRegistryLogicAUnpaused struct { + Account common.Address + Raw types.Log +} + +func (_AutomationRegistryLogicA *AutomationRegistryLogicAFilterer) FilterUnpaused(opts *bind.FilterOpts) (*AutomationRegistryLogicAUnpausedIterator, error) { + + logs, sub, err := _AutomationRegistryLogicA.contract.FilterLogs(opts, "Unpaused") + if err != nil { + return nil, err + } + return &AutomationRegistryLogicAUnpausedIterator{contract: _AutomationRegistryLogicA.contract, event: "Unpaused", logs: logs, sub: sub}, nil +} + +func (_AutomationRegistryLogicA *AutomationRegistryLogicAFilterer) WatchUnpaused(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicAUnpaused) (event.Subscription, error) { + + logs, sub, err := _AutomationRegistryLogicA.contract.WatchLogs(opts, "Unpaused") + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(AutomationRegistryLogicAUnpaused) + if err := _AutomationRegistryLogicA.contract.UnpackLog(event, "Unpaused", 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 (_AutomationRegistryLogicA *AutomationRegistryLogicAFilterer) ParseUnpaused(log types.Log) (*AutomationRegistryLogicAUnpaused, error) { + event := new(AutomationRegistryLogicAUnpaused) + if err := _AutomationRegistryLogicA.contract.UnpackLog(event, "Unpaused", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type AutomationRegistryLogicAUpkeepAdminTransferRequestedIterator struct { + Event *AutomationRegistryLogicAUpkeepAdminTransferRequested + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *AutomationRegistryLogicAUpkeepAdminTransferRequestedIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(AutomationRegistryLogicAUpkeepAdminTransferRequested) + 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(AutomationRegistryLogicAUpkeepAdminTransferRequested) + 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 *AutomationRegistryLogicAUpkeepAdminTransferRequestedIterator) Error() error { + return it.fail +} + +func (it *AutomationRegistryLogicAUpkeepAdminTransferRequestedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type AutomationRegistryLogicAUpkeepAdminTransferRequested struct { + Id *big.Int + From common.Address + To common.Address + Raw types.Log +} + +func (_AutomationRegistryLogicA *AutomationRegistryLogicAFilterer) FilterUpkeepAdminTransferRequested(opts *bind.FilterOpts, id []*big.Int, from []common.Address, to []common.Address) (*AutomationRegistryLogicAUpkeepAdminTransferRequestedIterator, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + 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 := _AutomationRegistryLogicA.contract.FilterLogs(opts, "UpkeepAdminTransferRequested", idRule, fromRule, toRule) + if err != nil { + return nil, err + } + return &AutomationRegistryLogicAUpkeepAdminTransferRequestedIterator{contract: _AutomationRegistryLogicA.contract, event: "UpkeepAdminTransferRequested", logs: logs, sub: sub}, nil +} + +func (_AutomationRegistryLogicA *AutomationRegistryLogicAFilterer) WatchUpkeepAdminTransferRequested(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicAUpkeepAdminTransferRequested, id []*big.Int, from []common.Address, to []common.Address) (event.Subscription, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + 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 := _AutomationRegistryLogicA.contract.WatchLogs(opts, "UpkeepAdminTransferRequested", idRule, 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(AutomationRegistryLogicAUpkeepAdminTransferRequested) + if err := _AutomationRegistryLogicA.contract.UnpackLog(event, "UpkeepAdminTransferRequested", 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 (_AutomationRegistryLogicA *AutomationRegistryLogicAFilterer) ParseUpkeepAdminTransferRequested(log types.Log) (*AutomationRegistryLogicAUpkeepAdminTransferRequested, error) { + event := new(AutomationRegistryLogicAUpkeepAdminTransferRequested) + if err := _AutomationRegistryLogicA.contract.UnpackLog(event, "UpkeepAdminTransferRequested", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type AutomationRegistryLogicAUpkeepAdminTransferredIterator struct { + Event *AutomationRegistryLogicAUpkeepAdminTransferred + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *AutomationRegistryLogicAUpkeepAdminTransferredIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(AutomationRegistryLogicAUpkeepAdminTransferred) + 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(AutomationRegistryLogicAUpkeepAdminTransferred) + 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 *AutomationRegistryLogicAUpkeepAdminTransferredIterator) Error() error { + return it.fail +} + +func (it *AutomationRegistryLogicAUpkeepAdminTransferredIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type AutomationRegistryLogicAUpkeepAdminTransferred struct { + Id *big.Int + From common.Address + To common.Address + Raw types.Log +} + +func (_AutomationRegistryLogicA *AutomationRegistryLogicAFilterer) FilterUpkeepAdminTransferred(opts *bind.FilterOpts, id []*big.Int, from []common.Address, to []common.Address) (*AutomationRegistryLogicAUpkeepAdminTransferredIterator, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + 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 := _AutomationRegistryLogicA.contract.FilterLogs(opts, "UpkeepAdminTransferred", idRule, fromRule, toRule) + if err != nil { + return nil, err + } + return &AutomationRegistryLogicAUpkeepAdminTransferredIterator{contract: _AutomationRegistryLogicA.contract, event: "UpkeepAdminTransferred", logs: logs, sub: sub}, nil +} + +func (_AutomationRegistryLogicA *AutomationRegistryLogicAFilterer) WatchUpkeepAdminTransferred(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicAUpkeepAdminTransferred, id []*big.Int, from []common.Address, to []common.Address) (event.Subscription, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + 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 := _AutomationRegistryLogicA.contract.WatchLogs(opts, "UpkeepAdminTransferred", idRule, 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(AutomationRegistryLogicAUpkeepAdminTransferred) + if err := _AutomationRegistryLogicA.contract.UnpackLog(event, "UpkeepAdminTransferred", 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 (_AutomationRegistryLogicA *AutomationRegistryLogicAFilterer) ParseUpkeepAdminTransferred(log types.Log) (*AutomationRegistryLogicAUpkeepAdminTransferred, error) { + event := new(AutomationRegistryLogicAUpkeepAdminTransferred) + if err := _AutomationRegistryLogicA.contract.UnpackLog(event, "UpkeepAdminTransferred", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type AutomationRegistryLogicAUpkeepCanceledIterator struct { + Event *AutomationRegistryLogicAUpkeepCanceled + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *AutomationRegistryLogicAUpkeepCanceledIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(AutomationRegistryLogicAUpkeepCanceled) + 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(AutomationRegistryLogicAUpkeepCanceled) + 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 *AutomationRegistryLogicAUpkeepCanceledIterator) Error() error { + return it.fail +} + +func (it *AutomationRegistryLogicAUpkeepCanceledIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type AutomationRegistryLogicAUpkeepCanceled struct { + Id *big.Int + AtBlockHeight uint64 + Raw types.Log +} + +func (_AutomationRegistryLogicA *AutomationRegistryLogicAFilterer) FilterUpkeepCanceled(opts *bind.FilterOpts, id []*big.Int, atBlockHeight []uint64) (*AutomationRegistryLogicAUpkeepCanceledIterator, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + var atBlockHeightRule []interface{} + for _, atBlockHeightItem := range atBlockHeight { + atBlockHeightRule = append(atBlockHeightRule, atBlockHeightItem) + } + + logs, sub, err := _AutomationRegistryLogicA.contract.FilterLogs(opts, "UpkeepCanceled", idRule, atBlockHeightRule) + if err != nil { + return nil, err + } + return &AutomationRegistryLogicAUpkeepCanceledIterator{contract: _AutomationRegistryLogicA.contract, event: "UpkeepCanceled", logs: logs, sub: sub}, nil +} + +func (_AutomationRegistryLogicA *AutomationRegistryLogicAFilterer) WatchUpkeepCanceled(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicAUpkeepCanceled, id []*big.Int, atBlockHeight []uint64) (event.Subscription, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + var atBlockHeightRule []interface{} + for _, atBlockHeightItem := range atBlockHeight { + atBlockHeightRule = append(atBlockHeightRule, atBlockHeightItem) + } + + logs, sub, err := _AutomationRegistryLogicA.contract.WatchLogs(opts, "UpkeepCanceled", idRule, atBlockHeightRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(AutomationRegistryLogicAUpkeepCanceled) + if err := _AutomationRegistryLogicA.contract.UnpackLog(event, "UpkeepCanceled", 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 (_AutomationRegistryLogicA *AutomationRegistryLogicAFilterer) ParseUpkeepCanceled(log types.Log) (*AutomationRegistryLogicAUpkeepCanceled, error) { + event := new(AutomationRegistryLogicAUpkeepCanceled) + if err := _AutomationRegistryLogicA.contract.UnpackLog(event, "UpkeepCanceled", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type AutomationRegistryLogicAUpkeepCheckDataSetIterator struct { + Event *AutomationRegistryLogicAUpkeepCheckDataSet + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *AutomationRegistryLogicAUpkeepCheckDataSetIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(AutomationRegistryLogicAUpkeepCheckDataSet) + 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(AutomationRegistryLogicAUpkeepCheckDataSet) + 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 *AutomationRegistryLogicAUpkeepCheckDataSetIterator) Error() error { + return it.fail +} + +func (it *AutomationRegistryLogicAUpkeepCheckDataSetIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type AutomationRegistryLogicAUpkeepCheckDataSet struct { + Id *big.Int + NewCheckData []byte + Raw types.Log +} + +func (_AutomationRegistryLogicA *AutomationRegistryLogicAFilterer) FilterUpkeepCheckDataSet(opts *bind.FilterOpts, id []*big.Int) (*AutomationRegistryLogicAUpkeepCheckDataSetIterator, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + + logs, sub, err := _AutomationRegistryLogicA.contract.FilterLogs(opts, "UpkeepCheckDataSet", idRule) + if err != nil { + return nil, err + } + return &AutomationRegistryLogicAUpkeepCheckDataSetIterator{contract: _AutomationRegistryLogicA.contract, event: "UpkeepCheckDataSet", logs: logs, sub: sub}, nil +} + +func (_AutomationRegistryLogicA *AutomationRegistryLogicAFilterer) WatchUpkeepCheckDataSet(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicAUpkeepCheckDataSet, id []*big.Int) (event.Subscription, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + + logs, sub, err := _AutomationRegistryLogicA.contract.WatchLogs(opts, "UpkeepCheckDataSet", idRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(AutomationRegistryLogicAUpkeepCheckDataSet) + if err := _AutomationRegistryLogicA.contract.UnpackLog(event, "UpkeepCheckDataSet", 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 (_AutomationRegistryLogicA *AutomationRegistryLogicAFilterer) ParseUpkeepCheckDataSet(log types.Log) (*AutomationRegistryLogicAUpkeepCheckDataSet, error) { + event := new(AutomationRegistryLogicAUpkeepCheckDataSet) + if err := _AutomationRegistryLogicA.contract.UnpackLog(event, "UpkeepCheckDataSet", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type AutomationRegistryLogicAUpkeepGasLimitSetIterator struct { + Event *AutomationRegistryLogicAUpkeepGasLimitSet + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *AutomationRegistryLogicAUpkeepGasLimitSetIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(AutomationRegistryLogicAUpkeepGasLimitSet) + 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(AutomationRegistryLogicAUpkeepGasLimitSet) + 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 *AutomationRegistryLogicAUpkeepGasLimitSetIterator) Error() error { + return it.fail +} + +func (it *AutomationRegistryLogicAUpkeepGasLimitSetIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type AutomationRegistryLogicAUpkeepGasLimitSet struct { + Id *big.Int + GasLimit *big.Int + Raw types.Log +} + +func (_AutomationRegistryLogicA *AutomationRegistryLogicAFilterer) FilterUpkeepGasLimitSet(opts *bind.FilterOpts, id []*big.Int) (*AutomationRegistryLogicAUpkeepGasLimitSetIterator, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + + logs, sub, err := _AutomationRegistryLogicA.contract.FilterLogs(opts, "UpkeepGasLimitSet", idRule) + if err != nil { + return nil, err + } + return &AutomationRegistryLogicAUpkeepGasLimitSetIterator{contract: _AutomationRegistryLogicA.contract, event: "UpkeepGasLimitSet", logs: logs, sub: sub}, nil +} + +func (_AutomationRegistryLogicA *AutomationRegistryLogicAFilterer) WatchUpkeepGasLimitSet(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicAUpkeepGasLimitSet, id []*big.Int) (event.Subscription, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + + logs, sub, err := _AutomationRegistryLogicA.contract.WatchLogs(opts, "UpkeepGasLimitSet", idRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(AutomationRegistryLogicAUpkeepGasLimitSet) + if err := _AutomationRegistryLogicA.contract.UnpackLog(event, "UpkeepGasLimitSet", 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 (_AutomationRegistryLogicA *AutomationRegistryLogicAFilterer) ParseUpkeepGasLimitSet(log types.Log) (*AutomationRegistryLogicAUpkeepGasLimitSet, error) { + event := new(AutomationRegistryLogicAUpkeepGasLimitSet) + if err := _AutomationRegistryLogicA.contract.UnpackLog(event, "UpkeepGasLimitSet", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type AutomationRegistryLogicAUpkeepMigratedIterator struct { + Event *AutomationRegistryLogicAUpkeepMigrated + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *AutomationRegistryLogicAUpkeepMigratedIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(AutomationRegistryLogicAUpkeepMigrated) + 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(AutomationRegistryLogicAUpkeepMigrated) + 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 *AutomationRegistryLogicAUpkeepMigratedIterator) Error() error { + return it.fail +} + +func (it *AutomationRegistryLogicAUpkeepMigratedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type AutomationRegistryLogicAUpkeepMigrated struct { + Id *big.Int + RemainingBalance *big.Int + Destination common.Address + Raw types.Log +} + +func (_AutomationRegistryLogicA *AutomationRegistryLogicAFilterer) FilterUpkeepMigrated(opts *bind.FilterOpts, id []*big.Int) (*AutomationRegistryLogicAUpkeepMigratedIterator, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + + logs, sub, err := _AutomationRegistryLogicA.contract.FilterLogs(opts, "UpkeepMigrated", idRule) + if err != nil { + return nil, err + } + return &AutomationRegistryLogicAUpkeepMigratedIterator{contract: _AutomationRegistryLogicA.contract, event: "UpkeepMigrated", logs: logs, sub: sub}, nil +} + +func (_AutomationRegistryLogicA *AutomationRegistryLogicAFilterer) WatchUpkeepMigrated(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicAUpkeepMigrated, id []*big.Int) (event.Subscription, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + + logs, sub, err := _AutomationRegistryLogicA.contract.WatchLogs(opts, "UpkeepMigrated", idRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(AutomationRegistryLogicAUpkeepMigrated) + if err := _AutomationRegistryLogicA.contract.UnpackLog(event, "UpkeepMigrated", 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 (_AutomationRegistryLogicA *AutomationRegistryLogicAFilterer) ParseUpkeepMigrated(log types.Log) (*AutomationRegistryLogicAUpkeepMigrated, error) { + event := new(AutomationRegistryLogicAUpkeepMigrated) + if err := _AutomationRegistryLogicA.contract.UnpackLog(event, "UpkeepMigrated", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type AutomationRegistryLogicAUpkeepOffchainConfigSetIterator struct { + Event *AutomationRegistryLogicAUpkeepOffchainConfigSet + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *AutomationRegistryLogicAUpkeepOffchainConfigSetIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(AutomationRegistryLogicAUpkeepOffchainConfigSet) + 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(AutomationRegistryLogicAUpkeepOffchainConfigSet) + 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 *AutomationRegistryLogicAUpkeepOffchainConfigSetIterator) Error() error { + return it.fail +} + +func (it *AutomationRegistryLogicAUpkeepOffchainConfigSetIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type AutomationRegistryLogicAUpkeepOffchainConfigSet struct { + Id *big.Int + OffchainConfig []byte + Raw types.Log +} + +func (_AutomationRegistryLogicA *AutomationRegistryLogicAFilterer) FilterUpkeepOffchainConfigSet(opts *bind.FilterOpts, id []*big.Int) (*AutomationRegistryLogicAUpkeepOffchainConfigSetIterator, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + + logs, sub, err := _AutomationRegistryLogicA.contract.FilterLogs(opts, "UpkeepOffchainConfigSet", idRule) + if err != nil { + return nil, err + } + return &AutomationRegistryLogicAUpkeepOffchainConfigSetIterator{contract: _AutomationRegistryLogicA.contract, event: "UpkeepOffchainConfigSet", logs: logs, sub: sub}, nil +} + +func (_AutomationRegistryLogicA *AutomationRegistryLogicAFilterer) WatchUpkeepOffchainConfigSet(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicAUpkeepOffchainConfigSet, id []*big.Int) (event.Subscription, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + + logs, sub, err := _AutomationRegistryLogicA.contract.WatchLogs(opts, "UpkeepOffchainConfigSet", idRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(AutomationRegistryLogicAUpkeepOffchainConfigSet) + if err := _AutomationRegistryLogicA.contract.UnpackLog(event, "UpkeepOffchainConfigSet", 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 (_AutomationRegistryLogicA *AutomationRegistryLogicAFilterer) ParseUpkeepOffchainConfigSet(log types.Log) (*AutomationRegistryLogicAUpkeepOffchainConfigSet, error) { + event := new(AutomationRegistryLogicAUpkeepOffchainConfigSet) + if err := _AutomationRegistryLogicA.contract.UnpackLog(event, "UpkeepOffchainConfigSet", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type AutomationRegistryLogicAUpkeepPausedIterator struct { + Event *AutomationRegistryLogicAUpkeepPaused + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *AutomationRegistryLogicAUpkeepPausedIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(AutomationRegistryLogicAUpkeepPaused) + 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(AutomationRegistryLogicAUpkeepPaused) + 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 *AutomationRegistryLogicAUpkeepPausedIterator) Error() error { + return it.fail +} + +func (it *AutomationRegistryLogicAUpkeepPausedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type AutomationRegistryLogicAUpkeepPaused struct { + Id *big.Int + Raw types.Log +} + +func (_AutomationRegistryLogicA *AutomationRegistryLogicAFilterer) FilterUpkeepPaused(opts *bind.FilterOpts, id []*big.Int) (*AutomationRegistryLogicAUpkeepPausedIterator, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + + logs, sub, err := _AutomationRegistryLogicA.contract.FilterLogs(opts, "UpkeepPaused", idRule) + if err != nil { + return nil, err + } + return &AutomationRegistryLogicAUpkeepPausedIterator{contract: _AutomationRegistryLogicA.contract, event: "UpkeepPaused", logs: logs, sub: sub}, nil +} + +func (_AutomationRegistryLogicA *AutomationRegistryLogicAFilterer) WatchUpkeepPaused(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicAUpkeepPaused, id []*big.Int) (event.Subscription, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + + logs, sub, err := _AutomationRegistryLogicA.contract.WatchLogs(opts, "UpkeepPaused", idRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(AutomationRegistryLogicAUpkeepPaused) + if err := _AutomationRegistryLogicA.contract.UnpackLog(event, "UpkeepPaused", 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 (_AutomationRegistryLogicA *AutomationRegistryLogicAFilterer) ParseUpkeepPaused(log types.Log) (*AutomationRegistryLogicAUpkeepPaused, error) { + event := new(AutomationRegistryLogicAUpkeepPaused) + if err := _AutomationRegistryLogicA.contract.UnpackLog(event, "UpkeepPaused", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type AutomationRegistryLogicAUpkeepPerformedIterator struct { + Event *AutomationRegistryLogicAUpkeepPerformed + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *AutomationRegistryLogicAUpkeepPerformedIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(AutomationRegistryLogicAUpkeepPerformed) + 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(AutomationRegistryLogicAUpkeepPerformed) + 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 *AutomationRegistryLogicAUpkeepPerformedIterator) Error() error { + return it.fail +} + +func (it *AutomationRegistryLogicAUpkeepPerformedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type AutomationRegistryLogicAUpkeepPerformed struct { + Id *big.Int + Success bool + TotalPayment *big.Int + GasUsed *big.Int + GasOverhead *big.Int + Trigger []byte + Raw types.Log +} + +func (_AutomationRegistryLogicA *AutomationRegistryLogicAFilterer) FilterUpkeepPerformed(opts *bind.FilterOpts, id []*big.Int, success []bool) (*AutomationRegistryLogicAUpkeepPerformedIterator, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + var successRule []interface{} + for _, successItem := range success { + successRule = append(successRule, successItem) + } + + logs, sub, err := _AutomationRegistryLogicA.contract.FilterLogs(opts, "UpkeepPerformed", idRule, successRule) + if err != nil { + return nil, err + } + return &AutomationRegistryLogicAUpkeepPerformedIterator{contract: _AutomationRegistryLogicA.contract, event: "UpkeepPerformed", logs: logs, sub: sub}, nil +} + +func (_AutomationRegistryLogicA *AutomationRegistryLogicAFilterer) WatchUpkeepPerformed(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicAUpkeepPerformed, id []*big.Int, success []bool) (event.Subscription, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + var successRule []interface{} + for _, successItem := range success { + successRule = append(successRule, successItem) + } + + logs, sub, err := _AutomationRegistryLogicA.contract.WatchLogs(opts, "UpkeepPerformed", idRule, successRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(AutomationRegistryLogicAUpkeepPerformed) + if err := _AutomationRegistryLogicA.contract.UnpackLog(event, "UpkeepPerformed", 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 (_AutomationRegistryLogicA *AutomationRegistryLogicAFilterer) ParseUpkeepPerformed(log types.Log) (*AutomationRegistryLogicAUpkeepPerformed, error) { + event := new(AutomationRegistryLogicAUpkeepPerformed) + if err := _AutomationRegistryLogicA.contract.UnpackLog(event, "UpkeepPerformed", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type AutomationRegistryLogicAUpkeepPrivilegeConfigSetIterator struct { + Event *AutomationRegistryLogicAUpkeepPrivilegeConfigSet + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *AutomationRegistryLogicAUpkeepPrivilegeConfigSetIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(AutomationRegistryLogicAUpkeepPrivilegeConfigSet) + 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(AutomationRegistryLogicAUpkeepPrivilegeConfigSet) + 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 *AutomationRegistryLogicAUpkeepPrivilegeConfigSetIterator) Error() error { + return it.fail +} + +func (it *AutomationRegistryLogicAUpkeepPrivilegeConfigSetIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type AutomationRegistryLogicAUpkeepPrivilegeConfigSet struct { + Id *big.Int + PrivilegeConfig []byte + Raw types.Log +} + +func (_AutomationRegistryLogicA *AutomationRegistryLogicAFilterer) FilterUpkeepPrivilegeConfigSet(opts *bind.FilterOpts, id []*big.Int) (*AutomationRegistryLogicAUpkeepPrivilegeConfigSetIterator, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + + logs, sub, err := _AutomationRegistryLogicA.contract.FilterLogs(opts, "UpkeepPrivilegeConfigSet", idRule) + if err != nil { + return nil, err + } + return &AutomationRegistryLogicAUpkeepPrivilegeConfigSetIterator{contract: _AutomationRegistryLogicA.contract, event: "UpkeepPrivilegeConfigSet", logs: logs, sub: sub}, nil +} + +func (_AutomationRegistryLogicA *AutomationRegistryLogicAFilterer) WatchUpkeepPrivilegeConfigSet(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicAUpkeepPrivilegeConfigSet, id []*big.Int) (event.Subscription, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + + logs, sub, err := _AutomationRegistryLogicA.contract.WatchLogs(opts, "UpkeepPrivilegeConfigSet", idRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(AutomationRegistryLogicAUpkeepPrivilegeConfigSet) + if err := _AutomationRegistryLogicA.contract.UnpackLog(event, "UpkeepPrivilegeConfigSet", 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 (_AutomationRegistryLogicA *AutomationRegistryLogicAFilterer) ParseUpkeepPrivilegeConfigSet(log types.Log) (*AutomationRegistryLogicAUpkeepPrivilegeConfigSet, error) { + event := new(AutomationRegistryLogicAUpkeepPrivilegeConfigSet) + if err := _AutomationRegistryLogicA.contract.UnpackLog(event, "UpkeepPrivilegeConfigSet", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type AutomationRegistryLogicAUpkeepReceivedIterator struct { + Event *AutomationRegistryLogicAUpkeepReceived + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *AutomationRegistryLogicAUpkeepReceivedIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(AutomationRegistryLogicAUpkeepReceived) + 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(AutomationRegistryLogicAUpkeepReceived) + 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 *AutomationRegistryLogicAUpkeepReceivedIterator) Error() error { + return it.fail +} + +func (it *AutomationRegistryLogicAUpkeepReceivedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type AutomationRegistryLogicAUpkeepReceived struct { + Id *big.Int + StartingBalance *big.Int + ImportedFrom common.Address + Raw types.Log +} + +func (_AutomationRegistryLogicA *AutomationRegistryLogicAFilterer) FilterUpkeepReceived(opts *bind.FilterOpts, id []*big.Int) (*AutomationRegistryLogicAUpkeepReceivedIterator, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + + logs, sub, err := _AutomationRegistryLogicA.contract.FilterLogs(opts, "UpkeepReceived", idRule) + if err != nil { + return nil, err + } + return &AutomationRegistryLogicAUpkeepReceivedIterator{contract: _AutomationRegistryLogicA.contract, event: "UpkeepReceived", logs: logs, sub: sub}, nil +} + +func (_AutomationRegistryLogicA *AutomationRegistryLogicAFilterer) WatchUpkeepReceived(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicAUpkeepReceived, id []*big.Int) (event.Subscription, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + + logs, sub, err := _AutomationRegistryLogicA.contract.WatchLogs(opts, "UpkeepReceived", idRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(AutomationRegistryLogicAUpkeepReceived) + if err := _AutomationRegistryLogicA.contract.UnpackLog(event, "UpkeepReceived", 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 (_AutomationRegistryLogicA *AutomationRegistryLogicAFilterer) ParseUpkeepReceived(log types.Log) (*AutomationRegistryLogicAUpkeepReceived, error) { + event := new(AutomationRegistryLogicAUpkeepReceived) + if err := _AutomationRegistryLogicA.contract.UnpackLog(event, "UpkeepReceived", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type AutomationRegistryLogicAUpkeepRegisteredIterator struct { + Event *AutomationRegistryLogicAUpkeepRegistered + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *AutomationRegistryLogicAUpkeepRegisteredIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(AutomationRegistryLogicAUpkeepRegistered) + 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(AutomationRegistryLogicAUpkeepRegistered) + 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 *AutomationRegistryLogicAUpkeepRegisteredIterator) Error() error { + return it.fail +} + +func (it *AutomationRegistryLogicAUpkeepRegisteredIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type AutomationRegistryLogicAUpkeepRegistered struct { + Id *big.Int + PerformGas uint32 + Admin common.Address + Raw types.Log +} + +func (_AutomationRegistryLogicA *AutomationRegistryLogicAFilterer) FilterUpkeepRegistered(opts *bind.FilterOpts, id []*big.Int) (*AutomationRegistryLogicAUpkeepRegisteredIterator, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + + logs, sub, err := _AutomationRegistryLogicA.contract.FilterLogs(opts, "UpkeepRegistered", idRule) + if err != nil { + return nil, err + } + return &AutomationRegistryLogicAUpkeepRegisteredIterator{contract: _AutomationRegistryLogicA.contract, event: "UpkeepRegistered", logs: logs, sub: sub}, nil +} + +func (_AutomationRegistryLogicA *AutomationRegistryLogicAFilterer) WatchUpkeepRegistered(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicAUpkeepRegistered, id []*big.Int) (event.Subscription, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + + logs, sub, err := _AutomationRegistryLogicA.contract.WatchLogs(opts, "UpkeepRegistered", idRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(AutomationRegistryLogicAUpkeepRegistered) + if err := _AutomationRegistryLogicA.contract.UnpackLog(event, "UpkeepRegistered", 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 (_AutomationRegistryLogicA *AutomationRegistryLogicAFilterer) ParseUpkeepRegistered(log types.Log) (*AutomationRegistryLogicAUpkeepRegistered, error) { + event := new(AutomationRegistryLogicAUpkeepRegistered) + if err := _AutomationRegistryLogicA.contract.UnpackLog(event, "UpkeepRegistered", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type AutomationRegistryLogicAUpkeepTriggerConfigSetIterator struct { + Event *AutomationRegistryLogicAUpkeepTriggerConfigSet + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *AutomationRegistryLogicAUpkeepTriggerConfigSetIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(AutomationRegistryLogicAUpkeepTriggerConfigSet) + 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(AutomationRegistryLogicAUpkeepTriggerConfigSet) + 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 *AutomationRegistryLogicAUpkeepTriggerConfigSetIterator) Error() error { + return it.fail +} + +func (it *AutomationRegistryLogicAUpkeepTriggerConfigSetIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type AutomationRegistryLogicAUpkeepTriggerConfigSet struct { + Id *big.Int + TriggerConfig []byte + Raw types.Log +} + +func (_AutomationRegistryLogicA *AutomationRegistryLogicAFilterer) FilterUpkeepTriggerConfigSet(opts *bind.FilterOpts, id []*big.Int) (*AutomationRegistryLogicAUpkeepTriggerConfigSetIterator, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + + logs, sub, err := _AutomationRegistryLogicA.contract.FilterLogs(opts, "UpkeepTriggerConfigSet", idRule) + if err != nil { + return nil, err + } + return &AutomationRegistryLogicAUpkeepTriggerConfigSetIterator{contract: _AutomationRegistryLogicA.contract, event: "UpkeepTriggerConfigSet", logs: logs, sub: sub}, nil +} + +func (_AutomationRegistryLogicA *AutomationRegistryLogicAFilterer) WatchUpkeepTriggerConfigSet(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicAUpkeepTriggerConfigSet, id []*big.Int) (event.Subscription, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + + logs, sub, err := _AutomationRegistryLogicA.contract.WatchLogs(opts, "UpkeepTriggerConfigSet", idRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(AutomationRegistryLogicAUpkeepTriggerConfigSet) + if err := _AutomationRegistryLogicA.contract.UnpackLog(event, "UpkeepTriggerConfigSet", 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 (_AutomationRegistryLogicA *AutomationRegistryLogicAFilterer) ParseUpkeepTriggerConfigSet(log types.Log) (*AutomationRegistryLogicAUpkeepTriggerConfigSet, error) { + event := new(AutomationRegistryLogicAUpkeepTriggerConfigSet) + if err := _AutomationRegistryLogicA.contract.UnpackLog(event, "UpkeepTriggerConfigSet", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type AutomationRegistryLogicAUpkeepUnpausedIterator struct { + Event *AutomationRegistryLogicAUpkeepUnpaused + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *AutomationRegistryLogicAUpkeepUnpausedIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(AutomationRegistryLogicAUpkeepUnpaused) + 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(AutomationRegistryLogicAUpkeepUnpaused) + 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 *AutomationRegistryLogicAUpkeepUnpausedIterator) Error() error { + return it.fail +} + +func (it *AutomationRegistryLogicAUpkeepUnpausedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type AutomationRegistryLogicAUpkeepUnpaused struct { + Id *big.Int + Raw types.Log +} + +func (_AutomationRegistryLogicA *AutomationRegistryLogicAFilterer) FilterUpkeepUnpaused(opts *bind.FilterOpts, id []*big.Int) (*AutomationRegistryLogicAUpkeepUnpausedIterator, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + + logs, sub, err := _AutomationRegistryLogicA.contract.FilterLogs(opts, "UpkeepUnpaused", idRule) + if err != nil { + return nil, err + } + return &AutomationRegistryLogicAUpkeepUnpausedIterator{contract: _AutomationRegistryLogicA.contract, event: "UpkeepUnpaused", logs: logs, sub: sub}, nil +} + +func (_AutomationRegistryLogicA *AutomationRegistryLogicAFilterer) WatchUpkeepUnpaused(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicAUpkeepUnpaused, id []*big.Int) (event.Subscription, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + + logs, sub, err := _AutomationRegistryLogicA.contract.WatchLogs(opts, "UpkeepUnpaused", idRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(AutomationRegistryLogicAUpkeepUnpaused) + if err := _AutomationRegistryLogicA.contract.UnpackLog(event, "UpkeepUnpaused", 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 (_AutomationRegistryLogicA *AutomationRegistryLogicAFilterer) ParseUpkeepUnpaused(log types.Log) (*AutomationRegistryLogicAUpkeepUnpaused, error) { + event := new(AutomationRegistryLogicAUpkeepUnpaused) + if err := _AutomationRegistryLogicA.contract.UnpackLog(event, "UpkeepUnpaused", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +func (_AutomationRegistryLogicA *AutomationRegistryLogicA) ParseLog(log types.Log) (generated.AbigenLog, error) { + switch log.Topics[0] { + case _AutomationRegistryLogicA.abi.Events["AdminPrivilegeConfigSet"].ID: + return _AutomationRegistryLogicA.ParseAdminPrivilegeConfigSet(log) + case _AutomationRegistryLogicA.abi.Events["CancelledUpkeepReport"].ID: + return _AutomationRegistryLogicA.ParseCancelledUpkeepReport(log) + case _AutomationRegistryLogicA.abi.Events["DedupKeyAdded"].ID: + return _AutomationRegistryLogicA.ParseDedupKeyAdded(log) + case _AutomationRegistryLogicA.abi.Events["FundsAdded"].ID: + return _AutomationRegistryLogicA.ParseFundsAdded(log) + case _AutomationRegistryLogicA.abi.Events["FundsWithdrawn"].ID: + return _AutomationRegistryLogicA.ParseFundsWithdrawn(log) + case _AutomationRegistryLogicA.abi.Events["InsufficientFundsUpkeepReport"].ID: + return _AutomationRegistryLogicA.ParseInsufficientFundsUpkeepReport(log) + case _AutomationRegistryLogicA.abi.Events["OwnerFundsWithdrawn"].ID: + return _AutomationRegistryLogicA.ParseOwnerFundsWithdrawn(log) + case _AutomationRegistryLogicA.abi.Events["OwnershipTransferRequested"].ID: + return _AutomationRegistryLogicA.ParseOwnershipTransferRequested(log) + case _AutomationRegistryLogicA.abi.Events["OwnershipTransferred"].ID: + return _AutomationRegistryLogicA.ParseOwnershipTransferred(log) + case _AutomationRegistryLogicA.abi.Events["Paused"].ID: + return _AutomationRegistryLogicA.ParsePaused(log) + case _AutomationRegistryLogicA.abi.Events["PayeesUpdated"].ID: + return _AutomationRegistryLogicA.ParsePayeesUpdated(log) + case _AutomationRegistryLogicA.abi.Events["PayeeshipTransferRequested"].ID: + return _AutomationRegistryLogicA.ParsePayeeshipTransferRequested(log) + case _AutomationRegistryLogicA.abi.Events["PayeeshipTransferred"].ID: + return _AutomationRegistryLogicA.ParsePayeeshipTransferred(log) + case _AutomationRegistryLogicA.abi.Events["PaymentWithdrawn"].ID: + return _AutomationRegistryLogicA.ParsePaymentWithdrawn(log) + case _AutomationRegistryLogicA.abi.Events["ReorgedUpkeepReport"].ID: + return _AutomationRegistryLogicA.ParseReorgedUpkeepReport(log) + case _AutomationRegistryLogicA.abi.Events["StaleUpkeepReport"].ID: + return _AutomationRegistryLogicA.ParseStaleUpkeepReport(log) + case _AutomationRegistryLogicA.abi.Events["Unpaused"].ID: + return _AutomationRegistryLogicA.ParseUnpaused(log) + case _AutomationRegistryLogicA.abi.Events["UpkeepAdminTransferRequested"].ID: + return _AutomationRegistryLogicA.ParseUpkeepAdminTransferRequested(log) + case _AutomationRegistryLogicA.abi.Events["UpkeepAdminTransferred"].ID: + return _AutomationRegistryLogicA.ParseUpkeepAdminTransferred(log) + case _AutomationRegistryLogicA.abi.Events["UpkeepCanceled"].ID: + return _AutomationRegistryLogicA.ParseUpkeepCanceled(log) + case _AutomationRegistryLogicA.abi.Events["UpkeepCheckDataSet"].ID: + return _AutomationRegistryLogicA.ParseUpkeepCheckDataSet(log) + case _AutomationRegistryLogicA.abi.Events["UpkeepGasLimitSet"].ID: + return _AutomationRegistryLogicA.ParseUpkeepGasLimitSet(log) + case _AutomationRegistryLogicA.abi.Events["UpkeepMigrated"].ID: + return _AutomationRegistryLogicA.ParseUpkeepMigrated(log) + case _AutomationRegistryLogicA.abi.Events["UpkeepOffchainConfigSet"].ID: + return _AutomationRegistryLogicA.ParseUpkeepOffchainConfigSet(log) + case _AutomationRegistryLogicA.abi.Events["UpkeepPaused"].ID: + return _AutomationRegistryLogicA.ParseUpkeepPaused(log) + case _AutomationRegistryLogicA.abi.Events["UpkeepPerformed"].ID: + return _AutomationRegistryLogicA.ParseUpkeepPerformed(log) + case _AutomationRegistryLogicA.abi.Events["UpkeepPrivilegeConfigSet"].ID: + return _AutomationRegistryLogicA.ParseUpkeepPrivilegeConfigSet(log) + case _AutomationRegistryLogicA.abi.Events["UpkeepReceived"].ID: + return _AutomationRegistryLogicA.ParseUpkeepReceived(log) + case _AutomationRegistryLogicA.abi.Events["UpkeepRegistered"].ID: + return _AutomationRegistryLogicA.ParseUpkeepRegistered(log) + case _AutomationRegistryLogicA.abi.Events["UpkeepTriggerConfigSet"].ID: + return _AutomationRegistryLogicA.ParseUpkeepTriggerConfigSet(log) + case _AutomationRegistryLogicA.abi.Events["UpkeepUnpaused"].ID: + return _AutomationRegistryLogicA.ParseUpkeepUnpaused(log) + + default: + return nil, fmt.Errorf("abigen wrapper received unknown log topic: %v", log.Topics[0]) + } +} + +func (AutomationRegistryLogicAAdminPrivilegeConfigSet) Topic() common.Hash { + return common.HexToHash("0x7c44b4eb59ee7873514e7e43e7718c269d872965938b288aa143befca62f99d2") +} + +func (AutomationRegistryLogicACancelledUpkeepReport) Topic() common.Hash { + return common.HexToHash("0xc3237c8807c467c1b39b8d0395eff077313e691bf0a7388106792564ebfd5636") +} + +func (AutomationRegistryLogicADedupKeyAdded) Topic() common.Hash { + return common.HexToHash("0xa4a4e334c0e330143f9437484fe516c13bc560b86b5b0daf58e7084aaac228f2") +} + +func (AutomationRegistryLogicAFundsAdded) Topic() common.Hash { + return common.HexToHash("0xafd24114486da8ebfc32f3626dada8863652e187461aa74d4bfa734891506203") +} + +func (AutomationRegistryLogicAFundsWithdrawn) Topic() common.Hash { + return common.HexToHash("0xf3b5906e5672f3e524854103bcafbbdba80dbdfeca2c35e116127b1060a68318") +} + +func (AutomationRegistryLogicAInsufficientFundsUpkeepReport) Topic() common.Hash { + return common.HexToHash("0x377c8b0c126ae5248d27aca1c76fac4608aff85673ee3caf09747e1044549e02") +} + +func (AutomationRegistryLogicAOwnerFundsWithdrawn) Topic() common.Hash { + return common.HexToHash("0x1d07d0b0be43d3e5fee41a80b579af370affee03fa595bf56d5d4c19328162f1") +} + +func (AutomationRegistryLogicAOwnershipTransferRequested) Topic() common.Hash { + return common.HexToHash("0xed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae1278") +} + +func (AutomationRegistryLogicAOwnershipTransferred) Topic() common.Hash { + return common.HexToHash("0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0") +} + +func (AutomationRegistryLogicAPaused) Topic() common.Hash { + return common.HexToHash("0x62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a258") +} + +func (AutomationRegistryLogicAPayeesUpdated) Topic() common.Hash { + return common.HexToHash("0xa46de38886467c59be07a0675f14781206a5477d871628af46c2443822fcb725") +} + +func (AutomationRegistryLogicAPayeeshipTransferRequested) Topic() common.Hash { + return common.HexToHash("0x84f7c7c80bb8ed2279b4aab5f61cd05e6374073d38f46d7f32de8c30e9e38367") +} + +func (AutomationRegistryLogicAPayeeshipTransferred) Topic() common.Hash { + return common.HexToHash("0x78af32efdcad432315431e9b03d27e6cd98fb79c405fdc5af7c1714d9c0f75b3") +} + +func (AutomationRegistryLogicAPaymentWithdrawn) Topic() common.Hash { + return common.HexToHash("0x9819093176a1851202c7bcfa46845809b4e47c261866550e94ed3775d2f40698") +} + +func (AutomationRegistryLogicAReorgedUpkeepReport) Topic() common.Hash { + return common.HexToHash("0x6aa7f60c176da7af894b384daea2249497448137f5943c1237ada8bc92bdc301") +} + +func (AutomationRegistryLogicAStaleUpkeepReport) Topic() common.Hash { + return common.HexToHash("0x405288ea7be309e16cfdf481367f90a413e1d4634fcdaf8966546db9b93012e8") +} + +func (AutomationRegistryLogicAUnpaused) Topic() common.Hash { + return common.HexToHash("0x5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa") +} + +func (AutomationRegistryLogicAUpkeepAdminTransferRequested) Topic() common.Hash { + return common.HexToHash("0xb1cbb2c4b8480034c27e06da5f096b8233a8fd4497028593a41ff6df79726b35") +} + +func (AutomationRegistryLogicAUpkeepAdminTransferred) Topic() common.Hash { + return common.HexToHash("0x5cff4db96bef051785e999f44bfcd21c18823e034fb92dd376e3db4ce0feeb2c") +} + +func (AutomationRegistryLogicAUpkeepCanceled) Topic() common.Hash { + return common.HexToHash("0x91cb3bb75cfbd718bbfccc56b7f53d92d7048ef4ca39a3b7b7c6d4af1f791181") +} + +func (AutomationRegistryLogicAUpkeepCheckDataSet) Topic() common.Hash { + return common.HexToHash("0xcba2d5723b2ee59e53a8e8a82a4a7caf4fdfe70e9f7c582950bf7e7a5c24e83d") +} + +func (AutomationRegistryLogicAUpkeepGasLimitSet) Topic() common.Hash { + return common.HexToHash("0xc24c07e655ce79fba8a589778987d3c015bc6af1632bb20cf9182e02a65d972c") +} + +func (AutomationRegistryLogicAUpkeepMigrated) Topic() common.Hash { + return common.HexToHash("0xb38647142fbb1ea4c000fc4569b37a4e9a9f6313317b84ee3e5326c1a6cd06ff") +} + +func (AutomationRegistryLogicAUpkeepOffchainConfigSet) Topic() common.Hash { + return common.HexToHash("0x3e8740446213c8a77d40e08f79136ce3f347d13ed270a6ebdf57159e0faf4850") +} + +func (AutomationRegistryLogicAUpkeepPaused) Topic() common.Hash { + return common.HexToHash("0x8ab10247ce168c27748e656ecf852b951fcaac790c18106b19aa0ae57a8b741f") +} + +func (AutomationRegistryLogicAUpkeepPerformed) Topic() common.Hash { + return common.HexToHash("0xad8cc9579b21dfe2c2f6ea35ba15b656e46b4f5b0cb424f52739b8ce5cac9c5b") +} + +func (AutomationRegistryLogicAUpkeepPrivilegeConfigSet) Topic() common.Hash { + return common.HexToHash("0x2fd8d70753a007014349d4591843cc031c2dd7a260d7dd82eca8253686ae7769") +} + +func (AutomationRegistryLogicAUpkeepReceived) Topic() common.Hash { + return common.HexToHash("0x74931a144e43a50694897f241d973aecb5024c0e910f9bb80a163ea3c1cf5a71") +} + +func (AutomationRegistryLogicAUpkeepRegistered) Topic() common.Hash { + return common.HexToHash("0xbae366358c023f887e791d7a62f2e4316f1026bd77f6fb49501a917b3bc5d012") +} + +func (AutomationRegistryLogicAUpkeepTriggerConfigSet) Topic() common.Hash { + return common.HexToHash("0x2b72ac786c97e68dbab71023ed6f2bdbfc80ad9bb7808941929229d71b7d5664") +} + +func (AutomationRegistryLogicAUpkeepUnpaused) Topic() common.Hash { + return common.HexToHash("0x7bada562044eb163f6b4003c4553e4e62825344c0418eea087bed5ee05a47456") +} + +func (_AutomationRegistryLogicA *AutomationRegistryLogicA) Address() common.Address { + return _AutomationRegistryLogicA.address +} + +type AutomationRegistryLogicAInterface interface { + FallbackTo(opts *bind.CallOpts) (common.Address, error) + + Owner(opts *bind.CallOpts) (common.Address, error) + + AcceptOwnership(opts *bind.TransactOpts) (*types.Transaction, error) + + AddFunds(opts *bind.TransactOpts, id *big.Int, amount *big.Int) (*types.Transaction, error) + + 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) + + ReceiveUpkeeps(opts *bind.TransactOpts, encodedUpkeeps []byte) (*types.Transaction, error) + + RegisterUpkeep(opts *bind.TransactOpts, target common.Address, gasLimit uint32, admin common.Address, triggerType uint8, checkData []byte, triggerConfig []byte, offchainConfig []byte) (*types.Transaction, error) + + RegisterUpkeep0(opts *bind.TransactOpts, target common.Address, gasLimit uint32, admin common.Address, checkData []byte, offchainConfig []byte) (*types.Transaction, error) + + SetUpkeepTriggerConfig(opts *bind.TransactOpts, id *big.Int, triggerConfig []byte) (*types.Transaction, error) + + TransferOwnership(opts *bind.TransactOpts, to common.Address) (*types.Transaction, error) + + Fallback(opts *bind.TransactOpts, calldata []byte) (*types.Transaction, error) + + FilterAdminPrivilegeConfigSet(opts *bind.FilterOpts, admin []common.Address) (*AutomationRegistryLogicAAdminPrivilegeConfigSetIterator, error) + + WatchAdminPrivilegeConfigSet(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicAAdminPrivilegeConfigSet, admin []common.Address) (event.Subscription, error) + + ParseAdminPrivilegeConfigSet(log types.Log) (*AutomationRegistryLogicAAdminPrivilegeConfigSet, error) + + FilterCancelledUpkeepReport(opts *bind.FilterOpts, id []*big.Int) (*AutomationRegistryLogicACancelledUpkeepReportIterator, error) + + WatchCancelledUpkeepReport(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicACancelledUpkeepReport, id []*big.Int) (event.Subscription, error) + + ParseCancelledUpkeepReport(log types.Log) (*AutomationRegistryLogicACancelledUpkeepReport, error) + + FilterDedupKeyAdded(opts *bind.FilterOpts, dedupKey [][32]byte) (*AutomationRegistryLogicADedupKeyAddedIterator, error) + + WatchDedupKeyAdded(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicADedupKeyAdded, dedupKey [][32]byte) (event.Subscription, error) + + ParseDedupKeyAdded(log types.Log) (*AutomationRegistryLogicADedupKeyAdded, error) + + FilterFundsAdded(opts *bind.FilterOpts, id []*big.Int, from []common.Address) (*AutomationRegistryLogicAFundsAddedIterator, error) + + WatchFundsAdded(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicAFundsAdded, id []*big.Int, from []common.Address) (event.Subscription, error) + + ParseFundsAdded(log types.Log) (*AutomationRegistryLogicAFundsAdded, error) + + FilterFundsWithdrawn(opts *bind.FilterOpts, id []*big.Int) (*AutomationRegistryLogicAFundsWithdrawnIterator, error) + + WatchFundsWithdrawn(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicAFundsWithdrawn, id []*big.Int) (event.Subscription, error) + + ParseFundsWithdrawn(log types.Log) (*AutomationRegistryLogicAFundsWithdrawn, error) + + FilterInsufficientFundsUpkeepReport(opts *bind.FilterOpts, id []*big.Int) (*AutomationRegistryLogicAInsufficientFundsUpkeepReportIterator, error) + + WatchInsufficientFundsUpkeepReport(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicAInsufficientFundsUpkeepReport, id []*big.Int) (event.Subscription, error) + + ParseInsufficientFundsUpkeepReport(log types.Log) (*AutomationRegistryLogicAInsufficientFundsUpkeepReport, error) + + FilterOwnerFundsWithdrawn(opts *bind.FilterOpts) (*AutomationRegistryLogicAOwnerFundsWithdrawnIterator, error) + + WatchOwnerFundsWithdrawn(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicAOwnerFundsWithdrawn) (event.Subscription, error) + + ParseOwnerFundsWithdrawn(log types.Log) (*AutomationRegistryLogicAOwnerFundsWithdrawn, error) + + FilterOwnershipTransferRequested(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*AutomationRegistryLogicAOwnershipTransferRequestedIterator, error) + + WatchOwnershipTransferRequested(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicAOwnershipTransferRequested, from []common.Address, to []common.Address) (event.Subscription, error) + + ParseOwnershipTransferRequested(log types.Log) (*AutomationRegistryLogicAOwnershipTransferRequested, error) + + FilterOwnershipTransferred(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*AutomationRegistryLogicAOwnershipTransferredIterator, error) + + WatchOwnershipTransferred(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicAOwnershipTransferred, from []common.Address, to []common.Address) (event.Subscription, error) + + ParseOwnershipTransferred(log types.Log) (*AutomationRegistryLogicAOwnershipTransferred, error) + + FilterPaused(opts *bind.FilterOpts) (*AutomationRegistryLogicAPausedIterator, error) + + WatchPaused(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicAPaused) (event.Subscription, error) + + ParsePaused(log types.Log) (*AutomationRegistryLogicAPaused, error) + + FilterPayeesUpdated(opts *bind.FilterOpts) (*AutomationRegistryLogicAPayeesUpdatedIterator, error) + + WatchPayeesUpdated(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicAPayeesUpdated) (event.Subscription, error) + + ParsePayeesUpdated(log types.Log) (*AutomationRegistryLogicAPayeesUpdated, error) + + FilterPayeeshipTransferRequested(opts *bind.FilterOpts, transmitter []common.Address, from []common.Address, to []common.Address) (*AutomationRegistryLogicAPayeeshipTransferRequestedIterator, error) + + WatchPayeeshipTransferRequested(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicAPayeeshipTransferRequested, transmitter []common.Address, from []common.Address, to []common.Address) (event.Subscription, error) + + ParsePayeeshipTransferRequested(log types.Log) (*AutomationRegistryLogicAPayeeshipTransferRequested, error) + + FilterPayeeshipTransferred(opts *bind.FilterOpts, transmitter []common.Address, from []common.Address, to []common.Address) (*AutomationRegistryLogicAPayeeshipTransferredIterator, error) + + WatchPayeeshipTransferred(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicAPayeeshipTransferred, transmitter []common.Address, from []common.Address, to []common.Address) (event.Subscription, error) + + ParsePayeeshipTransferred(log types.Log) (*AutomationRegistryLogicAPayeeshipTransferred, error) + + FilterPaymentWithdrawn(opts *bind.FilterOpts, transmitter []common.Address, amount []*big.Int, to []common.Address) (*AutomationRegistryLogicAPaymentWithdrawnIterator, error) + + WatchPaymentWithdrawn(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicAPaymentWithdrawn, transmitter []common.Address, amount []*big.Int, to []common.Address) (event.Subscription, error) + + ParsePaymentWithdrawn(log types.Log) (*AutomationRegistryLogicAPaymentWithdrawn, error) + + FilterReorgedUpkeepReport(opts *bind.FilterOpts, id []*big.Int) (*AutomationRegistryLogicAReorgedUpkeepReportIterator, error) + + WatchReorgedUpkeepReport(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicAReorgedUpkeepReport, id []*big.Int) (event.Subscription, error) + + ParseReorgedUpkeepReport(log types.Log) (*AutomationRegistryLogicAReorgedUpkeepReport, error) + + FilterStaleUpkeepReport(opts *bind.FilterOpts, id []*big.Int) (*AutomationRegistryLogicAStaleUpkeepReportIterator, error) + + WatchStaleUpkeepReport(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicAStaleUpkeepReport, id []*big.Int) (event.Subscription, error) + + ParseStaleUpkeepReport(log types.Log) (*AutomationRegistryLogicAStaleUpkeepReport, error) + + FilterUnpaused(opts *bind.FilterOpts) (*AutomationRegistryLogicAUnpausedIterator, error) + + WatchUnpaused(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicAUnpaused) (event.Subscription, error) + + ParseUnpaused(log types.Log) (*AutomationRegistryLogicAUnpaused, error) + + FilterUpkeepAdminTransferRequested(opts *bind.FilterOpts, id []*big.Int, from []common.Address, to []common.Address) (*AutomationRegistryLogicAUpkeepAdminTransferRequestedIterator, error) + + WatchUpkeepAdminTransferRequested(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicAUpkeepAdminTransferRequested, id []*big.Int, from []common.Address, to []common.Address) (event.Subscription, error) + + ParseUpkeepAdminTransferRequested(log types.Log) (*AutomationRegistryLogicAUpkeepAdminTransferRequested, error) + + FilterUpkeepAdminTransferred(opts *bind.FilterOpts, id []*big.Int, from []common.Address, to []common.Address) (*AutomationRegistryLogicAUpkeepAdminTransferredIterator, error) + + WatchUpkeepAdminTransferred(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicAUpkeepAdminTransferred, id []*big.Int, from []common.Address, to []common.Address) (event.Subscription, error) + + ParseUpkeepAdminTransferred(log types.Log) (*AutomationRegistryLogicAUpkeepAdminTransferred, error) + + FilterUpkeepCanceled(opts *bind.FilterOpts, id []*big.Int, atBlockHeight []uint64) (*AutomationRegistryLogicAUpkeepCanceledIterator, error) + + WatchUpkeepCanceled(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicAUpkeepCanceled, id []*big.Int, atBlockHeight []uint64) (event.Subscription, error) + + ParseUpkeepCanceled(log types.Log) (*AutomationRegistryLogicAUpkeepCanceled, error) + + FilterUpkeepCheckDataSet(opts *bind.FilterOpts, id []*big.Int) (*AutomationRegistryLogicAUpkeepCheckDataSetIterator, error) + + WatchUpkeepCheckDataSet(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicAUpkeepCheckDataSet, id []*big.Int) (event.Subscription, error) + + ParseUpkeepCheckDataSet(log types.Log) (*AutomationRegistryLogicAUpkeepCheckDataSet, error) + + FilterUpkeepGasLimitSet(opts *bind.FilterOpts, id []*big.Int) (*AutomationRegistryLogicAUpkeepGasLimitSetIterator, error) + + WatchUpkeepGasLimitSet(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicAUpkeepGasLimitSet, id []*big.Int) (event.Subscription, error) + + ParseUpkeepGasLimitSet(log types.Log) (*AutomationRegistryLogicAUpkeepGasLimitSet, error) + + FilterUpkeepMigrated(opts *bind.FilterOpts, id []*big.Int) (*AutomationRegistryLogicAUpkeepMigratedIterator, error) + + WatchUpkeepMigrated(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicAUpkeepMigrated, id []*big.Int) (event.Subscription, error) + + ParseUpkeepMigrated(log types.Log) (*AutomationRegistryLogicAUpkeepMigrated, error) + + FilterUpkeepOffchainConfigSet(opts *bind.FilterOpts, id []*big.Int) (*AutomationRegistryLogicAUpkeepOffchainConfigSetIterator, error) + + WatchUpkeepOffchainConfigSet(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicAUpkeepOffchainConfigSet, id []*big.Int) (event.Subscription, error) + + ParseUpkeepOffchainConfigSet(log types.Log) (*AutomationRegistryLogicAUpkeepOffchainConfigSet, error) + + FilterUpkeepPaused(opts *bind.FilterOpts, id []*big.Int) (*AutomationRegistryLogicAUpkeepPausedIterator, error) + + WatchUpkeepPaused(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicAUpkeepPaused, id []*big.Int) (event.Subscription, error) + + ParseUpkeepPaused(log types.Log) (*AutomationRegistryLogicAUpkeepPaused, error) + + FilterUpkeepPerformed(opts *bind.FilterOpts, id []*big.Int, success []bool) (*AutomationRegistryLogicAUpkeepPerformedIterator, error) + + WatchUpkeepPerformed(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicAUpkeepPerformed, id []*big.Int, success []bool) (event.Subscription, error) + + ParseUpkeepPerformed(log types.Log) (*AutomationRegistryLogicAUpkeepPerformed, error) + + FilterUpkeepPrivilegeConfigSet(opts *bind.FilterOpts, id []*big.Int) (*AutomationRegistryLogicAUpkeepPrivilegeConfigSetIterator, error) + + WatchUpkeepPrivilegeConfigSet(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicAUpkeepPrivilegeConfigSet, id []*big.Int) (event.Subscription, error) + + ParseUpkeepPrivilegeConfigSet(log types.Log) (*AutomationRegistryLogicAUpkeepPrivilegeConfigSet, error) + + FilterUpkeepReceived(opts *bind.FilterOpts, id []*big.Int) (*AutomationRegistryLogicAUpkeepReceivedIterator, error) + + WatchUpkeepReceived(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicAUpkeepReceived, id []*big.Int) (event.Subscription, error) + + ParseUpkeepReceived(log types.Log) (*AutomationRegistryLogicAUpkeepReceived, error) + + FilterUpkeepRegistered(opts *bind.FilterOpts, id []*big.Int) (*AutomationRegistryLogicAUpkeepRegisteredIterator, error) + + WatchUpkeepRegistered(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicAUpkeepRegistered, id []*big.Int) (event.Subscription, error) + + ParseUpkeepRegistered(log types.Log) (*AutomationRegistryLogicAUpkeepRegistered, error) + + FilterUpkeepTriggerConfigSet(opts *bind.FilterOpts, id []*big.Int) (*AutomationRegistryLogicAUpkeepTriggerConfigSetIterator, error) + + WatchUpkeepTriggerConfigSet(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicAUpkeepTriggerConfigSet, id []*big.Int) (event.Subscription, error) + + ParseUpkeepTriggerConfigSet(log types.Log) (*AutomationRegistryLogicAUpkeepTriggerConfigSet, error) + + FilterUpkeepUnpaused(opts *bind.FilterOpts, id []*big.Int) (*AutomationRegistryLogicAUpkeepUnpausedIterator, error) + + WatchUpkeepUnpaused(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicAUpkeepUnpaused, id []*big.Int) (event.Subscription, error) + + ParseUpkeepUnpaused(log types.Log) (*AutomationRegistryLogicAUpkeepUnpaused, error) + + ParseLog(log types.Log) (generated.AbigenLog, error) + + Address() common.Address +} diff --git a/core/gethwrappers/generated/keeper_registry_logic_b_wrapper_2_2/keeper_registry_logic_b_wrapper_2_2.go b/core/gethwrappers/generated/keeper_registry_logic_b_wrapper_2_2/keeper_registry_logic_b_wrapper_2_2.go new file mode 100644 index 0000000000..1805d53568 --- /dev/null +++ b/core/gethwrappers/generated/keeper_registry_logic_b_wrapper_2_2/keeper_registry_logic_b_wrapper_2_2.go @@ -0,0 +1,5708 @@ +// Code generated - DO NOT EDIT. +// This file is a generated binding and any manual changes will be lost. + +package keeper_registry_logic_b_wrapper_2_2 + +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 +) + +type AutomationRegistryBase22OnchainConfig struct { + PaymentPremiumPPB uint32 + FlatFeeMicroLink uint32 + CheckGasLimit uint32 + StalenessSeconds *big.Int + GasCeilingMultiplier uint16 + MinUpkeepSpend *big.Int + MaxPerformGas uint32 + MaxCheckDataSize uint32 + MaxPerformDataSize uint32 + MaxRevertDataSize uint32 + FallbackGasPrice *big.Int + FallbackLinkPrice *big.Int + Transcoder common.Address + Registrars []common.Address + UpkeepPrivilegeManager common.Address +} + +type AutomationRegistryBase22State struct { + Nonce uint32 + OwnerLinkBalance *big.Int + ExpectedLinkBalance *big.Int + TotalPremium *big.Int + NumUpkeeps *big.Int + ConfigCount uint32 + LatestConfigBlockNumber uint32 + LatestConfigDigest [32]byte + LatestEpoch uint32 + Paused bool +} + +type AutomationRegistryBase22UpkeepInfo struct { + Target common.Address + PerformGas uint32 + CheckData []byte + Balance *big.Int + Admin common.Address + MaxValidBlocknumber uint64 + LastPerformedBlockNumber uint32 + AmountSpent *big.Int + Paused bool + OffchainConfig []byte +} + +var AutomationRegistryLogicBMetaData = &bind.MetaData{ + ABI: "[{\"inputs\":[{\"internalType\":\"enumAutomationRegistryBase2_2.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\":[],\"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\":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\":\"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\"},{\"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\":\"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\":\"contractIAutomationForwarder\",\"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\":\"enumAutomationRegistryBase2_2.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\":\"enumAutomationRegistryBase2_2.Mode\",\"name\":\"\",\"type\":\"uint8\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"peer\",\"type\":\"address\"}],\"name\":\"getPeerRegistryMigrationPermission\",\"outputs\":[{\"internalType\":\"enumAutomationRegistryBase2_2.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\":\"structAutomationRegistryBase2_2.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\":\"structAutomationRegistryBase2_2.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\":\"enumAutomationRegistryBase2_2.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\":\"structAutomationRegistryBase2_2.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\":\"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\":\"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\":\"enumAutomationRegistryBase2_2.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\":\"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\":[],\"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\":\"enumUpkeepFormat\",\"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\"}]", + Bin: "0x6101206040523480156200001257600080fd5b5060405162004fbc38038062004fbc8339810160408190526200003591620001e9565b84848484843380600081620000915760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b0384811691909117909155811615620000c457620000c48162000121565b505050846002811115620000dc57620000dc6200025e565b60e0816002811115620000f357620000f36200025e565b9052506001600160a01b0393841660805291831660a052821660c05216610100525062000274945050505050565b336001600160a01b038216036200017b5760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c66000000000000000000604482015260640162000088565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b80516001600160a01b0381168114620001e457600080fd5b919050565b600080600080600060a086880312156200020257600080fd5b8551600381106200021257600080fd5b94506200022260208701620001cc565b93506200023260408701620001cc565b92506200024260608701620001cc565b91506200025260808701620001cc565b90509295509295909350565b634e487b7160e01b600052602160045260246000fd5b60805160a05160c05160e05161010051614cbd620002ff600039600061058701526000818161052501528181613352015281816138d50152613a680152600081816105f4015261314601526000818161071c01526132200152600081816107aa01528181611bab01528181611e81015281816122ee0152818161280101526128850152614cbd6000f3fe608060405234801561001057600080fd5b50600436106103365760003560e01c806379ba5097116101b2578063b121e147116100f9578063ca30e603116100a2578063eb5dcd6c1161007c578063eb5dcd6c146107f4578063ed56b3e114610807578063f2fde38b1461087a578063faa3e9961461088d57600080fd5b8063ca30e603146107a8578063cd7f71b5146107ce578063d7632648146107e157600080fd5b8063b657bc9c116100d3578063b657bc9c1461076d578063b79550be14610780578063c7c3a19a1461078857600080fd5b8063b121e14714610740578063b148ab6b14610753578063b6511a2a1461076657600080fd5b80638dcf0fe71161015b578063aab9edd611610135578063aab9edd614610703578063abc76ae014610712578063b10b673c1461071a57600080fd5b80638dcf0fe7146106ca578063a710b221146106dd578063a72aa27e146106f057600080fd5b80638456cb591161018c5780638456cb59146106915780638765ecbe146106995780638da5cb5b146106ac57600080fd5b806379ba50971461063e57806379ea9943146106465780637d9b97e01461068957600080fd5b8063421d183b116102815780635165f2f51161022a5780636209e1e9116102045780636209e1e9146105df5780636709d0e5146105f2578063671d36ed14610618578063744bfe611461062b57600080fd5b80635165f2f5146105725780635425d8ac146105855780635b6aa71c146105cc57600080fd5b80634b4fd03b1161025b5780634b4fd03b146105235780634ca16c52146105495780635147cd591461055257600080fd5b8063421d183b1461047a57806344cb70b8146104e057806348013d7b1461051357600080fd5b80631a2af011116102e3578063232c1cc5116102bd578063232c1cc5146104585780633b9cce591461045f5780633f4ba83a1461047257600080fd5b80631a2af011146103d45780631e010439146103e7578063207b65161461044557600080fd5b80631865c57d116103145780631865c57d14610388578063187256e8146103a157806319d97a94146103b457600080fd5b8063050ee65d1461033b57806306e3b632146103535780630b7d33e614610373575b600080fd5b6201adb05b6040519081526020015b60405180910390f35b610366610361366004613df3565b6108d3565b60405161034a9190613e15565b610386610381366004613ea2565b6109f0565b005b610390610aaa565b60405161034a9594939291906140a5565b6103866103af3660046141dc565b610ec3565b6103c76103c2366004614219565b610f34565b60405161034a91906142a0565b6103866103e23660046142b3565b610fd6565b6104286103f5366004614219565b6000908152600460205260409020600101546c0100000000000000000000000090046bffffffffffffffffffffffff1690565b6040516bffffffffffffffffffffffff909116815260200161034a565b6103c7610453366004614219565b6110dc565b6014610340565b61038661046d3660046142d8565b6110f9565b61038661134f565b61048d61048836600461434d565b6113b5565b60408051951515865260ff90941660208601526bffffffffffffffffffffffff9283169385019390935216606083015273ffffffffffffffffffffffffffffffffffffffff16608082015260a00161034a565b6105036104ee366004614219565b60009081526008602052604090205460ff1690565b604051901515815260200161034a565b60005b60405161034a91906143a9565b7f0000000000000000000000000000000000000000000000000000000000000000610516565b62015f90610340565b610565610560366004614219565b6114e8565b60405161034a91906143bc565b610386610580366004614219565b6114f3565b7f00000000000000000000000000000000000000000000000000000000000000005b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200161034a565b6104286105da3660046143e9565b61166a565b6103c76105ed36600461434d565b61179c565b7f00000000000000000000000000000000000000000000000000000000000000006105a7565b610386610626366004614422565b6117d0565b6103866106393660046142b3565b6118aa565b610386611ca7565b6105a7610654366004614219565b6000908152600460205260409020546901000000000000000000900473ffffffffffffffffffffffffffffffffffffffff1690565b610386611da9565b610386611f04565b6103866106a7366004614219565b611f75565b60005473ffffffffffffffffffffffffffffffffffffffff166105a7565b6103866106d8366004613ea2565b6120ef565b6103866106eb36600461445e565b612144565b6103866106fe36600461448c565b6123c0565b6040516003815260200161034a565b611d4c610340565b7f00000000000000000000000000000000000000000000000000000000000000006105a7565b61038661074e36600461434d565b6124b5565b610386610761366004614219565b6125ad565b6032610340565b61042861077b366004614219565b61279b565b6103866127c8565b61079b610796366004614219565b612924565b60405161034a91906144af565b7f00000000000000000000000000000000000000000000000000000000000000006105a7565b6103866107dc366004613ea2565b612cf7565b6104286107ef366004614219565b612d8e565b61038661080236600461445e565b612d99565b61086161081536600461434d565b73ffffffffffffffffffffffffffffffffffffffff166000908152600c602090815260409182902082518084019093525460ff8082161515808552610100909204169290910182905291565b60408051921515835260ff90911660208301520161034a565b61038661088836600461434d565b612ef7565b6108c661089b36600461434d565b73ffffffffffffffffffffffffffffffffffffffff1660009081526019602052604090205460ff1690565b60405161034a91906145e6565b606060006108e16002612f0b565b905080841061091c576040517f1390f2a100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60006109288486614629565b905081811180610936575083155b6109405780610942565b815b90506000610950868361463c565b67ffffffffffffffff8111156109685761096861464f565b604051908082528060200260200182016040528015610991578160200160208202803683370190505b50905060005b81518110156109e4576109b56109ad8883614629565b600290612f15565b8282815181106109c7576109c761467e565b6020908102919091010152806109dc816146ad565b915050610997565b50925050505b92915050565b6015546c01000000000000000000000000900473ffffffffffffffffffffffffffffffffffffffff163314610a51576040517f77c3599200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000838152601c60205260409020610a6a828483614787565b50827f2fd8d70753a007014349d4591843cc031c2dd7a260d7dd82eca8253686ae77698383604051610a9d9291906148a2565b60405180910390a2505050565b6040805161014081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e081018290526101008101829052610120810191909152604080516101e08101825260008082526020820181905291810182905260608082018390526080820183905260a0820183905260c0820183905260e08201839052610100820183905261012082018390526101408201839052610160820183905261018082018390526101a08201526101c0810191909152604080516101408101825260145463ffffffff7401000000000000000000000000000000000000000082041682526bffffffffffffffffffffffff908116602083015260185492820192909252601254700100000000000000000000000000000000900490911660608281019190915290819060009060808101610bf76002612f0b565b81526014547801000000000000000000000000000000000000000000000000810463ffffffff9081166020808501919091527c0100000000000000000000000000000000000000000000000000000000808404831660408087019190915260115460608088019190915260125492830485166080808901919091526e010000000000000000000000000000840460ff16151560a09889015282516101e081018452610100808604881682526501000000000086048816968201969096526c010000000000000000000000008089048816948201949094526901000000000000000000850462ffffff16928101929092529282900461ffff16928101929092526013546bffffffffffffffffffffffff811696830196909652700100000000000000000000000000000000909404831660c082015260155480841660e0830152640100000000810484169282019290925268010000000000000000909104909116610120820152601654610140820152601754610160820152910473ffffffffffffffffffffffffffffffffffffffff166101808201529095506101a08101610d9f6009612f28565b81526015546c01000000000000000000000000900473ffffffffffffffffffffffffffffffffffffffff16602091820152601254600d80546040805182860281018601909152818152949850899489949293600e9360ff909116928591830182828015610e4257602002820191906000526020600020905b815473ffffffffffffffffffffffffffffffffffffffff168152600190910190602001808311610e17575b5050505050925081805480602002602001604051908101604052809291908181526020018280548015610eab57602002820191906000526020600020905b815473ffffffffffffffffffffffffffffffffffffffff168152600190910190602001808311610e80575b50505050509150945094509450945094509091929394565b610ecb612f35565b73ffffffffffffffffffffffffffffffffffffffff8216600090815260196020526040902080548291907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001836003811115610f2b57610f2b61436a565b02179055505050565b6000818152601c60205260409020805460609190610f51906146e5565b80601f0160208091040260200160405190810160405280929190818152602001828054610f7d906146e5565b8015610fca5780601f10610f9f57610100808354040283529160200191610fca565b820191906000526020600020905b815481529060010190602001808311610fad57829003601f168201915b50505050509050919050565b610fdf82612fb8565b3373ffffffffffffffffffffffffffffffffffffffff82160361102e576040517f8c8728c700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008281526006602052604090205473ffffffffffffffffffffffffffffffffffffffff8281169116146110d85760008281526006602052604080822080547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff851690811790915590519091339185917fb1cbb2c4b8480034c27e06da5f096b8233a8fd4497028593a41ff6df79726b3591a45b5050565b6000818152601a60205260409020805460609190610f51906146e5565b611101612f35565b600e54811461113c576040517fcf54c06a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60005b600e5481101561130e576000600e828154811061115e5761115e61467e565b600091825260208083209091015473ffffffffffffffffffffffffffffffffffffffff908116808452600f909252604083205491935016908585858181106111a8576111a861467e565b90506020020160208101906111bd919061434d565b905073ffffffffffffffffffffffffffffffffffffffff81161580611250575073ffffffffffffffffffffffffffffffffffffffff82161580159061122e57508073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1614155b8015611250575073ffffffffffffffffffffffffffffffffffffffff81811614155b15611287576040517fb387a23800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff818116146112f85773ffffffffffffffffffffffffffffffffffffffff8381166000908152600f6020526040902080547fffffffffffffffffffffffff0000000000000000000000000000000000000000169183169190911790555b5050508080611306906146ad565b91505061113f565b507fa46de38886467c59be07a0675f14781206a5477d871628af46c2443822fcb725600e8383604051611343939291906148ef565b60405180910390a15050565b611357612f35565b601280547fffffffffffffffffffffffffffffffffff00ffffffffffffffffffffffffffff1690556040513381527f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa906020015b60405180910390a1565b73ffffffffffffffffffffffffffffffffffffffff81166000908152600b602090815260408083208151608081018352905460ff80821615801584526101008304909116948301949094526bffffffffffffffffffffffff6201000082048116938301939093526e01000000000000000000000000000090049091166060820152829182918291829190829061148f57606082015160125460009161147b9170010000000000000000000000000000000090046bffffffffffffffffffffffff166149a1565b600e5490915061148b90826149f5565b9150505b8151602083015160408401516114a6908490614a20565b6060949094015173ffffffffffffffffffffffffffffffffffffffff9a8b166000908152600f6020526040902054929b919a9499509750921694509092505050565b60006109ea8261306c565b6114fc81612fb8565b600081815260046020908152604091829020825160e081018452815460ff8116151580835263ffffffff610100830481169584019590955265010000000000820485169583019590955273ffffffffffffffffffffffffffffffffffffffff69010000000000000000009091041660608201526001909101546bffffffffffffffffffffffff80821660808401526c0100000000000000000000000082041660a08301527801000000000000000000000000000000000000000000000000900490911660c0820152906115fb576040517f1b88a78400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600082815260046020526040902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016905561163a600283613117565b5060405182907f7bada562044eb163f6b4003c4553e4e62825344c0418eea087bed5ee05a4745690600090a25050565b604080516101208101825260125460ff808216835263ffffffff6101008084048216602086015265010000000000840482169585019590955262ffffff6901000000000000000000840416606085015261ffff6c0100000000000000000000000084041660808501526e01000000000000000000000000000083048216151560a08501526f010000000000000000000000000000008304909116151560c08401526bffffffffffffffffffffffff70010000000000000000000000000000000083041660e08401527c01000000000000000000000000000000000000000000000000000000009091041691810191909152600090818061176983613123565b91509150611792838787601360020160049054906101000a900463ffffffff1686866000613301565b9695505050505050565b73ffffffffffffffffffffffffffffffffffffffff81166000908152601d60205260409020805460609190610f51906146e5565b6015546c01000000000000000000000000900473ffffffffffffffffffffffffffffffffffffffff163314611831576040517f77c3599200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff83166000908152601d60205260409020611861828483614787565b508273ffffffffffffffffffffffffffffffffffffffff167f7c44b4eb59ee7873514e7e43e7718c269d872965938b288aa143befca62f99d28383604051610a9d9291906148a2565b6012546f01000000000000000000000000000000900460ff16156118fa576040517f37ed32e800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b601280547fffffffffffffffffffffffffffffffff00ffffffffffffffffffffffffffffff166f0100000000000000000000000000000017905573ffffffffffffffffffffffffffffffffffffffff8116611981576040517f9c8d2cd200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000828152600460209081526040808320815160e081018352815460ff81161515825263ffffffff610100820481168387015265010000000000820481168386015273ffffffffffffffffffffffffffffffffffffffff6901000000000000000000909204821660608401526001909301546bffffffffffffffffffffffff80821660808501526c0100000000000000000000000082041660a08401527801000000000000000000000000000000000000000000000000900490921660c082015286855260059093529220549091163314611a88576040517fa47c170600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611a9061334c565b816040015163ffffffff161115611ad3576040517fff84e5dd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000838152600460205260409020600101546018546c010000000000000000000000009091046bffffffffffffffffffffffff1690611b1390829061463c565b60185560008481526004602081905260409182902060010180547fffffffffffffffff000000000000000000000000ffffffffffffffffffffffff16905590517fa9059cbb00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff858116928201929092526bffffffffffffffffffffffff831660248201527f00000000000000000000000000000000000000000000000000000000000000009091169063a9059cbb906044016020604051808303816000875af1158015611bf6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c1a9190614a45565b50604080516bffffffffffffffffffffffff8316815273ffffffffffffffffffffffffffffffffffffffff8516602082015285917ff3b5906e5672f3e524854103bcafbbdba80dbdfeca2c35e116127b1060a68318910160405180910390a25050601280547fffffffffffffffffffffffffffffffff00ffffffffffffffffffffffffffffff1690555050565b60015473ffffffffffffffffffffffffffffffffffffffff163314611d2d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e65720000000000000000000060448201526064015b60405180910390fd5b60008054337fffffffffffffffffffffffff00000000000000000000000000000000000000008083168217845560018054909116905560405173ffffffffffffffffffffffffffffffffffffffff90921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b611db1612f35565b6014546018546bffffffffffffffffffffffff90911690611dd390829061463c565b601855601480547fffffffffffffffffffffffffffffffffffffffff0000000000000000000000001690556040516bffffffffffffffffffffffff821681527f1d07d0b0be43d3e5fee41a80b579af370affee03fa595bf56d5d4c19328162f19060200160405180910390a16040517fa9059cbb0000000000000000000000000000000000000000000000000000000081523360048201526bffffffffffffffffffffffff821660248201527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff169063a9059cbb906044015b6020604051808303816000875af1158015611ee0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110d89190614a45565b611f0c612f35565b601280547fffffffffffffffffffffffffffffffffff00ffffffffffffffffffffffffffff166e0100000000000000000000000000001790556040513381527f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a258906020016113ab565b611f7e81612fb8565b600081815260046020908152604091829020825160e081018452815460ff8116158015835263ffffffff610100830481169584019590955265010000000000820485169583019590955273ffffffffffffffffffffffffffffffffffffffff69010000000000000000009091041660608201526001909101546bffffffffffffffffffffffff80821660808401526c0100000000000000000000000082041660a08301527801000000000000000000000000000000000000000000000000900490911660c08201529061207d576040517f514b6c2400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600082815260046020526040902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790556120bf600283613401565b5060405182907f8ab10247ce168c27748e656ecf852b951fcaac790c18106b19aa0ae57a8b741f90600090a25050565b6120f883612fb8565b6000838152601b60205260409020612111828483614787565b50827f3e8740446213c8a77d40e08f79136ce3f347d13ed270a6ebdf57159e0faf48508383604051610a9d9291906148a2565b73ffffffffffffffffffffffffffffffffffffffff8116612191576040517f9c8d2cd200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff8281166000908152600f60205260409020541633146121f1576040517fcebf515b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b601254600e5460009161222891859170010000000000000000000000000000000090046bffffffffffffffffffffffff169061340d565b73ffffffffffffffffffffffffffffffffffffffff84166000908152600b6020526040902080547fffffffffffffffffffffffffffffffffffff000000000000000000000000ffff169055601854909150612292906bffffffffffffffffffffffff83169061463c565b6018556040517fa9059cbb00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff83811660048301526bffffffffffffffffffffffff831660248301527f0000000000000000000000000000000000000000000000000000000000000000169063a9059cbb906044016020604051808303816000875af1158015612337573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061235b9190614a45565b5060405133815273ffffffffffffffffffffffffffffffffffffffff808416916bffffffffffffffffffffffff8416918616907f9819093176a1851202c7bcfa46845809b4e47c261866550e94ed3775d2f406989060200160405180910390a4505050565b6108fc8163ffffffff1610806123f5575060145463ffffffff7001000000000000000000000000000000009091048116908216115b1561242c576040517f14c237fb00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61243582612fb8565b60008281526004602090815260409182902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffff00000000ff1661010063ffffffff861690810291909117909155915191825283917fc24c07e655ce79fba8a589778987d3c015bc6af1632bb20cf9182e02a65d972c910160405180910390a25050565b73ffffffffffffffffffffffffffffffffffffffff818116600090815260106020526040902054163314612515576040517f6752e7aa00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff8181166000818152600f602090815260408083208054337fffffffffffffffffffffffff000000000000000000000000000000000000000080831682179093556010909452828520805490921690915590519416939092849290917f78af32efdcad432315431e9b03d27e6cd98fb79c405fdc5af7c1714d9c0f75b39190a45050565b600081815260046020908152604091829020825160e081018452815460ff81161515825263ffffffff6101008204811694830194909452650100000000008104841694820185905273ffffffffffffffffffffffffffffffffffffffff69010000000000000000009091041660608201526001909101546bffffffffffffffffffffffff80821660808401526c0100000000000000000000000082041660a083015278010000000000000000000000000000000000000000000000009004821660c082015291146126aa576040517f9c0083a200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008281526006602052604090205473ffffffffffffffffffffffffffffffffffffffff163314612707576040517f6352a85300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008281526005602090815260408083208054337fffffffffffffffffffffffff0000000000000000000000000000000000000000808316821790935560069094528285208054909216909155905173ffffffffffffffffffffffffffffffffffffffff90911692839186917f5cff4db96bef051785e999f44bfcd21c18823e034fb92dd376e3db4ce0feeb2c91a4505050565b60006109ea6127a98361306c565b600084815260046020526040902054610100900463ffffffff1661166a565b6127d0612f35565b6040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201526000907f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16906370a0823190602401602060405180830381865afa15801561285d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128819190614a67565b90507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663a9059cbb33601854846128ce919061463c565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e085901b16815273ffffffffffffffffffffffffffffffffffffffff90921660048301526024820152604401611ec1565b604080516101408101825260008082526020820181905260609282018390528282018190526080820181905260a0820181905260c0820181905260e082018190526101008201526101208101919091526000828152600460209081526040808320815160e081018352815460ff811615158252610100810463ffffffff90811695830195909552650100000000008104851693820193909352690100000000000000000090920473ffffffffffffffffffffffffffffffffffffffff16606083018190526001909101546bffffffffffffffffffffffff80821660808501526c0100000000000000000000000082041660a08401527801000000000000000000000000000000000000000000000000900490921660c0820152919015612abc57816060015173ffffffffffffffffffffffffffffffffffffffff1663f00e6a2a6040518163ffffffff1660e01b8152600401602060405180830381865afa158015612a93573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612ab79190614a80565b612abf565b60005b90506040518061014001604052808273ffffffffffffffffffffffffffffffffffffffff168152602001836020015163ffffffff168152602001600760008781526020019081526020016000208054612b17906146e5565b80601f0160208091040260200160405190810160405280929190818152602001828054612b43906146e5565b8015612b905780601f10612b6557610100808354040283529160200191612b90565b820191906000526020600020905b815481529060010190602001808311612b7357829003601f168201915b505050505081526020018360a001516bffffffffffffffffffffffff1681526020016005600087815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001836040015163ffffffff1667ffffffffffffffff1681526020018360c0015163ffffffff16815260200183608001516bffffffffffffffffffffffff168152602001836000015115158152602001601b60008781526020019081526020016000208054612c6d906146e5565b80601f0160208091040260200160405190810160405280929190818152602001828054612c99906146e5565b8015612ce65780601f10612cbb57610100808354040283529160200191612ce6565b820191906000526020600020905b815481529060010190602001808311612cc957829003601f168201915b505050505081525092505050919050565b612d0083612fb8565b60155463ffffffff16811115612d42576040517fae7235df00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000838152600760205260409020612d5b828483614787565b50827fcba2d5723b2ee59e53a8e8a82a4a7caf4fdfe70e9f7c582950bf7e7a5c24e83d8383604051610a9d9291906148a2565b60006109ea8261279b565b73ffffffffffffffffffffffffffffffffffffffff8281166000908152600f6020526040902054163314612df9576040517fcebf515b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b3373ffffffffffffffffffffffffffffffffffffffff821603612e48576040517f8c8728c700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff8281166000908152601060205260409020548116908216146110d85773ffffffffffffffffffffffffffffffffffffffff82811660008181526010602052604080822080547fffffffffffffffffffffffff0000000000000000000000000000000000000000169486169485179055513392917f84f7c7c80bb8ed2279b4aab5f61cd05e6374073d38f46d7f32de8c30e9e3836791a45050565b612eff612f35565b612f0881613615565b50565b60006109ea825490565b6000612f21838361370a565b9392505050565b60606000612f2183613734565b60005473ffffffffffffffffffffffffffffffffffffffff163314612fb6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e6572000000000000000000006044820152606401611d24565b565b60008181526005602052604090205473ffffffffffffffffffffffffffffffffffffffff163314613015576040517fa47c170600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008181526004602052604090205465010000000000900463ffffffff90811614612f08576040517f9c0083a200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000818160045b600f8110156130f9577fff0000000000000000000000000000000000000000000000000000000000000082168382602081106130b1576130b161467e565b1a60f81b7effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916146130e757506000949350505050565b806130f1816146ad565b915050613073565b5081600f1a600181111561310f5761310f61436a565b949350505050565b6000612f21838361378f565b6000806000836060015162ffffff1690506000808263ffffffff161190506000807f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663feaf968c6040518163ffffffff1660e01b815260040160a060405180830381865afa1580156131af573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906131d39190614ab7565b50945090925050506000811315806131ea57508142105b8061320b575082801561320b5750613202824261463c565b8463ffffffff16105b1561321a57601654955061321e565b8095505b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663feaf968c6040518163ffffffff1660e01b815260040160a060405180830381865afa158015613289573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906132ad9190614ab7565b50945090925050506000811315806132c457508142105b806132e557508280156132e557506132dc824261463c565b8463ffffffff16105b156132f45760175494506132f8565b8094505b50505050915091565b60008061331388878b600001516137de565b905060008061332e8b8a63ffffffff16858a8a60018b6138a0565b909250905061333d8183614a20565b9b9a5050505050505050505050565b600060017f000000000000000000000000000000000000000000000000000000000000000060028111156133825761338261436a565b036133fc57606473ffffffffffffffffffffffffffffffffffffffff1663a3b1b31d6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156133d3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906133f79190614a67565b905090565b504390565b6000612f218383613cf9565b73ffffffffffffffffffffffffffffffffffffffff83166000908152600b602090815260408083208151608081018352905460ff80821615801584526101008304909116948301949094526bffffffffffffffffffffffff6201000082048116938301939093526e01000000000000000000000000000090049091166060820152906136095760008160600151856134a591906149a1565b905060006134b385836149f5565b905080836040018181516134c79190614a20565b6bffffffffffffffffffffffff169052506134e28582614b07565b836060018181516134f39190614a20565b6bffffffffffffffffffffffff90811690915273ffffffffffffffffffffffffffffffffffffffff89166000908152600b602090815260409182902087518154928901519389015160608a015186166e010000000000000000000000000000027fffffffffffff000000000000000000000000ffffffffffffffffffffffffffff919096166201000002167fffffffffffff000000000000000000000000000000000000000000000000ffff60ff95909516610100027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff921515929092167fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000909416939093171792909216179190911790555050505b60400151949350505050565b3373ffffffffffffffffffffffffffffffffffffffff821603613694576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c660000000000000000006044820152606401611d24565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b60008260000182815481106137215761372161467e565b9060005260206000200154905092915050565b606081600001805480602002602001604051908101604052809291908181526020018280548015610fca57602002820191906000526020600020905b8154815260200190600101908083116137705750505050509050919050565b60008181526001830160205260408120546137d6575081546001818101845560008481526020808220909301849055845484825282860190935260409020919091556109ea565b5060006109ea565b600080808560018111156137f4576137f461436a565b03613803575062015f90613858565b60018560018111156138175761381761436a565b0361382657506201adb0613858565b6040517ff2b2d41200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61386963ffffffff85166014614b3b565b613874846001614b78565b6138839060ff16611d4c614b3b565b61388d9083614629565b6138979190614629565b95945050505050565b6000806000896080015161ffff16876138b99190614b3b565b90508380156138c75750803a105b156138cf57503a5b600060027f000000000000000000000000000000000000000000000000000000000000000060028111156139055761390561436a565b03613a6457604080516000815260208101909152851561396357600036604051806080016040528060488152602001614c696048913960405160200161394d93929190614b91565b60405160208183030381529060405290506139cb565b60155461397f90640100000000900463ffffffff166004614bb8565b63ffffffff1667ffffffffffffffff81111561399d5761399d61464f565b6040519080825280601f01601f1916602001820160405280156139c7576020820181803683370190505b5090505b6040517f49948e0e00000000000000000000000000000000000000000000000000000000815273420000000000000000000000000000000000000f906349948e0e90613a1b9084906004016142a0565b602060405180830381865afa158015613a38573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613a5c9190614a67565b915050613bbe565b60017f00000000000000000000000000000000000000000000000000000000000000006002811115613a9857613a9861436a565b03613bbe578415613b1a57606c73ffffffffffffffffffffffffffffffffffffffff1663c6f7de0e6040518163ffffffff1660e01b8152600401602060405180830381865afa158015613aef573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613b139190614a67565b9050613bbe565b6000606c73ffffffffffffffffffffffffffffffffffffffff166341b247a86040518163ffffffff1660e01b815260040160c060405180830381865afa158015613b68573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613b8c9190614bdb565b5050601554929450613baf93505050640100000000900463ffffffff1682614b3b565b613bba906010614b3b565b9150505b84613bda57808b6080015161ffff16613bd79190614b3b565b90505b613be861ffff871682614c25565b905060008782613bf88c8e614629565b613c029086614b3b565b613c0c9190614629565b613c1e90670de0b6b3a7640000614b3b565b613c289190614c25565b905060008c6040015163ffffffff1664e8d4a51000613c479190614b3b565b898e6020015163ffffffff16858f88613c609190614b3b565b613c6a9190614629565b613c7890633b9aca00614b3b565b613c829190614b3b565b613c8c9190614c25565b613c969190614629565b90506b033b2e3c9fd0803ce8000000613caf8284614629565b1115613ce7576040517f2ad7547a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b909c909b509950505050505050505050565b60008181526001830160205260408120548015613de2576000613d1d60018361463c565b8554909150600090613d319060019061463c565b9050818114613d96576000866000018281548110613d5157613d5161467e565b9060005260206000200154905080876000018481548110613d7457613d7461467e565b6000918252602080832090910192909255918252600188019052604090208390555b8554869080613da757613da7614c39565b6001900381819060005260206000200160009055905585600101600086815260200190815260200160002060009055600193505050506109ea565b60009150506109ea565b5092915050565b60008060408385031215613e0657600080fd5b50508035926020909101359150565b6020808252825182820181905260009190848201906040850190845b81811015613e4d57835183529284019291840191600101613e31565b50909695505050505050565b60008083601f840112613e6b57600080fd5b50813567ffffffffffffffff811115613e8357600080fd5b602083019150836020828501011115613e9b57600080fd5b9250929050565b600080600060408486031215613eb757600080fd5b83359250602084013567ffffffffffffffff811115613ed557600080fd5b613ee186828701613e59565b9497909650939450505050565b600081518084526020808501945080840160005b83811015613f3457815173ffffffffffffffffffffffffffffffffffffffff1687529582019590820190600101613f02565b509495945050505050565b805163ffffffff16825260006101e06020830151613f65602086018263ffffffff169052565b506040830151613f7d604086018263ffffffff169052565b506060830151613f94606086018262ffffff169052565b506080830151613faa608086018261ffff169052565b5060a0830151613fca60a08601826bffffffffffffffffffffffff169052565b5060c0830151613fe260c086018263ffffffff169052565b5060e0830151613ffa60e086018263ffffffff169052565b506101008381015163ffffffff908116918601919091526101208085015190911690850152610140808401519085015261016080840151908501526101808084015173ffffffffffffffffffffffffffffffffffffffff16908501526101a08084015181860183905261406f83870182613eee565b925050506101c08084015161409b8287018273ffffffffffffffffffffffffffffffffffffffff169052565b5090949350505050565b855163ffffffff16815260006101c060208801516140d360208501826bffffffffffffffffffffffff169052565b506040880151604084015260608801516140fd60608501826bffffffffffffffffffffffff169052565b506080880151608084015260a088015161411f60a085018263ffffffff169052565b5060c088015161413760c085018263ffffffff169052565b5060e088015160e08401526101008089015161415a8286018263ffffffff169052565b505061012088810151151590840152610140830181905261417d81840188613f3f565b90508281036101608401526141928187613eee565b90508281036101808401526141a78186613eee565b9150506117926101a083018460ff169052565b73ffffffffffffffffffffffffffffffffffffffff81168114612f0857600080fd5b600080604083850312156141ef57600080fd5b82356141fa816141ba565b915060208301356004811061420e57600080fd5b809150509250929050565b60006020828403121561422b57600080fd5b5035919050565b60005b8381101561424d578181015183820152602001614235565b50506000910152565b6000815180845261426e816020860160208601614232565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b602081526000612f216020830184614256565b600080604083850312156142c657600080fd5b82359150602083013561420e816141ba565b600080602083850312156142eb57600080fd5b823567ffffffffffffffff8082111561430357600080fd5b818501915085601f83011261431757600080fd5b81358181111561432657600080fd5b8660208260051b850101111561433b57600080fd5b60209290920196919550909350505050565b60006020828403121561435f57600080fd5b8135612f21816141ba565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b60038110612f0857612f0861436a565b602081016143b683614399565b91905290565b60208101600283106143b6576143b661436a565b803563ffffffff811681146143e457600080fd5b919050565b600080604083850312156143fc57600080fd5b82356002811061440b57600080fd5b9150614419602084016143d0565b90509250929050565b60008060006040848603121561443757600080fd5b8335614442816141ba565b9250602084013567ffffffffffffffff811115613ed557600080fd5b6000806040838503121561447157600080fd5b823561447c816141ba565b9150602083013561420e816141ba565b6000806040838503121561449f57600080fd5b82359150614419602084016143d0565b602081526144d660208201835173ffffffffffffffffffffffffffffffffffffffff169052565b600060208301516144ef604084018263ffffffff169052565b50604083015161014080606085015261450c610160850183614256565b9150606085015161452d60808601826bffffffffffffffffffffffff169052565b50608085015173ffffffffffffffffffffffffffffffffffffffff811660a08601525060a085015167ffffffffffffffff811660c08601525060c085015163ffffffff811660e08601525060e0850151610100614599818701836bffffffffffffffffffffffff169052565b86015190506101206145ae8682018315159052565b8601518584037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0018387015290506117928382614256565b60208101600483106143b6576143b661436a565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b808201808211156109ea576109ea6145fa565b818103818111156109ea576109ea6145fa565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82036146de576146de6145fa565b5060010190565b600181811c908216806146f957607f821691505b602082108103614732577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b50919050565b601f82111561478257600081815260208120601f850160051c8101602086101561475f5750805b601f850160051c820191505b8181101561477e5782815560010161476b565b5050505b505050565b67ffffffffffffffff83111561479f5761479f61464f565b6147b3836147ad83546146e5565b83614738565b6000601f84116001811461480557600085156147cf5750838201355b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600387901b1c1916600186901b17835561489b565b6000838152602090207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0861690835b828110156148545786850135825560209485019460019092019101614834565b508682101561488f577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60f88860031b161c19848701351681555b505060018560011b0183555b5050505050565b60208152816020820152818360408301376000818301604090810191909152601f9092017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0160101919050565b6000604082016040835280865480835260608501915087600052602092508260002060005b8281101561494657815473ffffffffffffffffffffffffffffffffffffffff1684529284019260019182019101614914565b505050838103828501528481528590820160005b8681101561499557823561496d816141ba565b73ffffffffffffffffffffffffffffffffffffffff168252918301919083019060010161495a565b50979650505050505050565b6bffffffffffffffffffffffff828116828216039080821115613dec57613dec6145fa565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b60006bffffffffffffffffffffffff80841680614a1457614a146149c6565b92169190910492915050565b6bffffffffffffffffffffffff818116838216019080821115613dec57613dec6145fa565b600060208284031215614a5757600080fd5b81518015158114612f2157600080fd5b600060208284031215614a7957600080fd5b5051919050565b600060208284031215614a9257600080fd5b8151612f21816141ba565b805169ffffffffffffffffffff811681146143e457600080fd5b600080600080600060a08688031215614acf57600080fd5b614ad886614a9d565b9450602086015193506040860151925060608601519150614afb60808701614a9d565b90509295509295909350565b60006bffffffffffffffffffffffff80831681851681830481118215151615614b3257614b326145fa565b02949350505050565b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0483118215151615614b7357614b736145fa565b500290565b60ff81811683821601908111156109ea576109ea6145fa565b828482376000838201600081528351614bae818360208801614232565b0195945050505050565b600063ffffffff80831681851681830481118215151615614b3257614b326145fa565b60008060008060008060c08789031215614bf457600080fd5b865195506020870151945060408701519350606087015192506080870151915060a087015190509295509295509295565b600082614c3457614c346149c6565b500490565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fdfe307866666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666a164736f6c6343000810000a", +} + +var AutomationRegistryLogicBABI = AutomationRegistryLogicBMetaData.ABI + +var AutomationRegistryLogicBBin = AutomationRegistryLogicBMetaData.Bin + +func DeployAutomationRegistryLogicB(auth *bind.TransactOpts, backend bind.ContractBackend, mode uint8, link common.Address, linkNativeFeed common.Address, fastGasFeed common.Address, automationForwarderLogic common.Address) (common.Address, *types.Transaction, *AutomationRegistryLogicB, error) { + parsed, err := AutomationRegistryLogicBMetaData.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(AutomationRegistryLogicBBin), backend, mode, link, linkNativeFeed, fastGasFeed, automationForwarderLogic) + if err != nil { + return common.Address{}, nil, nil, err + } + return address, tx, &AutomationRegistryLogicB{address: address, abi: *parsed, AutomationRegistryLogicBCaller: AutomationRegistryLogicBCaller{contract: contract}, AutomationRegistryLogicBTransactor: AutomationRegistryLogicBTransactor{contract: contract}, AutomationRegistryLogicBFilterer: AutomationRegistryLogicBFilterer{contract: contract}}, nil +} + +type AutomationRegistryLogicB struct { + address common.Address + abi abi.ABI + AutomationRegistryLogicBCaller + AutomationRegistryLogicBTransactor + AutomationRegistryLogicBFilterer +} + +type AutomationRegistryLogicBCaller struct { + contract *bind.BoundContract +} + +type AutomationRegistryLogicBTransactor struct { + contract *bind.BoundContract +} + +type AutomationRegistryLogicBFilterer struct { + contract *bind.BoundContract +} + +type AutomationRegistryLogicBSession struct { + Contract *AutomationRegistryLogicB + CallOpts bind.CallOpts + TransactOpts bind.TransactOpts +} + +type AutomationRegistryLogicBCallerSession struct { + Contract *AutomationRegistryLogicBCaller + CallOpts bind.CallOpts +} + +type AutomationRegistryLogicBTransactorSession struct { + Contract *AutomationRegistryLogicBTransactor + TransactOpts bind.TransactOpts +} + +type AutomationRegistryLogicBRaw struct { + Contract *AutomationRegistryLogicB +} + +type AutomationRegistryLogicBCallerRaw struct { + Contract *AutomationRegistryLogicBCaller +} + +type AutomationRegistryLogicBTransactorRaw struct { + Contract *AutomationRegistryLogicBTransactor +} + +func NewAutomationRegistryLogicB(address common.Address, backend bind.ContractBackend) (*AutomationRegistryLogicB, error) { + abi, err := abi.JSON(strings.NewReader(AutomationRegistryLogicBABI)) + if err != nil { + return nil, err + } + contract, err := bindAutomationRegistryLogicB(address, backend, backend, backend) + if err != nil { + return nil, err + } + return &AutomationRegistryLogicB{address: address, abi: abi, AutomationRegistryLogicBCaller: AutomationRegistryLogicBCaller{contract: contract}, AutomationRegistryLogicBTransactor: AutomationRegistryLogicBTransactor{contract: contract}, AutomationRegistryLogicBFilterer: AutomationRegistryLogicBFilterer{contract: contract}}, nil +} + +func NewAutomationRegistryLogicBCaller(address common.Address, caller bind.ContractCaller) (*AutomationRegistryLogicBCaller, error) { + contract, err := bindAutomationRegistryLogicB(address, caller, nil, nil) + if err != nil { + return nil, err + } + return &AutomationRegistryLogicBCaller{contract: contract}, nil +} + +func NewAutomationRegistryLogicBTransactor(address common.Address, transactor bind.ContractTransactor) (*AutomationRegistryLogicBTransactor, error) { + contract, err := bindAutomationRegistryLogicB(address, nil, transactor, nil) + if err != nil { + return nil, err + } + return &AutomationRegistryLogicBTransactor{contract: contract}, nil +} + +func NewAutomationRegistryLogicBFilterer(address common.Address, filterer bind.ContractFilterer) (*AutomationRegistryLogicBFilterer, error) { + contract, err := bindAutomationRegistryLogicB(address, nil, nil, filterer) + if err != nil { + return nil, err + } + return &AutomationRegistryLogicBFilterer{contract: contract}, nil +} + +func bindAutomationRegistryLogicB(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) { + parsed, err := AutomationRegistryLogicBMetaData.GetAbi() + if err != nil { + return nil, err + } + return bind.NewBoundContract(address, *parsed, caller, transactor, filterer), nil +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _AutomationRegistryLogicB.Contract.AutomationRegistryLogicBCaller.contract.Call(opts, result, method, params...) +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _AutomationRegistryLogicB.Contract.AutomationRegistryLogicBTransactor.contract.Transfer(opts) +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _AutomationRegistryLogicB.Contract.AutomationRegistryLogicBTransactor.contract.Transact(opts, method, params...) +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _AutomationRegistryLogicB.Contract.contract.Call(opts, result, method, params...) +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _AutomationRegistryLogicB.Contract.contract.Transfer(opts) +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _AutomationRegistryLogicB.Contract.contract.Transact(opts, method, params...) +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBCaller) GetActiveUpkeepIDs(opts *bind.CallOpts, startIndex *big.Int, maxCount *big.Int) ([]*big.Int, error) { + var out []interface{} + err := _AutomationRegistryLogicB.contract.Call(opts, &out, "getActiveUpkeepIDs", startIndex, maxCount) + + if err != nil { + return *new([]*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new([]*big.Int)).(*[]*big.Int) + + return out0, err + +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBSession) GetActiveUpkeepIDs(startIndex *big.Int, maxCount *big.Int) ([]*big.Int, error) { + return _AutomationRegistryLogicB.Contract.GetActiveUpkeepIDs(&_AutomationRegistryLogicB.CallOpts, startIndex, maxCount) +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBCallerSession) GetActiveUpkeepIDs(startIndex *big.Int, maxCount *big.Int) ([]*big.Int, error) { + return _AutomationRegistryLogicB.Contract.GetActiveUpkeepIDs(&_AutomationRegistryLogicB.CallOpts, startIndex, maxCount) +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBCaller) GetAdminPrivilegeConfig(opts *bind.CallOpts, admin common.Address) ([]byte, error) { + var out []interface{} + err := _AutomationRegistryLogicB.contract.Call(opts, &out, "getAdminPrivilegeConfig", admin) + + if err != nil { + return *new([]byte), err + } + + out0 := *abi.ConvertType(out[0], new([]byte)).(*[]byte) + + return out0, err + +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBSession) GetAdminPrivilegeConfig(admin common.Address) ([]byte, error) { + return _AutomationRegistryLogicB.Contract.GetAdminPrivilegeConfig(&_AutomationRegistryLogicB.CallOpts, admin) +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBCallerSession) GetAdminPrivilegeConfig(admin common.Address) ([]byte, error) { + return _AutomationRegistryLogicB.Contract.GetAdminPrivilegeConfig(&_AutomationRegistryLogicB.CallOpts, admin) +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBCaller) GetAutomationForwarderLogic(opts *bind.CallOpts) (common.Address, error) { + var out []interface{} + err := _AutomationRegistryLogicB.contract.Call(opts, &out, "getAutomationForwarderLogic") + + if err != nil { + return *new(common.Address), err + } + + out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) + + return out0, err + +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBSession) GetAutomationForwarderLogic() (common.Address, error) { + return _AutomationRegistryLogicB.Contract.GetAutomationForwarderLogic(&_AutomationRegistryLogicB.CallOpts) +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBCallerSession) GetAutomationForwarderLogic() (common.Address, error) { + return _AutomationRegistryLogicB.Contract.GetAutomationForwarderLogic(&_AutomationRegistryLogicB.CallOpts) +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBCaller) GetBalance(opts *bind.CallOpts, id *big.Int) (*big.Int, error) { + var out []interface{} + err := _AutomationRegistryLogicB.contract.Call(opts, &out, "getBalance", id) + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBSession) GetBalance(id *big.Int) (*big.Int, error) { + return _AutomationRegistryLogicB.Contract.GetBalance(&_AutomationRegistryLogicB.CallOpts, id) +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBCallerSession) GetBalance(id *big.Int) (*big.Int, error) { + return _AutomationRegistryLogicB.Contract.GetBalance(&_AutomationRegistryLogicB.CallOpts, id) +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBCaller) GetCancellationDelay(opts *bind.CallOpts) (*big.Int, error) { + var out []interface{} + err := _AutomationRegistryLogicB.contract.Call(opts, &out, "getCancellationDelay") + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBSession) GetCancellationDelay() (*big.Int, error) { + return _AutomationRegistryLogicB.Contract.GetCancellationDelay(&_AutomationRegistryLogicB.CallOpts) +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBCallerSession) GetCancellationDelay() (*big.Int, error) { + return _AutomationRegistryLogicB.Contract.GetCancellationDelay(&_AutomationRegistryLogicB.CallOpts) +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBCaller) GetConditionalGasOverhead(opts *bind.CallOpts) (*big.Int, error) { + var out []interface{} + err := _AutomationRegistryLogicB.contract.Call(opts, &out, "getConditionalGasOverhead") + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBSession) GetConditionalGasOverhead() (*big.Int, error) { + return _AutomationRegistryLogicB.Contract.GetConditionalGasOverhead(&_AutomationRegistryLogicB.CallOpts) +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBCallerSession) GetConditionalGasOverhead() (*big.Int, error) { + return _AutomationRegistryLogicB.Contract.GetConditionalGasOverhead(&_AutomationRegistryLogicB.CallOpts) +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBCaller) GetFastGasFeedAddress(opts *bind.CallOpts) (common.Address, error) { + var out []interface{} + err := _AutomationRegistryLogicB.contract.Call(opts, &out, "getFastGasFeedAddress") + + if err != nil { + return *new(common.Address), err + } + + out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) + + return out0, err + +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBSession) GetFastGasFeedAddress() (common.Address, error) { + return _AutomationRegistryLogicB.Contract.GetFastGasFeedAddress(&_AutomationRegistryLogicB.CallOpts) +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBCallerSession) GetFastGasFeedAddress() (common.Address, error) { + return _AutomationRegistryLogicB.Contract.GetFastGasFeedAddress(&_AutomationRegistryLogicB.CallOpts) +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBCaller) GetForwarder(opts *bind.CallOpts, upkeepID *big.Int) (common.Address, error) { + var out []interface{} + err := _AutomationRegistryLogicB.contract.Call(opts, &out, "getForwarder", upkeepID) + + if err != nil { + return *new(common.Address), err + } + + out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) + + return out0, err + +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBSession) GetForwarder(upkeepID *big.Int) (common.Address, error) { + return _AutomationRegistryLogicB.Contract.GetForwarder(&_AutomationRegistryLogicB.CallOpts, upkeepID) +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBCallerSession) GetForwarder(upkeepID *big.Int) (common.Address, error) { + return _AutomationRegistryLogicB.Contract.GetForwarder(&_AutomationRegistryLogicB.CallOpts, upkeepID) +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBCaller) GetLinkAddress(opts *bind.CallOpts) (common.Address, error) { + var out []interface{} + err := _AutomationRegistryLogicB.contract.Call(opts, &out, "getLinkAddress") + + if err != nil { + return *new(common.Address), err + } + + out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) + + return out0, err + +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBSession) GetLinkAddress() (common.Address, error) { + return _AutomationRegistryLogicB.Contract.GetLinkAddress(&_AutomationRegistryLogicB.CallOpts) +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBCallerSession) GetLinkAddress() (common.Address, error) { + return _AutomationRegistryLogicB.Contract.GetLinkAddress(&_AutomationRegistryLogicB.CallOpts) +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBCaller) GetLinkNativeFeedAddress(opts *bind.CallOpts) (common.Address, error) { + var out []interface{} + err := _AutomationRegistryLogicB.contract.Call(opts, &out, "getLinkNativeFeedAddress") + + if err != nil { + return *new(common.Address), err + } + + out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) + + return out0, err + +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBSession) GetLinkNativeFeedAddress() (common.Address, error) { + return _AutomationRegistryLogicB.Contract.GetLinkNativeFeedAddress(&_AutomationRegistryLogicB.CallOpts) +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBCallerSession) GetLinkNativeFeedAddress() (common.Address, error) { + return _AutomationRegistryLogicB.Contract.GetLinkNativeFeedAddress(&_AutomationRegistryLogicB.CallOpts) +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBCaller) GetLogGasOverhead(opts *bind.CallOpts) (*big.Int, error) { + var out []interface{} + err := _AutomationRegistryLogicB.contract.Call(opts, &out, "getLogGasOverhead") + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBSession) GetLogGasOverhead() (*big.Int, error) { + return _AutomationRegistryLogicB.Contract.GetLogGasOverhead(&_AutomationRegistryLogicB.CallOpts) +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBCallerSession) GetLogGasOverhead() (*big.Int, error) { + return _AutomationRegistryLogicB.Contract.GetLogGasOverhead(&_AutomationRegistryLogicB.CallOpts) +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBCaller) GetMaxPaymentForGas(opts *bind.CallOpts, triggerType uint8, gasLimit uint32) (*big.Int, error) { + var out []interface{} + err := _AutomationRegistryLogicB.contract.Call(opts, &out, "getMaxPaymentForGas", triggerType, gasLimit) + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBSession) GetMaxPaymentForGas(triggerType uint8, gasLimit uint32) (*big.Int, error) { + return _AutomationRegistryLogicB.Contract.GetMaxPaymentForGas(&_AutomationRegistryLogicB.CallOpts, triggerType, gasLimit) +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBCallerSession) GetMaxPaymentForGas(triggerType uint8, gasLimit uint32) (*big.Int, error) { + return _AutomationRegistryLogicB.Contract.GetMaxPaymentForGas(&_AutomationRegistryLogicB.CallOpts, triggerType, gasLimit) +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBCaller) GetMinBalance(opts *bind.CallOpts, id *big.Int) (*big.Int, error) { + var out []interface{} + err := _AutomationRegistryLogicB.contract.Call(opts, &out, "getMinBalance", id) + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBSession) GetMinBalance(id *big.Int) (*big.Int, error) { + return _AutomationRegistryLogicB.Contract.GetMinBalance(&_AutomationRegistryLogicB.CallOpts, id) +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBCallerSession) GetMinBalance(id *big.Int) (*big.Int, error) { + return _AutomationRegistryLogicB.Contract.GetMinBalance(&_AutomationRegistryLogicB.CallOpts, id) +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBCaller) GetMinBalanceForUpkeep(opts *bind.CallOpts, id *big.Int) (*big.Int, error) { + var out []interface{} + err := _AutomationRegistryLogicB.contract.Call(opts, &out, "getMinBalanceForUpkeep", id) + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBSession) GetMinBalanceForUpkeep(id *big.Int) (*big.Int, error) { + return _AutomationRegistryLogicB.Contract.GetMinBalanceForUpkeep(&_AutomationRegistryLogicB.CallOpts, id) +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBCallerSession) GetMinBalanceForUpkeep(id *big.Int) (*big.Int, error) { + return _AutomationRegistryLogicB.Contract.GetMinBalanceForUpkeep(&_AutomationRegistryLogicB.CallOpts, id) +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBCaller) GetMode(opts *bind.CallOpts) (uint8, error) { + var out []interface{} + err := _AutomationRegistryLogicB.contract.Call(opts, &out, "getMode") + + if err != nil { + return *new(uint8), err + } + + out0 := *abi.ConvertType(out[0], new(uint8)).(*uint8) + + return out0, err + +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBSession) GetMode() (uint8, error) { + return _AutomationRegistryLogicB.Contract.GetMode(&_AutomationRegistryLogicB.CallOpts) +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBCallerSession) GetMode() (uint8, error) { + return _AutomationRegistryLogicB.Contract.GetMode(&_AutomationRegistryLogicB.CallOpts) +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBCaller) GetPeerRegistryMigrationPermission(opts *bind.CallOpts, peer common.Address) (uint8, error) { + var out []interface{} + err := _AutomationRegistryLogicB.contract.Call(opts, &out, "getPeerRegistryMigrationPermission", peer) + + if err != nil { + return *new(uint8), err + } + + out0 := *abi.ConvertType(out[0], new(uint8)).(*uint8) + + return out0, err + +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBSession) GetPeerRegistryMigrationPermission(peer common.Address) (uint8, error) { + return _AutomationRegistryLogicB.Contract.GetPeerRegistryMigrationPermission(&_AutomationRegistryLogicB.CallOpts, peer) +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBCallerSession) GetPeerRegistryMigrationPermission(peer common.Address) (uint8, error) { + return _AutomationRegistryLogicB.Contract.GetPeerRegistryMigrationPermission(&_AutomationRegistryLogicB.CallOpts, peer) +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBCaller) GetPerPerformByteGasOverhead(opts *bind.CallOpts) (*big.Int, error) { + var out []interface{} + err := _AutomationRegistryLogicB.contract.Call(opts, &out, "getPerPerformByteGasOverhead") + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBSession) GetPerPerformByteGasOverhead() (*big.Int, error) { + return _AutomationRegistryLogicB.Contract.GetPerPerformByteGasOverhead(&_AutomationRegistryLogicB.CallOpts) +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBCallerSession) GetPerPerformByteGasOverhead() (*big.Int, error) { + return _AutomationRegistryLogicB.Contract.GetPerPerformByteGasOverhead(&_AutomationRegistryLogicB.CallOpts) +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBCaller) GetPerSignerGasOverhead(opts *bind.CallOpts) (*big.Int, error) { + var out []interface{} + err := _AutomationRegistryLogicB.contract.Call(opts, &out, "getPerSignerGasOverhead") + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBSession) GetPerSignerGasOverhead() (*big.Int, error) { + return _AutomationRegistryLogicB.Contract.GetPerSignerGasOverhead(&_AutomationRegistryLogicB.CallOpts) +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBCallerSession) GetPerSignerGasOverhead() (*big.Int, error) { + return _AutomationRegistryLogicB.Contract.GetPerSignerGasOverhead(&_AutomationRegistryLogicB.CallOpts) +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBCaller) GetSignerInfo(opts *bind.CallOpts, query common.Address) (GetSignerInfo, + + error) { + var out []interface{} + err := _AutomationRegistryLogicB.contract.Call(opts, &out, "getSignerInfo", query) + + outstruct := new(GetSignerInfo) + if err != nil { + return *outstruct, err + } + + outstruct.Active = *abi.ConvertType(out[0], new(bool)).(*bool) + outstruct.Index = *abi.ConvertType(out[1], new(uint8)).(*uint8) + + return *outstruct, err + +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBSession) GetSignerInfo(query common.Address) (GetSignerInfo, + + error) { + return _AutomationRegistryLogicB.Contract.GetSignerInfo(&_AutomationRegistryLogicB.CallOpts, query) +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBCallerSession) GetSignerInfo(query common.Address) (GetSignerInfo, + + error) { + return _AutomationRegistryLogicB.Contract.GetSignerInfo(&_AutomationRegistryLogicB.CallOpts, query) +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBCaller) GetState(opts *bind.CallOpts) (GetState, + + error) { + var out []interface{} + err := _AutomationRegistryLogicB.contract.Call(opts, &out, "getState") + + outstruct := new(GetState) + if err != nil { + return *outstruct, err + } + + outstruct.State = *abi.ConvertType(out[0], new(AutomationRegistryBase22State)).(*AutomationRegistryBase22State) + outstruct.Config = *abi.ConvertType(out[1], new(AutomationRegistryBase22OnchainConfig)).(*AutomationRegistryBase22OnchainConfig) + outstruct.Signers = *abi.ConvertType(out[2], new([]common.Address)).(*[]common.Address) + outstruct.Transmitters = *abi.ConvertType(out[3], new([]common.Address)).(*[]common.Address) + outstruct.F = *abi.ConvertType(out[4], new(uint8)).(*uint8) + + return *outstruct, err + +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBSession) GetState() (GetState, + + error) { + return _AutomationRegistryLogicB.Contract.GetState(&_AutomationRegistryLogicB.CallOpts) +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBCallerSession) GetState() (GetState, + + error) { + return _AutomationRegistryLogicB.Contract.GetState(&_AutomationRegistryLogicB.CallOpts) +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBCaller) GetTransmitterInfo(opts *bind.CallOpts, query common.Address) (GetTransmitterInfo, + + error) { + var out []interface{} + err := _AutomationRegistryLogicB.contract.Call(opts, &out, "getTransmitterInfo", query) + + outstruct := new(GetTransmitterInfo) + if err != nil { + return *outstruct, err + } + + outstruct.Active = *abi.ConvertType(out[0], new(bool)).(*bool) + outstruct.Index = *abi.ConvertType(out[1], new(uint8)).(*uint8) + outstruct.Balance = *abi.ConvertType(out[2], new(*big.Int)).(**big.Int) + outstruct.LastCollected = *abi.ConvertType(out[3], new(*big.Int)).(**big.Int) + outstruct.Payee = *abi.ConvertType(out[4], new(common.Address)).(*common.Address) + + return *outstruct, err + +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBSession) GetTransmitterInfo(query common.Address) (GetTransmitterInfo, + + error) { + return _AutomationRegistryLogicB.Contract.GetTransmitterInfo(&_AutomationRegistryLogicB.CallOpts, query) +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBCallerSession) GetTransmitterInfo(query common.Address) (GetTransmitterInfo, + + error) { + return _AutomationRegistryLogicB.Contract.GetTransmitterInfo(&_AutomationRegistryLogicB.CallOpts, query) +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBCaller) GetTriggerType(opts *bind.CallOpts, upkeepId *big.Int) (uint8, error) { + var out []interface{} + err := _AutomationRegistryLogicB.contract.Call(opts, &out, "getTriggerType", upkeepId) + + if err != nil { + return *new(uint8), err + } + + out0 := *abi.ConvertType(out[0], new(uint8)).(*uint8) + + return out0, err + +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBSession) GetTriggerType(upkeepId *big.Int) (uint8, error) { + return _AutomationRegistryLogicB.Contract.GetTriggerType(&_AutomationRegistryLogicB.CallOpts, upkeepId) +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBCallerSession) GetTriggerType(upkeepId *big.Int) (uint8, error) { + return _AutomationRegistryLogicB.Contract.GetTriggerType(&_AutomationRegistryLogicB.CallOpts, upkeepId) +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBCaller) GetUpkeep(opts *bind.CallOpts, id *big.Int) (AutomationRegistryBase22UpkeepInfo, error) { + var out []interface{} + err := _AutomationRegistryLogicB.contract.Call(opts, &out, "getUpkeep", id) + + if err != nil { + return *new(AutomationRegistryBase22UpkeepInfo), err + } + + out0 := *abi.ConvertType(out[0], new(AutomationRegistryBase22UpkeepInfo)).(*AutomationRegistryBase22UpkeepInfo) + + return out0, err + +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBSession) GetUpkeep(id *big.Int) (AutomationRegistryBase22UpkeepInfo, error) { + return _AutomationRegistryLogicB.Contract.GetUpkeep(&_AutomationRegistryLogicB.CallOpts, id) +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBCallerSession) GetUpkeep(id *big.Int) (AutomationRegistryBase22UpkeepInfo, error) { + return _AutomationRegistryLogicB.Contract.GetUpkeep(&_AutomationRegistryLogicB.CallOpts, id) +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBCaller) GetUpkeepPrivilegeConfig(opts *bind.CallOpts, upkeepId *big.Int) ([]byte, error) { + var out []interface{} + err := _AutomationRegistryLogicB.contract.Call(opts, &out, "getUpkeepPrivilegeConfig", upkeepId) + + if err != nil { + return *new([]byte), err + } + + out0 := *abi.ConvertType(out[0], new([]byte)).(*[]byte) + + return out0, err + +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBSession) GetUpkeepPrivilegeConfig(upkeepId *big.Int) ([]byte, error) { + return _AutomationRegistryLogicB.Contract.GetUpkeepPrivilegeConfig(&_AutomationRegistryLogicB.CallOpts, upkeepId) +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBCallerSession) GetUpkeepPrivilegeConfig(upkeepId *big.Int) ([]byte, error) { + return _AutomationRegistryLogicB.Contract.GetUpkeepPrivilegeConfig(&_AutomationRegistryLogicB.CallOpts, upkeepId) +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBCaller) GetUpkeepTriggerConfig(opts *bind.CallOpts, upkeepId *big.Int) ([]byte, error) { + var out []interface{} + err := _AutomationRegistryLogicB.contract.Call(opts, &out, "getUpkeepTriggerConfig", upkeepId) + + if err != nil { + return *new([]byte), err + } + + out0 := *abi.ConvertType(out[0], new([]byte)).(*[]byte) + + return out0, err + +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBSession) GetUpkeepTriggerConfig(upkeepId *big.Int) ([]byte, error) { + return _AutomationRegistryLogicB.Contract.GetUpkeepTriggerConfig(&_AutomationRegistryLogicB.CallOpts, upkeepId) +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBCallerSession) GetUpkeepTriggerConfig(upkeepId *big.Int) ([]byte, error) { + return _AutomationRegistryLogicB.Contract.GetUpkeepTriggerConfig(&_AutomationRegistryLogicB.CallOpts, upkeepId) +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBCaller) HasDedupKey(opts *bind.CallOpts, dedupKey [32]byte) (bool, error) { + var out []interface{} + err := _AutomationRegistryLogicB.contract.Call(opts, &out, "hasDedupKey", dedupKey) + + if err != nil { + return *new(bool), err + } + + out0 := *abi.ConvertType(out[0], new(bool)).(*bool) + + return out0, err + +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBSession) HasDedupKey(dedupKey [32]byte) (bool, error) { + return _AutomationRegistryLogicB.Contract.HasDedupKey(&_AutomationRegistryLogicB.CallOpts, dedupKey) +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBCallerSession) HasDedupKey(dedupKey [32]byte) (bool, error) { + return _AutomationRegistryLogicB.Contract.HasDedupKey(&_AutomationRegistryLogicB.CallOpts, dedupKey) +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBCaller) Owner(opts *bind.CallOpts) (common.Address, error) { + var out []interface{} + err := _AutomationRegistryLogicB.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 (_AutomationRegistryLogicB *AutomationRegistryLogicBSession) Owner() (common.Address, error) { + return _AutomationRegistryLogicB.Contract.Owner(&_AutomationRegistryLogicB.CallOpts) +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBCallerSession) Owner() (common.Address, error) { + return _AutomationRegistryLogicB.Contract.Owner(&_AutomationRegistryLogicB.CallOpts) +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBCaller) UpkeepTranscoderVersion(opts *bind.CallOpts) (uint8, error) { + var out []interface{} + err := _AutomationRegistryLogicB.contract.Call(opts, &out, "upkeepTranscoderVersion") + + if err != nil { + return *new(uint8), err + } + + out0 := *abi.ConvertType(out[0], new(uint8)).(*uint8) + + return out0, err + +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBSession) UpkeepTranscoderVersion() (uint8, error) { + return _AutomationRegistryLogicB.Contract.UpkeepTranscoderVersion(&_AutomationRegistryLogicB.CallOpts) +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBCallerSession) UpkeepTranscoderVersion() (uint8, error) { + return _AutomationRegistryLogicB.Contract.UpkeepTranscoderVersion(&_AutomationRegistryLogicB.CallOpts) +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBCaller) UpkeepVersion(opts *bind.CallOpts) (uint8, error) { + var out []interface{} + err := _AutomationRegistryLogicB.contract.Call(opts, &out, "upkeepVersion") + + if err != nil { + return *new(uint8), err + } + + out0 := *abi.ConvertType(out[0], new(uint8)).(*uint8) + + return out0, err + +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBSession) UpkeepVersion() (uint8, error) { + return _AutomationRegistryLogicB.Contract.UpkeepVersion(&_AutomationRegistryLogicB.CallOpts) +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBCallerSession) UpkeepVersion() (uint8, error) { + return _AutomationRegistryLogicB.Contract.UpkeepVersion(&_AutomationRegistryLogicB.CallOpts) +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBTransactor) AcceptOwnership(opts *bind.TransactOpts) (*types.Transaction, error) { + return _AutomationRegistryLogicB.contract.Transact(opts, "acceptOwnership") +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBSession) AcceptOwnership() (*types.Transaction, error) { + return _AutomationRegistryLogicB.Contract.AcceptOwnership(&_AutomationRegistryLogicB.TransactOpts) +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBTransactorSession) AcceptOwnership() (*types.Transaction, error) { + return _AutomationRegistryLogicB.Contract.AcceptOwnership(&_AutomationRegistryLogicB.TransactOpts) +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBTransactor) AcceptPayeeship(opts *bind.TransactOpts, transmitter common.Address) (*types.Transaction, error) { + return _AutomationRegistryLogicB.contract.Transact(opts, "acceptPayeeship", transmitter) +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBSession) AcceptPayeeship(transmitter common.Address) (*types.Transaction, error) { + return _AutomationRegistryLogicB.Contract.AcceptPayeeship(&_AutomationRegistryLogicB.TransactOpts, transmitter) +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBTransactorSession) AcceptPayeeship(transmitter common.Address) (*types.Transaction, error) { + return _AutomationRegistryLogicB.Contract.AcceptPayeeship(&_AutomationRegistryLogicB.TransactOpts, transmitter) +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBTransactor) AcceptUpkeepAdmin(opts *bind.TransactOpts, id *big.Int) (*types.Transaction, error) { + return _AutomationRegistryLogicB.contract.Transact(opts, "acceptUpkeepAdmin", id) +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBSession) AcceptUpkeepAdmin(id *big.Int) (*types.Transaction, error) { + return _AutomationRegistryLogicB.Contract.AcceptUpkeepAdmin(&_AutomationRegistryLogicB.TransactOpts, id) +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBTransactorSession) AcceptUpkeepAdmin(id *big.Int) (*types.Transaction, error) { + return _AutomationRegistryLogicB.Contract.AcceptUpkeepAdmin(&_AutomationRegistryLogicB.TransactOpts, id) +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBTransactor) Pause(opts *bind.TransactOpts) (*types.Transaction, error) { + return _AutomationRegistryLogicB.contract.Transact(opts, "pause") +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBSession) Pause() (*types.Transaction, error) { + return _AutomationRegistryLogicB.Contract.Pause(&_AutomationRegistryLogicB.TransactOpts) +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBTransactorSession) Pause() (*types.Transaction, error) { + return _AutomationRegistryLogicB.Contract.Pause(&_AutomationRegistryLogicB.TransactOpts) +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBTransactor) PauseUpkeep(opts *bind.TransactOpts, id *big.Int) (*types.Transaction, error) { + return _AutomationRegistryLogicB.contract.Transact(opts, "pauseUpkeep", id) +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBSession) PauseUpkeep(id *big.Int) (*types.Transaction, error) { + return _AutomationRegistryLogicB.Contract.PauseUpkeep(&_AutomationRegistryLogicB.TransactOpts, id) +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBTransactorSession) PauseUpkeep(id *big.Int) (*types.Transaction, error) { + return _AutomationRegistryLogicB.Contract.PauseUpkeep(&_AutomationRegistryLogicB.TransactOpts, id) +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBTransactor) RecoverFunds(opts *bind.TransactOpts) (*types.Transaction, error) { + return _AutomationRegistryLogicB.contract.Transact(opts, "recoverFunds") +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBSession) RecoverFunds() (*types.Transaction, error) { + return _AutomationRegistryLogicB.Contract.RecoverFunds(&_AutomationRegistryLogicB.TransactOpts) +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBTransactorSession) RecoverFunds() (*types.Transaction, error) { + return _AutomationRegistryLogicB.Contract.RecoverFunds(&_AutomationRegistryLogicB.TransactOpts) +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBTransactor) SetAdminPrivilegeConfig(opts *bind.TransactOpts, admin common.Address, newPrivilegeConfig []byte) (*types.Transaction, error) { + return _AutomationRegistryLogicB.contract.Transact(opts, "setAdminPrivilegeConfig", admin, newPrivilegeConfig) +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBSession) SetAdminPrivilegeConfig(admin common.Address, newPrivilegeConfig []byte) (*types.Transaction, error) { + return _AutomationRegistryLogicB.Contract.SetAdminPrivilegeConfig(&_AutomationRegistryLogicB.TransactOpts, admin, newPrivilegeConfig) +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBTransactorSession) SetAdminPrivilegeConfig(admin common.Address, newPrivilegeConfig []byte) (*types.Transaction, error) { + return _AutomationRegistryLogicB.Contract.SetAdminPrivilegeConfig(&_AutomationRegistryLogicB.TransactOpts, admin, newPrivilegeConfig) +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBTransactor) SetPayees(opts *bind.TransactOpts, payees []common.Address) (*types.Transaction, error) { + return _AutomationRegistryLogicB.contract.Transact(opts, "setPayees", payees) +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBSession) SetPayees(payees []common.Address) (*types.Transaction, error) { + return _AutomationRegistryLogicB.Contract.SetPayees(&_AutomationRegistryLogicB.TransactOpts, payees) +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBTransactorSession) SetPayees(payees []common.Address) (*types.Transaction, error) { + return _AutomationRegistryLogicB.Contract.SetPayees(&_AutomationRegistryLogicB.TransactOpts, payees) +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBTransactor) SetPeerRegistryMigrationPermission(opts *bind.TransactOpts, peer common.Address, permission uint8) (*types.Transaction, error) { + return _AutomationRegistryLogicB.contract.Transact(opts, "setPeerRegistryMigrationPermission", peer, permission) +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBSession) SetPeerRegistryMigrationPermission(peer common.Address, permission uint8) (*types.Transaction, error) { + return _AutomationRegistryLogicB.Contract.SetPeerRegistryMigrationPermission(&_AutomationRegistryLogicB.TransactOpts, peer, permission) +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBTransactorSession) SetPeerRegistryMigrationPermission(peer common.Address, permission uint8) (*types.Transaction, error) { + return _AutomationRegistryLogicB.Contract.SetPeerRegistryMigrationPermission(&_AutomationRegistryLogicB.TransactOpts, peer, permission) +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBTransactor) SetUpkeepCheckData(opts *bind.TransactOpts, id *big.Int, newCheckData []byte) (*types.Transaction, error) { + return _AutomationRegistryLogicB.contract.Transact(opts, "setUpkeepCheckData", id, newCheckData) +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBSession) SetUpkeepCheckData(id *big.Int, newCheckData []byte) (*types.Transaction, error) { + return _AutomationRegistryLogicB.Contract.SetUpkeepCheckData(&_AutomationRegistryLogicB.TransactOpts, id, newCheckData) +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBTransactorSession) SetUpkeepCheckData(id *big.Int, newCheckData []byte) (*types.Transaction, error) { + return _AutomationRegistryLogicB.Contract.SetUpkeepCheckData(&_AutomationRegistryLogicB.TransactOpts, id, newCheckData) +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBTransactor) SetUpkeepGasLimit(opts *bind.TransactOpts, id *big.Int, gasLimit uint32) (*types.Transaction, error) { + return _AutomationRegistryLogicB.contract.Transact(opts, "setUpkeepGasLimit", id, gasLimit) +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBSession) SetUpkeepGasLimit(id *big.Int, gasLimit uint32) (*types.Transaction, error) { + return _AutomationRegistryLogicB.Contract.SetUpkeepGasLimit(&_AutomationRegistryLogicB.TransactOpts, id, gasLimit) +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBTransactorSession) SetUpkeepGasLimit(id *big.Int, gasLimit uint32) (*types.Transaction, error) { + return _AutomationRegistryLogicB.Contract.SetUpkeepGasLimit(&_AutomationRegistryLogicB.TransactOpts, id, gasLimit) +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBTransactor) SetUpkeepOffchainConfig(opts *bind.TransactOpts, id *big.Int, config []byte) (*types.Transaction, error) { + return _AutomationRegistryLogicB.contract.Transact(opts, "setUpkeepOffchainConfig", id, config) +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBSession) SetUpkeepOffchainConfig(id *big.Int, config []byte) (*types.Transaction, error) { + return _AutomationRegistryLogicB.Contract.SetUpkeepOffchainConfig(&_AutomationRegistryLogicB.TransactOpts, id, config) +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBTransactorSession) SetUpkeepOffchainConfig(id *big.Int, config []byte) (*types.Transaction, error) { + return _AutomationRegistryLogicB.Contract.SetUpkeepOffchainConfig(&_AutomationRegistryLogicB.TransactOpts, id, config) +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBTransactor) SetUpkeepPrivilegeConfig(opts *bind.TransactOpts, upkeepId *big.Int, newPrivilegeConfig []byte) (*types.Transaction, error) { + return _AutomationRegistryLogicB.contract.Transact(opts, "setUpkeepPrivilegeConfig", upkeepId, newPrivilegeConfig) +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBSession) SetUpkeepPrivilegeConfig(upkeepId *big.Int, newPrivilegeConfig []byte) (*types.Transaction, error) { + return _AutomationRegistryLogicB.Contract.SetUpkeepPrivilegeConfig(&_AutomationRegistryLogicB.TransactOpts, upkeepId, newPrivilegeConfig) +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBTransactorSession) SetUpkeepPrivilegeConfig(upkeepId *big.Int, newPrivilegeConfig []byte) (*types.Transaction, error) { + return _AutomationRegistryLogicB.Contract.SetUpkeepPrivilegeConfig(&_AutomationRegistryLogicB.TransactOpts, upkeepId, newPrivilegeConfig) +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBTransactor) TransferOwnership(opts *bind.TransactOpts, to common.Address) (*types.Transaction, error) { + return _AutomationRegistryLogicB.contract.Transact(opts, "transferOwnership", to) +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBSession) TransferOwnership(to common.Address) (*types.Transaction, error) { + return _AutomationRegistryLogicB.Contract.TransferOwnership(&_AutomationRegistryLogicB.TransactOpts, to) +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBTransactorSession) TransferOwnership(to common.Address) (*types.Transaction, error) { + return _AutomationRegistryLogicB.Contract.TransferOwnership(&_AutomationRegistryLogicB.TransactOpts, to) +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBTransactor) TransferPayeeship(opts *bind.TransactOpts, transmitter common.Address, proposed common.Address) (*types.Transaction, error) { + return _AutomationRegistryLogicB.contract.Transact(opts, "transferPayeeship", transmitter, proposed) +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBSession) TransferPayeeship(transmitter common.Address, proposed common.Address) (*types.Transaction, error) { + return _AutomationRegistryLogicB.Contract.TransferPayeeship(&_AutomationRegistryLogicB.TransactOpts, transmitter, proposed) +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBTransactorSession) TransferPayeeship(transmitter common.Address, proposed common.Address) (*types.Transaction, error) { + return _AutomationRegistryLogicB.Contract.TransferPayeeship(&_AutomationRegistryLogicB.TransactOpts, transmitter, proposed) +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBTransactor) TransferUpkeepAdmin(opts *bind.TransactOpts, id *big.Int, proposed common.Address) (*types.Transaction, error) { + return _AutomationRegistryLogicB.contract.Transact(opts, "transferUpkeepAdmin", id, proposed) +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBSession) TransferUpkeepAdmin(id *big.Int, proposed common.Address) (*types.Transaction, error) { + return _AutomationRegistryLogicB.Contract.TransferUpkeepAdmin(&_AutomationRegistryLogicB.TransactOpts, id, proposed) +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBTransactorSession) TransferUpkeepAdmin(id *big.Int, proposed common.Address) (*types.Transaction, error) { + return _AutomationRegistryLogicB.Contract.TransferUpkeepAdmin(&_AutomationRegistryLogicB.TransactOpts, id, proposed) +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBTransactor) Unpause(opts *bind.TransactOpts) (*types.Transaction, error) { + return _AutomationRegistryLogicB.contract.Transact(opts, "unpause") +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBSession) Unpause() (*types.Transaction, error) { + return _AutomationRegistryLogicB.Contract.Unpause(&_AutomationRegistryLogicB.TransactOpts) +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBTransactorSession) Unpause() (*types.Transaction, error) { + return _AutomationRegistryLogicB.Contract.Unpause(&_AutomationRegistryLogicB.TransactOpts) +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBTransactor) UnpauseUpkeep(opts *bind.TransactOpts, id *big.Int) (*types.Transaction, error) { + return _AutomationRegistryLogicB.contract.Transact(opts, "unpauseUpkeep", id) +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBSession) UnpauseUpkeep(id *big.Int) (*types.Transaction, error) { + return _AutomationRegistryLogicB.Contract.UnpauseUpkeep(&_AutomationRegistryLogicB.TransactOpts, id) +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBTransactorSession) UnpauseUpkeep(id *big.Int) (*types.Transaction, error) { + return _AutomationRegistryLogicB.Contract.UnpauseUpkeep(&_AutomationRegistryLogicB.TransactOpts, id) +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBTransactor) WithdrawFunds(opts *bind.TransactOpts, id *big.Int, to common.Address) (*types.Transaction, error) { + return _AutomationRegistryLogicB.contract.Transact(opts, "withdrawFunds", id, to) +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBSession) WithdrawFunds(id *big.Int, to common.Address) (*types.Transaction, error) { + return _AutomationRegistryLogicB.Contract.WithdrawFunds(&_AutomationRegistryLogicB.TransactOpts, id, to) +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBTransactorSession) WithdrawFunds(id *big.Int, to common.Address) (*types.Transaction, error) { + return _AutomationRegistryLogicB.Contract.WithdrawFunds(&_AutomationRegistryLogicB.TransactOpts, id, to) +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBTransactor) WithdrawOwnerFunds(opts *bind.TransactOpts) (*types.Transaction, error) { + return _AutomationRegistryLogicB.contract.Transact(opts, "withdrawOwnerFunds") +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBSession) WithdrawOwnerFunds() (*types.Transaction, error) { + return _AutomationRegistryLogicB.Contract.WithdrawOwnerFunds(&_AutomationRegistryLogicB.TransactOpts) +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBTransactorSession) WithdrawOwnerFunds() (*types.Transaction, error) { + return _AutomationRegistryLogicB.Contract.WithdrawOwnerFunds(&_AutomationRegistryLogicB.TransactOpts) +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBTransactor) WithdrawPayment(opts *bind.TransactOpts, from common.Address, to common.Address) (*types.Transaction, error) { + return _AutomationRegistryLogicB.contract.Transact(opts, "withdrawPayment", from, to) +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBSession) WithdrawPayment(from common.Address, to common.Address) (*types.Transaction, error) { + return _AutomationRegistryLogicB.Contract.WithdrawPayment(&_AutomationRegistryLogicB.TransactOpts, from, to) +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBTransactorSession) WithdrawPayment(from common.Address, to common.Address) (*types.Transaction, error) { + return _AutomationRegistryLogicB.Contract.WithdrawPayment(&_AutomationRegistryLogicB.TransactOpts, from, to) +} + +type AutomationRegistryLogicBAdminPrivilegeConfigSetIterator struct { + Event *AutomationRegistryLogicBAdminPrivilegeConfigSet + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *AutomationRegistryLogicBAdminPrivilegeConfigSetIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(AutomationRegistryLogicBAdminPrivilegeConfigSet) + 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(AutomationRegistryLogicBAdminPrivilegeConfigSet) + 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 *AutomationRegistryLogicBAdminPrivilegeConfigSetIterator) Error() error { + return it.fail +} + +func (it *AutomationRegistryLogicBAdminPrivilegeConfigSetIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type AutomationRegistryLogicBAdminPrivilegeConfigSet struct { + Admin common.Address + PrivilegeConfig []byte + Raw types.Log +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBFilterer) FilterAdminPrivilegeConfigSet(opts *bind.FilterOpts, admin []common.Address) (*AutomationRegistryLogicBAdminPrivilegeConfigSetIterator, error) { + + var adminRule []interface{} + for _, adminItem := range admin { + adminRule = append(adminRule, adminItem) + } + + logs, sub, err := _AutomationRegistryLogicB.contract.FilterLogs(opts, "AdminPrivilegeConfigSet", adminRule) + if err != nil { + return nil, err + } + return &AutomationRegistryLogicBAdminPrivilegeConfigSetIterator{contract: _AutomationRegistryLogicB.contract, event: "AdminPrivilegeConfigSet", logs: logs, sub: sub}, nil +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBFilterer) WatchAdminPrivilegeConfigSet(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicBAdminPrivilegeConfigSet, admin []common.Address) (event.Subscription, error) { + + var adminRule []interface{} + for _, adminItem := range admin { + adminRule = append(adminRule, adminItem) + } + + logs, sub, err := _AutomationRegistryLogicB.contract.WatchLogs(opts, "AdminPrivilegeConfigSet", adminRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(AutomationRegistryLogicBAdminPrivilegeConfigSet) + if err := _AutomationRegistryLogicB.contract.UnpackLog(event, "AdminPrivilegeConfigSet", 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 (_AutomationRegistryLogicB *AutomationRegistryLogicBFilterer) ParseAdminPrivilegeConfigSet(log types.Log) (*AutomationRegistryLogicBAdminPrivilegeConfigSet, error) { + event := new(AutomationRegistryLogicBAdminPrivilegeConfigSet) + if err := _AutomationRegistryLogicB.contract.UnpackLog(event, "AdminPrivilegeConfigSet", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type AutomationRegistryLogicBCancelledUpkeepReportIterator struct { + Event *AutomationRegistryLogicBCancelledUpkeepReport + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *AutomationRegistryLogicBCancelledUpkeepReportIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(AutomationRegistryLogicBCancelledUpkeepReport) + 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(AutomationRegistryLogicBCancelledUpkeepReport) + 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 *AutomationRegistryLogicBCancelledUpkeepReportIterator) Error() error { + return it.fail +} + +func (it *AutomationRegistryLogicBCancelledUpkeepReportIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type AutomationRegistryLogicBCancelledUpkeepReport struct { + Id *big.Int + Trigger []byte + Raw types.Log +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBFilterer) FilterCancelledUpkeepReport(opts *bind.FilterOpts, id []*big.Int) (*AutomationRegistryLogicBCancelledUpkeepReportIterator, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + + logs, sub, err := _AutomationRegistryLogicB.contract.FilterLogs(opts, "CancelledUpkeepReport", idRule) + if err != nil { + return nil, err + } + return &AutomationRegistryLogicBCancelledUpkeepReportIterator{contract: _AutomationRegistryLogicB.contract, event: "CancelledUpkeepReport", logs: logs, sub: sub}, nil +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBFilterer) WatchCancelledUpkeepReport(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicBCancelledUpkeepReport, id []*big.Int) (event.Subscription, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + + logs, sub, err := _AutomationRegistryLogicB.contract.WatchLogs(opts, "CancelledUpkeepReport", idRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(AutomationRegistryLogicBCancelledUpkeepReport) + if err := _AutomationRegistryLogicB.contract.UnpackLog(event, "CancelledUpkeepReport", 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 (_AutomationRegistryLogicB *AutomationRegistryLogicBFilterer) ParseCancelledUpkeepReport(log types.Log) (*AutomationRegistryLogicBCancelledUpkeepReport, error) { + event := new(AutomationRegistryLogicBCancelledUpkeepReport) + if err := _AutomationRegistryLogicB.contract.UnpackLog(event, "CancelledUpkeepReport", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type AutomationRegistryLogicBDedupKeyAddedIterator struct { + Event *AutomationRegistryLogicBDedupKeyAdded + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *AutomationRegistryLogicBDedupKeyAddedIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(AutomationRegistryLogicBDedupKeyAdded) + 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(AutomationRegistryLogicBDedupKeyAdded) + 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 *AutomationRegistryLogicBDedupKeyAddedIterator) Error() error { + return it.fail +} + +func (it *AutomationRegistryLogicBDedupKeyAddedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type AutomationRegistryLogicBDedupKeyAdded struct { + DedupKey [32]byte + Raw types.Log +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBFilterer) FilterDedupKeyAdded(opts *bind.FilterOpts, dedupKey [][32]byte) (*AutomationRegistryLogicBDedupKeyAddedIterator, error) { + + var dedupKeyRule []interface{} + for _, dedupKeyItem := range dedupKey { + dedupKeyRule = append(dedupKeyRule, dedupKeyItem) + } + + logs, sub, err := _AutomationRegistryLogicB.contract.FilterLogs(opts, "DedupKeyAdded", dedupKeyRule) + if err != nil { + return nil, err + } + return &AutomationRegistryLogicBDedupKeyAddedIterator{contract: _AutomationRegistryLogicB.contract, event: "DedupKeyAdded", logs: logs, sub: sub}, nil +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBFilterer) WatchDedupKeyAdded(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicBDedupKeyAdded, dedupKey [][32]byte) (event.Subscription, error) { + + var dedupKeyRule []interface{} + for _, dedupKeyItem := range dedupKey { + dedupKeyRule = append(dedupKeyRule, dedupKeyItem) + } + + logs, sub, err := _AutomationRegistryLogicB.contract.WatchLogs(opts, "DedupKeyAdded", dedupKeyRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(AutomationRegistryLogicBDedupKeyAdded) + if err := _AutomationRegistryLogicB.contract.UnpackLog(event, "DedupKeyAdded", 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 (_AutomationRegistryLogicB *AutomationRegistryLogicBFilterer) ParseDedupKeyAdded(log types.Log) (*AutomationRegistryLogicBDedupKeyAdded, error) { + event := new(AutomationRegistryLogicBDedupKeyAdded) + if err := _AutomationRegistryLogicB.contract.UnpackLog(event, "DedupKeyAdded", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type AutomationRegistryLogicBFundsAddedIterator struct { + Event *AutomationRegistryLogicBFundsAdded + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *AutomationRegistryLogicBFundsAddedIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(AutomationRegistryLogicBFundsAdded) + 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(AutomationRegistryLogicBFundsAdded) + 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 *AutomationRegistryLogicBFundsAddedIterator) Error() error { + return it.fail +} + +func (it *AutomationRegistryLogicBFundsAddedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type AutomationRegistryLogicBFundsAdded struct { + Id *big.Int + From common.Address + Amount *big.Int + Raw types.Log +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBFilterer) FilterFundsAdded(opts *bind.FilterOpts, id []*big.Int, from []common.Address) (*AutomationRegistryLogicBFundsAddedIterator, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + var fromRule []interface{} + for _, fromItem := range from { + fromRule = append(fromRule, fromItem) + } + + logs, sub, err := _AutomationRegistryLogicB.contract.FilterLogs(opts, "FundsAdded", idRule, fromRule) + if err != nil { + return nil, err + } + return &AutomationRegistryLogicBFundsAddedIterator{contract: _AutomationRegistryLogicB.contract, event: "FundsAdded", logs: logs, sub: sub}, nil +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBFilterer) WatchFundsAdded(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicBFundsAdded, id []*big.Int, from []common.Address) (event.Subscription, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + var fromRule []interface{} + for _, fromItem := range from { + fromRule = append(fromRule, fromItem) + } + + logs, sub, err := _AutomationRegistryLogicB.contract.WatchLogs(opts, "FundsAdded", idRule, fromRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(AutomationRegistryLogicBFundsAdded) + if err := _AutomationRegistryLogicB.contract.UnpackLog(event, "FundsAdded", 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 (_AutomationRegistryLogicB *AutomationRegistryLogicBFilterer) ParseFundsAdded(log types.Log) (*AutomationRegistryLogicBFundsAdded, error) { + event := new(AutomationRegistryLogicBFundsAdded) + if err := _AutomationRegistryLogicB.contract.UnpackLog(event, "FundsAdded", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type AutomationRegistryLogicBFundsWithdrawnIterator struct { + Event *AutomationRegistryLogicBFundsWithdrawn + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *AutomationRegistryLogicBFundsWithdrawnIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(AutomationRegistryLogicBFundsWithdrawn) + 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(AutomationRegistryLogicBFundsWithdrawn) + 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 *AutomationRegistryLogicBFundsWithdrawnIterator) Error() error { + return it.fail +} + +func (it *AutomationRegistryLogicBFundsWithdrawnIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type AutomationRegistryLogicBFundsWithdrawn struct { + Id *big.Int + Amount *big.Int + To common.Address + Raw types.Log +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBFilterer) FilterFundsWithdrawn(opts *bind.FilterOpts, id []*big.Int) (*AutomationRegistryLogicBFundsWithdrawnIterator, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + + logs, sub, err := _AutomationRegistryLogicB.contract.FilterLogs(opts, "FundsWithdrawn", idRule) + if err != nil { + return nil, err + } + return &AutomationRegistryLogicBFundsWithdrawnIterator{contract: _AutomationRegistryLogicB.contract, event: "FundsWithdrawn", logs: logs, sub: sub}, nil +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBFilterer) WatchFundsWithdrawn(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicBFundsWithdrawn, id []*big.Int) (event.Subscription, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + + logs, sub, err := _AutomationRegistryLogicB.contract.WatchLogs(opts, "FundsWithdrawn", idRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(AutomationRegistryLogicBFundsWithdrawn) + if err := _AutomationRegistryLogicB.contract.UnpackLog(event, "FundsWithdrawn", 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 (_AutomationRegistryLogicB *AutomationRegistryLogicBFilterer) ParseFundsWithdrawn(log types.Log) (*AutomationRegistryLogicBFundsWithdrawn, error) { + event := new(AutomationRegistryLogicBFundsWithdrawn) + if err := _AutomationRegistryLogicB.contract.UnpackLog(event, "FundsWithdrawn", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type AutomationRegistryLogicBInsufficientFundsUpkeepReportIterator struct { + Event *AutomationRegistryLogicBInsufficientFundsUpkeepReport + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *AutomationRegistryLogicBInsufficientFundsUpkeepReportIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(AutomationRegistryLogicBInsufficientFundsUpkeepReport) + 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(AutomationRegistryLogicBInsufficientFundsUpkeepReport) + 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 *AutomationRegistryLogicBInsufficientFundsUpkeepReportIterator) Error() error { + return it.fail +} + +func (it *AutomationRegistryLogicBInsufficientFundsUpkeepReportIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type AutomationRegistryLogicBInsufficientFundsUpkeepReport struct { + Id *big.Int + Trigger []byte + Raw types.Log +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBFilterer) FilterInsufficientFundsUpkeepReport(opts *bind.FilterOpts, id []*big.Int) (*AutomationRegistryLogicBInsufficientFundsUpkeepReportIterator, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + + logs, sub, err := _AutomationRegistryLogicB.contract.FilterLogs(opts, "InsufficientFundsUpkeepReport", idRule) + if err != nil { + return nil, err + } + return &AutomationRegistryLogicBInsufficientFundsUpkeepReportIterator{contract: _AutomationRegistryLogicB.contract, event: "InsufficientFundsUpkeepReport", logs: logs, sub: sub}, nil +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBFilterer) WatchInsufficientFundsUpkeepReport(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicBInsufficientFundsUpkeepReport, id []*big.Int) (event.Subscription, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + + logs, sub, err := _AutomationRegistryLogicB.contract.WatchLogs(opts, "InsufficientFundsUpkeepReport", idRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(AutomationRegistryLogicBInsufficientFundsUpkeepReport) + if err := _AutomationRegistryLogicB.contract.UnpackLog(event, "InsufficientFundsUpkeepReport", 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 (_AutomationRegistryLogicB *AutomationRegistryLogicBFilterer) ParseInsufficientFundsUpkeepReport(log types.Log) (*AutomationRegistryLogicBInsufficientFundsUpkeepReport, error) { + event := new(AutomationRegistryLogicBInsufficientFundsUpkeepReport) + if err := _AutomationRegistryLogicB.contract.UnpackLog(event, "InsufficientFundsUpkeepReport", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type AutomationRegistryLogicBOwnerFundsWithdrawnIterator struct { + Event *AutomationRegistryLogicBOwnerFundsWithdrawn + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *AutomationRegistryLogicBOwnerFundsWithdrawnIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(AutomationRegistryLogicBOwnerFundsWithdrawn) + 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(AutomationRegistryLogicBOwnerFundsWithdrawn) + 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 *AutomationRegistryLogicBOwnerFundsWithdrawnIterator) Error() error { + return it.fail +} + +func (it *AutomationRegistryLogicBOwnerFundsWithdrawnIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type AutomationRegistryLogicBOwnerFundsWithdrawn struct { + Amount *big.Int + Raw types.Log +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBFilterer) FilterOwnerFundsWithdrawn(opts *bind.FilterOpts) (*AutomationRegistryLogicBOwnerFundsWithdrawnIterator, error) { + + logs, sub, err := _AutomationRegistryLogicB.contract.FilterLogs(opts, "OwnerFundsWithdrawn") + if err != nil { + return nil, err + } + return &AutomationRegistryLogicBOwnerFundsWithdrawnIterator{contract: _AutomationRegistryLogicB.contract, event: "OwnerFundsWithdrawn", logs: logs, sub: sub}, nil +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBFilterer) WatchOwnerFundsWithdrawn(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicBOwnerFundsWithdrawn) (event.Subscription, error) { + + logs, sub, err := _AutomationRegistryLogicB.contract.WatchLogs(opts, "OwnerFundsWithdrawn") + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(AutomationRegistryLogicBOwnerFundsWithdrawn) + if err := _AutomationRegistryLogicB.contract.UnpackLog(event, "OwnerFundsWithdrawn", 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 (_AutomationRegistryLogicB *AutomationRegistryLogicBFilterer) ParseOwnerFundsWithdrawn(log types.Log) (*AutomationRegistryLogicBOwnerFundsWithdrawn, error) { + event := new(AutomationRegistryLogicBOwnerFundsWithdrawn) + if err := _AutomationRegistryLogicB.contract.UnpackLog(event, "OwnerFundsWithdrawn", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type AutomationRegistryLogicBOwnershipTransferRequestedIterator struct { + Event *AutomationRegistryLogicBOwnershipTransferRequested + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *AutomationRegistryLogicBOwnershipTransferRequestedIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(AutomationRegistryLogicBOwnershipTransferRequested) + 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(AutomationRegistryLogicBOwnershipTransferRequested) + 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 *AutomationRegistryLogicBOwnershipTransferRequestedIterator) Error() error { + return it.fail +} + +func (it *AutomationRegistryLogicBOwnershipTransferRequestedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type AutomationRegistryLogicBOwnershipTransferRequested struct { + From common.Address + To common.Address + Raw types.Log +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBFilterer) FilterOwnershipTransferRequested(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*AutomationRegistryLogicBOwnershipTransferRequestedIterator, 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 := _AutomationRegistryLogicB.contract.FilterLogs(opts, "OwnershipTransferRequested", fromRule, toRule) + if err != nil { + return nil, err + } + return &AutomationRegistryLogicBOwnershipTransferRequestedIterator{contract: _AutomationRegistryLogicB.contract, event: "OwnershipTransferRequested", logs: logs, sub: sub}, nil +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBFilterer) WatchOwnershipTransferRequested(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicBOwnershipTransferRequested, 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 := _AutomationRegistryLogicB.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(AutomationRegistryLogicBOwnershipTransferRequested) + if err := _AutomationRegistryLogicB.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 (_AutomationRegistryLogicB *AutomationRegistryLogicBFilterer) ParseOwnershipTransferRequested(log types.Log) (*AutomationRegistryLogicBOwnershipTransferRequested, error) { + event := new(AutomationRegistryLogicBOwnershipTransferRequested) + if err := _AutomationRegistryLogicB.contract.UnpackLog(event, "OwnershipTransferRequested", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type AutomationRegistryLogicBOwnershipTransferredIterator struct { + Event *AutomationRegistryLogicBOwnershipTransferred + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *AutomationRegistryLogicBOwnershipTransferredIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(AutomationRegistryLogicBOwnershipTransferred) + 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(AutomationRegistryLogicBOwnershipTransferred) + 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 *AutomationRegistryLogicBOwnershipTransferredIterator) Error() error { + return it.fail +} + +func (it *AutomationRegistryLogicBOwnershipTransferredIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type AutomationRegistryLogicBOwnershipTransferred struct { + From common.Address + To common.Address + Raw types.Log +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBFilterer) FilterOwnershipTransferred(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*AutomationRegistryLogicBOwnershipTransferredIterator, 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 := _AutomationRegistryLogicB.contract.FilterLogs(opts, "OwnershipTransferred", fromRule, toRule) + if err != nil { + return nil, err + } + return &AutomationRegistryLogicBOwnershipTransferredIterator{contract: _AutomationRegistryLogicB.contract, event: "OwnershipTransferred", logs: logs, sub: sub}, nil +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBFilterer) WatchOwnershipTransferred(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicBOwnershipTransferred, 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 := _AutomationRegistryLogicB.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(AutomationRegistryLogicBOwnershipTransferred) + if err := _AutomationRegistryLogicB.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 (_AutomationRegistryLogicB *AutomationRegistryLogicBFilterer) ParseOwnershipTransferred(log types.Log) (*AutomationRegistryLogicBOwnershipTransferred, error) { + event := new(AutomationRegistryLogicBOwnershipTransferred) + if err := _AutomationRegistryLogicB.contract.UnpackLog(event, "OwnershipTransferred", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type AutomationRegistryLogicBPausedIterator struct { + Event *AutomationRegistryLogicBPaused + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *AutomationRegistryLogicBPausedIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(AutomationRegistryLogicBPaused) + 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(AutomationRegistryLogicBPaused) + 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 *AutomationRegistryLogicBPausedIterator) Error() error { + return it.fail +} + +func (it *AutomationRegistryLogicBPausedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type AutomationRegistryLogicBPaused struct { + Account common.Address + Raw types.Log +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBFilterer) FilterPaused(opts *bind.FilterOpts) (*AutomationRegistryLogicBPausedIterator, error) { + + logs, sub, err := _AutomationRegistryLogicB.contract.FilterLogs(opts, "Paused") + if err != nil { + return nil, err + } + return &AutomationRegistryLogicBPausedIterator{contract: _AutomationRegistryLogicB.contract, event: "Paused", logs: logs, sub: sub}, nil +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBFilterer) WatchPaused(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicBPaused) (event.Subscription, error) { + + logs, sub, err := _AutomationRegistryLogicB.contract.WatchLogs(opts, "Paused") + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(AutomationRegistryLogicBPaused) + if err := _AutomationRegistryLogicB.contract.UnpackLog(event, "Paused", 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 (_AutomationRegistryLogicB *AutomationRegistryLogicBFilterer) ParsePaused(log types.Log) (*AutomationRegistryLogicBPaused, error) { + event := new(AutomationRegistryLogicBPaused) + if err := _AutomationRegistryLogicB.contract.UnpackLog(event, "Paused", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type AutomationRegistryLogicBPayeesUpdatedIterator struct { + Event *AutomationRegistryLogicBPayeesUpdated + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *AutomationRegistryLogicBPayeesUpdatedIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(AutomationRegistryLogicBPayeesUpdated) + 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(AutomationRegistryLogicBPayeesUpdated) + 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 *AutomationRegistryLogicBPayeesUpdatedIterator) Error() error { + return it.fail +} + +func (it *AutomationRegistryLogicBPayeesUpdatedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type AutomationRegistryLogicBPayeesUpdated struct { + Transmitters []common.Address + Payees []common.Address + Raw types.Log +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBFilterer) FilterPayeesUpdated(opts *bind.FilterOpts) (*AutomationRegistryLogicBPayeesUpdatedIterator, error) { + + logs, sub, err := _AutomationRegistryLogicB.contract.FilterLogs(opts, "PayeesUpdated") + if err != nil { + return nil, err + } + return &AutomationRegistryLogicBPayeesUpdatedIterator{contract: _AutomationRegistryLogicB.contract, event: "PayeesUpdated", logs: logs, sub: sub}, nil +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBFilterer) WatchPayeesUpdated(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicBPayeesUpdated) (event.Subscription, error) { + + logs, sub, err := _AutomationRegistryLogicB.contract.WatchLogs(opts, "PayeesUpdated") + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(AutomationRegistryLogicBPayeesUpdated) + if err := _AutomationRegistryLogicB.contract.UnpackLog(event, "PayeesUpdated", 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 (_AutomationRegistryLogicB *AutomationRegistryLogicBFilterer) ParsePayeesUpdated(log types.Log) (*AutomationRegistryLogicBPayeesUpdated, error) { + event := new(AutomationRegistryLogicBPayeesUpdated) + if err := _AutomationRegistryLogicB.contract.UnpackLog(event, "PayeesUpdated", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type AutomationRegistryLogicBPayeeshipTransferRequestedIterator struct { + Event *AutomationRegistryLogicBPayeeshipTransferRequested + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *AutomationRegistryLogicBPayeeshipTransferRequestedIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(AutomationRegistryLogicBPayeeshipTransferRequested) + 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(AutomationRegistryLogicBPayeeshipTransferRequested) + 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 *AutomationRegistryLogicBPayeeshipTransferRequestedIterator) Error() error { + return it.fail +} + +func (it *AutomationRegistryLogicBPayeeshipTransferRequestedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type AutomationRegistryLogicBPayeeshipTransferRequested struct { + Transmitter common.Address + From common.Address + To common.Address + Raw types.Log +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBFilterer) FilterPayeeshipTransferRequested(opts *bind.FilterOpts, transmitter []common.Address, from []common.Address, to []common.Address) (*AutomationRegistryLogicBPayeeshipTransferRequestedIterator, error) { + + var transmitterRule []interface{} + for _, transmitterItem := range transmitter { + transmitterRule = append(transmitterRule, transmitterItem) + } + 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 := _AutomationRegistryLogicB.contract.FilterLogs(opts, "PayeeshipTransferRequested", transmitterRule, fromRule, toRule) + if err != nil { + return nil, err + } + return &AutomationRegistryLogicBPayeeshipTransferRequestedIterator{contract: _AutomationRegistryLogicB.contract, event: "PayeeshipTransferRequested", logs: logs, sub: sub}, nil +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBFilterer) WatchPayeeshipTransferRequested(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicBPayeeshipTransferRequested, transmitter []common.Address, from []common.Address, to []common.Address) (event.Subscription, error) { + + var transmitterRule []interface{} + for _, transmitterItem := range transmitter { + transmitterRule = append(transmitterRule, transmitterItem) + } + 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 := _AutomationRegistryLogicB.contract.WatchLogs(opts, "PayeeshipTransferRequested", transmitterRule, 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(AutomationRegistryLogicBPayeeshipTransferRequested) + if err := _AutomationRegistryLogicB.contract.UnpackLog(event, "PayeeshipTransferRequested", 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 (_AutomationRegistryLogicB *AutomationRegistryLogicBFilterer) ParsePayeeshipTransferRequested(log types.Log) (*AutomationRegistryLogicBPayeeshipTransferRequested, error) { + event := new(AutomationRegistryLogicBPayeeshipTransferRequested) + if err := _AutomationRegistryLogicB.contract.UnpackLog(event, "PayeeshipTransferRequested", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type AutomationRegistryLogicBPayeeshipTransferredIterator struct { + Event *AutomationRegistryLogicBPayeeshipTransferred + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *AutomationRegistryLogicBPayeeshipTransferredIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(AutomationRegistryLogicBPayeeshipTransferred) + 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(AutomationRegistryLogicBPayeeshipTransferred) + 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 *AutomationRegistryLogicBPayeeshipTransferredIterator) Error() error { + return it.fail +} + +func (it *AutomationRegistryLogicBPayeeshipTransferredIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type AutomationRegistryLogicBPayeeshipTransferred struct { + Transmitter common.Address + From common.Address + To common.Address + Raw types.Log +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBFilterer) FilterPayeeshipTransferred(opts *bind.FilterOpts, transmitter []common.Address, from []common.Address, to []common.Address) (*AutomationRegistryLogicBPayeeshipTransferredIterator, error) { + + var transmitterRule []interface{} + for _, transmitterItem := range transmitter { + transmitterRule = append(transmitterRule, transmitterItem) + } + 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 := _AutomationRegistryLogicB.contract.FilterLogs(opts, "PayeeshipTransferred", transmitterRule, fromRule, toRule) + if err != nil { + return nil, err + } + return &AutomationRegistryLogicBPayeeshipTransferredIterator{contract: _AutomationRegistryLogicB.contract, event: "PayeeshipTransferred", logs: logs, sub: sub}, nil +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBFilterer) WatchPayeeshipTransferred(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicBPayeeshipTransferred, transmitter []common.Address, from []common.Address, to []common.Address) (event.Subscription, error) { + + var transmitterRule []interface{} + for _, transmitterItem := range transmitter { + transmitterRule = append(transmitterRule, transmitterItem) + } + 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 := _AutomationRegistryLogicB.contract.WatchLogs(opts, "PayeeshipTransferred", transmitterRule, 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(AutomationRegistryLogicBPayeeshipTransferred) + if err := _AutomationRegistryLogicB.contract.UnpackLog(event, "PayeeshipTransferred", 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 (_AutomationRegistryLogicB *AutomationRegistryLogicBFilterer) ParsePayeeshipTransferred(log types.Log) (*AutomationRegistryLogicBPayeeshipTransferred, error) { + event := new(AutomationRegistryLogicBPayeeshipTransferred) + if err := _AutomationRegistryLogicB.contract.UnpackLog(event, "PayeeshipTransferred", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type AutomationRegistryLogicBPaymentWithdrawnIterator struct { + Event *AutomationRegistryLogicBPaymentWithdrawn + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *AutomationRegistryLogicBPaymentWithdrawnIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(AutomationRegistryLogicBPaymentWithdrawn) + 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(AutomationRegistryLogicBPaymentWithdrawn) + 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 *AutomationRegistryLogicBPaymentWithdrawnIterator) Error() error { + return it.fail +} + +func (it *AutomationRegistryLogicBPaymentWithdrawnIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type AutomationRegistryLogicBPaymentWithdrawn struct { + Transmitter common.Address + Amount *big.Int + To common.Address + Payee common.Address + Raw types.Log +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBFilterer) FilterPaymentWithdrawn(opts *bind.FilterOpts, transmitter []common.Address, amount []*big.Int, to []common.Address) (*AutomationRegistryLogicBPaymentWithdrawnIterator, error) { + + var transmitterRule []interface{} + for _, transmitterItem := range transmitter { + transmitterRule = append(transmitterRule, transmitterItem) + } + var amountRule []interface{} + for _, amountItem := range amount { + amountRule = append(amountRule, amountItem) + } + var toRule []interface{} + for _, toItem := range to { + toRule = append(toRule, toItem) + } + + logs, sub, err := _AutomationRegistryLogicB.contract.FilterLogs(opts, "PaymentWithdrawn", transmitterRule, amountRule, toRule) + if err != nil { + return nil, err + } + return &AutomationRegistryLogicBPaymentWithdrawnIterator{contract: _AutomationRegistryLogicB.contract, event: "PaymentWithdrawn", logs: logs, sub: sub}, nil +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBFilterer) WatchPaymentWithdrawn(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicBPaymentWithdrawn, transmitter []common.Address, amount []*big.Int, to []common.Address) (event.Subscription, error) { + + var transmitterRule []interface{} + for _, transmitterItem := range transmitter { + transmitterRule = append(transmitterRule, transmitterItem) + } + var amountRule []interface{} + for _, amountItem := range amount { + amountRule = append(amountRule, amountItem) + } + var toRule []interface{} + for _, toItem := range to { + toRule = append(toRule, toItem) + } + + logs, sub, err := _AutomationRegistryLogicB.contract.WatchLogs(opts, "PaymentWithdrawn", transmitterRule, amountRule, 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(AutomationRegistryLogicBPaymentWithdrawn) + if err := _AutomationRegistryLogicB.contract.UnpackLog(event, "PaymentWithdrawn", 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 (_AutomationRegistryLogicB *AutomationRegistryLogicBFilterer) ParsePaymentWithdrawn(log types.Log) (*AutomationRegistryLogicBPaymentWithdrawn, error) { + event := new(AutomationRegistryLogicBPaymentWithdrawn) + if err := _AutomationRegistryLogicB.contract.UnpackLog(event, "PaymentWithdrawn", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type AutomationRegistryLogicBReorgedUpkeepReportIterator struct { + Event *AutomationRegistryLogicBReorgedUpkeepReport + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *AutomationRegistryLogicBReorgedUpkeepReportIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(AutomationRegistryLogicBReorgedUpkeepReport) + 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(AutomationRegistryLogicBReorgedUpkeepReport) + 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 *AutomationRegistryLogicBReorgedUpkeepReportIterator) Error() error { + return it.fail +} + +func (it *AutomationRegistryLogicBReorgedUpkeepReportIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type AutomationRegistryLogicBReorgedUpkeepReport struct { + Id *big.Int + Trigger []byte + Raw types.Log +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBFilterer) FilterReorgedUpkeepReport(opts *bind.FilterOpts, id []*big.Int) (*AutomationRegistryLogicBReorgedUpkeepReportIterator, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + + logs, sub, err := _AutomationRegistryLogicB.contract.FilterLogs(opts, "ReorgedUpkeepReport", idRule) + if err != nil { + return nil, err + } + return &AutomationRegistryLogicBReorgedUpkeepReportIterator{contract: _AutomationRegistryLogicB.contract, event: "ReorgedUpkeepReport", logs: logs, sub: sub}, nil +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBFilterer) WatchReorgedUpkeepReport(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicBReorgedUpkeepReport, id []*big.Int) (event.Subscription, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + + logs, sub, err := _AutomationRegistryLogicB.contract.WatchLogs(opts, "ReorgedUpkeepReport", idRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(AutomationRegistryLogicBReorgedUpkeepReport) + if err := _AutomationRegistryLogicB.contract.UnpackLog(event, "ReorgedUpkeepReport", 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 (_AutomationRegistryLogicB *AutomationRegistryLogicBFilterer) ParseReorgedUpkeepReport(log types.Log) (*AutomationRegistryLogicBReorgedUpkeepReport, error) { + event := new(AutomationRegistryLogicBReorgedUpkeepReport) + if err := _AutomationRegistryLogicB.contract.UnpackLog(event, "ReorgedUpkeepReport", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type AutomationRegistryLogicBStaleUpkeepReportIterator struct { + Event *AutomationRegistryLogicBStaleUpkeepReport + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *AutomationRegistryLogicBStaleUpkeepReportIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(AutomationRegistryLogicBStaleUpkeepReport) + 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(AutomationRegistryLogicBStaleUpkeepReport) + 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 *AutomationRegistryLogicBStaleUpkeepReportIterator) Error() error { + return it.fail +} + +func (it *AutomationRegistryLogicBStaleUpkeepReportIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type AutomationRegistryLogicBStaleUpkeepReport struct { + Id *big.Int + Trigger []byte + Raw types.Log +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBFilterer) FilterStaleUpkeepReport(opts *bind.FilterOpts, id []*big.Int) (*AutomationRegistryLogicBStaleUpkeepReportIterator, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + + logs, sub, err := _AutomationRegistryLogicB.contract.FilterLogs(opts, "StaleUpkeepReport", idRule) + if err != nil { + return nil, err + } + return &AutomationRegistryLogicBStaleUpkeepReportIterator{contract: _AutomationRegistryLogicB.contract, event: "StaleUpkeepReport", logs: logs, sub: sub}, nil +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBFilterer) WatchStaleUpkeepReport(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicBStaleUpkeepReport, id []*big.Int) (event.Subscription, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + + logs, sub, err := _AutomationRegistryLogicB.contract.WatchLogs(opts, "StaleUpkeepReport", idRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(AutomationRegistryLogicBStaleUpkeepReport) + if err := _AutomationRegistryLogicB.contract.UnpackLog(event, "StaleUpkeepReport", 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 (_AutomationRegistryLogicB *AutomationRegistryLogicBFilterer) ParseStaleUpkeepReport(log types.Log) (*AutomationRegistryLogicBStaleUpkeepReport, error) { + event := new(AutomationRegistryLogicBStaleUpkeepReport) + if err := _AutomationRegistryLogicB.contract.UnpackLog(event, "StaleUpkeepReport", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type AutomationRegistryLogicBUnpausedIterator struct { + Event *AutomationRegistryLogicBUnpaused + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *AutomationRegistryLogicBUnpausedIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(AutomationRegistryLogicBUnpaused) + 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(AutomationRegistryLogicBUnpaused) + 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 *AutomationRegistryLogicBUnpausedIterator) Error() error { + return it.fail +} + +func (it *AutomationRegistryLogicBUnpausedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type AutomationRegistryLogicBUnpaused struct { + Account common.Address + Raw types.Log +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBFilterer) FilterUnpaused(opts *bind.FilterOpts) (*AutomationRegistryLogicBUnpausedIterator, error) { + + logs, sub, err := _AutomationRegistryLogicB.contract.FilterLogs(opts, "Unpaused") + if err != nil { + return nil, err + } + return &AutomationRegistryLogicBUnpausedIterator{contract: _AutomationRegistryLogicB.contract, event: "Unpaused", logs: logs, sub: sub}, nil +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBFilterer) WatchUnpaused(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicBUnpaused) (event.Subscription, error) { + + logs, sub, err := _AutomationRegistryLogicB.contract.WatchLogs(opts, "Unpaused") + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(AutomationRegistryLogicBUnpaused) + if err := _AutomationRegistryLogicB.contract.UnpackLog(event, "Unpaused", 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 (_AutomationRegistryLogicB *AutomationRegistryLogicBFilterer) ParseUnpaused(log types.Log) (*AutomationRegistryLogicBUnpaused, error) { + event := new(AutomationRegistryLogicBUnpaused) + if err := _AutomationRegistryLogicB.contract.UnpackLog(event, "Unpaused", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type AutomationRegistryLogicBUpkeepAdminTransferRequestedIterator struct { + Event *AutomationRegistryLogicBUpkeepAdminTransferRequested + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *AutomationRegistryLogicBUpkeepAdminTransferRequestedIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(AutomationRegistryLogicBUpkeepAdminTransferRequested) + 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(AutomationRegistryLogicBUpkeepAdminTransferRequested) + 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 *AutomationRegistryLogicBUpkeepAdminTransferRequestedIterator) Error() error { + return it.fail +} + +func (it *AutomationRegistryLogicBUpkeepAdminTransferRequestedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type AutomationRegistryLogicBUpkeepAdminTransferRequested struct { + Id *big.Int + From common.Address + To common.Address + Raw types.Log +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBFilterer) FilterUpkeepAdminTransferRequested(opts *bind.FilterOpts, id []*big.Int, from []common.Address, to []common.Address) (*AutomationRegistryLogicBUpkeepAdminTransferRequestedIterator, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + 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 := _AutomationRegistryLogicB.contract.FilterLogs(opts, "UpkeepAdminTransferRequested", idRule, fromRule, toRule) + if err != nil { + return nil, err + } + return &AutomationRegistryLogicBUpkeepAdminTransferRequestedIterator{contract: _AutomationRegistryLogicB.contract, event: "UpkeepAdminTransferRequested", logs: logs, sub: sub}, nil +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBFilterer) WatchUpkeepAdminTransferRequested(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicBUpkeepAdminTransferRequested, id []*big.Int, from []common.Address, to []common.Address) (event.Subscription, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + 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 := _AutomationRegistryLogicB.contract.WatchLogs(opts, "UpkeepAdminTransferRequested", idRule, 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(AutomationRegistryLogicBUpkeepAdminTransferRequested) + if err := _AutomationRegistryLogicB.contract.UnpackLog(event, "UpkeepAdminTransferRequested", 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 (_AutomationRegistryLogicB *AutomationRegistryLogicBFilterer) ParseUpkeepAdminTransferRequested(log types.Log) (*AutomationRegistryLogicBUpkeepAdminTransferRequested, error) { + event := new(AutomationRegistryLogicBUpkeepAdminTransferRequested) + if err := _AutomationRegistryLogicB.contract.UnpackLog(event, "UpkeepAdminTransferRequested", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type AutomationRegistryLogicBUpkeepAdminTransferredIterator struct { + Event *AutomationRegistryLogicBUpkeepAdminTransferred + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *AutomationRegistryLogicBUpkeepAdminTransferredIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(AutomationRegistryLogicBUpkeepAdminTransferred) + 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(AutomationRegistryLogicBUpkeepAdminTransferred) + 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 *AutomationRegistryLogicBUpkeepAdminTransferredIterator) Error() error { + return it.fail +} + +func (it *AutomationRegistryLogicBUpkeepAdminTransferredIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type AutomationRegistryLogicBUpkeepAdminTransferred struct { + Id *big.Int + From common.Address + To common.Address + Raw types.Log +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBFilterer) FilterUpkeepAdminTransferred(opts *bind.FilterOpts, id []*big.Int, from []common.Address, to []common.Address) (*AutomationRegistryLogicBUpkeepAdminTransferredIterator, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + 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 := _AutomationRegistryLogicB.contract.FilterLogs(opts, "UpkeepAdminTransferred", idRule, fromRule, toRule) + if err != nil { + return nil, err + } + return &AutomationRegistryLogicBUpkeepAdminTransferredIterator{contract: _AutomationRegistryLogicB.contract, event: "UpkeepAdminTransferred", logs: logs, sub: sub}, nil +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBFilterer) WatchUpkeepAdminTransferred(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicBUpkeepAdminTransferred, id []*big.Int, from []common.Address, to []common.Address) (event.Subscription, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + 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 := _AutomationRegistryLogicB.contract.WatchLogs(opts, "UpkeepAdminTransferred", idRule, 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(AutomationRegistryLogicBUpkeepAdminTransferred) + if err := _AutomationRegistryLogicB.contract.UnpackLog(event, "UpkeepAdminTransferred", 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 (_AutomationRegistryLogicB *AutomationRegistryLogicBFilterer) ParseUpkeepAdminTransferred(log types.Log) (*AutomationRegistryLogicBUpkeepAdminTransferred, error) { + event := new(AutomationRegistryLogicBUpkeepAdminTransferred) + if err := _AutomationRegistryLogicB.contract.UnpackLog(event, "UpkeepAdminTransferred", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type AutomationRegistryLogicBUpkeepCanceledIterator struct { + Event *AutomationRegistryLogicBUpkeepCanceled + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *AutomationRegistryLogicBUpkeepCanceledIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(AutomationRegistryLogicBUpkeepCanceled) + 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(AutomationRegistryLogicBUpkeepCanceled) + 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 *AutomationRegistryLogicBUpkeepCanceledIterator) Error() error { + return it.fail +} + +func (it *AutomationRegistryLogicBUpkeepCanceledIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type AutomationRegistryLogicBUpkeepCanceled struct { + Id *big.Int + AtBlockHeight uint64 + Raw types.Log +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBFilterer) FilterUpkeepCanceled(opts *bind.FilterOpts, id []*big.Int, atBlockHeight []uint64) (*AutomationRegistryLogicBUpkeepCanceledIterator, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + var atBlockHeightRule []interface{} + for _, atBlockHeightItem := range atBlockHeight { + atBlockHeightRule = append(atBlockHeightRule, atBlockHeightItem) + } + + logs, sub, err := _AutomationRegistryLogicB.contract.FilterLogs(opts, "UpkeepCanceled", idRule, atBlockHeightRule) + if err != nil { + return nil, err + } + return &AutomationRegistryLogicBUpkeepCanceledIterator{contract: _AutomationRegistryLogicB.contract, event: "UpkeepCanceled", logs: logs, sub: sub}, nil +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBFilterer) WatchUpkeepCanceled(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicBUpkeepCanceled, id []*big.Int, atBlockHeight []uint64) (event.Subscription, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + var atBlockHeightRule []interface{} + for _, atBlockHeightItem := range atBlockHeight { + atBlockHeightRule = append(atBlockHeightRule, atBlockHeightItem) + } + + logs, sub, err := _AutomationRegistryLogicB.contract.WatchLogs(opts, "UpkeepCanceled", idRule, atBlockHeightRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(AutomationRegistryLogicBUpkeepCanceled) + if err := _AutomationRegistryLogicB.contract.UnpackLog(event, "UpkeepCanceled", 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 (_AutomationRegistryLogicB *AutomationRegistryLogicBFilterer) ParseUpkeepCanceled(log types.Log) (*AutomationRegistryLogicBUpkeepCanceled, error) { + event := new(AutomationRegistryLogicBUpkeepCanceled) + if err := _AutomationRegistryLogicB.contract.UnpackLog(event, "UpkeepCanceled", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type AutomationRegistryLogicBUpkeepCheckDataSetIterator struct { + Event *AutomationRegistryLogicBUpkeepCheckDataSet + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *AutomationRegistryLogicBUpkeepCheckDataSetIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(AutomationRegistryLogicBUpkeepCheckDataSet) + 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(AutomationRegistryLogicBUpkeepCheckDataSet) + 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 *AutomationRegistryLogicBUpkeepCheckDataSetIterator) Error() error { + return it.fail +} + +func (it *AutomationRegistryLogicBUpkeepCheckDataSetIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type AutomationRegistryLogicBUpkeepCheckDataSet struct { + Id *big.Int + NewCheckData []byte + Raw types.Log +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBFilterer) FilterUpkeepCheckDataSet(opts *bind.FilterOpts, id []*big.Int) (*AutomationRegistryLogicBUpkeepCheckDataSetIterator, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + + logs, sub, err := _AutomationRegistryLogicB.contract.FilterLogs(opts, "UpkeepCheckDataSet", idRule) + if err != nil { + return nil, err + } + return &AutomationRegistryLogicBUpkeepCheckDataSetIterator{contract: _AutomationRegistryLogicB.contract, event: "UpkeepCheckDataSet", logs: logs, sub: sub}, nil +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBFilterer) WatchUpkeepCheckDataSet(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicBUpkeepCheckDataSet, id []*big.Int) (event.Subscription, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + + logs, sub, err := _AutomationRegistryLogicB.contract.WatchLogs(opts, "UpkeepCheckDataSet", idRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(AutomationRegistryLogicBUpkeepCheckDataSet) + if err := _AutomationRegistryLogicB.contract.UnpackLog(event, "UpkeepCheckDataSet", 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 (_AutomationRegistryLogicB *AutomationRegistryLogicBFilterer) ParseUpkeepCheckDataSet(log types.Log) (*AutomationRegistryLogicBUpkeepCheckDataSet, error) { + event := new(AutomationRegistryLogicBUpkeepCheckDataSet) + if err := _AutomationRegistryLogicB.contract.UnpackLog(event, "UpkeepCheckDataSet", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type AutomationRegistryLogicBUpkeepGasLimitSetIterator struct { + Event *AutomationRegistryLogicBUpkeepGasLimitSet + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *AutomationRegistryLogicBUpkeepGasLimitSetIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(AutomationRegistryLogicBUpkeepGasLimitSet) + 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(AutomationRegistryLogicBUpkeepGasLimitSet) + 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 *AutomationRegistryLogicBUpkeepGasLimitSetIterator) Error() error { + return it.fail +} + +func (it *AutomationRegistryLogicBUpkeepGasLimitSetIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type AutomationRegistryLogicBUpkeepGasLimitSet struct { + Id *big.Int + GasLimit *big.Int + Raw types.Log +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBFilterer) FilterUpkeepGasLimitSet(opts *bind.FilterOpts, id []*big.Int) (*AutomationRegistryLogicBUpkeepGasLimitSetIterator, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + + logs, sub, err := _AutomationRegistryLogicB.contract.FilterLogs(opts, "UpkeepGasLimitSet", idRule) + if err != nil { + return nil, err + } + return &AutomationRegistryLogicBUpkeepGasLimitSetIterator{contract: _AutomationRegistryLogicB.contract, event: "UpkeepGasLimitSet", logs: logs, sub: sub}, nil +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBFilterer) WatchUpkeepGasLimitSet(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicBUpkeepGasLimitSet, id []*big.Int) (event.Subscription, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + + logs, sub, err := _AutomationRegistryLogicB.contract.WatchLogs(opts, "UpkeepGasLimitSet", idRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(AutomationRegistryLogicBUpkeepGasLimitSet) + if err := _AutomationRegistryLogicB.contract.UnpackLog(event, "UpkeepGasLimitSet", 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 (_AutomationRegistryLogicB *AutomationRegistryLogicBFilterer) ParseUpkeepGasLimitSet(log types.Log) (*AutomationRegistryLogicBUpkeepGasLimitSet, error) { + event := new(AutomationRegistryLogicBUpkeepGasLimitSet) + if err := _AutomationRegistryLogicB.contract.UnpackLog(event, "UpkeepGasLimitSet", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type AutomationRegistryLogicBUpkeepMigratedIterator struct { + Event *AutomationRegistryLogicBUpkeepMigrated + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *AutomationRegistryLogicBUpkeepMigratedIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(AutomationRegistryLogicBUpkeepMigrated) + 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(AutomationRegistryLogicBUpkeepMigrated) + 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 *AutomationRegistryLogicBUpkeepMigratedIterator) Error() error { + return it.fail +} + +func (it *AutomationRegistryLogicBUpkeepMigratedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type AutomationRegistryLogicBUpkeepMigrated struct { + Id *big.Int + RemainingBalance *big.Int + Destination common.Address + Raw types.Log +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBFilterer) FilterUpkeepMigrated(opts *bind.FilterOpts, id []*big.Int) (*AutomationRegistryLogicBUpkeepMigratedIterator, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + + logs, sub, err := _AutomationRegistryLogicB.contract.FilterLogs(opts, "UpkeepMigrated", idRule) + if err != nil { + return nil, err + } + return &AutomationRegistryLogicBUpkeepMigratedIterator{contract: _AutomationRegistryLogicB.contract, event: "UpkeepMigrated", logs: logs, sub: sub}, nil +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBFilterer) WatchUpkeepMigrated(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicBUpkeepMigrated, id []*big.Int) (event.Subscription, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + + logs, sub, err := _AutomationRegistryLogicB.contract.WatchLogs(opts, "UpkeepMigrated", idRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(AutomationRegistryLogicBUpkeepMigrated) + if err := _AutomationRegistryLogicB.contract.UnpackLog(event, "UpkeepMigrated", 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 (_AutomationRegistryLogicB *AutomationRegistryLogicBFilterer) ParseUpkeepMigrated(log types.Log) (*AutomationRegistryLogicBUpkeepMigrated, error) { + event := new(AutomationRegistryLogicBUpkeepMigrated) + if err := _AutomationRegistryLogicB.contract.UnpackLog(event, "UpkeepMigrated", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type AutomationRegistryLogicBUpkeepOffchainConfigSetIterator struct { + Event *AutomationRegistryLogicBUpkeepOffchainConfigSet + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *AutomationRegistryLogicBUpkeepOffchainConfigSetIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(AutomationRegistryLogicBUpkeepOffchainConfigSet) + 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(AutomationRegistryLogicBUpkeepOffchainConfigSet) + 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 *AutomationRegistryLogicBUpkeepOffchainConfigSetIterator) Error() error { + return it.fail +} + +func (it *AutomationRegistryLogicBUpkeepOffchainConfigSetIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type AutomationRegistryLogicBUpkeepOffchainConfigSet struct { + Id *big.Int + OffchainConfig []byte + Raw types.Log +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBFilterer) FilterUpkeepOffchainConfigSet(opts *bind.FilterOpts, id []*big.Int) (*AutomationRegistryLogicBUpkeepOffchainConfigSetIterator, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + + logs, sub, err := _AutomationRegistryLogicB.contract.FilterLogs(opts, "UpkeepOffchainConfigSet", idRule) + if err != nil { + return nil, err + } + return &AutomationRegistryLogicBUpkeepOffchainConfigSetIterator{contract: _AutomationRegistryLogicB.contract, event: "UpkeepOffchainConfigSet", logs: logs, sub: sub}, nil +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBFilterer) WatchUpkeepOffchainConfigSet(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicBUpkeepOffchainConfigSet, id []*big.Int) (event.Subscription, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + + logs, sub, err := _AutomationRegistryLogicB.contract.WatchLogs(opts, "UpkeepOffchainConfigSet", idRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(AutomationRegistryLogicBUpkeepOffchainConfigSet) + if err := _AutomationRegistryLogicB.contract.UnpackLog(event, "UpkeepOffchainConfigSet", 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 (_AutomationRegistryLogicB *AutomationRegistryLogicBFilterer) ParseUpkeepOffchainConfigSet(log types.Log) (*AutomationRegistryLogicBUpkeepOffchainConfigSet, error) { + event := new(AutomationRegistryLogicBUpkeepOffchainConfigSet) + if err := _AutomationRegistryLogicB.contract.UnpackLog(event, "UpkeepOffchainConfigSet", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type AutomationRegistryLogicBUpkeepPausedIterator struct { + Event *AutomationRegistryLogicBUpkeepPaused + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *AutomationRegistryLogicBUpkeepPausedIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(AutomationRegistryLogicBUpkeepPaused) + 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(AutomationRegistryLogicBUpkeepPaused) + 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 *AutomationRegistryLogicBUpkeepPausedIterator) Error() error { + return it.fail +} + +func (it *AutomationRegistryLogicBUpkeepPausedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type AutomationRegistryLogicBUpkeepPaused struct { + Id *big.Int + Raw types.Log +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBFilterer) FilterUpkeepPaused(opts *bind.FilterOpts, id []*big.Int) (*AutomationRegistryLogicBUpkeepPausedIterator, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + + logs, sub, err := _AutomationRegistryLogicB.contract.FilterLogs(opts, "UpkeepPaused", idRule) + if err != nil { + return nil, err + } + return &AutomationRegistryLogicBUpkeepPausedIterator{contract: _AutomationRegistryLogicB.contract, event: "UpkeepPaused", logs: logs, sub: sub}, nil +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBFilterer) WatchUpkeepPaused(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicBUpkeepPaused, id []*big.Int) (event.Subscription, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + + logs, sub, err := _AutomationRegistryLogicB.contract.WatchLogs(opts, "UpkeepPaused", idRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(AutomationRegistryLogicBUpkeepPaused) + if err := _AutomationRegistryLogicB.contract.UnpackLog(event, "UpkeepPaused", 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 (_AutomationRegistryLogicB *AutomationRegistryLogicBFilterer) ParseUpkeepPaused(log types.Log) (*AutomationRegistryLogicBUpkeepPaused, error) { + event := new(AutomationRegistryLogicBUpkeepPaused) + if err := _AutomationRegistryLogicB.contract.UnpackLog(event, "UpkeepPaused", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type AutomationRegistryLogicBUpkeepPerformedIterator struct { + Event *AutomationRegistryLogicBUpkeepPerformed + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *AutomationRegistryLogicBUpkeepPerformedIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(AutomationRegistryLogicBUpkeepPerformed) + 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(AutomationRegistryLogicBUpkeepPerformed) + 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 *AutomationRegistryLogicBUpkeepPerformedIterator) Error() error { + return it.fail +} + +func (it *AutomationRegistryLogicBUpkeepPerformedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type AutomationRegistryLogicBUpkeepPerformed struct { + Id *big.Int + Success bool + TotalPayment *big.Int + GasUsed *big.Int + GasOverhead *big.Int + Trigger []byte + Raw types.Log +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBFilterer) FilterUpkeepPerformed(opts *bind.FilterOpts, id []*big.Int, success []bool) (*AutomationRegistryLogicBUpkeepPerformedIterator, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + var successRule []interface{} + for _, successItem := range success { + successRule = append(successRule, successItem) + } + + logs, sub, err := _AutomationRegistryLogicB.contract.FilterLogs(opts, "UpkeepPerformed", idRule, successRule) + if err != nil { + return nil, err + } + return &AutomationRegistryLogicBUpkeepPerformedIterator{contract: _AutomationRegistryLogicB.contract, event: "UpkeepPerformed", logs: logs, sub: sub}, nil +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBFilterer) WatchUpkeepPerformed(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicBUpkeepPerformed, id []*big.Int, success []bool) (event.Subscription, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + var successRule []interface{} + for _, successItem := range success { + successRule = append(successRule, successItem) + } + + logs, sub, err := _AutomationRegistryLogicB.contract.WatchLogs(opts, "UpkeepPerformed", idRule, successRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(AutomationRegistryLogicBUpkeepPerformed) + if err := _AutomationRegistryLogicB.contract.UnpackLog(event, "UpkeepPerformed", 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 (_AutomationRegistryLogicB *AutomationRegistryLogicBFilterer) ParseUpkeepPerformed(log types.Log) (*AutomationRegistryLogicBUpkeepPerformed, error) { + event := new(AutomationRegistryLogicBUpkeepPerformed) + if err := _AutomationRegistryLogicB.contract.UnpackLog(event, "UpkeepPerformed", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type AutomationRegistryLogicBUpkeepPrivilegeConfigSetIterator struct { + Event *AutomationRegistryLogicBUpkeepPrivilegeConfigSet + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *AutomationRegistryLogicBUpkeepPrivilegeConfigSetIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(AutomationRegistryLogicBUpkeepPrivilegeConfigSet) + 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(AutomationRegistryLogicBUpkeepPrivilegeConfigSet) + 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 *AutomationRegistryLogicBUpkeepPrivilegeConfigSetIterator) Error() error { + return it.fail +} + +func (it *AutomationRegistryLogicBUpkeepPrivilegeConfigSetIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type AutomationRegistryLogicBUpkeepPrivilegeConfigSet struct { + Id *big.Int + PrivilegeConfig []byte + Raw types.Log +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBFilterer) FilterUpkeepPrivilegeConfigSet(opts *bind.FilterOpts, id []*big.Int) (*AutomationRegistryLogicBUpkeepPrivilegeConfigSetIterator, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + + logs, sub, err := _AutomationRegistryLogicB.contract.FilterLogs(opts, "UpkeepPrivilegeConfigSet", idRule) + if err != nil { + return nil, err + } + return &AutomationRegistryLogicBUpkeepPrivilegeConfigSetIterator{contract: _AutomationRegistryLogicB.contract, event: "UpkeepPrivilegeConfigSet", logs: logs, sub: sub}, nil +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBFilterer) WatchUpkeepPrivilegeConfigSet(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicBUpkeepPrivilegeConfigSet, id []*big.Int) (event.Subscription, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + + logs, sub, err := _AutomationRegistryLogicB.contract.WatchLogs(opts, "UpkeepPrivilegeConfigSet", idRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(AutomationRegistryLogicBUpkeepPrivilegeConfigSet) + if err := _AutomationRegistryLogicB.contract.UnpackLog(event, "UpkeepPrivilegeConfigSet", 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 (_AutomationRegistryLogicB *AutomationRegistryLogicBFilterer) ParseUpkeepPrivilegeConfigSet(log types.Log) (*AutomationRegistryLogicBUpkeepPrivilegeConfigSet, error) { + event := new(AutomationRegistryLogicBUpkeepPrivilegeConfigSet) + if err := _AutomationRegistryLogicB.contract.UnpackLog(event, "UpkeepPrivilegeConfigSet", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type AutomationRegistryLogicBUpkeepReceivedIterator struct { + Event *AutomationRegistryLogicBUpkeepReceived + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *AutomationRegistryLogicBUpkeepReceivedIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(AutomationRegistryLogicBUpkeepReceived) + 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(AutomationRegistryLogicBUpkeepReceived) + 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 *AutomationRegistryLogicBUpkeepReceivedIterator) Error() error { + return it.fail +} + +func (it *AutomationRegistryLogicBUpkeepReceivedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type AutomationRegistryLogicBUpkeepReceived struct { + Id *big.Int + StartingBalance *big.Int + ImportedFrom common.Address + Raw types.Log +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBFilterer) FilterUpkeepReceived(opts *bind.FilterOpts, id []*big.Int) (*AutomationRegistryLogicBUpkeepReceivedIterator, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + + logs, sub, err := _AutomationRegistryLogicB.contract.FilterLogs(opts, "UpkeepReceived", idRule) + if err != nil { + return nil, err + } + return &AutomationRegistryLogicBUpkeepReceivedIterator{contract: _AutomationRegistryLogicB.contract, event: "UpkeepReceived", logs: logs, sub: sub}, nil +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBFilterer) WatchUpkeepReceived(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicBUpkeepReceived, id []*big.Int) (event.Subscription, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + + logs, sub, err := _AutomationRegistryLogicB.contract.WatchLogs(opts, "UpkeepReceived", idRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(AutomationRegistryLogicBUpkeepReceived) + if err := _AutomationRegistryLogicB.contract.UnpackLog(event, "UpkeepReceived", 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 (_AutomationRegistryLogicB *AutomationRegistryLogicBFilterer) ParseUpkeepReceived(log types.Log) (*AutomationRegistryLogicBUpkeepReceived, error) { + event := new(AutomationRegistryLogicBUpkeepReceived) + if err := _AutomationRegistryLogicB.contract.UnpackLog(event, "UpkeepReceived", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type AutomationRegistryLogicBUpkeepRegisteredIterator struct { + Event *AutomationRegistryLogicBUpkeepRegistered + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *AutomationRegistryLogicBUpkeepRegisteredIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(AutomationRegistryLogicBUpkeepRegistered) + 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(AutomationRegistryLogicBUpkeepRegistered) + 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 *AutomationRegistryLogicBUpkeepRegisteredIterator) Error() error { + return it.fail +} + +func (it *AutomationRegistryLogicBUpkeepRegisteredIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type AutomationRegistryLogicBUpkeepRegistered struct { + Id *big.Int + PerformGas uint32 + Admin common.Address + Raw types.Log +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBFilterer) FilterUpkeepRegistered(opts *bind.FilterOpts, id []*big.Int) (*AutomationRegistryLogicBUpkeepRegisteredIterator, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + + logs, sub, err := _AutomationRegistryLogicB.contract.FilterLogs(opts, "UpkeepRegistered", idRule) + if err != nil { + return nil, err + } + return &AutomationRegistryLogicBUpkeepRegisteredIterator{contract: _AutomationRegistryLogicB.contract, event: "UpkeepRegistered", logs: logs, sub: sub}, nil +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBFilterer) WatchUpkeepRegistered(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicBUpkeepRegistered, id []*big.Int) (event.Subscription, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + + logs, sub, err := _AutomationRegistryLogicB.contract.WatchLogs(opts, "UpkeepRegistered", idRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(AutomationRegistryLogicBUpkeepRegistered) + if err := _AutomationRegistryLogicB.contract.UnpackLog(event, "UpkeepRegistered", 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 (_AutomationRegistryLogicB *AutomationRegistryLogicBFilterer) ParseUpkeepRegistered(log types.Log) (*AutomationRegistryLogicBUpkeepRegistered, error) { + event := new(AutomationRegistryLogicBUpkeepRegistered) + if err := _AutomationRegistryLogicB.contract.UnpackLog(event, "UpkeepRegistered", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type AutomationRegistryLogicBUpkeepTriggerConfigSetIterator struct { + Event *AutomationRegistryLogicBUpkeepTriggerConfigSet + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *AutomationRegistryLogicBUpkeepTriggerConfigSetIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(AutomationRegistryLogicBUpkeepTriggerConfigSet) + 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(AutomationRegistryLogicBUpkeepTriggerConfigSet) + 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 *AutomationRegistryLogicBUpkeepTriggerConfigSetIterator) Error() error { + return it.fail +} + +func (it *AutomationRegistryLogicBUpkeepTriggerConfigSetIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type AutomationRegistryLogicBUpkeepTriggerConfigSet struct { + Id *big.Int + TriggerConfig []byte + Raw types.Log +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBFilterer) FilterUpkeepTriggerConfigSet(opts *bind.FilterOpts, id []*big.Int) (*AutomationRegistryLogicBUpkeepTriggerConfigSetIterator, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + + logs, sub, err := _AutomationRegistryLogicB.contract.FilterLogs(opts, "UpkeepTriggerConfigSet", idRule) + if err != nil { + return nil, err + } + return &AutomationRegistryLogicBUpkeepTriggerConfigSetIterator{contract: _AutomationRegistryLogicB.contract, event: "UpkeepTriggerConfigSet", logs: logs, sub: sub}, nil +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBFilterer) WatchUpkeepTriggerConfigSet(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicBUpkeepTriggerConfigSet, id []*big.Int) (event.Subscription, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + + logs, sub, err := _AutomationRegistryLogicB.contract.WatchLogs(opts, "UpkeepTriggerConfigSet", idRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(AutomationRegistryLogicBUpkeepTriggerConfigSet) + if err := _AutomationRegistryLogicB.contract.UnpackLog(event, "UpkeepTriggerConfigSet", 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 (_AutomationRegistryLogicB *AutomationRegistryLogicBFilterer) ParseUpkeepTriggerConfigSet(log types.Log) (*AutomationRegistryLogicBUpkeepTriggerConfigSet, error) { + event := new(AutomationRegistryLogicBUpkeepTriggerConfigSet) + if err := _AutomationRegistryLogicB.contract.UnpackLog(event, "UpkeepTriggerConfigSet", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type AutomationRegistryLogicBUpkeepUnpausedIterator struct { + Event *AutomationRegistryLogicBUpkeepUnpaused + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *AutomationRegistryLogicBUpkeepUnpausedIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(AutomationRegistryLogicBUpkeepUnpaused) + 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(AutomationRegistryLogicBUpkeepUnpaused) + 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 *AutomationRegistryLogicBUpkeepUnpausedIterator) Error() error { + return it.fail +} + +func (it *AutomationRegistryLogicBUpkeepUnpausedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type AutomationRegistryLogicBUpkeepUnpaused struct { + Id *big.Int + Raw types.Log +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBFilterer) FilterUpkeepUnpaused(opts *bind.FilterOpts, id []*big.Int) (*AutomationRegistryLogicBUpkeepUnpausedIterator, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + + logs, sub, err := _AutomationRegistryLogicB.contract.FilterLogs(opts, "UpkeepUnpaused", idRule) + if err != nil { + return nil, err + } + return &AutomationRegistryLogicBUpkeepUnpausedIterator{contract: _AutomationRegistryLogicB.contract, event: "UpkeepUnpaused", logs: logs, sub: sub}, nil +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBFilterer) WatchUpkeepUnpaused(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicBUpkeepUnpaused, id []*big.Int) (event.Subscription, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + + logs, sub, err := _AutomationRegistryLogicB.contract.WatchLogs(opts, "UpkeepUnpaused", idRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(AutomationRegistryLogicBUpkeepUnpaused) + if err := _AutomationRegistryLogicB.contract.UnpackLog(event, "UpkeepUnpaused", 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 (_AutomationRegistryLogicB *AutomationRegistryLogicBFilterer) ParseUpkeepUnpaused(log types.Log) (*AutomationRegistryLogicBUpkeepUnpaused, error) { + event := new(AutomationRegistryLogicBUpkeepUnpaused) + if err := _AutomationRegistryLogicB.contract.UnpackLog(event, "UpkeepUnpaused", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type GetSignerInfo struct { + Active bool + Index uint8 +} +type GetState struct { + State AutomationRegistryBase22State + Config AutomationRegistryBase22OnchainConfig + Signers []common.Address + Transmitters []common.Address + F uint8 +} +type GetTransmitterInfo struct { + Active bool + Index uint8 + Balance *big.Int + LastCollected *big.Int + Payee common.Address +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicB) ParseLog(log types.Log) (generated.AbigenLog, error) { + switch log.Topics[0] { + case _AutomationRegistryLogicB.abi.Events["AdminPrivilegeConfigSet"].ID: + return _AutomationRegistryLogicB.ParseAdminPrivilegeConfigSet(log) + case _AutomationRegistryLogicB.abi.Events["CancelledUpkeepReport"].ID: + return _AutomationRegistryLogicB.ParseCancelledUpkeepReport(log) + case _AutomationRegistryLogicB.abi.Events["DedupKeyAdded"].ID: + return _AutomationRegistryLogicB.ParseDedupKeyAdded(log) + case _AutomationRegistryLogicB.abi.Events["FundsAdded"].ID: + return _AutomationRegistryLogicB.ParseFundsAdded(log) + case _AutomationRegistryLogicB.abi.Events["FundsWithdrawn"].ID: + return _AutomationRegistryLogicB.ParseFundsWithdrawn(log) + case _AutomationRegistryLogicB.abi.Events["InsufficientFundsUpkeepReport"].ID: + return _AutomationRegistryLogicB.ParseInsufficientFundsUpkeepReport(log) + case _AutomationRegistryLogicB.abi.Events["OwnerFundsWithdrawn"].ID: + return _AutomationRegistryLogicB.ParseOwnerFundsWithdrawn(log) + case _AutomationRegistryLogicB.abi.Events["OwnershipTransferRequested"].ID: + return _AutomationRegistryLogicB.ParseOwnershipTransferRequested(log) + case _AutomationRegistryLogicB.abi.Events["OwnershipTransferred"].ID: + return _AutomationRegistryLogicB.ParseOwnershipTransferred(log) + case _AutomationRegistryLogicB.abi.Events["Paused"].ID: + return _AutomationRegistryLogicB.ParsePaused(log) + case _AutomationRegistryLogicB.abi.Events["PayeesUpdated"].ID: + return _AutomationRegistryLogicB.ParsePayeesUpdated(log) + case _AutomationRegistryLogicB.abi.Events["PayeeshipTransferRequested"].ID: + return _AutomationRegistryLogicB.ParsePayeeshipTransferRequested(log) + case _AutomationRegistryLogicB.abi.Events["PayeeshipTransferred"].ID: + return _AutomationRegistryLogicB.ParsePayeeshipTransferred(log) + case _AutomationRegistryLogicB.abi.Events["PaymentWithdrawn"].ID: + return _AutomationRegistryLogicB.ParsePaymentWithdrawn(log) + case _AutomationRegistryLogicB.abi.Events["ReorgedUpkeepReport"].ID: + return _AutomationRegistryLogicB.ParseReorgedUpkeepReport(log) + case _AutomationRegistryLogicB.abi.Events["StaleUpkeepReport"].ID: + return _AutomationRegistryLogicB.ParseStaleUpkeepReport(log) + case _AutomationRegistryLogicB.abi.Events["Unpaused"].ID: + return _AutomationRegistryLogicB.ParseUnpaused(log) + case _AutomationRegistryLogicB.abi.Events["UpkeepAdminTransferRequested"].ID: + return _AutomationRegistryLogicB.ParseUpkeepAdminTransferRequested(log) + case _AutomationRegistryLogicB.abi.Events["UpkeepAdminTransferred"].ID: + return _AutomationRegistryLogicB.ParseUpkeepAdminTransferred(log) + case _AutomationRegistryLogicB.abi.Events["UpkeepCanceled"].ID: + return _AutomationRegistryLogicB.ParseUpkeepCanceled(log) + case _AutomationRegistryLogicB.abi.Events["UpkeepCheckDataSet"].ID: + return _AutomationRegistryLogicB.ParseUpkeepCheckDataSet(log) + case _AutomationRegistryLogicB.abi.Events["UpkeepGasLimitSet"].ID: + return _AutomationRegistryLogicB.ParseUpkeepGasLimitSet(log) + case _AutomationRegistryLogicB.abi.Events["UpkeepMigrated"].ID: + return _AutomationRegistryLogicB.ParseUpkeepMigrated(log) + case _AutomationRegistryLogicB.abi.Events["UpkeepOffchainConfigSet"].ID: + return _AutomationRegistryLogicB.ParseUpkeepOffchainConfigSet(log) + case _AutomationRegistryLogicB.abi.Events["UpkeepPaused"].ID: + return _AutomationRegistryLogicB.ParseUpkeepPaused(log) + case _AutomationRegistryLogicB.abi.Events["UpkeepPerformed"].ID: + return _AutomationRegistryLogicB.ParseUpkeepPerformed(log) + case _AutomationRegistryLogicB.abi.Events["UpkeepPrivilegeConfigSet"].ID: + return _AutomationRegistryLogicB.ParseUpkeepPrivilegeConfigSet(log) + case _AutomationRegistryLogicB.abi.Events["UpkeepReceived"].ID: + return _AutomationRegistryLogicB.ParseUpkeepReceived(log) + case _AutomationRegistryLogicB.abi.Events["UpkeepRegistered"].ID: + return _AutomationRegistryLogicB.ParseUpkeepRegistered(log) + case _AutomationRegistryLogicB.abi.Events["UpkeepTriggerConfigSet"].ID: + return _AutomationRegistryLogicB.ParseUpkeepTriggerConfigSet(log) + case _AutomationRegistryLogicB.abi.Events["UpkeepUnpaused"].ID: + return _AutomationRegistryLogicB.ParseUpkeepUnpaused(log) + + default: + return nil, fmt.Errorf("abigen wrapper received unknown log topic: %v", log.Topics[0]) + } +} + +func (AutomationRegistryLogicBAdminPrivilegeConfigSet) Topic() common.Hash { + return common.HexToHash("0x7c44b4eb59ee7873514e7e43e7718c269d872965938b288aa143befca62f99d2") +} + +func (AutomationRegistryLogicBCancelledUpkeepReport) Topic() common.Hash { + return common.HexToHash("0xc3237c8807c467c1b39b8d0395eff077313e691bf0a7388106792564ebfd5636") +} + +func (AutomationRegistryLogicBDedupKeyAdded) Topic() common.Hash { + return common.HexToHash("0xa4a4e334c0e330143f9437484fe516c13bc560b86b5b0daf58e7084aaac228f2") +} + +func (AutomationRegistryLogicBFundsAdded) Topic() common.Hash { + return common.HexToHash("0xafd24114486da8ebfc32f3626dada8863652e187461aa74d4bfa734891506203") +} + +func (AutomationRegistryLogicBFundsWithdrawn) Topic() common.Hash { + return common.HexToHash("0xf3b5906e5672f3e524854103bcafbbdba80dbdfeca2c35e116127b1060a68318") +} + +func (AutomationRegistryLogicBInsufficientFundsUpkeepReport) Topic() common.Hash { + return common.HexToHash("0x377c8b0c126ae5248d27aca1c76fac4608aff85673ee3caf09747e1044549e02") +} + +func (AutomationRegistryLogicBOwnerFundsWithdrawn) Topic() common.Hash { + return common.HexToHash("0x1d07d0b0be43d3e5fee41a80b579af370affee03fa595bf56d5d4c19328162f1") +} + +func (AutomationRegistryLogicBOwnershipTransferRequested) Topic() common.Hash { + return common.HexToHash("0xed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae1278") +} + +func (AutomationRegistryLogicBOwnershipTransferred) Topic() common.Hash { + return common.HexToHash("0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0") +} + +func (AutomationRegistryLogicBPaused) Topic() common.Hash { + return common.HexToHash("0x62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a258") +} + +func (AutomationRegistryLogicBPayeesUpdated) Topic() common.Hash { + return common.HexToHash("0xa46de38886467c59be07a0675f14781206a5477d871628af46c2443822fcb725") +} + +func (AutomationRegistryLogicBPayeeshipTransferRequested) Topic() common.Hash { + return common.HexToHash("0x84f7c7c80bb8ed2279b4aab5f61cd05e6374073d38f46d7f32de8c30e9e38367") +} + +func (AutomationRegistryLogicBPayeeshipTransferred) Topic() common.Hash { + return common.HexToHash("0x78af32efdcad432315431e9b03d27e6cd98fb79c405fdc5af7c1714d9c0f75b3") +} + +func (AutomationRegistryLogicBPaymentWithdrawn) Topic() common.Hash { + return common.HexToHash("0x9819093176a1851202c7bcfa46845809b4e47c261866550e94ed3775d2f40698") +} + +func (AutomationRegistryLogicBReorgedUpkeepReport) Topic() common.Hash { + return common.HexToHash("0x6aa7f60c176da7af894b384daea2249497448137f5943c1237ada8bc92bdc301") +} + +func (AutomationRegistryLogicBStaleUpkeepReport) Topic() common.Hash { + return common.HexToHash("0x405288ea7be309e16cfdf481367f90a413e1d4634fcdaf8966546db9b93012e8") +} + +func (AutomationRegistryLogicBUnpaused) Topic() common.Hash { + return common.HexToHash("0x5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa") +} + +func (AutomationRegistryLogicBUpkeepAdminTransferRequested) Topic() common.Hash { + return common.HexToHash("0xb1cbb2c4b8480034c27e06da5f096b8233a8fd4497028593a41ff6df79726b35") +} + +func (AutomationRegistryLogicBUpkeepAdminTransferred) Topic() common.Hash { + return common.HexToHash("0x5cff4db96bef051785e999f44bfcd21c18823e034fb92dd376e3db4ce0feeb2c") +} + +func (AutomationRegistryLogicBUpkeepCanceled) Topic() common.Hash { + return common.HexToHash("0x91cb3bb75cfbd718bbfccc56b7f53d92d7048ef4ca39a3b7b7c6d4af1f791181") +} + +func (AutomationRegistryLogicBUpkeepCheckDataSet) Topic() common.Hash { + return common.HexToHash("0xcba2d5723b2ee59e53a8e8a82a4a7caf4fdfe70e9f7c582950bf7e7a5c24e83d") +} + +func (AutomationRegistryLogicBUpkeepGasLimitSet) Topic() common.Hash { + return common.HexToHash("0xc24c07e655ce79fba8a589778987d3c015bc6af1632bb20cf9182e02a65d972c") +} + +func (AutomationRegistryLogicBUpkeepMigrated) Topic() common.Hash { + return common.HexToHash("0xb38647142fbb1ea4c000fc4569b37a4e9a9f6313317b84ee3e5326c1a6cd06ff") +} + +func (AutomationRegistryLogicBUpkeepOffchainConfigSet) Topic() common.Hash { + return common.HexToHash("0x3e8740446213c8a77d40e08f79136ce3f347d13ed270a6ebdf57159e0faf4850") +} + +func (AutomationRegistryLogicBUpkeepPaused) Topic() common.Hash { + return common.HexToHash("0x8ab10247ce168c27748e656ecf852b951fcaac790c18106b19aa0ae57a8b741f") +} + +func (AutomationRegistryLogicBUpkeepPerformed) Topic() common.Hash { + return common.HexToHash("0xad8cc9579b21dfe2c2f6ea35ba15b656e46b4f5b0cb424f52739b8ce5cac9c5b") +} + +func (AutomationRegistryLogicBUpkeepPrivilegeConfigSet) Topic() common.Hash { + return common.HexToHash("0x2fd8d70753a007014349d4591843cc031c2dd7a260d7dd82eca8253686ae7769") +} + +func (AutomationRegistryLogicBUpkeepReceived) Topic() common.Hash { + return common.HexToHash("0x74931a144e43a50694897f241d973aecb5024c0e910f9bb80a163ea3c1cf5a71") +} + +func (AutomationRegistryLogicBUpkeepRegistered) Topic() common.Hash { + return common.HexToHash("0xbae366358c023f887e791d7a62f2e4316f1026bd77f6fb49501a917b3bc5d012") +} + +func (AutomationRegistryLogicBUpkeepTriggerConfigSet) Topic() common.Hash { + return common.HexToHash("0x2b72ac786c97e68dbab71023ed6f2bdbfc80ad9bb7808941929229d71b7d5664") +} + +func (AutomationRegistryLogicBUpkeepUnpaused) Topic() common.Hash { + return common.HexToHash("0x7bada562044eb163f6b4003c4553e4e62825344c0418eea087bed5ee05a47456") +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicB) Address() common.Address { + return _AutomationRegistryLogicB.address +} + +type AutomationRegistryLogicBInterface interface { + GetActiveUpkeepIDs(opts *bind.CallOpts, startIndex *big.Int, maxCount *big.Int) ([]*big.Int, error) + + GetAdminPrivilegeConfig(opts *bind.CallOpts, admin common.Address) ([]byte, error) + + GetAutomationForwarderLogic(opts *bind.CallOpts) (common.Address, error) + + GetBalance(opts *bind.CallOpts, id *big.Int) (*big.Int, error) + + GetCancellationDelay(opts *bind.CallOpts) (*big.Int, error) + + GetConditionalGasOverhead(opts *bind.CallOpts) (*big.Int, error) + + GetFastGasFeedAddress(opts *bind.CallOpts) (common.Address, error) + + GetForwarder(opts *bind.CallOpts, upkeepID *big.Int) (common.Address, error) + + GetLinkAddress(opts *bind.CallOpts) (common.Address, error) + + GetLinkNativeFeedAddress(opts *bind.CallOpts) (common.Address, error) + + GetLogGasOverhead(opts *bind.CallOpts) (*big.Int, error) + + GetMaxPaymentForGas(opts *bind.CallOpts, triggerType uint8, gasLimit uint32) (*big.Int, error) + + GetMinBalance(opts *bind.CallOpts, id *big.Int) (*big.Int, error) + + GetMinBalanceForUpkeep(opts *bind.CallOpts, id *big.Int) (*big.Int, error) + + GetMode(opts *bind.CallOpts) (uint8, error) + + GetPeerRegistryMigrationPermission(opts *bind.CallOpts, peer common.Address) (uint8, error) + + GetPerPerformByteGasOverhead(opts *bind.CallOpts) (*big.Int, error) + + GetPerSignerGasOverhead(opts *bind.CallOpts) (*big.Int, error) + + GetSignerInfo(opts *bind.CallOpts, query common.Address) (GetSignerInfo, + + error) + + GetState(opts *bind.CallOpts) (GetState, + + error) + + GetTransmitterInfo(opts *bind.CallOpts, query common.Address) (GetTransmitterInfo, + + error) + + GetTriggerType(opts *bind.CallOpts, upkeepId *big.Int) (uint8, error) + + GetUpkeep(opts *bind.CallOpts, id *big.Int) (AutomationRegistryBase22UpkeepInfo, error) + + GetUpkeepPrivilegeConfig(opts *bind.CallOpts, upkeepId *big.Int) ([]byte, error) + + GetUpkeepTriggerConfig(opts *bind.CallOpts, upkeepId *big.Int) ([]byte, error) + + HasDedupKey(opts *bind.CallOpts, dedupKey [32]byte) (bool, error) + + Owner(opts *bind.CallOpts) (common.Address, error) + + UpkeepTranscoderVersion(opts *bind.CallOpts) (uint8, error) + + UpkeepVersion(opts *bind.CallOpts) (uint8, error) + + AcceptOwnership(opts *bind.TransactOpts) (*types.Transaction, error) + + AcceptPayeeship(opts *bind.TransactOpts, transmitter common.Address) (*types.Transaction, error) + + AcceptUpkeepAdmin(opts *bind.TransactOpts, id *big.Int) (*types.Transaction, error) + + Pause(opts *bind.TransactOpts) (*types.Transaction, error) + + PauseUpkeep(opts *bind.TransactOpts, id *big.Int) (*types.Transaction, error) + + RecoverFunds(opts *bind.TransactOpts) (*types.Transaction, error) + + SetAdminPrivilegeConfig(opts *bind.TransactOpts, admin common.Address, newPrivilegeConfig []byte) (*types.Transaction, error) + + SetPayees(opts *bind.TransactOpts, payees []common.Address) (*types.Transaction, error) + + SetPeerRegistryMigrationPermission(opts *bind.TransactOpts, peer common.Address, permission uint8) (*types.Transaction, error) + + SetUpkeepCheckData(opts *bind.TransactOpts, id *big.Int, newCheckData []byte) (*types.Transaction, error) + + SetUpkeepGasLimit(opts *bind.TransactOpts, id *big.Int, gasLimit uint32) (*types.Transaction, error) + + SetUpkeepOffchainConfig(opts *bind.TransactOpts, id *big.Int, config []byte) (*types.Transaction, error) + + SetUpkeepPrivilegeConfig(opts *bind.TransactOpts, upkeepId *big.Int, newPrivilegeConfig []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) + + TransferUpkeepAdmin(opts *bind.TransactOpts, id *big.Int, proposed common.Address) (*types.Transaction, error) + + Unpause(opts *bind.TransactOpts) (*types.Transaction, error) + + UnpauseUpkeep(opts *bind.TransactOpts, id *big.Int) (*types.Transaction, error) + + WithdrawFunds(opts *bind.TransactOpts, id *big.Int, to common.Address) (*types.Transaction, error) + + WithdrawOwnerFunds(opts *bind.TransactOpts) (*types.Transaction, error) + + WithdrawPayment(opts *bind.TransactOpts, from common.Address, to common.Address) (*types.Transaction, error) + + FilterAdminPrivilegeConfigSet(opts *bind.FilterOpts, admin []common.Address) (*AutomationRegistryLogicBAdminPrivilegeConfigSetIterator, error) + + WatchAdminPrivilegeConfigSet(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicBAdminPrivilegeConfigSet, admin []common.Address) (event.Subscription, error) + + ParseAdminPrivilegeConfigSet(log types.Log) (*AutomationRegistryLogicBAdminPrivilegeConfigSet, error) + + FilterCancelledUpkeepReport(opts *bind.FilterOpts, id []*big.Int) (*AutomationRegistryLogicBCancelledUpkeepReportIterator, error) + + WatchCancelledUpkeepReport(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicBCancelledUpkeepReport, id []*big.Int) (event.Subscription, error) + + ParseCancelledUpkeepReport(log types.Log) (*AutomationRegistryLogicBCancelledUpkeepReport, error) + + FilterDedupKeyAdded(opts *bind.FilterOpts, dedupKey [][32]byte) (*AutomationRegistryLogicBDedupKeyAddedIterator, error) + + WatchDedupKeyAdded(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicBDedupKeyAdded, dedupKey [][32]byte) (event.Subscription, error) + + ParseDedupKeyAdded(log types.Log) (*AutomationRegistryLogicBDedupKeyAdded, error) + + FilterFundsAdded(opts *bind.FilterOpts, id []*big.Int, from []common.Address) (*AutomationRegistryLogicBFundsAddedIterator, error) + + WatchFundsAdded(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicBFundsAdded, id []*big.Int, from []common.Address) (event.Subscription, error) + + ParseFundsAdded(log types.Log) (*AutomationRegistryLogicBFundsAdded, error) + + FilterFundsWithdrawn(opts *bind.FilterOpts, id []*big.Int) (*AutomationRegistryLogicBFundsWithdrawnIterator, error) + + WatchFundsWithdrawn(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicBFundsWithdrawn, id []*big.Int) (event.Subscription, error) + + ParseFundsWithdrawn(log types.Log) (*AutomationRegistryLogicBFundsWithdrawn, error) + + FilterInsufficientFundsUpkeepReport(opts *bind.FilterOpts, id []*big.Int) (*AutomationRegistryLogicBInsufficientFundsUpkeepReportIterator, error) + + WatchInsufficientFundsUpkeepReport(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicBInsufficientFundsUpkeepReport, id []*big.Int) (event.Subscription, error) + + ParseInsufficientFundsUpkeepReport(log types.Log) (*AutomationRegistryLogicBInsufficientFundsUpkeepReport, error) + + FilterOwnerFundsWithdrawn(opts *bind.FilterOpts) (*AutomationRegistryLogicBOwnerFundsWithdrawnIterator, error) + + WatchOwnerFundsWithdrawn(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicBOwnerFundsWithdrawn) (event.Subscription, error) + + ParseOwnerFundsWithdrawn(log types.Log) (*AutomationRegistryLogicBOwnerFundsWithdrawn, error) + + FilterOwnershipTransferRequested(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*AutomationRegistryLogicBOwnershipTransferRequestedIterator, error) + + WatchOwnershipTransferRequested(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicBOwnershipTransferRequested, from []common.Address, to []common.Address) (event.Subscription, error) + + ParseOwnershipTransferRequested(log types.Log) (*AutomationRegistryLogicBOwnershipTransferRequested, error) + + FilterOwnershipTransferred(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*AutomationRegistryLogicBOwnershipTransferredIterator, error) + + WatchOwnershipTransferred(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicBOwnershipTransferred, from []common.Address, to []common.Address) (event.Subscription, error) + + ParseOwnershipTransferred(log types.Log) (*AutomationRegistryLogicBOwnershipTransferred, error) + + FilterPaused(opts *bind.FilterOpts) (*AutomationRegistryLogicBPausedIterator, error) + + WatchPaused(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicBPaused) (event.Subscription, error) + + ParsePaused(log types.Log) (*AutomationRegistryLogicBPaused, error) + + FilterPayeesUpdated(opts *bind.FilterOpts) (*AutomationRegistryLogicBPayeesUpdatedIterator, error) + + WatchPayeesUpdated(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicBPayeesUpdated) (event.Subscription, error) + + ParsePayeesUpdated(log types.Log) (*AutomationRegistryLogicBPayeesUpdated, error) + + FilterPayeeshipTransferRequested(opts *bind.FilterOpts, transmitter []common.Address, from []common.Address, to []common.Address) (*AutomationRegistryLogicBPayeeshipTransferRequestedIterator, error) + + WatchPayeeshipTransferRequested(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicBPayeeshipTransferRequested, transmitter []common.Address, from []common.Address, to []common.Address) (event.Subscription, error) + + ParsePayeeshipTransferRequested(log types.Log) (*AutomationRegistryLogicBPayeeshipTransferRequested, error) + + FilterPayeeshipTransferred(opts *bind.FilterOpts, transmitter []common.Address, from []common.Address, to []common.Address) (*AutomationRegistryLogicBPayeeshipTransferredIterator, error) + + WatchPayeeshipTransferred(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicBPayeeshipTransferred, transmitter []common.Address, from []common.Address, to []common.Address) (event.Subscription, error) + + ParsePayeeshipTransferred(log types.Log) (*AutomationRegistryLogicBPayeeshipTransferred, error) + + FilterPaymentWithdrawn(opts *bind.FilterOpts, transmitter []common.Address, amount []*big.Int, to []common.Address) (*AutomationRegistryLogicBPaymentWithdrawnIterator, error) + + WatchPaymentWithdrawn(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicBPaymentWithdrawn, transmitter []common.Address, amount []*big.Int, to []common.Address) (event.Subscription, error) + + ParsePaymentWithdrawn(log types.Log) (*AutomationRegistryLogicBPaymentWithdrawn, error) + + FilterReorgedUpkeepReport(opts *bind.FilterOpts, id []*big.Int) (*AutomationRegistryLogicBReorgedUpkeepReportIterator, error) + + WatchReorgedUpkeepReport(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicBReorgedUpkeepReport, id []*big.Int) (event.Subscription, error) + + ParseReorgedUpkeepReport(log types.Log) (*AutomationRegistryLogicBReorgedUpkeepReport, error) + + FilterStaleUpkeepReport(opts *bind.FilterOpts, id []*big.Int) (*AutomationRegistryLogicBStaleUpkeepReportIterator, error) + + WatchStaleUpkeepReport(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicBStaleUpkeepReport, id []*big.Int) (event.Subscription, error) + + ParseStaleUpkeepReport(log types.Log) (*AutomationRegistryLogicBStaleUpkeepReport, error) + + FilterUnpaused(opts *bind.FilterOpts) (*AutomationRegistryLogicBUnpausedIterator, error) + + WatchUnpaused(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicBUnpaused) (event.Subscription, error) + + ParseUnpaused(log types.Log) (*AutomationRegistryLogicBUnpaused, error) + + FilterUpkeepAdminTransferRequested(opts *bind.FilterOpts, id []*big.Int, from []common.Address, to []common.Address) (*AutomationRegistryLogicBUpkeepAdminTransferRequestedIterator, error) + + WatchUpkeepAdminTransferRequested(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicBUpkeepAdminTransferRequested, id []*big.Int, from []common.Address, to []common.Address) (event.Subscription, error) + + ParseUpkeepAdminTransferRequested(log types.Log) (*AutomationRegistryLogicBUpkeepAdminTransferRequested, error) + + FilterUpkeepAdminTransferred(opts *bind.FilterOpts, id []*big.Int, from []common.Address, to []common.Address) (*AutomationRegistryLogicBUpkeepAdminTransferredIterator, error) + + WatchUpkeepAdminTransferred(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicBUpkeepAdminTransferred, id []*big.Int, from []common.Address, to []common.Address) (event.Subscription, error) + + ParseUpkeepAdminTransferred(log types.Log) (*AutomationRegistryLogicBUpkeepAdminTransferred, error) + + FilterUpkeepCanceled(opts *bind.FilterOpts, id []*big.Int, atBlockHeight []uint64) (*AutomationRegistryLogicBUpkeepCanceledIterator, error) + + WatchUpkeepCanceled(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicBUpkeepCanceled, id []*big.Int, atBlockHeight []uint64) (event.Subscription, error) + + ParseUpkeepCanceled(log types.Log) (*AutomationRegistryLogicBUpkeepCanceled, error) + + FilterUpkeepCheckDataSet(opts *bind.FilterOpts, id []*big.Int) (*AutomationRegistryLogicBUpkeepCheckDataSetIterator, error) + + WatchUpkeepCheckDataSet(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicBUpkeepCheckDataSet, id []*big.Int) (event.Subscription, error) + + ParseUpkeepCheckDataSet(log types.Log) (*AutomationRegistryLogicBUpkeepCheckDataSet, error) + + FilterUpkeepGasLimitSet(opts *bind.FilterOpts, id []*big.Int) (*AutomationRegistryLogicBUpkeepGasLimitSetIterator, error) + + WatchUpkeepGasLimitSet(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicBUpkeepGasLimitSet, id []*big.Int) (event.Subscription, error) + + ParseUpkeepGasLimitSet(log types.Log) (*AutomationRegistryLogicBUpkeepGasLimitSet, error) + + FilterUpkeepMigrated(opts *bind.FilterOpts, id []*big.Int) (*AutomationRegistryLogicBUpkeepMigratedIterator, error) + + WatchUpkeepMigrated(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicBUpkeepMigrated, id []*big.Int) (event.Subscription, error) + + ParseUpkeepMigrated(log types.Log) (*AutomationRegistryLogicBUpkeepMigrated, error) + + FilterUpkeepOffchainConfigSet(opts *bind.FilterOpts, id []*big.Int) (*AutomationRegistryLogicBUpkeepOffchainConfigSetIterator, error) + + WatchUpkeepOffchainConfigSet(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicBUpkeepOffchainConfigSet, id []*big.Int) (event.Subscription, error) + + ParseUpkeepOffchainConfigSet(log types.Log) (*AutomationRegistryLogicBUpkeepOffchainConfigSet, error) + + FilterUpkeepPaused(opts *bind.FilterOpts, id []*big.Int) (*AutomationRegistryLogicBUpkeepPausedIterator, error) + + WatchUpkeepPaused(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicBUpkeepPaused, id []*big.Int) (event.Subscription, error) + + ParseUpkeepPaused(log types.Log) (*AutomationRegistryLogicBUpkeepPaused, error) + + FilterUpkeepPerformed(opts *bind.FilterOpts, id []*big.Int, success []bool) (*AutomationRegistryLogicBUpkeepPerformedIterator, error) + + WatchUpkeepPerformed(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicBUpkeepPerformed, id []*big.Int, success []bool) (event.Subscription, error) + + ParseUpkeepPerformed(log types.Log) (*AutomationRegistryLogicBUpkeepPerformed, error) + + FilterUpkeepPrivilegeConfigSet(opts *bind.FilterOpts, id []*big.Int) (*AutomationRegistryLogicBUpkeepPrivilegeConfigSetIterator, error) + + WatchUpkeepPrivilegeConfigSet(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicBUpkeepPrivilegeConfigSet, id []*big.Int) (event.Subscription, error) + + ParseUpkeepPrivilegeConfigSet(log types.Log) (*AutomationRegistryLogicBUpkeepPrivilegeConfigSet, error) + + FilterUpkeepReceived(opts *bind.FilterOpts, id []*big.Int) (*AutomationRegistryLogicBUpkeepReceivedIterator, error) + + WatchUpkeepReceived(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicBUpkeepReceived, id []*big.Int) (event.Subscription, error) + + ParseUpkeepReceived(log types.Log) (*AutomationRegistryLogicBUpkeepReceived, error) + + FilterUpkeepRegistered(opts *bind.FilterOpts, id []*big.Int) (*AutomationRegistryLogicBUpkeepRegisteredIterator, error) + + WatchUpkeepRegistered(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicBUpkeepRegistered, id []*big.Int) (event.Subscription, error) + + ParseUpkeepRegistered(log types.Log) (*AutomationRegistryLogicBUpkeepRegistered, error) + + FilterUpkeepTriggerConfigSet(opts *bind.FilterOpts, id []*big.Int) (*AutomationRegistryLogicBUpkeepTriggerConfigSetIterator, error) + + WatchUpkeepTriggerConfigSet(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicBUpkeepTriggerConfigSet, id []*big.Int) (event.Subscription, error) + + ParseUpkeepTriggerConfigSet(log types.Log) (*AutomationRegistryLogicBUpkeepTriggerConfigSet, error) + + FilterUpkeepUnpaused(opts *bind.FilterOpts, id []*big.Int) (*AutomationRegistryLogicBUpkeepUnpausedIterator, error) + + WatchUpkeepUnpaused(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicBUpkeepUnpaused, id []*big.Int) (event.Subscription, error) + + ParseUpkeepUnpaused(log types.Log) (*AutomationRegistryLogicBUpkeepUnpaused, error) + + ParseLog(log types.Log) (generated.AbigenLog, error) + + Address() common.Address +} diff --git a/core/gethwrappers/generated/keeper_registry_wrapper_2_2/keeper_registry_wrapper_2_2.go b/core/gethwrappers/generated/keeper_registry_wrapper_2_2/keeper_registry_wrapper_2_2.go new file mode 100644 index 0000000000..89da6bc958 --- /dev/null +++ b/core/gethwrappers/generated/keeper_registry_wrapper_2_2/keeper_registry_wrapper_2_2.go @@ -0,0 +1,5169 @@ +// Code generated - DO NOT EDIT. +// This file is a generated binding and any manual changes will be lost. + +package keeper_registry_wrapper_2_2 + +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 +) + +type AutomationRegistryBase22OnchainConfig struct { + PaymentPremiumPPB uint32 + FlatFeeMicroLink uint32 + CheckGasLimit uint32 + StalenessSeconds *big.Int + GasCeilingMultiplier uint16 + MinUpkeepSpend *big.Int + MaxPerformGas uint32 + MaxCheckDataSize uint32 + MaxPerformDataSize uint32 + MaxRevertDataSize uint32 + FallbackGasPrice *big.Int + FallbackLinkPrice *big.Int + Transcoder common.Address + Registrars []common.Address + UpkeepPrivilegeManager common.Address +} + +var AutomationRegistryMetaData = &bind.MetaData{ + ABI: "[{\"inputs\":[{\"internalType\":\"contractAutomationRegistryLogicB2_2\",\"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\":\"structAutomationRegistryBase2_2.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\"}]", + Bin: "0x6101406040523480156200001257600080fd5b50604051620054c9380380620054c98339810160408190526200003591620003df565b80816001600160a01b0316634b4fd03b6040518163ffffffff1660e01b8152600401602060405180830381865afa15801562000075573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200009b919062000406565b826001600160a01b031663ca30e6036040518163ffffffff1660e01b8152600401602060405180830381865afa158015620000da573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620001009190620003df565b836001600160a01b031663b10b673c6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156200013f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620001659190620003df565b846001600160a01b0316636709d0e56040518163ffffffff1660e01b8152600401602060405180830381865afa158015620001a4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620001ca9190620003df565b856001600160a01b0316635425d8ac6040518163ffffffff1660e01b8152600401602060405180830381865afa15801562000209573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200022f9190620003df565b3380600081620002865760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b0384811691909117909155811615620002b957620002b9816200031b565b505050846002811115620002d157620002d162000429565b60e0816002811115620002e857620002e862000429565b9052506001600160a01b0393841660805291831660a052821660c0528116610100529190911661012052506200043f9050565b336001600160a01b03821603620003755760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c6600000000000000000060448201526064016200027d565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b6001600160a01b0381168114620003dc57600080fd5b50565b600060208284031215620003f257600080fd5b8151620003ff81620003c6565b9392505050565b6000602082840312156200041957600080fd5b815160038110620003ff57600080fd5b634e487b7160e01b600052602160045260246000fd5b60805160a05160c05160e0516101005161012051615028620004a16000396000818160d6015261016f01526000505060008181612eb60152818161321f015281816133b20152613a4901526000505060005050600061043b01526150286000f3fe608060405234801561001057600080fd5b50600436106100d45760003560e01c8063aed2e92911610081578063e29b753c1161005b578063e29b753c146102e8578063e3d0e712146102fb578063f2fde38b1461030e576100d4565b8063aed2e92914610262578063afcb95d71461028c578063b1dc65a4146102d5576100d4565b806381ff7048116100b257806381ff7048146101bc5780638da5cb5b14610231578063a4c0ed361461024f576100d4565b8063181f5a771461011b578063349e8cca1461016d57806379ba5097146101b4575b7f00000000000000000000000000000000000000000000000000000000000000003660008037600080366000845af43d6000803e808015610114573d6000f35b3d6000fd5b005b6101576040518060400160405280601881526020017f4175746f6d6174696f6e526567697374727920322e322e30000000000000000081525081565b6040516101649190613cc8565b60405180910390f35b7f00000000000000000000000000000000000000000000000000000000000000005b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610164565b610119610321565b61020e60145460115463ffffffff780100000000000000000000000000000000000000000000000083048116937c01000000000000000000000000000000000000000000000000000000009093041691565b6040805163ffffffff948516815293909216602084015290820152606001610164565b60005473ffffffffffffffffffffffffffffffffffffffff1661018f565b61011961025d366004613d4a565b610423565b610275610270366004613da6565b61063f565b604080519215158352602083019190915201610164565b601154601254604080516000815260208101939093527c010000000000000000000000000000000000000000000000000000000090910463ffffffff1690820152606001610164565b6101196102e3366004613e37565b6107a7565b6101196102f63660046142b2565b6112ea565b61011961030936600461437f565b6121e6565b61011961031c36600461440e565b61220f565b60015473ffffffffffffffffffffffffffffffffffffffff1633146103a7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e65720000000000000000000060448201526064015b60405180910390fd5b60008054337fffffffffffffffffffffffff00000000000000000000000000000000000000008083168217845560018054909116905560405173ffffffffffffffffffffffffffffffffffffffff90921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b3373ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001614610492576040517fc8bad78d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b602081146104cc576040517fdfe9309000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60006104da8284018461442b565b60008181526004602052604090205490915065010000000000900463ffffffff90811614610534576040517f9c0083a200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008181526004602052604090206001015461056f9085906c0100000000000000000000000090046bffffffffffffffffffffffff16614473565b600082815260046020526040902060010180546bffffffffffffffffffffffff929092166c01000000000000000000000000027fffffffffffffffff000000000000000000000000ffffffffffffffffffffffff9092169190911790556018546105da908590614498565b6018556040516bffffffffffffffffffffffff8516815273ffffffffffffffffffffffffffffffffffffffff86169082907fafd24114486da8ebfc32f3626dada8863652e187461aa74d4bfa7348915062039060200160405180910390a35050505050565b60008061064a612223565b6012546e010000000000000000000000000000900460ff1615610699576040517f24522f3400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600085815260046020908152604091829020825160e081018452815460ff811615158252610100810463ffffffff908116838601819052650100000000008304821684880152690100000000000000000090920473ffffffffffffffffffffffffffffffffffffffff16606084018190526001909401546bffffffffffffffffffffffff80821660808601526c0100000000000000000000000082041660a0850152780100000000000000000000000000000000000000000000000090041660c08301528451601f8901859004850281018501909552878552909361079893899089908190840183828082843760009201919091525061225d92505050565b9093509150505b935093915050565b60005a604080516101208101825260125460ff808216835261010080830463ffffffff90811660208601526501000000000084048116958501959095526901000000000000000000830462ffffff1660608501526c01000000000000000000000000830461ffff1660808501526e0100000000000000000000000000008304821615801560a08601526f010000000000000000000000000000008404909216151560c085015270010000000000000000000000000000000083046bffffffffffffffffffffffff1660e08501527c0100000000000000000000000000000000000000000000000000000000909204909316908201529192506108d5576040517f24522f3400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b336000908152600b602052604090205460ff1661091e576040517f1099ed7500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6011548a351461095a576040517fdfdcf8e700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b80516109679060016144da565b60ff16861415806109785750858414155b156109af576040517f0244f71a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6109bf8a8a8a8a8a8a8a8a612468565b60006109cb8a8a6126d1565b9050600081604001515167ffffffffffffffff8111156109ed576109ed613eee565b604051908082528060200260200182016040528015610ab157816020015b604080516101e0810182526000610100820181815261012083018290526101408301829052610160830182905261018083018290526101a083018290526101c0830182905282526020808301829052928201819052606082018190526080820181905260a0820181905260c0820181905260e082015282527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff909201910181610a0b5790505b5090506000805b836040015151811015610efa576004600085604001518381518110610adf57610adf6144ab565b6020908102919091018101518252818101929092526040908101600020815160e081018352815460ff811615158252610100810463ffffffff90811695830195909552650100000000008104851693820193909352690100000000000000000090920473ffffffffffffffffffffffffffffffffffffffff166060830152600101546bffffffffffffffffffffffff80821660808401526c0100000000000000000000000082041660a08301527801000000000000000000000000000000000000000000000000900490911660c08201528351849083908110610bc457610bc46144ab565b602002602001015160000181905250610bf984604001518281518110610bec57610bec6144ab565b602002602001015161278c565b838281518110610c0b57610c0b6144ab565b6020026020010151608001906001811115610c2857610c286144f3565b90816001811115610c3b57610c3b6144f3565b81525050610caf85848381518110610c5557610c556144ab565b60200260200101516080015186606001518481518110610c7757610c776144ab565b60200260200101518760a001518581518110610c9557610c956144ab565b602002602001015151886000015189602001516001612837565b838281518110610cc157610cc16144ab565b6020026020010151604001906bffffffffffffffffffffffff1690816bffffffffffffffffffffffff1681525050610d4d84604001518281518110610d0857610d086144ab565b602002602001015185608001518381518110610d2657610d266144ab565b6020026020010151858481518110610d4057610d406144ab565b6020026020010151612882565b848381518110610d5f57610d5f6144ab565b6020026020010151602001858481518110610d7c57610d7c6144ab565b602002602001015160e0018281525082151515158152505050828181518110610da757610da76144ab565b60200260200101516020015115610dca57610dc3600183614522565b9150610dcf565b610ee8565b610e35838281518110610de457610de46144ab565b6020026020010151600001516060015185606001518381518110610e0a57610e0a6144ab565b60200260200101518660a001518481518110610e2857610e286144ab565b602002602001015161225d565b848381518110610e4757610e476144ab565b6020026020010151606001858481518110610e6457610e646144ab565b602002602001015160a0018281525082151515158152505050828181518110610e8f57610e8f6144ab565b602002602001015160a0015186610ea6919061453d565b9550610ee884604001518281518110610ec157610ec16144ab565b6020026020010151848381518110610edb57610edb6144ab565b6020026020010151612a00565b80610ef281614550565b915050610ab8565b508061ffff16600003610f115750505050506112e0565b8351610f1e9060016144da565b610f2d9060ff1661044c614588565b616b6c610f3b8d6010614588565b5a610f46908961453d565b610f509190614498565b610f5a9190614498565b610f649190614498565b9450611b58610f7761ffff8316876145f4565b610f819190614498565b945060008060008060005b87604001515181101561118257868181518110610fab57610fab6144ab565b60200260200101516020015115611170576110078a888381518110610fd257610fd26144ab565b6020026020010151608001518a60a001518481518110610ff457610ff46144ab565b6020026020010151518c60000151612b12565b878281518110611019576110196144ab565b602002602001015160c00181815250506110758989604001518381518110611043576110436144ab565b602002602001015189848151811061105d5761105d6144ab565b60200260200101518b600001518c602001518b612b32565b90935091506110848285614473565b93506110908386614473565b94508681815181106110a4576110a46144ab565b6020026020010151606001511515886040015182815181106110c8576110c86144ab565b60200260200101517fad8cc9579b21dfe2c2f6ea35ba15b656e46b4f5b0cb424f52739b8ce5cac9c5b84866110fd9190614473565b8a858151811061110f5761110f6144ab565b602002602001015160a001518b868151811061112d5761112d6144ab565b602002602001015160c001518d60800151878151811061114f5761114f6144ab565b60200260200101516040516111679493929190614608565b60405180910390a35b8061117a81614550565b915050610f8c565b5050336000908152600b6020526040902080548492506002906111ba9084906201000090046bffffffffffffffffffffffff16614473565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff16021790555080601260000160108282829054906101000a90046bffffffffffffffffffffffff166112149190614473565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff16021790555060008f600160038110611257576112576144ab565b602002013560001c9050600060088264ffffffffff16901c905087610100015163ffffffff168163ffffffff1611156112d657601280547bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167c010000000000000000000000000000000000000000000000000000000063ffffffff8416021790555b5050505050505050505b5050505050505050565b6112f2612c25565b601f8651111561132e576040517f25d0209c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8360ff1660000361136b576040517fe77dba5600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8451865114158061138a5750611382846003614645565b60ff16865111155b156113c1576040517f1d2d1c5800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b601254600e547001000000000000000000000000000000009091046bffffffffffffffffffffffff169060005b816bffffffffffffffffffffffff1681101561145657611443600e828154811061141a5761141a6144ab565b60009182526020909120015473ffffffffffffffffffffffffffffffffffffffff168484612ca6565b508061144e81614550565b9150506113ee565b5060008060005b836bffffffffffffffffffffffff1681101561155f57600d8181548110611486576114866144ab565b600091825260209091200154600e805473ffffffffffffffffffffffffffffffffffffffff909216945090829081106114c1576114c16144ab565b600091825260208083209091015473ffffffffffffffffffffffffffffffffffffffff8681168452600c8352604080852080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00001690559116808452600b90925290912080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016905591508061155781614550565b91505061145d565b5061156c600d6000613b9d565b611578600e6000613b9d565b604080516080810182526000808252602082018190529181018290526060810182905290805b8c518110156119e157600c60008e83815181106115bd576115bd6144ab565b60209081029190910181015173ffffffffffffffffffffffffffffffffffffffff1682528101919091526040016000205460ff1615611628576040517f77cea0fa00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168d8281518110611652576116526144ab565b602002602001015173ffffffffffffffffffffffffffffffffffffffff16036116a7576040517f815e1d6400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60405180604001604052806001151581526020018260ff16815250600c60008f84815181106116d8576116d86144ab565b60209081029190910181015173ffffffffffffffffffffffffffffffffffffffff1682528181019290925260400160002082518154939092015160ff16610100027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff921515929092167fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000909316929092171790558b518c9082908110611780576117806144ab565b60200260200101519150600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16036117f0576040517f58a70a0a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff82166000908152600b60209081526040918290208251608081018452905460ff80821615801584526101008304909116938301939093526bffffffffffffffffffffffff6201000082048116948301949094526e010000000000000000000000000000900490921660608301529093506118ab576040517f6a7281ad00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001835260ff80821660208086019182526bffffffffffffffffffffffff808b166060880190815273ffffffffffffffffffffffffffffffffffffffff87166000908152600b909352604092839020885181549551948a0151925184166e010000000000000000000000000000027fffffffffffff000000000000000000000000ffffffffffffffffffffffffffff939094166201000002929092167fffffffffffff000000000000000000000000000000000000000000000000ffff94909616610100027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff921515929092167fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000090951694909417179190911692909217919091179055806119d981614550565b91505061159e565b50508a516119f79150600d9060208d0190613bbb565b508851611a0b90600e9060208c0190613bbb565b506040518061012001604052808960ff168152602001886000015163ffffffff168152602001886020015163ffffffff168152602001886060015162ffffff168152602001886080015161ffff1681526020016012600001600e9054906101000a900460ff16151581526020016012600001600f9054906101000a900460ff1615158152602001856bffffffffffffffffffffffff168152602001600063ffffffff16815250601260008201518160000160006101000a81548160ff021916908360ff16021790555060208201518160000160016101000a81548163ffffffff021916908363ffffffff16021790555060408201518160000160056101000a81548163ffffffff021916908363ffffffff16021790555060608201518160000160096101000a81548162ffffff021916908362ffffff160217905550608082015181600001600c6101000a81548161ffff021916908361ffff16021790555060a082015181600001600e6101000a81548160ff02191690831515021790555060c082015181600001600f6101000a81548160ff02191690831515021790555060e08201518160000160106101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff16021790555061010082015181600001601c6101000a81548163ffffffff021916908363ffffffff1602179055509050506040518061018001604052808860a001516bffffffffffffffffffffffff16815260200188610180015173ffffffffffffffffffffffffffffffffffffffff168152602001601360010160009054906101000a90046bffffffffffffffffffffffff166bffffffffffffffffffffffff168152602001886040015163ffffffff1681526020018860c0015163ffffffff168152602001601360010160149054906101000a900463ffffffff1663ffffffff168152602001601360010160189054906101000a900463ffffffff1663ffffffff1681526020016013600101601c9054906101000a900463ffffffff1663ffffffff1681526020018860e0015163ffffffff16815260200188610100015163ffffffff16815260200188610120015163ffffffff168152602001886101c0015173ffffffffffffffffffffffffffffffffffffffff16815250601360008201518160000160006101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff160217905550602082015181600001600c6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060408201518160010160006101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff160217905550606082015181600101600c6101000a81548163ffffffff021916908363ffffffff16021790555060808201518160010160106101000a81548163ffffffff021916908363ffffffff16021790555060a08201518160010160146101000a81548163ffffffff021916908363ffffffff16021790555060c08201518160010160186101000a81548163ffffffff021916908363ffffffff16021790555060e082015181600101601c6101000a81548163ffffffff021916908363ffffffff1602179055506101008201518160020160006101000a81548163ffffffff021916908363ffffffff1602179055506101208201518160020160046101000a81548163ffffffff021916908363ffffffff1602179055506101408201518160020160086101000a81548163ffffffff021916908363ffffffff16021790555061016082015181600201600c6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555090505086610140015160168190555086610160015160178190555060006013600101601c9054906101000a900463ffffffff169050611fcd612eb0565b601480547bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167c010000000000000000000000000000000000000000000000000000000063ffffffff9384160217808255600192601891612048918591780100000000000000000000000000000000000000000000000090041661466e565b92506101000a81548163ffffffff021916908363ffffffff16021790555060008860405160200161207991906146dc565b604080518083037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe00181529190526014549091506120e290469030907801000000000000000000000000000000000000000000000000900463ffffffff168f8f8f878f8f612f65565b60115560005b6120f2600961300f565b8110156121225761210f612107600983613019565b600990613025565b508061211a81614550565b9150506120e8565b5060005b896101a0015151811015612179576121668a6101a00151828151811061214e5761214e6144ab565b6020026020010151600961304790919063ffffffff16565b508061217181614550565b915050612126565b507f1591690b8638f5fb2dbec82ac741805ac5da8b45dc5263f4875b0496fdce4e0582601154601360010160189054906101000a900463ffffffff168f8f8f878f8f6040516121d099989796959493929190614840565b60405180910390a1505050505050505050505050565b612207868686868060200190518101906122009190614971565b86866112ea565b505050505050565b612217612c25565b61222081613069565b50565b321561225b576040517fb60ac5db00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b565b60125460009081906f01000000000000000000000000000000900460ff16156122b2576040517f37ed32e800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b601280547fffffffffffffffffffffffffffffffff00ffffffffffffffffffffffffffffff166f010000000000000000000000000000001790556040517f4585e33b000000000000000000000000000000000000000000000000000000009061231f908590602401613cc8565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff000000000000000000000000000000000000000000000000000000009094169390931790925290517f79188d1600000000000000000000000000000000000000000000000000000000815290935073ffffffffffffffffffffffffffffffffffffffff8616906379188d16906123f29087908790600401614acb565b60408051808303816000875af1158015612410573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906124349190614ae4565b601280547fffffffffffffffffffffffffffffffff00ffffffffffffffffffffffffffffff16905590969095509350505050565b6000878760405161247a929190614b17565b604051908190038120612491918b90602001614b27565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081840301815282825280516020918201208383019092526000808452908301819052909250906000805b88811015612668576001858783602081106124fd576124fd6144ab565b61250a91901a601b6144da565b8c8c8581811061251c5761251c6144ab565b905060200201358b8b86818110612535576125356144ab565b9050602002013560405160008152602001604052604051612572949392919093845260ff9290921660208401526040830152606082015260800190565b6020604051602081039080840390855afa158015612594573d6000803e3d6000fd5b5050604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081015173ffffffffffffffffffffffffffffffffffffffff81166000908152600c602090815290849020838501909452925460ff8082161515808552610100909204169383019390935290955093509050612642576040517f0f4c073700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b826020015160080260ff166001901b84019350808061266090614550565b9150506124e0565b50827e010101010101010101010101010101010101010101010101010101010101018416146126c3576040517fc103be2e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b505050505050505050505050565b61270a6040518060c001604052806000815260200160008152602001606081526020016060815260200160608152602001606081525090565b600061271883850185614c18565b604081015151606082015151919250908114158061273b57508082608001515114155b8061274b5750808260a001515114155b15612782576040517fb55ac75400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5090505b92915050565b6000818160045b600f811015612819577fff0000000000000000000000000000000000000000000000000000000000000082168382602081106127d1576127d16144ab565b1a60f81b7effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff19161461280757506000949350505050565b8061281181614550565b915050612793565b5081600f1a600181111561282f5761282f6144f3565b949350505050565b60008061284988878b6000015161315e565b90506000806128648b8a63ffffffff16858a8a60018b6131ea565b90925090506128738183614473565b9b9a5050505050505050505050565b60008080808460800151600181111561289d5761289d6144f3565b036128c1576128ad868686613643565b6128bc5760009250905061079f565b612937565b6001846080015160018111156128d9576128d96144f3565b036129055760006128ea8787613737565b92509050806128ff575060009250905061079f565b50612937565b6040517ff2b2d41200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61293f612eb0565b84516040015163ffffffff161161299357857fc3237c8807c467c1b39b8d0395eff077313e691bf0a7388106792564ebfd5636866040516129809190613cc8565b60405180910390a260009250905061079f565b83604001516bffffffffffffffffffffffff16846000015160a001516bffffffffffffffffffffffff1610156129f357857f377c8b0c126ae5248d27aca1c76fac4608aff85673ee3caf09747e1044549e02866040516129809190613cc8565b6001969095509350505050565b600081608001516001811115612a1857612a186144f3565b03612a8a57612a25612eb0565b6000838152600460205260409020600101805463ffffffff929092167801000000000000000000000000000000000000000000000000027fffffffff00000000ffffffffffffffffffffffffffffffffffffffffffffffff9092169190911790555050565b600181608001516001811115612aa257612aa26144f3565b03612b0e5760e08101805160009081526008602052604080822080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055915191517fa4a4e334c0e330143f9437484fe516c13bc560b86b5b0daf58e7084aaac228f29190a25b5050565b6000612b1f84848461315e565b90508085101561282f5750929392505050565b600080612b4d888760a001518860c0015188888860016131ea565b90925090506000612b5e8284614473565b600089815260046020526040902060010180549192508291600c90612ba29084906c0100000000000000000000000090046bffffffffffffffffffffffff16614d05565b82546101009290920a6bffffffffffffffffffffffff81810219909316918316021790915560008a815260046020526040812060010180548594509092612beb91859116614473565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff16021790555050965096945050505050565b60005473ffffffffffffffffffffffffffffffffffffffff16331461225b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e657200000000000000000000604482015260640161039e565b73ffffffffffffffffffffffffffffffffffffffff83166000908152600b602090815260408083208151608081018352905460ff80821615801584526101008304909116948301949094526bffffffffffffffffffffffff6201000082048116938301939093526e0100000000000000000000000000009004909116606082015290612ea2576000816060015185612d3e9190614d05565b90506000612d4c8583614d2a565b90508083604001818151612d609190614473565b6bffffffffffffffffffffffff16905250612d7b8582614d55565b83606001818151612d8c9190614473565b6bffffffffffffffffffffffff90811690915273ffffffffffffffffffffffffffffffffffffffff89166000908152600b602090815260409182902087518154928901519389015160608a015186166e010000000000000000000000000000027fffffffffffff000000000000000000000000ffffffffffffffffffffffffffff919096166201000002167fffffffffffff000000000000000000000000000000000000000000000000ffff60ff95909516610100027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff921515929092167fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000909416939093171792909216179190911790555050505b6040015190505b9392505050565b600060017f00000000000000000000000000000000000000000000000000000000000000006002811115612ee657612ee66144f3565b03612f6057606473ffffffffffffffffffffffffffffffffffffffff1663a3b1b31d6040518163ffffffff1660e01b8152600401602060405180830381865afa158015612f37573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612f5b9190614d89565b905090565b504390565b6000808a8a8a8a8a8a8a8a8a604051602001612f8999989796959493929190614da2565b604080518083037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe001815291905280516020909101207dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff167e01000000000000000000000000000000000000000000000000000000000000179b9a5050505050505050505050565b6000612786825490565b6000612ea983836138d0565b6000612ea98373ffffffffffffffffffffffffffffffffffffffff84166138fa565b6000612ea98373ffffffffffffffffffffffffffffffffffffffff84166139f4565b3373ffffffffffffffffffffffffffffffffffffffff8216036130e8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c66000000000000000000604482015260640161039e565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b60008080856001811115613174576131746144f3565b03613183575062015f906131a2565b6001856001811115613197576131976144f3565b0361290557506201adb05b6131b363ffffffff85166014614588565b6131be8460016144da565b6131cd9060ff16611d4c614588565b6131d79083614498565b6131e19190614498565b95945050505050565b6000806000896080015161ffff16876132039190614588565b90508380156132115750803a105b1561321957503a5b600060027f0000000000000000000000000000000000000000000000000000000000000000600281111561324f5761324f6144f3565b036133ae5760408051600081526020810190915285156132ad57600036604051806080016040528060488152602001614fd46048913960405160200161329793929190614e37565b6040516020818303038152906040529050613315565b6015546132c990640100000000900463ffffffff166004614e5e565b63ffffffff1667ffffffffffffffff8111156132e7576132e7613eee565b6040519080825280601f01601f191660200182016040528015613311576020820181803683370190505b5090505b6040517f49948e0e00000000000000000000000000000000000000000000000000000000815273420000000000000000000000000000000000000f906349948e0e90613365908490600401613cc8565b602060405180830381865afa158015613382573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906133a69190614d89565b915050613508565b60017f000000000000000000000000000000000000000000000000000000000000000060028111156133e2576133e26144f3565b0361350857841561346457606c73ffffffffffffffffffffffffffffffffffffffff1663c6f7de0e6040518163ffffffff1660e01b8152600401602060405180830381865afa158015613439573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061345d9190614d89565b9050613508565b6000606c73ffffffffffffffffffffffffffffffffffffffff166341b247a86040518163ffffffff1660e01b815260040160c060405180830381865afa1580156134b2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906134d69190614e81565b50506015549294506134f993505050640100000000900463ffffffff1682614588565b613504906010614588565b9150505b8461352457808b6080015161ffff166135219190614588565b90505b61353261ffff8716826145f4565b9050600087826135428c8e614498565b61354c9086614588565b6135569190614498565b61356890670de0b6b3a7640000614588565b61357291906145f4565b905060008c6040015163ffffffff1664e8d4a510006135919190614588565b898e6020015163ffffffff16858f886135aa9190614588565b6135b49190614498565b6135c290633b9aca00614588565b6135cc9190614588565b6135d691906145f4565b6135e09190614498565b90506b033b2e3c9fd0803ce80000006135f98284614498565b1115613631576040517f2ad7547a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b909c909b509950505050505050505050565b6000808380602001905181019061365a9190614ecb565b835160c00151815191925063ffffffff908116911610156136b757847f405288ea7be309e16cfdf481367f90a413e1d4634fcdaf8966546db9b93012e8856040516136a59190613cc8565b60405180910390a26000915050612ea9565b6020810151158015906136de5750602081015181516136db9063ffffffff16613a43565b14155b806136f757506136ec612eb0565b815163ffffffff1610155b1561372c57847f6aa7f60c176da7af894b384daea2249497448137f5943c1237ada8bc92bdc301856040516136a59190613cc8565b506001949350505050565b6000806000838060200190518101906137509190614f23565b90506000858260000151836020015184604001516040516020016137b294939291909384526020840192909252604083015260e01b7fffffffff0000000000000000000000000000000000000000000000000000000016606082015260640190565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152919052805160209091012060808301519091501580159061381457508160800151613811836060015163ffffffff16613a43565b14155b806138305750613822612eb0565b826060015163ffffffff1610155b1561387a57857f6aa7f60c176da7af894b384daea2249497448137f5943c1237ada8bc92bdc301866040516138659190613cc8565b60405180910390a26000935091506138c99050565b60008181526008602052604090205460ff16156138c157857f405288ea7be309e16cfdf481367f90a413e1d4634fcdaf8966546db9b93012e8866040516138659190613cc8565b600193509150505b9250929050565b60008260000182815481106138e7576138e76144ab565b9060005260206000200154905092915050565b600081815260018301602052604081205480156139e357600061391e60018361453d565b85549091506000906139329060019061453d565b9050818114613997576000866000018281548110613952576139526144ab565b9060005260206000200154905080876000018481548110613975576139756144ab565b6000918252602080832090910192909255918252600188019052604090208390555b85548690806139a8576139a8614fa4565b600190038181906000526020600020016000905590558560010160008681526020019081526020016000206000905560019350505050612786565b6000915050612786565b5092915050565b6000818152600183016020526040812054613a3b57508154600181810184556000848152602080822090930184905584548482528286019093526040902091909155612786565b506000612786565b600060017f00000000000000000000000000000000000000000000000000000000000000006002811115613a7957613a796144f3565b03613b93576000606473ffffffffffffffffffffffffffffffffffffffff1663a3b1b31d6040518163ffffffff1660e01b8152600401602060405180830381865afa158015613acc573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613af09190614d89565b90508083101580613b0b5750610100613b09848361453d565b115b15613b195750600092915050565b6040517f2b407a8200000000000000000000000000000000000000000000000000000000815260048101849052606490632b407a8290602401602060405180830381865afa158015613b6f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612ea99190614d89565b504090565b919050565b50805460008255906000526020600020908101906122209190613c45565b828054828255906000526020600020908101928215613c35579160200282015b82811115613c3557825182547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff909116178255602090920191600190910190613bdb565b50613c41929150613c45565b5090565b5b80821115613c415760008155600101613c46565b60005b83811015613c75578181015183820152602001613c5d565b50506000910152565b60008151808452613c96816020860160208601613c5a565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b602081526000612ea96020830184613c7e565b73ffffffffffffffffffffffffffffffffffffffff8116811461222057600080fd5b8035613b9881613cdb565b60008083601f840112613d1a57600080fd5b50813567ffffffffffffffff811115613d3257600080fd5b6020830191508360208285010111156138c957600080fd5b60008060008060608587031215613d6057600080fd5b8435613d6b81613cdb565b935060208501359250604085013567ffffffffffffffff811115613d8e57600080fd5b613d9a87828801613d08565b95989497509550505050565b600080600060408486031215613dbb57600080fd5b83359250602084013567ffffffffffffffff811115613dd957600080fd5b613de586828701613d08565b9497909650939450505050565b60008083601f840112613e0457600080fd5b50813567ffffffffffffffff811115613e1c57600080fd5b6020830191508360208260051b85010111156138c957600080fd5b60008060008060008060008060e0898b031215613e5357600080fd5b606089018a811115613e6457600080fd5b8998503567ffffffffffffffff80821115613e7e57600080fd5b613e8a8c838d01613d08565b909950975060808b0135915080821115613ea357600080fd5b613eaf8c838d01613df2565b909750955060a08b0135915080821115613ec857600080fd5b50613ed58b828c01613df2565b999c989b50969995989497949560c00135949350505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6040516101e0810167ffffffffffffffff81118282101715613f4157613f41613eee565b60405290565b60405160c0810167ffffffffffffffff81118282101715613f4157613f41613eee565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715613fb157613fb1613eee565b604052919050565b600067ffffffffffffffff821115613fd357613fd3613eee565b5060051b60200190565b600082601f830112613fee57600080fd5b81356020614003613ffe83613fb9565b613f6a565b82815260059290921b8401810191818101908684111561402257600080fd5b8286015b8481101561404657803561403981613cdb565b8352918301918301614026565b509695505050505050565b803560ff81168114613b9857600080fd5b63ffffffff8116811461222057600080fd5b8035613b9881614062565b62ffffff8116811461222057600080fd5b8035613b988161407f565b61ffff8116811461222057600080fd5b8035613b988161409b565b6bffffffffffffffffffffffff8116811461222057600080fd5b8035613b98816140b6565b60006101e082840312156140ee57600080fd5b6140f6613f1d565b905061410182614074565b815261410f60208301614074565b602082015261412060408301614074565b604082015261413160608301614090565b6060820152614142608083016140ab565b608082015261415360a083016140d0565b60a082015261416460c08301614074565b60c082015261417560e08301614074565b60e0820152610100614188818401614074565b9082015261012061419a838201614074565b90820152610140828101359082015261016080830135908201526101806141c2818401613cfd565b908201526101a08281013567ffffffffffffffff8111156141e257600080fd5b6141ee85828601613fdd565b8284015250506101c0614202818401613cfd565b9082015292915050565b803567ffffffffffffffff81168114613b9857600080fd5b600082601f83011261423557600080fd5b813567ffffffffffffffff81111561424f5761424f613eee565b61428060207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f84011601613f6a565b81815284602083860101111561429557600080fd5b816020850160208301376000918101602001919091529392505050565b60008060008060008060c087890312156142cb57600080fd5b863567ffffffffffffffff808211156142e357600080fd5b6142ef8a838b01613fdd565b9750602089013591508082111561430557600080fd5b6143118a838b01613fdd565b965061431f60408a01614051565b9550606089013591508082111561433557600080fd5b6143418a838b016140db565b945061434f60808a0161420c565b935060a089013591508082111561436557600080fd5b5061437289828a01614224565b9150509295509295509295565b60008060008060008060c0878903121561439857600080fd5b863567ffffffffffffffff808211156143b057600080fd5b6143bc8a838b01613fdd565b975060208901359150808211156143d257600080fd5b6143de8a838b01613fdd565b96506143ec60408a01614051565b9550606089013591508082111561440257600080fd5b6143418a838b01614224565b60006020828403121561442057600080fd5b8135612ea981613cdb565b60006020828403121561443d57600080fd5b5035919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b6bffffffffffffffffffffffff8181168382160190808211156139ed576139ed614444565b8082018082111561278657612786614444565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60ff818116838216019081111561278657612786614444565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b61ffff8181168382160190808211156139ed576139ed614444565b8181038181111561278657612786614444565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff820361458157614581614444565b5060010190565b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff04831182151516156145c0576145c0614444565b500290565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b600082614603576146036145c5565b500490565b6bffffffffffffffffffffffff8516815283602082015282604082015260806060820152600061463b6080830184613c7e565b9695505050505050565b600060ff821660ff84168160ff048111821515161561466657614666614444565b029392505050565b63ffffffff8181168382160190808211156139ed576139ed614444565b600081518084526020808501945080840160005b838110156146d157815173ffffffffffffffffffffffffffffffffffffffff168752958201959082019060010161469f565b509495945050505050565b602081526146f360208201835163ffffffff169052565b6000602083015161470c604084018263ffffffff169052565b50604083015163ffffffff8116606084015250606083015162ffffff8116608084015250608083015161ffff811660a08401525060a08301516bffffffffffffffffffffffff811660c08401525060c083015163ffffffff811660e08401525060e08301516101006147858185018363ffffffff169052565b840151905061012061479e8482018363ffffffff169052565b84015190506101406147b78482018363ffffffff169052565b840151610160848101919091528401516101808085019190915284015190506101a06147fa8185018373ffffffffffffffffffffffffffffffffffffffff169052565b808501519150506101e06101c0818186015261481a61020086018461468b565b95015173ffffffffffffffffffffffffffffffffffffffff169301929092525090919050565b600061012063ffffffff808d1684528b6020850152808b166040850152508060608401526148708184018a61468b565b90508281036080840152614884818961468b565b905060ff871660a084015282810360c08401526148a18187613c7e565b905067ffffffffffffffff851660e08401528281036101008401526148c68185613c7e565b9c9b505050505050505050505050565b8051613b9881614062565b8051613b988161407f565b8051613b988161409b565b8051613b98816140b6565b8051613b9881613cdb565b600082601f83011261491e57600080fd5b8151602061492e613ffe83613fb9565b82815260059290921b8401810191818101908684111561494d57600080fd5b8286015b8481101561404657805161496481613cdb565b8352918301918301614951565b60006020828403121561498357600080fd5b815167ffffffffffffffff8082111561499b57600080fd5b908301906101e082860312156149b057600080fd5b6149b8613f1d565b6149c1836148d6565b81526149cf602084016148d6565b60208201526149e0604084016148d6565b60408201526149f1606084016148e1565b6060820152614a02608084016148ec565b6080820152614a1360a084016148f7565b60a0820152614a2460c084016148d6565b60c0820152614a3560e084016148d6565b60e0820152610100614a488185016148d6565b90820152610120614a5a8482016148d6565b9082015261014083810151908201526101608084015190820152610180614a82818501614902565b908201526101a08381015183811115614a9a57600080fd5b614aa68882870161490d565b8284015250506101c09150614abc828401614902565b91810191909152949350505050565b82815260406020820152600061282f6040830184613c7e565b60008060408385031215614af757600080fd5b82518015158114614b0757600080fd5b6020939093015192949293505050565b8183823760009101908152919050565b8281526080810160608360208401379392505050565b600082601f830112614b4e57600080fd5b81356020614b5e613ffe83613fb9565b82815260059290921b84018101918181019086841115614b7d57600080fd5b8286015b848110156140465780358352918301918301614b81565b600082601f830112614ba957600080fd5b81356020614bb9613ffe83613fb9565b82815260059290921b84018101918181019086841115614bd857600080fd5b8286015b8481101561404657803567ffffffffffffffff811115614bfc5760008081fd5b614c0a8986838b0101614224565b845250918301918301614bdc565b600060208284031215614c2a57600080fd5b813567ffffffffffffffff80821115614c4257600080fd5b9083019060c08286031215614c5657600080fd5b614c5e613f47565b8235815260208301356020820152604083013582811115614c7e57600080fd5b614c8a87828601614b3d565b604083015250606083013582811115614ca257600080fd5b614cae87828601614b3d565b606083015250608083013582811115614cc657600080fd5b614cd287828601614b98565b60808301525060a083013582811115614cea57600080fd5b614cf687828601614b98565b60a08301525095945050505050565b6bffffffffffffffffffffffff8281168282160390808211156139ed576139ed614444565b60006bffffffffffffffffffffffff80841680614d4957614d496145c5565b92169190910492915050565b60006bffffffffffffffffffffffff80831681851681830481118215151615614d8057614d80614444565b02949350505050565b600060208284031215614d9b57600080fd5b5051919050565b60006101208b835273ffffffffffffffffffffffffffffffffffffffff8b16602084015267ffffffffffffffff808b166040850152816060850152614de98285018b61468b565b91508382036080850152614dfd828a61468b565b915060ff881660a085015283820360c0850152614e1a8288613c7e565b90861660e085015283810361010085015290506148c68185613c7e565b828482376000838201600081528351614e54818360208801613c5a565b0195945050505050565b600063ffffffff80831681851681830481118215151615614d8057614d80614444565b60008060008060008060c08789031215614e9a57600080fd5b865195506020870151945060408701519350606087015192506080870151915060a087015190509295509295509295565b600060408284031215614edd57600080fd5b6040516040810181811067ffffffffffffffff82111715614f0057614f00613eee565b6040528251614f0e81614062565b81526020928301519281019290925250919050565b600060a08284031215614f3557600080fd5b60405160a0810181811067ffffffffffffffff82111715614f5857614f58613eee565b806040525082518152602083015160208201526040830151614f7981614062565b60408201526060830151614f8c81614062565b60608201526080928301519281019290925250919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fdfe307866666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666a164736f6c6343000810000a", +} + +var AutomationRegistryABI = AutomationRegistryMetaData.ABI + +var AutomationRegistryBin = AutomationRegistryMetaData.Bin + +func DeployAutomationRegistry(auth *bind.TransactOpts, backend bind.ContractBackend, logicA common.Address) (common.Address, *types.Transaction, *AutomationRegistry, error) { + parsed, err := AutomationRegistryMetaData.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(AutomationRegistryBin), backend, logicA) + if err != nil { + return common.Address{}, nil, nil, err + } + return address, tx, &AutomationRegistry{address: address, abi: *parsed, AutomationRegistryCaller: AutomationRegistryCaller{contract: contract}, AutomationRegistryTransactor: AutomationRegistryTransactor{contract: contract}, AutomationRegistryFilterer: AutomationRegistryFilterer{contract: contract}}, nil +} + +type AutomationRegistry struct { + address common.Address + abi abi.ABI + AutomationRegistryCaller + AutomationRegistryTransactor + AutomationRegistryFilterer +} + +type AutomationRegistryCaller struct { + contract *bind.BoundContract +} + +type AutomationRegistryTransactor struct { + contract *bind.BoundContract +} + +type AutomationRegistryFilterer struct { + contract *bind.BoundContract +} + +type AutomationRegistrySession struct { + Contract *AutomationRegistry + CallOpts bind.CallOpts + TransactOpts bind.TransactOpts +} + +type AutomationRegistryCallerSession struct { + Contract *AutomationRegistryCaller + CallOpts bind.CallOpts +} + +type AutomationRegistryTransactorSession struct { + Contract *AutomationRegistryTransactor + TransactOpts bind.TransactOpts +} + +type AutomationRegistryRaw struct { + Contract *AutomationRegistry +} + +type AutomationRegistryCallerRaw struct { + Contract *AutomationRegistryCaller +} + +type AutomationRegistryTransactorRaw struct { + Contract *AutomationRegistryTransactor +} + +func NewAutomationRegistry(address common.Address, backend bind.ContractBackend) (*AutomationRegistry, error) { + abi, err := abi.JSON(strings.NewReader(AutomationRegistryABI)) + if err != nil { + return nil, err + } + contract, err := bindAutomationRegistry(address, backend, backend, backend) + if err != nil { + return nil, err + } + return &AutomationRegistry{address: address, abi: abi, AutomationRegistryCaller: AutomationRegistryCaller{contract: contract}, AutomationRegistryTransactor: AutomationRegistryTransactor{contract: contract}, AutomationRegistryFilterer: AutomationRegistryFilterer{contract: contract}}, nil +} + +func NewAutomationRegistryCaller(address common.Address, caller bind.ContractCaller) (*AutomationRegistryCaller, error) { + contract, err := bindAutomationRegistry(address, caller, nil, nil) + if err != nil { + return nil, err + } + return &AutomationRegistryCaller{contract: contract}, nil +} + +func NewAutomationRegistryTransactor(address common.Address, transactor bind.ContractTransactor) (*AutomationRegistryTransactor, error) { + contract, err := bindAutomationRegistry(address, nil, transactor, nil) + if err != nil { + return nil, err + } + return &AutomationRegistryTransactor{contract: contract}, nil +} + +func NewAutomationRegistryFilterer(address common.Address, filterer bind.ContractFilterer) (*AutomationRegistryFilterer, error) { + contract, err := bindAutomationRegistry(address, nil, nil, filterer) + if err != nil { + return nil, err + } + return &AutomationRegistryFilterer{contract: contract}, nil +} + +func bindAutomationRegistry(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) { + parsed, err := AutomationRegistryMetaData.GetAbi() + if err != nil { + return nil, err + } + return bind.NewBoundContract(address, *parsed, caller, transactor, filterer), nil +} + +func (_AutomationRegistry *AutomationRegistryRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _AutomationRegistry.Contract.AutomationRegistryCaller.contract.Call(opts, result, method, params...) +} + +func (_AutomationRegistry *AutomationRegistryRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _AutomationRegistry.Contract.AutomationRegistryTransactor.contract.Transfer(opts) +} + +func (_AutomationRegistry *AutomationRegistryRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _AutomationRegistry.Contract.AutomationRegistryTransactor.contract.Transact(opts, method, params...) +} + +func (_AutomationRegistry *AutomationRegistryCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _AutomationRegistry.Contract.contract.Call(opts, result, method, params...) +} + +func (_AutomationRegistry *AutomationRegistryTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _AutomationRegistry.Contract.contract.Transfer(opts) +} + +func (_AutomationRegistry *AutomationRegistryTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _AutomationRegistry.Contract.contract.Transact(opts, method, params...) +} + +func (_AutomationRegistry *AutomationRegistryCaller) FallbackTo(opts *bind.CallOpts) (common.Address, error) { + var out []interface{} + err := _AutomationRegistry.contract.Call(opts, &out, "fallbackTo") + + if err != nil { + return *new(common.Address), err + } + + out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) + + return out0, err + +} + +func (_AutomationRegistry *AutomationRegistrySession) FallbackTo() (common.Address, error) { + return _AutomationRegistry.Contract.FallbackTo(&_AutomationRegistry.CallOpts) +} + +func (_AutomationRegistry *AutomationRegistryCallerSession) FallbackTo() (common.Address, error) { + return _AutomationRegistry.Contract.FallbackTo(&_AutomationRegistry.CallOpts) +} + +func (_AutomationRegistry *AutomationRegistryCaller) LatestConfigDetails(opts *bind.CallOpts) (LatestConfigDetails, + + error) { + var out []interface{} + err := _AutomationRegistry.contract.Call(opts, &out, "latestConfigDetails") + + outstruct := new(LatestConfigDetails) + if err != nil { + return *outstruct, err + } + + outstruct.ConfigCount = *abi.ConvertType(out[0], new(uint32)).(*uint32) + outstruct.BlockNumber = *abi.ConvertType(out[1], new(uint32)).(*uint32) + outstruct.ConfigDigest = *abi.ConvertType(out[2], new([32]byte)).(*[32]byte) + + return *outstruct, err + +} + +func (_AutomationRegistry *AutomationRegistrySession) LatestConfigDetails() (LatestConfigDetails, + + error) { + return _AutomationRegistry.Contract.LatestConfigDetails(&_AutomationRegistry.CallOpts) +} + +func (_AutomationRegistry *AutomationRegistryCallerSession) LatestConfigDetails() (LatestConfigDetails, + + error) { + return _AutomationRegistry.Contract.LatestConfigDetails(&_AutomationRegistry.CallOpts) +} + +func (_AutomationRegistry *AutomationRegistryCaller) LatestConfigDigestAndEpoch(opts *bind.CallOpts) (LatestConfigDigestAndEpoch, + + error) { + var out []interface{} + err := _AutomationRegistry.contract.Call(opts, &out, "latestConfigDigestAndEpoch") + + outstruct := new(LatestConfigDigestAndEpoch) + if err != nil { + return *outstruct, err + } + + outstruct.ScanLogs = *abi.ConvertType(out[0], new(bool)).(*bool) + outstruct.ConfigDigest = *abi.ConvertType(out[1], new([32]byte)).(*[32]byte) + outstruct.Epoch = *abi.ConvertType(out[2], new(uint32)).(*uint32) + + return *outstruct, err + +} + +func (_AutomationRegistry *AutomationRegistrySession) LatestConfigDigestAndEpoch() (LatestConfigDigestAndEpoch, + + error) { + return _AutomationRegistry.Contract.LatestConfigDigestAndEpoch(&_AutomationRegistry.CallOpts) +} + +func (_AutomationRegistry *AutomationRegistryCallerSession) LatestConfigDigestAndEpoch() (LatestConfigDigestAndEpoch, + + error) { + return _AutomationRegistry.Contract.LatestConfigDigestAndEpoch(&_AutomationRegistry.CallOpts) +} + +func (_AutomationRegistry *AutomationRegistryCaller) Owner(opts *bind.CallOpts) (common.Address, error) { + var out []interface{} + err := _AutomationRegistry.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 (_AutomationRegistry *AutomationRegistrySession) Owner() (common.Address, error) { + return _AutomationRegistry.Contract.Owner(&_AutomationRegistry.CallOpts) +} + +func (_AutomationRegistry *AutomationRegistryCallerSession) Owner() (common.Address, error) { + return _AutomationRegistry.Contract.Owner(&_AutomationRegistry.CallOpts) +} + +func (_AutomationRegistry *AutomationRegistryCaller) TypeAndVersion(opts *bind.CallOpts) (string, error) { + var out []interface{} + err := _AutomationRegistry.contract.Call(opts, &out, "typeAndVersion") + + if err != nil { + return *new(string), err + } + + out0 := *abi.ConvertType(out[0], new(string)).(*string) + + return out0, err + +} + +func (_AutomationRegistry *AutomationRegistrySession) TypeAndVersion() (string, error) { + return _AutomationRegistry.Contract.TypeAndVersion(&_AutomationRegistry.CallOpts) +} + +func (_AutomationRegistry *AutomationRegistryCallerSession) TypeAndVersion() (string, error) { + return _AutomationRegistry.Contract.TypeAndVersion(&_AutomationRegistry.CallOpts) +} + +func (_AutomationRegistry *AutomationRegistryTransactor) AcceptOwnership(opts *bind.TransactOpts) (*types.Transaction, error) { + return _AutomationRegistry.contract.Transact(opts, "acceptOwnership") +} + +func (_AutomationRegistry *AutomationRegistrySession) AcceptOwnership() (*types.Transaction, error) { + return _AutomationRegistry.Contract.AcceptOwnership(&_AutomationRegistry.TransactOpts) +} + +func (_AutomationRegistry *AutomationRegistryTransactorSession) AcceptOwnership() (*types.Transaction, error) { + return _AutomationRegistry.Contract.AcceptOwnership(&_AutomationRegistry.TransactOpts) +} + +func (_AutomationRegistry *AutomationRegistryTransactor) OnTokenTransfer(opts *bind.TransactOpts, sender common.Address, amount *big.Int, data []byte) (*types.Transaction, error) { + return _AutomationRegistry.contract.Transact(opts, "onTokenTransfer", sender, amount, data) +} + +func (_AutomationRegistry *AutomationRegistrySession) OnTokenTransfer(sender common.Address, amount *big.Int, data []byte) (*types.Transaction, error) { + return _AutomationRegistry.Contract.OnTokenTransfer(&_AutomationRegistry.TransactOpts, sender, amount, data) +} + +func (_AutomationRegistry *AutomationRegistryTransactorSession) OnTokenTransfer(sender common.Address, amount *big.Int, data []byte) (*types.Transaction, error) { + return _AutomationRegistry.Contract.OnTokenTransfer(&_AutomationRegistry.TransactOpts, sender, amount, data) +} + +func (_AutomationRegistry *AutomationRegistryTransactor) SetConfig(opts *bind.TransactOpts, signers []common.Address, transmitters []common.Address, f uint8, onchainConfigBytes []byte, offchainConfigVersion uint64, offchainConfig []byte) (*types.Transaction, error) { + return _AutomationRegistry.contract.Transact(opts, "setConfig", signers, transmitters, f, onchainConfigBytes, offchainConfigVersion, offchainConfig) +} + +func (_AutomationRegistry *AutomationRegistrySession) SetConfig(signers []common.Address, transmitters []common.Address, f uint8, onchainConfigBytes []byte, offchainConfigVersion uint64, offchainConfig []byte) (*types.Transaction, error) { + return _AutomationRegistry.Contract.SetConfig(&_AutomationRegistry.TransactOpts, signers, transmitters, f, onchainConfigBytes, offchainConfigVersion, offchainConfig) +} + +func (_AutomationRegistry *AutomationRegistryTransactorSession) SetConfig(signers []common.Address, transmitters []common.Address, f uint8, onchainConfigBytes []byte, offchainConfigVersion uint64, offchainConfig []byte) (*types.Transaction, error) { + return _AutomationRegistry.Contract.SetConfig(&_AutomationRegistry.TransactOpts, signers, transmitters, f, onchainConfigBytes, offchainConfigVersion, offchainConfig) +} + +func (_AutomationRegistry *AutomationRegistryTransactor) SetConfigTypeSafe(opts *bind.TransactOpts, signers []common.Address, transmitters []common.Address, f uint8, onchainConfig AutomationRegistryBase22OnchainConfig, offchainConfigVersion uint64, offchainConfig []byte) (*types.Transaction, error) { + return _AutomationRegistry.contract.Transact(opts, "setConfigTypeSafe", signers, transmitters, f, onchainConfig, offchainConfigVersion, offchainConfig) +} + +func (_AutomationRegistry *AutomationRegistrySession) SetConfigTypeSafe(signers []common.Address, transmitters []common.Address, f uint8, onchainConfig AutomationRegistryBase22OnchainConfig, offchainConfigVersion uint64, offchainConfig []byte) (*types.Transaction, error) { + return _AutomationRegistry.Contract.SetConfigTypeSafe(&_AutomationRegistry.TransactOpts, signers, transmitters, f, onchainConfig, offchainConfigVersion, offchainConfig) +} + +func (_AutomationRegistry *AutomationRegistryTransactorSession) SetConfigTypeSafe(signers []common.Address, transmitters []common.Address, f uint8, onchainConfig AutomationRegistryBase22OnchainConfig, offchainConfigVersion uint64, offchainConfig []byte) (*types.Transaction, error) { + return _AutomationRegistry.Contract.SetConfigTypeSafe(&_AutomationRegistry.TransactOpts, signers, transmitters, f, onchainConfig, offchainConfigVersion, offchainConfig) +} + +func (_AutomationRegistry *AutomationRegistryTransactor) SimulatePerformUpkeep(opts *bind.TransactOpts, id *big.Int, performData []byte) (*types.Transaction, error) { + return _AutomationRegistry.contract.Transact(opts, "simulatePerformUpkeep", id, performData) +} + +func (_AutomationRegistry *AutomationRegistrySession) SimulatePerformUpkeep(id *big.Int, performData []byte) (*types.Transaction, error) { + return _AutomationRegistry.Contract.SimulatePerformUpkeep(&_AutomationRegistry.TransactOpts, id, performData) +} + +func (_AutomationRegistry *AutomationRegistryTransactorSession) SimulatePerformUpkeep(id *big.Int, performData []byte) (*types.Transaction, error) { + return _AutomationRegistry.Contract.SimulatePerformUpkeep(&_AutomationRegistry.TransactOpts, id, performData) +} + +func (_AutomationRegistry *AutomationRegistryTransactor) TransferOwnership(opts *bind.TransactOpts, to common.Address) (*types.Transaction, error) { + return _AutomationRegistry.contract.Transact(opts, "transferOwnership", to) +} + +func (_AutomationRegistry *AutomationRegistrySession) TransferOwnership(to common.Address) (*types.Transaction, error) { + return _AutomationRegistry.Contract.TransferOwnership(&_AutomationRegistry.TransactOpts, to) +} + +func (_AutomationRegistry *AutomationRegistryTransactorSession) TransferOwnership(to common.Address) (*types.Transaction, error) { + return _AutomationRegistry.Contract.TransferOwnership(&_AutomationRegistry.TransactOpts, to) +} + +func (_AutomationRegistry *AutomationRegistryTransactor) Transmit(opts *bind.TransactOpts, reportContext [3][32]byte, rawReport []byte, rs [][32]byte, ss [][32]byte, rawVs [32]byte) (*types.Transaction, error) { + return _AutomationRegistry.contract.Transact(opts, "transmit", reportContext, rawReport, rs, ss, rawVs) +} + +func (_AutomationRegistry *AutomationRegistrySession) Transmit(reportContext [3][32]byte, rawReport []byte, rs [][32]byte, ss [][32]byte, rawVs [32]byte) (*types.Transaction, error) { + return _AutomationRegistry.Contract.Transmit(&_AutomationRegistry.TransactOpts, reportContext, rawReport, rs, ss, rawVs) +} + +func (_AutomationRegistry *AutomationRegistryTransactorSession) Transmit(reportContext [3][32]byte, rawReport []byte, rs [][32]byte, ss [][32]byte, rawVs [32]byte) (*types.Transaction, error) { + return _AutomationRegistry.Contract.Transmit(&_AutomationRegistry.TransactOpts, reportContext, rawReport, rs, ss, rawVs) +} + +func (_AutomationRegistry *AutomationRegistryTransactor) Fallback(opts *bind.TransactOpts, calldata []byte) (*types.Transaction, error) { + return _AutomationRegistry.contract.RawTransact(opts, calldata) +} + +func (_AutomationRegistry *AutomationRegistrySession) Fallback(calldata []byte) (*types.Transaction, error) { + return _AutomationRegistry.Contract.Fallback(&_AutomationRegistry.TransactOpts, calldata) +} + +func (_AutomationRegistry *AutomationRegistryTransactorSession) Fallback(calldata []byte) (*types.Transaction, error) { + return _AutomationRegistry.Contract.Fallback(&_AutomationRegistry.TransactOpts, calldata) +} + +type AutomationRegistryAdminPrivilegeConfigSetIterator struct { + Event *AutomationRegistryAdminPrivilegeConfigSet + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *AutomationRegistryAdminPrivilegeConfigSetIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(AutomationRegistryAdminPrivilegeConfigSet) + 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(AutomationRegistryAdminPrivilegeConfigSet) + 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 *AutomationRegistryAdminPrivilegeConfigSetIterator) Error() error { + return it.fail +} + +func (it *AutomationRegistryAdminPrivilegeConfigSetIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type AutomationRegistryAdminPrivilegeConfigSet struct { + Admin common.Address + PrivilegeConfig []byte + Raw types.Log +} + +func (_AutomationRegistry *AutomationRegistryFilterer) FilterAdminPrivilegeConfigSet(opts *bind.FilterOpts, admin []common.Address) (*AutomationRegistryAdminPrivilegeConfigSetIterator, error) { + + var adminRule []interface{} + for _, adminItem := range admin { + adminRule = append(adminRule, adminItem) + } + + logs, sub, err := _AutomationRegistry.contract.FilterLogs(opts, "AdminPrivilegeConfigSet", adminRule) + if err != nil { + return nil, err + } + return &AutomationRegistryAdminPrivilegeConfigSetIterator{contract: _AutomationRegistry.contract, event: "AdminPrivilegeConfigSet", logs: logs, sub: sub}, nil +} + +func (_AutomationRegistry *AutomationRegistryFilterer) WatchAdminPrivilegeConfigSet(opts *bind.WatchOpts, sink chan<- *AutomationRegistryAdminPrivilegeConfigSet, admin []common.Address) (event.Subscription, error) { + + var adminRule []interface{} + for _, adminItem := range admin { + adminRule = append(adminRule, adminItem) + } + + logs, sub, err := _AutomationRegistry.contract.WatchLogs(opts, "AdminPrivilegeConfigSet", adminRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(AutomationRegistryAdminPrivilegeConfigSet) + if err := _AutomationRegistry.contract.UnpackLog(event, "AdminPrivilegeConfigSet", 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 (_AutomationRegistry *AutomationRegistryFilterer) ParseAdminPrivilegeConfigSet(log types.Log) (*AutomationRegistryAdminPrivilegeConfigSet, error) { + event := new(AutomationRegistryAdminPrivilegeConfigSet) + if err := _AutomationRegistry.contract.UnpackLog(event, "AdminPrivilegeConfigSet", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type AutomationRegistryCancelledUpkeepReportIterator struct { + Event *AutomationRegistryCancelledUpkeepReport + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *AutomationRegistryCancelledUpkeepReportIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(AutomationRegistryCancelledUpkeepReport) + 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(AutomationRegistryCancelledUpkeepReport) + 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 *AutomationRegistryCancelledUpkeepReportIterator) Error() error { + return it.fail +} + +func (it *AutomationRegistryCancelledUpkeepReportIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type AutomationRegistryCancelledUpkeepReport struct { + Id *big.Int + Trigger []byte + Raw types.Log +} + +func (_AutomationRegistry *AutomationRegistryFilterer) FilterCancelledUpkeepReport(opts *bind.FilterOpts, id []*big.Int) (*AutomationRegistryCancelledUpkeepReportIterator, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + + logs, sub, err := _AutomationRegistry.contract.FilterLogs(opts, "CancelledUpkeepReport", idRule) + if err != nil { + return nil, err + } + return &AutomationRegistryCancelledUpkeepReportIterator{contract: _AutomationRegistry.contract, event: "CancelledUpkeepReport", logs: logs, sub: sub}, nil +} + +func (_AutomationRegistry *AutomationRegistryFilterer) WatchCancelledUpkeepReport(opts *bind.WatchOpts, sink chan<- *AutomationRegistryCancelledUpkeepReport, id []*big.Int) (event.Subscription, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + + logs, sub, err := _AutomationRegistry.contract.WatchLogs(opts, "CancelledUpkeepReport", idRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(AutomationRegistryCancelledUpkeepReport) + if err := _AutomationRegistry.contract.UnpackLog(event, "CancelledUpkeepReport", 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 (_AutomationRegistry *AutomationRegistryFilterer) ParseCancelledUpkeepReport(log types.Log) (*AutomationRegistryCancelledUpkeepReport, error) { + event := new(AutomationRegistryCancelledUpkeepReport) + if err := _AutomationRegistry.contract.UnpackLog(event, "CancelledUpkeepReport", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type AutomationRegistryConfigSetIterator struct { + Event *AutomationRegistryConfigSet + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *AutomationRegistryConfigSetIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(AutomationRegistryConfigSet) + 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(AutomationRegistryConfigSet) + 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 *AutomationRegistryConfigSetIterator) Error() error { + return it.fail +} + +func (it *AutomationRegistryConfigSetIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type AutomationRegistryConfigSet struct { + PreviousConfigBlockNumber uint32 + ConfigDigest [32]byte + ConfigCount uint64 + Signers []common.Address + Transmitters []common.Address + F uint8 + OnchainConfig []byte + OffchainConfigVersion uint64 + OffchainConfig []byte + Raw types.Log +} + +func (_AutomationRegistry *AutomationRegistryFilterer) FilterConfigSet(opts *bind.FilterOpts) (*AutomationRegistryConfigSetIterator, error) { + + logs, sub, err := _AutomationRegistry.contract.FilterLogs(opts, "ConfigSet") + if err != nil { + return nil, err + } + return &AutomationRegistryConfigSetIterator{contract: _AutomationRegistry.contract, event: "ConfigSet", logs: logs, sub: sub}, nil +} + +func (_AutomationRegistry *AutomationRegistryFilterer) WatchConfigSet(opts *bind.WatchOpts, sink chan<- *AutomationRegistryConfigSet) (event.Subscription, error) { + + logs, sub, err := _AutomationRegistry.contract.WatchLogs(opts, "ConfigSet") + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(AutomationRegistryConfigSet) + if err := _AutomationRegistry.contract.UnpackLog(event, "ConfigSet", 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 (_AutomationRegistry *AutomationRegistryFilterer) ParseConfigSet(log types.Log) (*AutomationRegistryConfigSet, error) { + event := new(AutomationRegistryConfigSet) + if err := _AutomationRegistry.contract.UnpackLog(event, "ConfigSet", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type AutomationRegistryDedupKeyAddedIterator struct { + Event *AutomationRegistryDedupKeyAdded + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *AutomationRegistryDedupKeyAddedIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(AutomationRegistryDedupKeyAdded) + 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(AutomationRegistryDedupKeyAdded) + 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 *AutomationRegistryDedupKeyAddedIterator) Error() error { + return it.fail +} + +func (it *AutomationRegistryDedupKeyAddedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type AutomationRegistryDedupKeyAdded struct { + DedupKey [32]byte + Raw types.Log +} + +func (_AutomationRegistry *AutomationRegistryFilterer) FilterDedupKeyAdded(opts *bind.FilterOpts, dedupKey [][32]byte) (*AutomationRegistryDedupKeyAddedIterator, error) { + + var dedupKeyRule []interface{} + for _, dedupKeyItem := range dedupKey { + dedupKeyRule = append(dedupKeyRule, dedupKeyItem) + } + + logs, sub, err := _AutomationRegistry.contract.FilterLogs(opts, "DedupKeyAdded", dedupKeyRule) + if err != nil { + return nil, err + } + return &AutomationRegistryDedupKeyAddedIterator{contract: _AutomationRegistry.contract, event: "DedupKeyAdded", logs: logs, sub: sub}, nil +} + +func (_AutomationRegistry *AutomationRegistryFilterer) WatchDedupKeyAdded(opts *bind.WatchOpts, sink chan<- *AutomationRegistryDedupKeyAdded, dedupKey [][32]byte) (event.Subscription, error) { + + var dedupKeyRule []interface{} + for _, dedupKeyItem := range dedupKey { + dedupKeyRule = append(dedupKeyRule, dedupKeyItem) + } + + logs, sub, err := _AutomationRegistry.contract.WatchLogs(opts, "DedupKeyAdded", dedupKeyRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(AutomationRegistryDedupKeyAdded) + if err := _AutomationRegistry.contract.UnpackLog(event, "DedupKeyAdded", 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 (_AutomationRegistry *AutomationRegistryFilterer) ParseDedupKeyAdded(log types.Log) (*AutomationRegistryDedupKeyAdded, error) { + event := new(AutomationRegistryDedupKeyAdded) + if err := _AutomationRegistry.contract.UnpackLog(event, "DedupKeyAdded", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type AutomationRegistryFundsAddedIterator struct { + Event *AutomationRegistryFundsAdded + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *AutomationRegistryFundsAddedIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(AutomationRegistryFundsAdded) + 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(AutomationRegistryFundsAdded) + 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 *AutomationRegistryFundsAddedIterator) Error() error { + return it.fail +} + +func (it *AutomationRegistryFundsAddedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type AutomationRegistryFundsAdded struct { + Id *big.Int + From common.Address + Amount *big.Int + Raw types.Log +} + +func (_AutomationRegistry *AutomationRegistryFilterer) FilterFundsAdded(opts *bind.FilterOpts, id []*big.Int, from []common.Address) (*AutomationRegistryFundsAddedIterator, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + var fromRule []interface{} + for _, fromItem := range from { + fromRule = append(fromRule, fromItem) + } + + logs, sub, err := _AutomationRegistry.contract.FilterLogs(opts, "FundsAdded", idRule, fromRule) + if err != nil { + return nil, err + } + return &AutomationRegistryFundsAddedIterator{contract: _AutomationRegistry.contract, event: "FundsAdded", logs: logs, sub: sub}, nil +} + +func (_AutomationRegistry *AutomationRegistryFilterer) WatchFundsAdded(opts *bind.WatchOpts, sink chan<- *AutomationRegistryFundsAdded, id []*big.Int, from []common.Address) (event.Subscription, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + var fromRule []interface{} + for _, fromItem := range from { + fromRule = append(fromRule, fromItem) + } + + logs, sub, err := _AutomationRegistry.contract.WatchLogs(opts, "FundsAdded", idRule, fromRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(AutomationRegistryFundsAdded) + if err := _AutomationRegistry.contract.UnpackLog(event, "FundsAdded", 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 (_AutomationRegistry *AutomationRegistryFilterer) ParseFundsAdded(log types.Log) (*AutomationRegistryFundsAdded, error) { + event := new(AutomationRegistryFundsAdded) + if err := _AutomationRegistry.contract.UnpackLog(event, "FundsAdded", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type AutomationRegistryFundsWithdrawnIterator struct { + Event *AutomationRegistryFundsWithdrawn + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *AutomationRegistryFundsWithdrawnIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(AutomationRegistryFundsWithdrawn) + 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(AutomationRegistryFundsWithdrawn) + 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 *AutomationRegistryFundsWithdrawnIterator) Error() error { + return it.fail +} + +func (it *AutomationRegistryFundsWithdrawnIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type AutomationRegistryFundsWithdrawn struct { + Id *big.Int + Amount *big.Int + To common.Address + Raw types.Log +} + +func (_AutomationRegistry *AutomationRegistryFilterer) FilterFundsWithdrawn(opts *bind.FilterOpts, id []*big.Int) (*AutomationRegistryFundsWithdrawnIterator, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + + logs, sub, err := _AutomationRegistry.contract.FilterLogs(opts, "FundsWithdrawn", idRule) + if err != nil { + return nil, err + } + return &AutomationRegistryFundsWithdrawnIterator{contract: _AutomationRegistry.contract, event: "FundsWithdrawn", logs: logs, sub: sub}, nil +} + +func (_AutomationRegistry *AutomationRegistryFilterer) WatchFundsWithdrawn(opts *bind.WatchOpts, sink chan<- *AutomationRegistryFundsWithdrawn, id []*big.Int) (event.Subscription, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + + logs, sub, err := _AutomationRegistry.contract.WatchLogs(opts, "FundsWithdrawn", idRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(AutomationRegistryFundsWithdrawn) + if err := _AutomationRegistry.contract.UnpackLog(event, "FundsWithdrawn", 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 (_AutomationRegistry *AutomationRegistryFilterer) ParseFundsWithdrawn(log types.Log) (*AutomationRegistryFundsWithdrawn, error) { + event := new(AutomationRegistryFundsWithdrawn) + if err := _AutomationRegistry.contract.UnpackLog(event, "FundsWithdrawn", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type AutomationRegistryInsufficientFundsUpkeepReportIterator struct { + Event *AutomationRegistryInsufficientFundsUpkeepReport + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *AutomationRegistryInsufficientFundsUpkeepReportIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(AutomationRegistryInsufficientFundsUpkeepReport) + 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(AutomationRegistryInsufficientFundsUpkeepReport) + 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 *AutomationRegistryInsufficientFundsUpkeepReportIterator) Error() error { + return it.fail +} + +func (it *AutomationRegistryInsufficientFundsUpkeepReportIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type AutomationRegistryInsufficientFundsUpkeepReport struct { + Id *big.Int + Trigger []byte + Raw types.Log +} + +func (_AutomationRegistry *AutomationRegistryFilterer) FilterInsufficientFundsUpkeepReport(opts *bind.FilterOpts, id []*big.Int) (*AutomationRegistryInsufficientFundsUpkeepReportIterator, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + + logs, sub, err := _AutomationRegistry.contract.FilterLogs(opts, "InsufficientFundsUpkeepReport", idRule) + if err != nil { + return nil, err + } + return &AutomationRegistryInsufficientFundsUpkeepReportIterator{contract: _AutomationRegistry.contract, event: "InsufficientFundsUpkeepReport", logs: logs, sub: sub}, nil +} + +func (_AutomationRegistry *AutomationRegistryFilterer) WatchInsufficientFundsUpkeepReport(opts *bind.WatchOpts, sink chan<- *AutomationRegistryInsufficientFundsUpkeepReport, id []*big.Int) (event.Subscription, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + + logs, sub, err := _AutomationRegistry.contract.WatchLogs(opts, "InsufficientFundsUpkeepReport", idRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(AutomationRegistryInsufficientFundsUpkeepReport) + if err := _AutomationRegistry.contract.UnpackLog(event, "InsufficientFundsUpkeepReport", 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 (_AutomationRegistry *AutomationRegistryFilterer) ParseInsufficientFundsUpkeepReport(log types.Log) (*AutomationRegistryInsufficientFundsUpkeepReport, error) { + event := new(AutomationRegistryInsufficientFundsUpkeepReport) + if err := _AutomationRegistry.contract.UnpackLog(event, "InsufficientFundsUpkeepReport", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type AutomationRegistryOwnerFundsWithdrawnIterator struct { + Event *AutomationRegistryOwnerFundsWithdrawn + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *AutomationRegistryOwnerFundsWithdrawnIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(AutomationRegistryOwnerFundsWithdrawn) + 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(AutomationRegistryOwnerFundsWithdrawn) + 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 *AutomationRegistryOwnerFundsWithdrawnIterator) Error() error { + return it.fail +} + +func (it *AutomationRegistryOwnerFundsWithdrawnIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type AutomationRegistryOwnerFundsWithdrawn struct { + Amount *big.Int + Raw types.Log +} + +func (_AutomationRegistry *AutomationRegistryFilterer) FilterOwnerFundsWithdrawn(opts *bind.FilterOpts) (*AutomationRegistryOwnerFundsWithdrawnIterator, error) { + + logs, sub, err := _AutomationRegistry.contract.FilterLogs(opts, "OwnerFundsWithdrawn") + if err != nil { + return nil, err + } + return &AutomationRegistryOwnerFundsWithdrawnIterator{contract: _AutomationRegistry.contract, event: "OwnerFundsWithdrawn", logs: logs, sub: sub}, nil +} + +func (_AutomationRegistry *AutomationRegistryFilterer) WatchOwnerFundsWithdrawn(opts *bind.WatchOpts, sink chan<- *AutomationRegistryOwnerFundsWithdrawn) (event.Subscription, error) { + + logs, sub, err := _AutomationRegistry.contract.WatchLogs(opts, "OwnerFundsWithdrawn") + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(AutomationRegistryOwnerFundsWithdrawn) + if err := _AutomationRegistry.contract.UnpackLog(event, "OwnerFundsWithdrawn", 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 (_AutomationRegistry *AutomationRegistryFilterer) ParseOwnerFundsWithdrawn(log types.Log) (*AutomationRegistryOwnerFundsWithdrawn, error) { + event := new(AutomationRegistryOwnerFundsWithdrawn) + if err := _AutomationRegistry.contract.UnpackLog(event, "OwnerFundsWithdrawn", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type AutomationRegistryOwnershipTransferRequestedIterator struct { + Event *AutomationRegistryOwnershipTransferRequested + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *AutomationRegistryOwnershipTransferRequestedIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(AutomationRegistryOwnershipTransferRequested) + 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(AutomationRegistryOwnershipTransferRequested) + 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 *AutomationRegistryOwnershipTransferRequestedIterator) Error() error { + return it.fail +} + +func (it *AutomationRegistryOwnershipTransferRequestedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type AutomationRegistryOwnershipTransferRequested struct { + From common.Address + To common.Address + Raw types.Log +} + +func (_AutomationRegistry *AutomationRegistryFilterer) FilterOwnershipTransferRequested(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*AutomationRegistryOwnershipTransferRequestedIterator, 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 := _AutomationRegistry.contract.FilterLogs(opts, "OwnershipTransferRequested", fromRule, toRule) + if err != nil { + return nil, err + } + return &AutomationRegistryOwnershipTransferRequestedIterator{contract: _AutomationRegistry.contract, event: "OwnershipTransferRequested", logs: logs, sub: sub}, nil +} + +func (_AutomationRegistry *AutomationRegistryFilterer) WatchOwnershipTransferRequested(opts *bind.WatchOpts, sink chan<- *AutomationRegistryOwnershipTransferRequested, 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 := _AutomationRegistry.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(AutomationRegistryOwnershipTransferRequested) + if err := _AutomationRegistry.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 (_AutomationRegistry *AutomationRegistryFilterer) ParseOwnershipTransferRequested(log types.Log) (*AutomationRegistryOwnershipTransferRequested, error) { + event := new(AutomationRegistryOwnershipTransferRequested) + if err := _AutomationRegistry.contract.UnpackLog(event, "OwnershipTransferRequested", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type AutomationRegistryOwnershipTransferredIterator struct { + Event *AutomationRegistryOwnershipTransferred + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *AutomationRegistryOwnershipTransferredIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(AutomationRegistryOwnershipTransferred) + 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(AutomationRegistryOwnershipTransferred) + 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 *AutomationRegistryOwnershipTransferredIterator) Error() error { + return it.fail +} + +func (it *AutomationRegistryOwnershipTransferredIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type AutomationRegistryOwnershipTransferred struct { + From common.Address + To common.Address + Raw types.Log +} + +func (_AutomationRegistry *AutomationRegistryFilterer) FilterOwnershipTransferred(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*AutomationRegistryOwnershipTransferredIterator, 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 := _AutomationRegistry.contract.FilterLogs(opts, "OwnershipTransferred", fromRule, toRule) + if err != nil { + return nil, err + } + return &AutomationRegistryOwnershipTransferredIterator{contract: _AutomationRegistry.contract, event: "OwnershipTransferred", logs: logs, sub: sub}, nil +} + +func (_AutomationRegistry *AutomationRegistryFilterer) WatchOwnershipTransferred(opts *bind.WatchOpts, sink chan<- *AutomationRegistryOwnershipTransferred, 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 := _AutomationRegistry.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(AutomationRegistryOwnershipTransferred) + if err := _AutomationRegistry.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 (_AutomationRegistry *AutomationRegistryFilterer) ParseOwnershipTransferred(log types.Log) (*AutomationRegistryOwnershipTransferred, error) { + event := new(AutomationRegistryOwnershipTransferred) + if err := _AutomationRegistry.contract.UnpackLog(event, "OwnershipTransferred", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type AutomationRegistryPausedIterator struct { + Event *AutomationRegistryPaused + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *AutomationRegistryPausedIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(AutomationRegistryPaused) + 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(AutomationRegistryPaused) + 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 *AutomationRegistryPausedIterator) Error() error { + return it.fail +} + +func (it *AutomationRegistryPausedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type AutomationRegistryPaused struct { + Account common.Address + Raw types.Log +} + +func (_AutomationRegistry *AutomationRegistryFilterer) FilterPaused(opts *bind.FilterOpts) (*AutomationRegistryPausedIterator, error) { + + logs, sub, err := _AutomationRegistry.contract.FilterLogs(opts, "Paused") + if err != nil { + return nil, err + } + return &AutomationRegistryPausedIterator{contract: _AutomationRegistry.contract, event: "Paused", logs: logs, sub: sub}, nil +} + +func (_AutomationRegistry *AutomationRegistryFilterer) WatchPaused(opts *bind.WatchOpts, sink chan<- *AutomationRegistryPaused) (event.Subscription, error) { + + logs, sub, err := _AutomationRegistry.contract.WatchLogs(opts, "Paused") + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(AutomationRegistryPaused) + if err := _AutomationRegistry.contract.UnpackLog(event, "Paused", 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 (_AutomationRegistry *AutomationRegistryFilterer) ParsePaused(log types.Log) (*AutomationRegistryPaused, error) { + event := new(AutomationRegistryPaused) + if err := _AutomationRegistry.contract.UnpackLog(event, "Paused", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type AutomationRegistryPayeesUpdatedIterator struct { + Event *AutomationRegistryPayeesUpdated + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *AutomationRegistryPayeesUpdatedIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(AutomationRegistryPayeesUpdated) + 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(AutomationRegistryPayeesUpdated) + 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 *AutomationRegistryPayeesUpdatedIterator) Error() error { + return it.fail +} + +func (it *AutomationRegistryPayeesUpdatedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type AutomationRegistryPayeesUpdated struct { + Transmitters []common.Address + Payees []common.Address + Raw types.Log +} + +func (_AutomationRegistry *AutomationRegistryFilterer) FilterPayeesUpdated(opts *bind.FilterOpts) (*AutomationRegistryPayeesUpdatedIterator, error) { + + logs, sub, err := _AutomationRegistry.contract.FilterLogs(opts, "PayeesUpdated") + if err != nil { + return nil, err + } + return &AutomationRegistryPayeesUpdatedIterator{contract: _AutomationRegistry.contract, event: "PayeesUpdated", logs: logs, sub: sub}, nil +} + +func (_AutomationRegistry *AutomationRegistryFilterer) WatchPayeesUpdated(opts *bind.WatchOpts, sink chan<- *AutomationRegistryPayeesUpdated) (event.Subscription, error) { + + logs, sub, err := _AutomationRegistry.contract.WatchLogs(opts, "PayeesUpdated") + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(AutomationRegistryPayeesUpdated) + if err := _AutomationRegistry.contract.UnpackLog(event, "PayeesUpdated", 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 (_AutomationRegistry *AutomationRegistryFilterer) ParsePayeesUpdated(log types.Log) (*AutomationRegistryPayeesUpdated, error) { + event := new(AutomationRegistryPayeesUpdated) + if err := _AutomationRegistry.contract.UnpackLog(event, "PayeesUpdated", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type AutomationRegistryPayeeshipTransferRequestedIterator struct { + Event *AutomationRegistryPayeeshipTransferRequested + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *AutomationRegistryPayeeshipTransferRequestedIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(AutomationRegistryPayeeshipTransferRequested) + 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(AutomationRegistryPayeeshipTransferRequested) + 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 *AutomationRegistryPayeeshipTransferRequestedIterator) Error() error { + return it.fail +} + +func (it *AutomationRegistryPayeeshipTransferRequestedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type AutomationRegistryPayeeshipTransferRequested struct { + Transmitter common.Address + From common.Address + To common.Address + Raw types.Log +} + +func (_AutomationRegistry *AutomationRegistryFilterer) FilterPayeeshipTransferRequested(opts *bind.FilterOpts, transmitter []common.Address, from []common.Address, to []common.Address) (*AutomationRegistryPayeeshipTransferRequestedIterator, error) { + + var transmitterRule []interface{} + for _, transmitterItem := range transmitter { + transmitterRule = append(transmitterRule, transmitterItem) + } + 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 := _AutomationRegistry.contract.FilterLogs(opts, "PayeeshipTransferRequested", transmitterRule, fromRule, toRule) + if err != nil { + return nil, err + } + return &AutomationRegistryPayeeshipTransferRequestedIterator{contract: _AutomationRegistry.contract, event: "PayeeshipTransferRequested", logs: logs, sub: sub}, nil +} + +func (_AutomationRegistry *AutomationRegistryFilterer) WatchPayeeshipTransferRequested(opts *bind.WatchOpts, sink chan<- *AutomationRegistryPayeeshipTransferRequested, transmitter []common.Address, from []common.Address, to []common.Address) (event.Subscription, error) { + + var transmitterRule []interface{} + for _, transmitterItem := range transmitter { + transmitterRule = append(transmitterRule, transmitterItem) + } + 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 := _AutomationRegistry.contract.WatchLogs(opts, "PayeeshipTransferRequested", transmitterRule, 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(AutomationRegistryPayeeshipTransferRequested) + if err := _AutomationRegistry.contract.UnpackLog(event, "PayeeshipTransferRequested", 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 (_AutomationRegistry *AutomationRegistryFilterer) ParsePayeeshipTransferRequested(log types.Log) (*AutomationRegistryPayeeshipTransferRequested, error) { + event := new(AutomationRegistryPayeeshipTransferRequested) + if err := _AutomationRegistry.contract.UnpackLog(event, "PayeeshipTransferRequested", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type AutomationRegistryPayeeshipTransferredIterator struct { + Event *AutomationRegistryPayeeshipTransferred + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *AutomationRegistryPayeeshipTransferredIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(AutomationRegistryPayeeshipTransferred) + 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(AutomationRegistryPayeeshipTransferred) + 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 *AutomationRegistryPayeeshipTransferredIterator) Error() error { + return it.fail +} + +func (it *AutomationRegistryPayeeshipTransferredIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type AutomationRegistryPayeeshipTransferred struct { + Transmitter common.Address + From common.Address + To common.Address + Raw types.Log +} + +func (_AutomationRegistry *AutomationRegistryFilterer) FilterPayeeshipTransferred(opts *bind.FilterOpts, transmitter []common.Address, from []common.Address, to []common.Address) (*AutomationRegistryPayeeshipTransferredIterator, error) { + + var transmitterRule []interface{} + for _, transmitterItem := range transmitter { + transmitterRule = append(transmitterRule, transmitterItem) + } + 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 := _AutomationRegistry.contract.FilterLogs(opts, "PayeeshipTransferred", transmitterRule, fromRule, toRule) + if err != nil { + return nil, err + } + return &AutomationRegistryPayeeshipTransferredIterator{contract: _AutomationRegistry.contract, event: "PayeeshipTransferred", logs: logs, sub: sub}, nil +} + +func (_AutomationRegistry *AutomationRegistryFilterer) WatchPayeeshipTransferred(opts *bind.WatchOpts, sink chan<- *AutomationRegistryPayeeshipTransferred, transmitter []common.Address, from []common.Address, to []common.Address) (event.Subscription, error) { + + var transmitterRule []interface{} + for _, transmitterItem := range transmitter { + transmitterRule = append(transmitterRule, transmitterItem) + } + 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 := _AutomationRegistry.contract.WatchLogs(opts, "PayeeshipTransferred", transmitterRule, 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(AutomationRegistryPayeeshipTransferred) + if err := _AutomationRegistry.contract.UnpackLog(event, "PayeeshipTransferred", 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 (_AutomationRegistry *AutomationRegistryFilterer) ParsePayeeshipTransferred(log types.Log) (*AutomationRegistryPayeeshipTransferred, error) { + event := new(AutomationRegistryPayeeshipTransferred) + if err := _AutomationRegistry.contract.UnpackLog(event, "PayeeshipTransferred", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type AutomationRegistryPaymentWithdrawnIterator struct { + Event *AutomationRegistryPaymentWithdrawn + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *AutomationRegistryPaymentWithdrawnIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(AutomationRegistryPaymentWithdrawn) + 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(AutomationRegistryPaymentWithdrawn) + 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 *AutomationRegistryPaymentWithdrawnIterator) Error() error { + return it.fail +} + +func (it *AutomationRegistryPaymentWithdrawnIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type AutomationRegistryPaymentWithdrawn struct { + Transmitter common.Address + Amount *big.Int + To common.Address + Payee common.Address + Raw types.Log +} + +func (_AutomationRegistry *AutomationRegistryFilterer) FilterPaymentWithdrawn(opts *bind.FilterOpts, transmitter []common.Address, amount []*big.Int, to []common.Address) (*AutomationRegistryPaymentWithdrawnIterator, error) { + + var transmitterRule []interface{} + for _, transmitterItem := range transmitter { + transmitterRule = append(transmitterRule, transmitterItem) + } + var amountRule []interface{} + for _, amountItem := range amount { + amountRule = append(amountRule, amountItem) + } + var toRule []interface{} + for _, toItem := range to { + toRule = append(toRule, toItem) + } + + logs, sub, err := _AutomationRegistry.contract.FilterLogs(opts, "PaymentWithdrawn", transmitterRule, amountRule, toRule) + if err != nil { + return nil, err + } + return &AutomationRegistryPaymentWithdrawnIterator{contract: _AutomationRegistry.contract, event: "PaymentWithdrawn", logs: logs, sub: sub}, nil +} + +func (_AutomationRegistry *AutomationRegistryFilterer) WatchPaymentWithdrawn(opts *bind.WatchOpts, sink chan<- *AutomationRegistryPaymentWithdrawn, transmitter []common.Address, amount []*big.Int, to []common.Address) (event.Subscription, error) { + + var transmitterRule []interface{} + for _, transmitterItem := range transmitter { + transmitterRule = append(transmitterRule, transmitterItem) + } + var amountRule []interface{} + for _, amountItem := range amount { + amountRule = append(amountRule, amountItem) + } + var toRule []interface{} + for _, toItem := range to { + toRule = append(toRule, toItem) + } + + logs, sub, err := _AutomationRegistry.contract.WatchLogs(opts, "PaymentWithdrawn", transmitterRule, amountRule, 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(AutomationRegistryPaymentWithdrawn) + if err := _AutomationRegistry.contract.UnpackLog(event, "PaymentWithdrawn", 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 (_AutomationRegistry *AutomationRegistryFilterer) ParsePaymentWithdrawn(log types.Log) (*AutomationRegistryPaymentWithdrawn, error) { + event := new(AutomationRegistryPaymentWithdrawn) + if err := _AutomationRegistry.contract.UnpackLog(event, "PaymentWithdrawn", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type AutomationRegistryReorgedUpkeepReportIterator struct { + Event *AutomationRegistryReorgedUpkeepReport + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *AutomationRegistryReorgedUpkeepReportIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(AutomationRegistryReorgedUpkeepReport) + 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(AutomationRegistryReorgedUpkeepReport) + 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 *AutomationRegistryReorgedUpkeepReportIterator) Error() error { + return it.fail +} + +func (it *AutomationRegistryReorgedUpkeepReportIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type AutomationRegistryReorgedUpkeepReport struct { + Id *big.Int + Trigger []byte + Raw types.Log +} + +func (_AutomationRegistry *AutomationRegistryFilterer) FilterReorgedUpkeepReport(opts *bind.FilterOpts, id []*big.Int) (*AutomationRegistryReorgedUpkeepReportIterator, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + + logs, sub, err := _AutomationRegistry.contract.FilterLogs(opts, "ReorgedUpkeepReport", idRule) + if err != nil { + return nil, err + } + return &AutomationRegistryReorgedUpkeepReportIterator{contract: _AutomationRegistry.contract, event: "ReorgedUpkeepReport", logs: logs, sub: sub}, nil +} + +func (_AutomationRegistry *AutomationRegistryFilterer) WatchReorgedUpkeepReport(opts *bind.WatchOpts, sink chan<- *AutomationRegistryReorgedUpkeepReport, id []*big.Int) (event.Subscription, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + + logs, sub, err := _AutomationRegistry.contract.WatchLogs(opts, "ReorgedUpkeepReport", idRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(AutomationRegistryReorgedUpkeepReport) + if err := _AutomationRegistry.contract.UnpackLog(event, "ReorgedUpkeepReport", 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 (_AutomationRegistry *AutomationRegistryFilterer) ParseReorgedUpkeepReport(log types.Log) (*AutomationRegistryReorgedUpkeepReport, error) { + event := new(AutomationRegistryReorgedUpkeepReport) + if err := _AutomationRegistry.contract.UnpackLog(event, "ReorgedUpkeepReport", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type AutomationRegistryStaleUpkeepReportIterator struct { + Event *AutomationRegistryStaleUpkeepReport + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *AutomationRegistryStaleUpkeepReportIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(AutomationRegistryStaleUpkeepReport) + 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(AutomationRegistryStaleUpkeepReport) + 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 *AutomationRegistryStaleUpkeepReportIterator) Error() error { + return it.fail +} + +func (it *AutomationRegistryStaleUpkeepReportIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type AutomationRegistryStaleUpkeepReport struct { + Id *big.Int + Trigger []byte + Raw types.Log +} + +func (_AutomationRegistry *AutomationRegistryFilterer) FilterStaleUpkeepReport(opts *bind.FilterOpts, id []*big.Int) (*AutomationRegistryStaleUpkeepReportIterator, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + + logs, sub, err := _AutomationRegistry.contract.FilterLogs(opts, "StaleUpkeepReport", idRule) + if err != nil { + return nil, err + } + return &AutomationRegistryStaleUpkeepReportIterator{contract: _AutomationRegistry.contract, event: "StaleUpkeepReport", logs: logs, sub: sub}, nil +} + +func (_AutomationRegistry *AutomationRegistryFilterer) WatchStaleUpkeepReport(opts *bind.WatchOpts, sink chan<- *AutomationRegistryStaleUpkeepReport, id []*big.Int) (event.Subscription, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + + logs, sub, err := _AutomationRegistry.contract.WatchLogs(opts, "StaleUpkeepReport", idRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(AutomationRegistryStaleUpkeepReport) + if err := _AutomationRegistry.contract.UnpackLog(event, "StaleUpkeepReport", 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 (_AutomationRegistry *AutomationRegistryFilterer) ParseStaleUpkeepReport(log types.Log) (*AutomationRegistryStaleUpkeepReport, error) { + event := new(AutomationRegistryStaleUpkeepReport) + if err := _AutomationRegistry.contract.UnpackLog(event, "StaleUpkeepReport", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type AutomationRegistryTransmittedIterator struct { + Event *AutomationRegistryTransmitted + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *AutomationRegistryTransmittedIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(AutomationRegistryTransmitted) + 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(AutomationRegistryTransmitted) + 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 *AutomationRegistryTransmittedIterator) Error() error { + return it.fail +} + +func (it *AutomationRegistryTransmittedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type AutomationRegistryTransmitted struct { + ConfigDigest [32]byte + Epoch uint32 + Raw types.Log +} + +func (_AutomationRegistry *AutomationRegistryFilterer) FilterTransmitted(opts *bind.FilterOpts) (*AutomationRegistryTransmittedIterator, error) { + + logs, sub, err := _AutomationRegistry.contract.FilterLogs(opts, "Transmitted") + if err != nil { + return nil, err + } + return &AutomationRegistryTransmittedIterator{contract: _AutomationRegistry.contract, event: "Transmitted", logs: logs, sub: sub}, nil +} + +func (_AutomationRegistry *AutomationRegistryFilterer) WatchTransmitted(opts *bind.WatchOpts, sink chan<- *AutomationRegistryTransmitted) (event.Subscription, error) { + + logs, sub, err := _AutomationRegistry.contract.WatchLogs(opts, "Transmitted") + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(AutomationRegistryTransmitted) + if err := _AutomationRegistry.contract.UnpackLog(event, "Transmitted", 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 (_AutomationRegistry *AutomationRegistryFilterer) ParseTransmitted(log types.Log) (*AutomationRegistryTransmitted, error) { + event := new(AutomationRegistryTransmitted) + if err := _AutomationRegistry.contract.UnpackLog(event, "Transmitted", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type AutomationRegistryUnpausedIterator struct { + Event *AutomationRegistryUnpaused + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *AutomationRegistryUnpausedIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(AutomationRegistryUnpaused) + 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(AutomationRegistryUnpaused) + 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 *AutomationRegistryUnpausedIterator) Error() error { + return it.fail +} + +func (it *AutomationRegistryUnpausedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type AutomationRegistryUnpaused struct { + Account common.Address + Raw types.Log +} + +func (_AutomationRegistry *AutomationRegistryFilterer) FilterUnpaused(opts *bind.FilterOpts) (*AutomationRegistryUnpausedIterator, error) { + + logs, sub, err := _AutomationRegistry.contract.FilterLogs(opts, "Unpaused") + if err != nil { + return nil, err + } + return &AutomationRegistryUnpausedIterator{contract: _AutomationRegistry.contract, event: "Unpaused", logs: logs, sub: sub}, nil +} + +func (_AutomationRegistry *AutomationRegistryFilterer) WatchUnpaused(opts *bind.WatchOpts, sink chan<- *AutomationRegistryUnpaused) (event.Subscription, error) { + + logs, sub, err := _AutomationRegistry.contract.WatchLogs(opts, "Unpaused") + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(AutomationRegistryUnpaused) + if err := _AutomationRegistry.contract.UnpackLog(event, "Unpaused", 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 (_AutomationRegistry *AutomationRegistryFilterer) ParseUnpaused(log types.Log) (*AutomationRegistryUnpaused, error) { + event := new(AutomationRegistryUnpaused) + if err := _AutomationRegistry.contract.UnpackLog(event, "Unpaused", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type AutomationRegistryUpkeepAdminTransferRequestedIterator struct { + Event *AutomationRegistryUpkeepAdminTransferRequested + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *AutomationRegistryUpkeepAdminTransferRequestedIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(AutomationRegistryUpkeepAdminTransferRequested) + 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(AutomationRegistryUpkeepAdminTransferRequested) + 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 *AutomationRegistryUpkeepAdminTransferRequestedIterator) Error() error { + return it.fail +} + +func (it *AutomationRegistryUpkeepAdminTransferRequestedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type AutomationRegistryUpkeepAdminTransferRequested struct { + Id *big.Int + From common.Address + To common.Address + Raw types.Log +} + +func (_AutomationRegistry *AutomationRegistryFilterer) FilterUpkeepAdminTransferRequested(opts *bind.FilterOpts, id []*big.Int, from []common.Address, to []common.Address) (*AutomationRegistryUpkeepAdminTransferRequestedIterator, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + 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 := _AutomationRegistry.contract.FilterLogs(opts, "UpkeepAdminTransferRequested", idRule, fromRule, toRule) + if err != nil { + return nil, err + } + return &AutomationRegistryUpkeepAdminTransferRequestedIterator{contract: _AutomationRegistry.contract, event: "UpkeepAdminTransferRequested", logs: logs, sub: sub}, nil +} + +func (_AutomationRegistry *AutomationRegistryFilterer) WatchUpkeepAdminTransferRequested(opts *bind.WatchOpts, sink chan<- *AutomationRegistryUpkeepAdminTransferRequested, id []*big.Int, from []common.Address, to []common.Address) (event.Subscription, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + 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 := _AutomationRegistry.contract.WatchLogs(opts, "UpkeepAdminTransferRequested", idRule, 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(AutomationRegistryUpkeepAdminTransferRequested) + if err := _AutomationRegistry.contract.UnpackLog(event, "UpkeepAdminTransferRequested", 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 (_AutomationRegistry *AutomationRegistryFilterer) ParseUpkeepAdminTransferRequested(log types.Log) (*AutomationRegistryUpkeepAdminTransferRequested, error) { + event := new(AutomationRegistryUpkeepAdminTransferRequested) + if err := _AutomationRegistry.contract.UnpackLog(event, "UpkeepAdminTransferRequested", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type AutomationRegistryUpkeepAdminTransferredIterator struct { + Event *AutomationRegistryUpkeepAdminTransferred + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *AutomationRegistryUpkeepAdminTransferredIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(AutomationRegistryUpkeepAdminTransferred) + 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(AutomationRegistryUpkeepAdminTransferred) + 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 *AutomationRegistryUpkeepAdminTransferredIterator) Error() error { + return it.fail +} + +func (it *AutomationRegistryUpkeepAdminTransferredIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type AutomationRegistryUpkeepAdminTransferred struct { + Id *big.Int + From common.Address + To common.Address + Raw types.Log +} + +func (_AutomationRegistry *AutomationRegistryFilterer) FilterUpkeepAdminTransferred(opts *bind.FilterOpts, id []*big.Int, from []common.Address, to []common.Address) (*AutomationRegistryUpkeepAdminTransferredIterator, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + 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 := _AutomationRegistry.contract.FilterLogs(opts, "UpkeepAdminTransferred", idRule, fromRule, toRule) + if err != nil { + return nil, err + } + return &AutomationRegistryUpkeepAdminTransferredIterator{contract: _AutomationRegistry.contract, event: "UpkeepAdminTransferred", logs: logs, sub: sub}, nil +} + +func (_AutomationRegistry *AutomationRegistryFilterer) WatchUpkeepAdminTransferred(opts *bind.WatchOpts, sink chan<- *AutomationRegistryUpkeepAdminTransferred, id []*big.Int, from []common.Address, to []common.Address) (event.Subscription, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + 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 := _AutomationRegistry.contract.WatchLogs(opts, "UpkeepAdminTransferred", idRule, 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(AutomationRegistryUpkeepAdminTransferred) + if err := _AutomationRegistry.contract.UnpackLog(event, "UpkeepAdminTransferred", 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 (_AutomationRegistry *AutomationRegistryFilterer) ParseUpkeepAdminTransferred(log types.Log) (*AutomationRegistryUpkeepAdminTransferred, error) { + event := new(AutomationRegistryUpkeepAdminTransferred) + if err := _AutomationRegistry.contract.UnpackLog(event, "UpkeepAdminTransferred", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type AutomationRegistryUpkeepCanceledIterator struct { + Event *AutomationRegistryUpkeepCanceled + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *AutomationRegistryUpkeepCanceledIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(AutomationRegistryUpkeepCanceled) + 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(AutomationRegistryUpkeepCanceled) + 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 *AutomationRegistryUpkeepCanceledIterator) Error() error { + return it.fail +} + +func (it *AutomationRegistryUpkeepCanceledIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type AutomationRegistryUpkeepCanceled struct { + Id *big.Int + AtBlockHeight uint64 + Raw types.Log +} + +func (_AutomationRegistry *AutomationRegistryFilterer) FilterUpkeepCanceled(opts *bind.FilterOpts, id []*big.Int, atBlockHeight []uint64) (*AutomationRegistryUpkeepCanceledIterator, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + var atBlockHeightRule []interface{} + for _, atBlockHeightItem := range atBlockHeight { + atBlockHeightRule = append(atBlockHeightRule, atBlockHeightItem) + } + + logs, sub, err := _AutomationRegistry.contract.FilterLogs(opts, "UpkeepCanceled", idRule, atBlockHeightRule) + if err != nil { + return nil, err + } + return &AutomationRegistryUpkeepCanceledIterator{contract: _AutomationRegistry.contract, event: "UpkeepCanceled", logs: logs, sub: sub}, nil +} + +func (_AutomationRegistry *AutomationRegistryFilterer) WatchUpkeepCanceled(opts *bind.WatchOpts, sink chan<- *AutomationRegistryUpkeepCanceled, id []*big.Int, atBlockHeight []uint64) (event.Subscription, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + var atBlockHeightRule []interface{} + for _, atBlockHeightItem := range atBlockHeight { + atBlockHeightRule = append(atBlockHeightRule, atBlockHeightItem) + } + + logs, sub, err := _AutomationRegistry.contract.WatchLogs(opts, "UpkeepCanceled", idRule, atBlockHeightRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(AutomationRegistryUpkeepCanceled) + if err := _AutomationRegistry.contract.UnpackLog(event, "UpkeepCanceled", 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 (_AutomationRegistry *AutomationRegistryFilterer) ParseUpkeepCanceled(log types.Log) (*AutomationRegistryUpkeepCanceled, error) { + event := new(AutomationRegistryUpkeepCanceled) + if err := _AutomationRegistry.contract.UnpackLog(event, "UpkeepCanceled", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type AutomationRegistryUpkeepCheckDataSetIterator struct { + Event *AutomationRegistryUpkeepCheckDataSet + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *AutomationRegistryUpkeepCheckDataSetIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(AutomationRegistryUpkeepCheckDataSet) + 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(AutomationRegistryUpkeepCheckDataSet) + 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 *AutomationRegistryUpkeepCheckDataSetIterator) Error() error { + return it.fail +} + +func (it *AutomationRegistryUpkeepCheckDataSetIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type AutomationRegistryUpkeepCheckDataSet struct { + Id *big.Int + NewCheckData []byte + Raw types.Log +} + +func (_AutomationRegistry *AutomationRegistryFilterer) FilterUpkeepCheckDataSet(opts *bind.FilterOpts, id []*big.Int) (*AutomationRegistryUpkeepCheckDataSetIterator, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + + logs, sub, err := _AutomationRegistry.contract.FilterLogs(opts, "UpkeepCheckDataSet", idRule) + if err != nil { + return nil, err + } + return &AutomationRegistryUpkeepCheckDataSetIterator{contract: _AutomationRegistry.contract, event: "UpkeepCheckDataSet", logs: logs, sub: sub}, nil +} + +func (_AutomationRegistry *AutomationRegistryFilterer) WatchUpkeepCheckDataSet(opts *bind.WatchOpts, sink chan<- *AutomationRegistryUpkeepCheckDataSet, id []*big.Int) (event.Subscription, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + + logs, sub, err := _AutomationRegistry.contract.WatchLogs(opts, "UpkeepCheckDataSet", idRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(AutomationRegistryUpkeepCheckDataSet) + if err := _AutomationRegistry.contract.UnpackLog(event, "UpkeepCheckDataSet", 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 (_AutomationRegistry *AutomationRegistryFilterer) ParseUpkeepCheckDataSet(log types.Log) (*AutomationRegistryUpkeepCheckDataSet, error) { + event := new(AutomationRegistryUpkeepCheckDataSet) + if err := _AutomationRegistry.contract.UnpackLog(event, "UpkeepCheckDataSet", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type AutomationRegistryUpkeepGasLimitSetIterator struct { + Event *AutomationRegistryUpkeepGasLimitSet + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *AutomationRegistryUpkeepGasLimitSetIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(AutomationRegistryUpkeepGasLimitSet) + 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(AutomationRegistryUpkeepGasLimitSet) + 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 *AutomationRegistryUpkeepGasLimitSetIterator) Error() error { + return it.fail +} + +func (it *AutomationRegistryUpkeepGasLimitSetIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type AutomationRegistryUpkeepGasLimitSet struct { + Id *big.Int + GasLimit *big.Int + Raw types.Log +} + +func (_AutomationRegistry *AutomationRegistryFilterer) FilterUpkeepGasLimitSet(opts *bind.FilterOpts, id []*big.Int) (*AutomationRegistryUpkeepGasLimitSetIterator, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + + logs, sub, err := _AutomationRegistry.contract.FilterLogs(opts, "UpkeepGasLimitSet", idRule) + if err != nil { + return nil, err + } + return &AutomationRegistryUpkeepGasLimitSetIterator{contract: _AutomationRegistry.contract, event: "UpkeepGasLimitSet", logs: logs, sub: sub}, nil +} + +func (_AutomationRegistry *AutomationRegistryFilterer) WatchUpkeepGasLimitSet(opts *bind.WatchOpts, sink chan<- *AutomationRegistryUpkeepGasLimitSet, id []*big.Int) (event.Subscription, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + + logs, sub, err := _AutomationRegistry.contract.WatchLogs(opts, "UpkeepGasLimitSet", idRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(AutomationRegistryUpkeepGasLimitSet) + if err := _AutomationRegistry.contract.UnpackLog(event, "UpkeepGasLimitSet", 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 (_AutomationRegistry *AutomationRegistryFilterer) ParseUpkeepGasLimitSet(log types.Log) (*AutomationRegistryUpkeepGasLimitSet, error) { + event := new(AutomationRegistryUpkeepGasLimitSet) + if err := _AutomationRegistry.contract.UnpackLog(event, "UpkeepGasLimitSet", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type AutomationRegistryUpkeepMigratedIterator struct { + Event *AutomationRegistryUpkeepMigrated + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *AutomationRegistryUpkeepMigratedIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(AutomationRegistryUpkeepMigrated) + 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(AutomationRegistryUpkeepMigrated) + 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 *AutomationRegistryUpkeepMigratedIterator) Error() error { + return it.fail +} + +func (it *AutomationRegistryUpkeepMigratedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type AutomationRegistryUpkeepMigrated struct { + Id *big.Int + RemainingBalance *big.Int + Destination common.Address + Raw types.Log +} + +func (_AutomationRegistry *AutomationRegistryFilterer) FilterUpkeepMigrated(opts *bind.FilterOpts, id []*big.Int) (*AutomationRegistryUpkeepMigratedIterator, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + + logs, sub, err := _AutomationRegistry.contract.FilterLogs(opts, "UpkeepMigrated", idRule) + if err != nil { + return nil, err + } + return &AutomationRegistryUpkeepMigratedIterator{contract: _AutomationRegistry.contract, event: "UpkeepMigrated", logs: logs, sub: sub}, nil +} + +func (_AutomationRegistry *AutomationRegistryFilterer) WatchUpkeepMigrated(opts *bind.WatchOpts, sink chan<- *AutomationRegistryUpkeepMigrated, id []*big.Int) (event.Subscription, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + + logs, sub, err := _AutomationRegistry.contract.WatchLogs(opts, "UpkeepMigrated", idRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(AutomationRegistryUpkeepMigrated) + if err := _AutomationRegistry.contract.UnpackLog(event, "UpkeepMigrated", 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 (_AutomationRegistry *AutomationRegistryFilterer) ParseUpkeepMigrated(log types.Log) (*AutomationRegistryUpkeepMigrated, error) { + event := new(AutomationRegistryUpkeepMigrated) + if err := _AutomationRegistry.contract.UnpackLog(event, "UpkeepMigrated", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type AutomationRegistryUpkeepOffchainConfigSetIterator struct { + Event *AutomationRegistryUpkeepOffchainConfigSet + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *AutomationRegistryUpkeepOffchainConfigSetIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(AutomationRegistryUpkeepOffchainConfigSet) + 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(AutomationRegistryUpkeepOffchainConfigSet) + 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 *AutomationRegistryUpkeepOffchainConfigSetIterator) Error() error { + return it.fail +} + +func (it *AutomationRegistryUpkeepOffchainConfigSetIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type AutomationRegistryUpkeepOffchainConfigSet struct { + Id *big.Int + OffchainConfig []byte + Raw types.Log +} + +func (_AutomationRegistry *AutomationRegistryFilterer) FilterUpkeepOffchainConfigSet(opts *bind.FilterOpts, id []*big.Int) (*AutomationRegistryUpkeepOffchainConfigSetIterator, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + + logs, sub, err := _AutomationRegistry.contract.FilterLogs(opts, "UpkeepOffchainConfigSet", idRule) + if err != nil { + return nil, err + } + return &AutomationRegistryUpkeepOffchainConfigSetIterator{contract: _AutomationRegistry.contract, event: "UpkeepOffchainConfigSet", logs: logs, sub: sub}, nil +} + +func (_AutomationRegistry *AutomationRegistryFilterer) WatchUpkeepOffchainConfigSet(opts *bind.WatchOpts, sink chan<- *AutomationRegistryUpkeepOffchainConfigSet, id []*big.Int) (event.Subscription, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + + logs, sub, err := _AutomationRegistry.contract.WatchLogs(opts, "UpkeepOffchainConfigSet", idRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(AutomationRegistryUpkeepOffchainConfigSet) + if err := _AutomationRegistry.contract.UnpackLog(event, "UpkeepOffchainConfigSet", 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 (_AutomationRegistry *AutomationRegistryFilterer) ParseUpkeepOffchainConfigSet(log types.Log) (*AutomationRegistryUpkeepOffchainConfigSet, error) { + event := new(AutomationRegistryUpkeepOffchainConfigSet) + if err := _AutomationRegistry.contract.UnpackLog(event, "UpkeepOffchainConfigSet", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type AutomationRegistryUpkeepPausedIterator struct { + Event *AutomationRegistryUpkeepPaused + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *AutomationRegistryUpkeepPausedIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(AutomationRegistryUpkeepPaused) + 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(AutomationRegistryUpkeepPaused) + 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 *AutomationRegistryUpkeepPausedIterator) Error() error { + return it.fail +} + +func (it *AutomationRegistryUpkeepPausedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type AutomationRegistryUpkeepPaused struct { + Id *big.Int + Raw types.Log +} + +func (_AutomationRegistry *AutomationRegistryFilterer) FilterUpkeepPaused(opts *bind.FilterOpts, id []*big.Int) (*AutomationRegistryUpkeepPausedIterator, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + + logs, sub, err := _AutomationRegistry.contract.FilterLogs(opts, "UpkeepPaused", idRule) + if err != nil { + return nil, err + } + return &AutomationRegistryUpkeepPausedIterator{contract: _AutomationRegistry.contract, event: "UpkeepPaused", logs: logs, sub: sub}, nil +} + +func (_AutomationRegistry *AutomationRegistryFilterer) WatchUpkeepPaused(opts *bind.WatchOpts, sink chan<- *AutomationRegistryUpkeepPaused, id []*big.Int) (event.Subscription, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + + logs, sub, err := _AutomationRegistry.contract.WatchLogs(opts, "UpkeepPaused", idRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(AutomationRegistryUpkeepPaused) + if err := _AutomationRegistry.contract.UnpackLog(event, "UpkeepPaused", 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 (_AutomationRegistry *AutomationRegistryFilterer) ParseUpkeepPaused(log types.Log) (*AutomationRegistryUpkeepPaused, error) { + event := new(AutomationRegistryUpkeepPaused) + if err := _AutomationRegistry.contract.UnpackLog(event, "UpkeepPaused", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type AutomationRegistryUpkeepPerformedIterator struct { + Event *AutomationRegistryUpkeepPerformed + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *AutomationRegistryUpkeepPerformedIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(AutomationRegistryUpkeepPerformed) + 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(AutomationRegistryUpkeepPerformed) + 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 *AutomationRegistryUpkeepPerformedIterator) Error() error { + return it.fail +} + +func (it *AutomationRegistryUpkeepPerformedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type AutomationRegistryUpkeepPerformed struct { + Id *big.Int + Success bool + TotalPayment *big.Int + GasUsed *big.Int + GasOverhead *big.Int + Trigger []byte + Raw types.Log +} + +func (_AutomationRegistry *AutomationRegistryFilterer) FilterUpkeepPerformed(opts *bind.FilterOpts, id []*big.Int, success []bool) (*AutomationRegistryUpkeepPerformedIterator, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + var successRule []interface{} + for _, successItem := range success { + successRule = append(successRule, successItem) + } + + logs, sub, err := _AutomationRegistry.contract.FilterLogs(opts, "UpkeepPerformed", idRule, successRule) + if err != nil { + return nil, err + } + return &AutomationRegistryUpkeepPerformedIterator{contract: _AutomationRegistry.contract, event: "UpkeepPerformed", logs: logs, sub: sub}, nil +} + +func (_AutomationRegistry *AutomationRegistryFilterer) WatchUpkeepPerformed(opts *bind.WatchOpts, sink chan<- *AutomationRegistryUpkeepPerformed, id []*big.Int, success []bool) (event.Subscription, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + var successRule []interface{} + for _, successItem := range success { + successRule = append(successRule, successItem) + } + + logs, sub, err := _AutomationRegistry.contract.WatchLogs(opts, "UpkeepPerformed", idRule, successRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(AutomationRegistryUpkeepPerformed) + if err := _AutomationRegistry.contract.UnpackLog(event, "UpkeepPerformed", 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 (_AutomationRegistry *AutomationRegistryFilterer) ParseUpkeepPerformed(log types.Log) (*AutomationRegistryUpkeepPerformed, error) { + event := new(AutomationRegistryUpkeepPerformed) + if err := _AutomationRegistry.contract.UnpackLog(event, "UpkeepPerformed", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type AutomationRegistryUpkeepPrivilegeConfigSetIterator struct { + Event *AutomationRegistryUpkeepPrivilegeConfigSet + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *AutomationRegistryUpkeepPrivilegeConfigSetIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(AutomationRegistryUpkeepPrivilegeConfigSet) + 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(AutomationRegistryUpkeepPrivilegeConfigSet) + 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 *AutomationRegistryUpkeepPrivilegeConfigSetIterator) Error() error { + return it.fail +} + +func (it *AutomationRegistryUpkeepPrivilegeConfigSetIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type AutomationRegistryUpkeepPrivilegeConfigSet struct { + Id *big.Int + PrivilegeConfig []byte + Raw types.Log +} + +func (_AutomationRegistry *AutomationRegistryFilterer) FilterUpkeepPrivilegeConfigSet(opts *bind.FilterOpts, id []*big.Int) (*AutomationRegistryUpkeepPrivilegeConfigSetIterator, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + + logs, sub, err := _AutomationRegistry.contract.FilterLogs(opts, "UpkeepPrivilegeConfigSet", idRule) + if err != nil { + return nil, err + } + return &AutomationRegistryUpkeepPrivilegeConfigSetIterator{contract: _AutomationRegistry.contract, event: "UpkeepPrivilegeConfigSet", logs: logs, sub: sub}, nil +} + +func (_AutomationRegistry *AutomationRegistryFilterer) WatchUpkeepPrivilegeConfigSet(opts *bind.WatchOpts, sink chan<- *AutomationRegistryUpkeepPrivilegeConfigSet, id []*big.Int) (event.Subscription, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + + logs, sub, err := _AutomationRegistry.contract.WatchLogs(opts, "UpkeepPrivilegeConfigSet", idRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(AutomationRegistryUpkeepPrivilegeConfigSet) + if err := _AutomationRegistry.contract.UnpackLog(event, "UpkeepPrivilegeConfigSet", 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 (_AutomationRegistry *AutomationRegistryFilterer) ParseUpkeepPrivilegeConfigSet(log types.Log) (*AutomationRegistryUpkeepPrivilegeConfigSet, error) { + event := new(AutomationRegistryUpkeepPrivilegeConfigSet) + if err := _AutomationRegistry.contract.UnpackLog(event, "UpkeepPrivilegeConfigSet", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type AutomationRegistryUpkeepReceivedIterator struct { + Event *AutomationRegistryUpkeepReceived + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *AutomationRegistryUpkeepReceivedIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(AutomationRegistryUpkeepReceived) + 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(AutomationRegistryUpkeepReceived) + 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 *AutomationRegistryUpkeepReceivedIterator) Error() error { + return it.fail +} + +func (it *AutomationRegistryUpkeepReceivedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type AutomationRegistryUpkeepReceived struct { + Id *big.Int + StartingBalance *big.Int + ImportedFrom common.Address + Raw types.Log +} + +func (_AutomationRegistry *AutomationRegistryFilterer) FilterUpkeepReceived(opts *bind.FilterOpts, id []*big.Int) (*AutomationRegistryUpkeepReceivedIterator, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + + logs, sub, err := _AutomationRegistry.contract.FilterLogs(opts, "UpkeepReceived", idRule) + if err != nil { + return nil, err + } + return &AutomationRegistryUpkeepReceivedIterator{contract: _AutomationRegistry.contract, event: "UpkeepReceived", logs: logs, sub: sub}, nil +} + +func (_AutomationRegistry *AutomationRegistryFilterer) WatchUpkeepReceived(opts *bind.WatchOpts, sink chan<- *AutomationRegistryUpkeepReceived, id []*big.Int) (event.Subscription, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + + logs, sub, err := _AutomationRegistry.contract.WatchLogs(opts, "UpkeepReceived", idRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(AutomationRegistryUpkeepReceived) + if err := _AutomationRegistry.contract.UnpackLog(event, "UpkeepReceived", 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 (_AutomationRegistry *AutomationRegistryFilterer) ParseUpkeepReceived(log types.Log) (*AutomationRegistryUpkeepReceived, error) { + event := new(AutomationRegistryUpkeepReceived) + if err := _AutomationRegistry.contract.UnpackLog(event, "UpkeepReceived", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type AutomationRegistryUpkeepRegisteredIterator struct { + Event *AutomationRegistryUpkeepRegistered + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *AutomationRegistryUpkeepRegisteredIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(AutomationRegistryUpkeepRegistered) + 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(AutomationRegistryUpkeepRegistered) + 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 *AutomationRegistryUpkeepRegisteredIterator) Error() error { + return it.fail +} + +func (it *AutomationRegistryUpkeepRegisteredIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type AutomationRegistryUpkeepRegistered struct { + Id *big.Int + PerformGas uint32 + Admin common.Address + Raw types.Log +} + +func (_AutomationRegistry *AutomationRegistryFilterer) FilterUpkeepRegistered(opts *bind.FilterOpts, id []*big.Int) (*AutomationRegistryUpkeepRegisteredIterator, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + + logs, sub, err := _AutomationRegistry.contract.FilterLogs(opts, "UpkeepRegistered", idRule) + if err != nil { + return nil, err + } + return &AutomationRegistryUpkeepRegisteredIterator{contract: _AutomationRegistry.contract, event: "UpkeepRegistered", logs: logs, sub: sub}, nil +} + +func (_AutomationRegistry *AutomationRegistryFilterer) WatchUpkeepRegistered(opts *bind.WatchOpts, sink chan<- *AutomationRegistryUpkeepRegistered, id []*big.Int) (event.Subscription, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + + logs, sub, err := _AutomationRegistry.contract.WatchLogs(opts, "UpkeepRegistered", idRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(AutomationRegistryUpkeepRegistered) + if err := _AutomationRegistry.contract.UnpackLog(event, "UpkeepRegistered", 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 (_AutomationRegistry *AutomationRegistryFilterer) ParseUpkeepRegistered(log types.Log) (*AutomationRegistryUpkeepRegistered, error) { + event := new(AutomationRegistryUpkeepRegistered) + if err := _AutomationRegistry.contract.UnpackLog(event, "UpkeepRegistered", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type AutomationRegistryUpkeepTriggerConfigSetIterator struct { + Event *AutomationRegistryUpkeepTriggerConfigSet + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *AutomationRegistryUpkeepTriggerConfigSetIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(AutomationRegistryUpkeepTriggerConfigSet) + 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(AutomationRegistryUpkeepTriggerConfigSet) + 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 *AutomationRegistryUpkeepTriggerConfigSetIterator) Error() error { + return it.fail +} + +func (it *AutomationRegistryUpkeepTriggerConfigSetIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type AutomationRegistryUpkeepTriggerConfigSet struct { + Id *big.Int + TriggerConfig []byte + Raw types.Log +} + +func (_AutomationRegistry *AutomationRegistryFilterer) FilterUpkeepTriggerConfigSet(opts *bind.FilterOpts, id []*big.Int) (*AutomationRegistryUpkeepTriggerConfigSetIterator, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + + logs, sub, err := _AutomationRegistry.contract.FilterLogs(opts, "UpkeepTriggerConfigSet", idRule) + if err != nil { + return nil, err + } + return &AutomationRegistryUpkeepTriggerConfigSetIterator{contract: _AutomationRegistry.contract, event: "UpkeepTriggerConfigSet", logs: logs, sub: sub}, nil +} + +func (_AutomationRegistry *AutomationRegistryFilterer) WatchUpkeepTriggerConfigSet(opts *bind.WatchOpts, sink chan<- *AutomationRegistryUpkeepTriggerConfigSet, id []*big.Int) (event.Subscription, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + + logs, sub, err := _AutomationRegistry.contract.WatchLogs(opts, "UpkeepTriggerConfigSet", idRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(AutomationRegistryUpkeepTriggerConfigSet) + if err := _AutomationRegistry.contract.UnpackLog(event, "UpkeepTriggerConfigSet", 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 (_AutomationRegistry *AutomationRegistryFilterer) ParseUpkeepTriggerConfigSet(log types.Log) (*AutomationRegistryUpkeepTriggerConfigSet, error) { + event := new(AutomationRegistryUpkeepTriggerConfigSet) + if err := _AutomationRegistry.contract.UnpackLog(event, "UpkeepTriggerConfigSet", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type AutomationRegistryUpkeepUnpausedIterator struct { + Event *AutomationRegistryUpkeepUnpaused + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *AutomationRegistryUpkeepUnpausedIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(AutomationRegistryUpkeepUnpaused) + 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(AutomationRegistryUpkeepUnpaused) + 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 *AutomationRegistryUpkeepUnpausedIterator) Error() error { + return it.fail +} + +func (it *AutomationRegistryUpkeepUnpausedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type AutomationRegistryUpkeepUnpaused struct { + Id *big.Int + Raw types.Log +} + +func (_AutomationRegistry *AutomationRegistryFilterer) FilterUpkeepUnpaused(opts *bind.FilterOpts, id []*big.Int) (*AutomationRegistryUpkeepUnpausedIterator, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + + logs, sub, err := _AutomationRegistry.contract.FilterLogs(opts, "UpkeepUnpaused", idRule) + if err != nil { + return nil, err + } + return &AutomationRegistryUpkeepUnpausedIterator{contract: _AutomationRegistry.contract, event: "UpkeepUnpaused", logs: logs, sub: sub}, nil +} + +func (_AutomationRegistry *AutomationRegistryFilterer) WatchUpkeepUnpaused(opts *bind.WatchOpts, sink chan<- *AutomationRegistryUpkeepUnpaused, id []*big.Int) (event.Subscription, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + + logs, sub, err := _AutomationRegistry.contract.WatchLogs(opts, "UpkeepUnpaused", idRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(AutomationRegistryUpkeepUnpaused) + if err := _AutomationRegistry.contract.UnpackLog(event, "UpkeepUnpaused", 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 (_AutomationRegistry *AutomationRegistryFilterer) ParseUpkeepUnpaused(log types.Log) (*AutomationRegistryUpkeepUnpaused, error) { + event := new(AutomationRegistryUpkeepUnpaused) + if err := _AutomationRegistry.contract.UnpackLog(event, "UpkeepUnpaused", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type LatestConfigDetails struct { + ConfigCount uint32 + BlockNumber uint32 + ConfigDigest [32]byte +} +type LatestConfigDigestAndEpoch struct { + ScanLogs bool + ConfigDigest [32]byte + Epoch uint32 +} + +func (_AutomationRegistry *AutomationRegistry) ParseLog(log types.Log) (generated.AbigenLog, error) { + switch log.Topics[0] { + case _AutomationRegistry.abi.Events["AdminPrivilegeConfigSet"].ID: + return _AutomationRegistry.ParseAdminPrivilegeConfigSet(log) + case _AutomationRegistry.abi.Events["CancelledUpkeepReport"].ID: + return _AutomationRegistry.ParseCancelledUpkeepReport(log) + case _AutomationRegistry.abi.Events["ConfigSet"].ID: + return _AutomationRegistry.ParseConfigSet(log) + case _AutomationRegistry.abi.Events["DedupKeyAdded"].ID: + return _AutomationRegistry.ParseDedupKeyAdded(log) + case _AutomationRegistry.abi.Events["FundsAdded"].ID: + return _AutomationRegistry.ParseFundsAdded(log) + case _AutomationRegistry.abi.Events["FundsWithdrawn"].ID: + return _AutomationRegistry.ParseFundsWithdrawn(log) + case _AutomationRegistry.abi.Events["InsufficientFundsUpkeepReport"].ID: + return _AutomationRegistry.ParseInsufficientFundsUpkeepReport(log) + case _AutomationRegistry.abi.Events["OwnerFundsWithdrawn"].ID: + return _AutomationRegistry.ParseOwnerFundsWithdrawn(log) + case _AutomationRegistry.abi.Events["OwnershipTransferRequested"].ID: + return _AutomationRegistry.ParseOwnershipTransferRequested(log) + case _AutomationRegistry.abi.Events["OwnershipTransferred"].ID: + return _AutomationRegistry.ParseOwnershipTransferred(log) + case _AutomationRegistry.abi.Events["Paused"].ID: + return _AutomationRegistry.ParsePaused(log) + case _AutomationRegistry.abi.Events["PayeesUpdated"].ID: + return _AutomationRegistry.ParsePayeesUpdated(log) + case _AutomationRegistry.abi.Events["PayeeshipTransferRequested"].ID: + return _AutomationRegistry.ParsePayeeshipTransferRequested(log) + case _AutomationRegistry.abi.Events["PayeeshipTransferred"].ID: + return _AutomationRegistry.ParsePayeeshipTransferred(log) + case _AutomationRegistry.abi.Events["PaymentWithdrawn"].ID: + return _AutomationRegistry.ParsePaymentWithdrawn(log) + case _AutomationRegistry.abi.Events["ReorgedUpkeepReport"].ID: + return _AutomationRegistry.ParseReorgedUpkeepReport(log) + case _AutomationRegistry.abi.Events["StaleUpkeepReport"].ID: + return _AutomationRegistry.ParseStaleUpkeepReport(log) + case _AutomationRegistry.abi.Events["Transmitted"].ID: + return _AutomationRegistry.ParseTransmitted(log) + case _AutomationRegistry.abi.Events["Unpaused"].ID: + return _AutomationRegistry.ParseUnpaused(log) + case _AutomationRegistry.abi.Events["UpkeepAdminTransferRequested"].ID: + return _AutomationRegistry.ParseUpkeepAdminTransferRequested(log) + case _AutomationRegistry.abi.Events["UpkeepAdminTransferred"].ID: + return _AutomationRegistry.ParseUpkeepAdminTransferred(log) + case _AutomationRegistry.abi.Events["UpkeepCanceled"].ID: + return _AutomationRegistry.ParseUpkeepCanceled(log) + case _AutomationRegistry.abi.Events["UpkeepCheckDataSet"].ID: + return _AutomationRegistry.ParseUpkeepCheckDataSet(log) + case _AutomationRegistry.abi.Events["UpkeepGasLimitSet"].ID: + return _AutomationRegistry.ParseUpkeepGasLimitSet(log) + case _AutomationRegistry.abi.Events["UpkeepMigrated"].ID: + return _AutomationRegistry.ParseUpkeepMigrated(log) + case _AutomationRegistry.abi.Events["UpkeepOffchainConfigSet"].ID: + return _AutomationRegistry.ParseUpkeepOffchainConfigSet(log) + case _AutomationRegistry.abi.Events["UpkeepPaused"].ID: + return _AutomationRegistry.ParseUpkeepPaused(log) + case _AutomationRegistry.abi.Events["UpkeepPerformed"].ID: + return _AutomationRegistry.ParseUpkeepPerformed(log) + case _AutomationRegistry.abi.Events["UpkeepPrivilegeConfigSet"].ID: + return _AutomationRegistry.ParseUpkeepPrivilegeConfigSet(log) + case _AutomationRegistry.abi.Events["UpkeepReceived"].ID: + return _AutomationRegistry.ParseUpkeepReceived(log) + case _AutomationRegistry.abi.Events["UpkeepRegistered"].ID: + return _AutomationRegistry.ParseUpkeepRegistered(log) + case _AutomationRegistry.abi.Events["UpkeepTriggerConfigSet"].ID: + return _AutomationRegistry.ParseUpkeepTriggerConfigSet(log) + case _AutomationRegistry.abi.Events["UpkeepUnpaused"].ID: + return _AutomationRegistry.ParseUpkeepUnpaused(log) + + default: + return nil, fmt.Errorf("abigen wrapper received unknown log topic: %v", log.Topics[0]) + } +} + +func (AutomationRegistryAdminPrivilegeConfigSet) Topic() common.Hash { + return common.HexToHash("0x7c44b4eb59ee7873514e7e43e7718c269d872965938b288aa143befca62f99d2") +} + +func (AutomationRegistryCancelledUpkeepReport) Topic() common.Hash { + return common.HexToHash("0xc3237c8807c467c1b39b8d0395eff077313e691bf0a7388106792564ebfd5636") +} + +func (AutomationRegistryConfigSet) Topic() common.Hash { + return common.HexToHash("0x1591690b8638f5fb2dbec82ac741805ac5da8b45dc5263f4875b0496fdce4e05") +} + +func (AutomationRegistryDedupKeyAdded) Topic() common.Hash { + return common.HexToHash("0xa4a4e334c0e330143f9437484fe516c13bc560b86b5b0daf58e7084aaac228f2") +} + +func (AutomationRegistryFundsAdded) Topic() common.Hash { + return common.HexToHash("0xafd24114486da8ebfc32f3626dada8863652e187461aa74d4bfa734891506203") +} + +func (AutomationRegistryFundsWithdrawn) Topic() common.Hash { + return common.HexToHash("0xf3b5906e5672f3e524854103bcafbbdba80dbdfeca2c35e116127b1060a68318") +} + +func (AutomationRegistryInsufficientFundsUpkeepReport) Topic() common.Hash { + return common.HexToHash("0x377c8b0c126ae5248d27aca1c76fac4608aff85673ee3caf09747e1044549e02") +} + +func (AutomationRegistryOwnerFundsWithdrawn) Topic() common.Hash { + return common.HexToHash("0x1d07d0b0be43d3e5fee41a80b579af370affee03fa595bf56d5d4c19328162f1") +} + +func (AutomationRegistryOwnershipTransferRequested) Topic() common.Hash { + return common.HexToHash("0xed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae1278") +} + +func (AutomationRegistryOwnershipTransferred) Topic() common.Hash { + return common.HexToHash("0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0") +} + +func (AutomationRegistryPaused) Topic() common.Hash { + return common.HexToHash("0x62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a258") +} + +func (AutomationRegistryPayeesUpdated) Topic() common.Hash { + return common.HexToHash("0xa46de38886467c59be07a0675f14781206a5477d871628af46c2443822fcb725") +} + +func (AutomationRegistryPayeeshipTransferRequested) Topic() common.Hash { + return common.HexToHash("0x84f7c7c80bb8ed2279b4aab5f61cd05e6374073d38f46d7f32de8c30e9e38367") +} + +func (AutomationRegistryPayeeshipTransferred) Topic() common.Hash { + return common.HexToHash("0x78af32efdcad432315431e9b03d27e6cd98fb79c405fdc5af7c1714d9c0f75b3") +} + +func (AutomationRegistryPaymentWithdrawn) Topic() common.Hash { + return common.HexToHash("0x9819093176a1851202c7bcfa46845809b4e47c261866550e94ed3775d2f40698") +} + +func (AutomationRegistryReorgedUpkeepReport) Topic() common.Hash { + return common.HexToHash("0x6aa7f60c176da7af894b384daea2249497448137f5943c1237ada8bc92bdc301") +} + +func (AutomationRegistryStaleUpkeepReport) Topic() common.Hash { + return common.HexToHash("0x405288ea7be309e16cfdf481367f90a413e1d4634fcdaf8966546db9b93012e8") +} + +func (AutomationRegistryTransmitted) Topic() common.Hash { + return common.HexToHash("0xb04e63db38c49950639fa09d29872f21f5d49d614f3a969d8adf3d4b52e41a62") +} + +func (AutomationRegistryUnpaused) Topic() common.Hash { + return common.HexToHash("0x5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa") +} + +func (AutomationRegistryUpkeepAdminTransferRequested) Topic() common.Hash { + return common.HexToHash("0xb1cbb2c4b8480034c27e06da5f096b8233a8fd4497028593a41ff6df79726b35") +} + +func (AutomationRegistryUpkeepAdminTransferred) Topic() common.Hash { + return common.HexToHash("0x5cff4db96bef051785e999f44bfcd21c18823e034fb92dd376e3db4ce0feeb2c") +} + +func (AutomationRegistryUpkeepCanceled) Topic() common.Hash { + return common.HexToHash("0x91cb3bb75cfbd718bbfccc56b7f53d92d7048ef4ca39a3b7b7c6d4af1f791181") +} + +func (AutomationRegistryUpkeepCheckDataSet) Topic() common.Hash { + return common.HexToHash("0xcba2d5723b2ee59e53a8e8a82a4a7caf4fdfe70e9f7c582950bf7e7a5c24e83d") +} + +func (AutomationRegistryUpkeepGasLimitSet) Topic() common.Hash { + return common.HexToHash("0xc24c07e655ce79fba8a589778987d3c015bc6af1632bb20cf9182e02a65d972c") +} + +func (AutomationRegistryUpkeepMigrated) Topic() common.Hash { + return common.HexToHash("0xb38647142fbb1ea4c000fc4569b37a4e9a9f6313317b84ee3e5326c1a6cd06ff") +} + +func (AutomationRegistryUpkeepOffchainConfigSet) Topic() common.Hash { + return common.HexToHash("0x3e8740446213c8a77d40e08f79136ce3f347d13ed270a6ebdf57159e0faf4850") +} + +func (AutomationRegistryUpkeepPaused) Topic() common.Hash { + return common.HexToHash("0x8ab10247ce168c27748e656ecf852b951fcaac790c18106b19aa0ae57a8b741f") +} + +func (AutomationRegistryUpkeepPerformed) Topic() common.Hash { + return common.HexToHash("0xad8cc9579b21dfe2c2f6ea35ba15b656e46b4f5b0cb424f52739b8ce5cac9c5b") +} + +func (AutomationRegistryUpkeepPrivilegeConfigSet) Topic() common.Hash { + return common.HexToHash("0x2fd8d70753a007014349d4591843cc031c2dd7a260d7dd82eca8253686ae7769") +} + +func (AutomationRegistryUpkeepReceived) Topic() common.Hash { + return common.HexToHash("0x74931a144e43a50694897f241d973aecb5024c0e910f9bb80a163ea3c1cf5a71") +} + +func (AutomationRegistryUpkeepRegistered) Topic() common.Hash { + return common.HexToHash("0xbae366358c023f887e791d7a62f2e4316f1026bd77f6fb49501a917b3bc5d012") +} + +func (AutomationRegistryUpkeepTriggerConfigSet) Topic() common.Hash { + return common.HexToHash("0x2b72ac786c97e68dbab71023ed6f2bdbfc80ad9bb7808941929229d71b7d5664") +} + +func (AutomationRegistryUpkeepUnpaused) Topic() common.Hash { + return common.HexToHash("0x7bada562044eb163f6b4003c4553e4e62825344c0418eea087bed5ee05a47456") +} + +func (_AutomationRegistry *AutomationRegistry) Address() common.Address { + return _AutomationRegistry.address +} + +type AutomationRegistryInterface interface { + FallbackTo(opts *bind.CallOpts) (common.Address, error) + + LatestConfigDetails(opts *bind.CallOpts) (LatestConfigDetails, + + error) + + LatestConfigDigestAndEpoch(opts *bind.CallOpts) (LatestConfigDigestAndEpoch, + + error) + + Owner(opts *bind.CallOpts) (common.Address, error) + + TypeAndVersion(opts *bind.CallOpts) (string, error) + + AcceptOwnership(opts *bind.TransactOpts) (*types.Transaction, error) + + OnTokenTransfer(opts *bind.TransactOpts, sender common.Address, amount *big.Int, data []byte) (*types.Transaction, error) + + SetConfig(opts *bind.TransactOpts, signers []common.Address, transmitters []common.Address, f uint8, onchainConfigBytes []byte, offchainConfigVersion uint64, offchainConfig []byte) (*types.Transaction, error) + + SetConfigTypeSafe(opts *bind.TransactOpts, signers []common.Address, transmitters []common.Address, f uint8, onchainConfig AutomationRegistryBase22OnchainConfig, offchainConfigVersion uint64, offchainConfig []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) + + Transmit(opts *bind.TransactOpts, reportContext [3][32]byte, rawReport []byte, rs [][32]byte, ss [][32]byte, rawVs [32]byte) (*types.Transaction, error) + + Fallback(opts *bind.TransactOpts, calldata []byte) (*types.Transaction, error) + + FilterAdminPrivilegeConfigSet(opts *bind.FilterOpts, admin []common.Address) (*AutomationRegistryAdminPrivilegeConfigSetIterator, error) + + WatchAdminPrivilegeConfigSet(opts *bind.WatchOpts, sink chan<- *AutomationRegistryAdminPrivilegeConfigSet, admin []common.Address) (event.Subscription, error) + + ParseAdminPrivilegeConfigSet(log types.Log) (*AutomationRegistryAdminPrivilegeConfigSet, error) + + FilterCancelledUpkeepReport(opts *bind.FilterOpts, id []*big.Int) (*AutomationRegistryCancelledUpkeepReportIterator, error) + + WatchCancelledUpkeepReport(opts *bind.WatchOpts, sink chan<- *AutomationRegistryCancelledUpkeepReport, id []*big.Int) (event.Subscription, error) + + ParseCancelledUpkeepReport(log types.Log) (*AutomationRegistryCancelledUpkeepReport, error) + + FilterConfigSet(opts *bind.FilterOpts) (*AutomationRegistryConfigSetIterator, error) + + WatchConfigSet(opts *bind.WatchOpts, sink chan<- *AutomationRegistryConfigSet) (event.Subscription, error) + + ParseConfigSet(log types.Log) (*AutomationRegistryConfigSet, error) + + FilterDedupKeyAdded(opts *bind.FilterOpts, dedupKey [][32]byte) (*AutomationRegistryDedupKeyAddedIterator, error) + + WatchDedupKeyAdded(opts *bind.WatchOpts, sink chan<- *AutomationRegistryDedupKeyAdded, dedupKey [][32]byte) (event.Subscription, error) + + ParseDedupKeyAdded(log types.Log) (*AutomationRegistryDedupKeyAdded, error) + + FilterFundsAdded(opts *bind.FilterOpts, id []*big.Int, from []common.Address) (*AutomationRegistryFundsAddedIterator, error) + + WatchFundsAdded(opts *bind.WatchOpts, sink chan<- *AutomationRegistryFundsAdded, id []*big.Int, from []common.Address) (event.Subscription, error) + + ParseFundsAdded(log types.Log) (*AutomationRegistryFundsAdded, error) + + FilterFundsWithdrawn(opts *bind.FilterOpts, id []*big.Int) (*AutomationRegistryFundsWithdrawnIterator, error) + + WatchFundsWithdrawn(opts *bind.WatchOpts, sink chan<- *AutomationRegistryFundsWithdrawn, id []*big.Int) (event.Subscription, error) + + ParseFundsWithdrawn(log types.Log) (*AutomationRegistryFundsWithdrawn, error) + + FilterInsufficientFundsUpkeepReport(opts *bind.FilterOpts, id []*big.Int) (*AutomationRegistryInsufficientFundsUpkeepReportIterator, error) + + WatchInsufficientFundsUpkeepReport(opts *bind.WatchOpts, sink chan<- *AutomationRegistryInsufficientFundsUpkeepReport, id []*big.Int) (event.Subscription, error) + + ParseInsufficientFundsUpkeepReport(log types.Log) (*AutomationRegistryInsufficientFundsUpkeepReport, error) + + FilterOwnerFundsWithdrawn(opts *bind.FilterOpts) (*AutomationRegistryOwnerFundsWithdrawnIterator, error) + + WatchOwnerFundsWithdrawn(opts *bind.WatchOpts, sink chan<- *AutomationRegistryOwnerFundsWithdrawn) (event.Subscription, error) + + ParseOwnerFundsWithdrawn(log types.Log) (*AutomationRegistryOwnerFundsWithdrawn, error) + + FilterOwnershipTransferRequested(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*AutomationRegistryOwnershipTransferRequestedIterator, error) + + WatchOwnershipTransferRequested(opts *bind.WatchOpts, sink chan<- *AutomationRegistryOwnershipTransferRequested, from []common.Address, to []common.Address) (event.Subscription, error) + + ParseOwnershipTransferRequested(log types.Log) (*AutomationRegistryOwnershipTransferRequested, error) + + FilterOwnershipTransferred(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*AutomationRegistryOwnershipTransferredIterator, error) + + WatchOwnershipTransferred(opts *bind.WatchOpts, sink chan<- *AutomationRegistryOwnershipTransferred, from []common.Address, to []common.Address) (event.Subscription, error) + + ParseOwnershipTransferred(log types.Log) (*AutomationRegistryOwnershipTransferred, error) + + FilterPaused(opts *bind.FilterOpts) (*AutomationRegistryPausedIterator, error) + + WatchPaused(opts *bind.WatchOpts, sink chan<- *AutomationRegistryPaused) (event.Subscription, error) + + ParsePaused(log types.Log) (*AutomationRegistryPaused, error) + + FilterPayeesUpdated(opts *bind.FilterOpts) (*AutomationRegistryPayeesUpdatedIterator, error) + + WatchPayeesUpdated(opts *bind.WatchOpts, sink chan<- *AutomationRegistryPayeesUpdated) (event.Subscription, error) + + ParsePayeesUpdated(log types.Log) (*AutomationRegistryPayeesUpdated, error) + + FilterPayeeshipTransferRequested(opts *bind.FilterOpts, transmitter []common.Address, from []common.Address, to []common.Address) (*AutomationRegistryPayeeshipTransferRequestedIterator, error) + + WatchPayeeshipTransferRequested(opts *bind.WatchOpts, sink chan<- *AutomationRegistryPayeeshipTransferRequested, transmitter []common.Address, from []common.Address, to []common.Address) (event.Subscription, error) + + ParsePayeeshipTransferRequested(log types.Log) (*AutomationRegistryPayeeshipTransferRequested, error) + + FilterPayeeshipTransferred(opts *bind.FilterOpts, transmitter []common.Address, from []common.Address, to []common.Address) (*AutomationRegistryPayeeshipTransferredIterator, error) + + WatchPayeeshipTransferred(opts *bind.WatchOpts, sink chan<- *AutomationRegistryPayeeshipTransferred, transmitter []common.Address, from []common.Address, to []common.Address) (event.Subscription, error) + + ParsePayeeshipTransferred(log types.Log) (*AutomationRegistryPayeeshipTransferred, error) + + FilterPaymentWithdrawn(opts *bind.FilterOpts, transmitter []common.Address, amount []*big.Int, to []common.Address) (*AutomationRegistryPaymentWithdrawnIterator, error) + + WatchPaymentWithdrawn(opts *bind.WatchOpts, sink chan<- *AutomationRegistryPaymentWithdrawn, transmitter []common.Address, amount []*big.Int, to []common.Address) (event.Subscription, error) + + ParsePaymentWithdrawn(log types.Log) (*AutomationRegistryPaymentWithdrawn, error) + + FilterReorgedUpkeepReport(opts *bind.FilterOpts, id []*big.Int) (*AutomationRegistryReorgedUpkeepReportIterator, error) + + WatchReorgedUpkeepReport(opts *bind.WatchOpts, sink chan<- *AutomationRegistryReorgedUpkeepReport, id []*big.Int) (event.Subscription, error) + + ParseReorgedUpkeepReport(log types.Log) (*AutomationRegistryReorgedUpkeepReport, error) + + FilterStaleUpkeepReport(opts *bind.FilterOpts, id []*big.Int) (*AutomationRegistryStaleUpkeepReportIterator, error) + + WatchStaleUpkeepReport(opts *bind.WatchOpts, sink chan<- *AutomationRegistryStaleUpkeepReport, id []*big.Int) (event.Subscription, error) + + ParseStaleUpkeepReport(log types.Log) (*AutomationRegistryStaleUpkeepReport, error) + + FilterTransmitted(opts *bind.FilterOpts) (*AutomationRegistryTransmittedIterator, error) + + WatchTransmitted(opts *bind.WatchOpts, sink chan<- *AutomationRegistryTransmitted) (event.Subscription, error) + + ParseTransmitted(log types.Log) (*AutomationRegistryTransmitted, error) + + FilterUnpaused(opts *bind.FilterOpts) (*AutomationRegistryUnpausedIterator, error) + + WatchUnpaused(opts *bind.WatchOpts, sink chan<- *AutomationRegistryUnpaused) (event.Subscription, error) + + ParseUnpaused(log types.Log) (*AutomationRegistryUnpaused, error) + + FilterUpkeepAdminTransferRequested(opts *bind.FilterOpts, id []*big.Int, from []common.Address, to []common.Address) (*AutomationRegistryUpkeepAdminTransferRequestedIterator, error) + + WatchUpkeepAdminTransferRequested(opts *bind.WatchOpts, sink chan<- *AutomationRegistryUpkeepAdminTransferRequested, id []*big.Int, from []common.Address, to []common.Address) (event.Subscription, error) + + ParseUpkeepAdminTransferRequested(log types.Log) (*AutomationRegistryUpkeepAdminTransferRequested, error) + + FilterUpkeepAdminTransferred(opts *bind.FilterOpts, id []*big.Int, from []common.Address, to []common.Address) (*AutomationRegistryUpkeepAdminTransferredIterator, error) + + WatchUpkeepAdminTransferred(opts *bind.WatchOpts, sink chan<- *AutomationRegistryUpkeepAdminTransferred, id []*big.Int, from []common.Address, to []common.Address) (event.Subscription, error) + + ParseUpkeepAdminTransferred(log types.Log) (*AutomationRegistryUpkeepAdminTransferred, error) + + FilterUpkeepCanceled(opts *bind.FilterOpts, id []*big.Int, atBlockHeight []uint64) (*AutomationRegistryUpkeepCanceledIterator, error) + + WatchUpkeepCanceled(opts *bind.WatchOpts, sink chan<- *AutomationRegistryUpkeepCanceled, id []*big.Int, atBlockHeight []uint64) (event.Subscription, error) + + ParseUpkeepCanceled(log types.Log) (*AutomationRegistryUpkeepCanceled, error) + + FilterUpkeepCheckDataSet(opts *bind.FilterOpts, id []*big.Int) (*AutomationRegistryUpkeepCheckDataSetIterator, error) + + WatchUpkeepCheckDataSet(opts *bind.WatchOpts, sink chan<- *AutomationRegistryUpkeepCheckDataSet, id []*big.Int) (event.Subscription, error) + + ParseUpkeepCheckDataSet(log types.Log) (*AutomationRegistryUpkeepCheckDataSet, error) + + FilterUpkeepGasLimitSet(opts *bind.FilterOpts, id []*big.Int) (*AutomationRegistryUpkeepGasLimitSetIterator, error) + + WatchUpkeepGasLimitSet(opts *bind.WatchOpts, sink chan<- *AutomationRegistryUpkeepGasLimitSet, id []*big.Int) (event.Subscription, error) + + ParseUpkeepGasLimitSet(log types.Log) (*AutomationRegistryUpkeepGasLimitSet, error) + + FilterUpkeepMigrated(opts *bind.FilterOpts, id []*big.Int) (*AutomationRegistryUpkeepMigratedIterator, error) + + WatchUpkeepMigrated(opts *bind.WatchOpts, sink chan<- *AutomationRegistryUpkeepMigrated, id []*big.Int) (event.Subscription, error) + + ParseUpkeepMigrated(log types.Log) (*AutomationRegistryUpkeepMigrated, error) + + FilterUpkeepOffchainConfigSet(opts *bind.FilterOpts, id []*big.Int) (*AutomationRegistryUpkeepOffchainConfigSetIterator, error) + + WatchUpkeepOffchainConfigSet(opts *bind.WatchOpts, sink chan<- *AutomationRegistryUpkeepOffchainConfigSet, id []*big.Int) (event.Subscription, error) + + ParseUpkeepOffchainConfigSet(log types.Log) (*AutomationRegistryUpkeepOffchainConfigSet, error) + + FilterUpkeepPaused(opts *bind.FilterOpts, id []*big.Int) (*AutomationRegistryUpkeepPausedIterator, error) + + WatchUpkeepPaused(opts *bind.WatchOpts, sink chan<- *AutomationRegistryUpkeepPaused, id []*big.Int) (event.Subscription, error) + + ParseUpkeepPaused(log types.Log) (*AutomationRegistryUpkeepPaused, error) + + FilterUpkeepPerformed(opts *bind.FilterOpts, id []*big.Int, success []bool) (*AutomationRegistryUpkeepPerformedIterator, error) + + WatchUpkeepPerformed(opts *bind.WatchOpts, sink chan<- *AutomationRegistryUpkeepPerformed, id []*big.Int, success []bool) (event.Subscription, error) + + ParseUpkeepPerformed(log types.Log) (*AutomationRegistryUpkeepPerformed, error) + + FilterUpkeepPrivilegeConfigSet(opts *bind.FilterOpts, id []*big.Int) (*AutomationRegistryUpkeepPrivilegeConfigSetIterator, error) + + WatchUpkeepPrivilegeConfigSet(opts *bind.WatchOpts, sink chan<- *AutomationRegistryUpkeepPrivilegeConfigSet, id []*big.Int) (event.Subscription, error) + + ParseUpkeepPrivilegeConfigSet(log types.Log) (*AutomationRegistryUpkeepPrivilegeConfigSet, error) + + FilterUpkeepReceived(opts *bind.FilterOpts, id []*big.Int) (*AutomationRegistryUpkeepReceivedIterator, error) + + WatchUpkeepReceived(opts *bind.WatchOpts, sink chan<- *AutomationRegistryUpkeepReceived, id []*big.Int) (event.Subscription, error) + + ParseUpkeepReceived(log types.Log) (*AutomationRegistryUpkeepReceived, error) + + FilterUpkeepRegistered(opts *bind.FilterOpts, id []*big.Int) (*AutomationRegistryUpkeepRegisteredIterator, error) + + WatchUpkeepRegistered(opts *bind.WatchOpts, sink chan<- *AutomationRegistryUpkeepRegistered, id []*big.Int) (event.Subscription, error) + + ParseUpkeepRegistered(log types.Log) (*AutomationRegistryUpkeepRegistered, error) + + FilterUpkeepTriggerConfigSet(opts *bind.FilterOpts, id []*big.Int) (*AutomationRegistryUpkeepTriggerConfigSetIterator, error) + + WatchUpkeepTriggerConfigSet(opts *bind.WatchOpts, sink chan<- *AutomationRegistryUpkeepTriggerConfigSet, id []*big.Int) (event.Subscription, error) + + ParseUpkeepTriggerConfigSet(log types.Log) (*AutomationRegistryUpkeepTriggerConfigSet, error) + + FilterUpkeepUnpaused(opts *bind.FilterOpts, id []*big.Int) (*AutomationRegistryUpkeepUnpausedIterator, error) + + WatchUpkeepUnpaused(opts *bind.WatchOpts, sink chan<- *AutomationRegistryUpkeepUnpaused, id []*big.Int) (event.Subscription, error) + + ParseUpkeepUnpaused(log types.Log) (*AutomationRegistryUpkeepUnpaused, error) + + ParseLog(log types.Log) (generated.AbigenLog, error) + + Address() common.Address +} diff --git a/core/gethwrappers/generated/vrf_coordinator_test_v2/vrf_coordinator_test_v2.go b/core/gethwrappers/generated/vrf_coordinator_test_v2/vrf_coordinator_test_v2.go new file mode 100644 index 0000000000..cb4e2cea01 --- /dev/null +++ b/core/gethwrappers/generated/vrf_coordinator_test_v2/vrf_coordinator_test_v2.go @@ -0,0 +1,3115 @@ +// Code generated - DO NOT EDIT. +// This file is a generated binding and any manual changes will be lost. + +package vrf_coordinator_test_v2 + +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 +) + +type VRFCoordinatorTestV2FeeConfig struct { + FulfillmentFlatFeeLinkPPMTier1 uint32 + FulfillmentFlatFeeLinkPPMTier2 uint32 + FulfillmentFlatFeeLinkPPMTier3 uint32 + FulfillmentFlatFeeLinkPPMTier4 uint32 + FulfillmentFlatFeeLinkPPMTier5 uint32 + ReqsForTier2 *big.Int + ReqsForTier3 *big.Int + ReqsForTier4 *big.Int + ReqsForTier5 *big.Int +} + +type VRFCoordinatorTestV2RequestCommitment struct { + BlockNum uint64 + SubId uint64 + CallbackGasLimit uint32 + NumWords uint32 + Sender common.Address +} + +type VRFProof struct { + Pk [2]*big.Int + Gamma [2]*big.Int + C *big.Int + S *big.Int + Seed *big.Int + UWitness common.Address + CGammaWitness [2]*big.Int + SHashWitness [2]*big.Int + ZInv *big.Int +} + +var VRFCoordinatorTestV2MetaData = &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\":\"structVRFCoordinatorTestV2.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\":\"structVRFCoordinatorTestV2.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\":\"structVRFCoordinatorTestV2.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: "0x60e06040523480156200001157600080fd5b5060405162005755380380620057558339810160408190526200003491620001b1565b33806000816200008b5760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b0384811691909117909155811615620000be57620000be81620000e8565b5050506001600160601b0319606093841b811660805290831b811660a052911b1660c052620001fb565b6001600160a01b038116331415620001435760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c66000000000000000000604482015260640162000082565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b80516001600160a01b0381168114620001ac57600080fd5b919050565b600080600060608486031215620001c757600080fd5b620001d28462000194565b9250620001e26020850162000194565b9150620001f26040850162000194565b90509250925092565b60805160601c60a05160601c60c05160601c6154f0620002656000396000818161051901526138180152600081816106030152613c0401526000818161036d015281816114df0152818161233c01528181612d7301528181612eaf01526134d401526154f06000f3fe608060405234801561001057600080fd5b506004361061025b5760003560e01c80636f64f03f11610145578063ad178361116100bd578063d2f9f9a71161008c578063e72f6e3011610071578063e72f6e30146106e0578063e82ad7d4146106f3578063f2fde38b1461071657600080fd5b8063d2f9f9a7146106ba578063d7ae1d30146106cd57600080fd5b8063ad178361146105fe578063af198b9714610625578063c3f909d414610655578063caf70c4a146106a757600080fd5b80638da5cb5b11610114578063a21a23e4116100f9578063a21a23e4146105c0578063a47c7696146105c8578063a4c0ed36146105eb57600080fd5b80638da5cb5b1461059c5780639f87fad7146105ad57600080fd5b80636f64f03f1461055b5780637341c10c1461056e57806379ba509714610581578063823597401461058957600080fd5b8063356dac71116101d85780635fbbc0d2116101a757806366316d8d1161018c57806366316d8d14610501578063689c45171461051457806369bcdb7d1461053b57600080fd5b80635fbbc0d2146103f357806364d51a2a146104f957600080fd5b8063356dac71146103a757806340d6bb82146103af5780634cb48a54146103cd5780635d3b1d30146103e057600080fd5b806308821d581161022f57806315c48b841161021457806315c48b841461030e578063181f5a77146103295780631b6b6d231461036857600080fd5b806308821d58146102cf57806312b58349146102e257600080fd5b80620122911461026057806302bcc5b61461028057806304c357cb1461029557806306bfa637146102a8575b600080fd5b610268610729565b6040516102779392919061503a565b60405180910390f35b61029361028e366004614e86565b6107a5565b005b6102936102a3366004614ea1565b610837565b60055467ffffffffffffffff165b60405167ffffffffffffffff9091168152602001610277565b6102936102dd366004614b97565b6109eb565b6005546801000000000000000090046bffffffffffffffffffffffff165b604051908152602001610277565b61031660c881565b60405161ffff9091168152602001610277565b604080518082018252601681527f565246436f6f7264696e61746f72563220312e302e3000000000000000000000602082015290516102779190614fe5565b61038f7f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b039091168152602001610277565b600a54610300565b6103b86101f481565b60405163ffffffff9091168152602001610277565b6102936103db366004614d30565b610bb0565b6103006103ee366004614c0a565b610fa7565b600c546040805163ffffffff80841682526401000000008404811660208301526801000000000000000084048116928201929092526c010000000000000000000000008304821660608201527001000000000000000000000000000000008304909116608082015262ffffff740100000000000000000000000000000000000000008304811660a0830152770100000000000000000000000000000000000000000000008304811660c08301527a0100000000000000000000000000000000000000000000000000008304811660e08301527d01000000000000000000000000000000000000000000000000000000000090920490911661010082015261012001610277565b610316606481565b61029361050f366004614b4f565b61138a565b61038f7f000000000000000000000000000000000000000000000000000000000000000081565b610300610549366004614e6d565b60009081526009602052604090205490565b610293610569366004614a94565b6115d9565b61029361057c366004614ea1565b611709565b610293611956565b610293610597366004614e86565b611a1f565b6000546001600160a01b031661038f565b6102936105bb366004614ea1565b611be5565b6102b6611fe4565b6105db6105d6366004614e86565b6121c7565b60405161027794939291906151d8565b6102936105f9366004614ac8565b6122ea565b61038f7f000000000000000000000000000000000000000000000000000000000000000081565b610638610633366004614c68565b612541565b6040516bffffffffffffffffffffffff9091168152602001610277565b600b546040805161ffff8316815263ffffffff6201000084048116602083015267010000000000000084048116928201929092526b010000000000000000000000909204166060820152608001610277565b6103006106b5366004614bb3565b6129db565b6103b86106c8366004614e86565b612a0b565b6102936106db366004614ea1565b612c00565b6102936106ee366004614a79565b612d3a565b610706610701366004614e86565b612f77565b6040519015158152602001610277565b610293610724366004614a79565b61319a565b600b546007805460408051602080840282018101909252828152600094859460609461ffff8316946201000090930463ffffffff1693919283919083018282801561079357602002820191906000526020600020905b81548152602001906001019080831161077f575b50505050509050925092509250909192565b6107ad6131ab565b67ffffffffffffffff81166000908152600360205260409020546001600160a01b0316610806576040517f1f6a65b600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b67ffffffffffffffff81166000908152600360205260409020546108349082906001600160a01b0316613207565b50565b67ffffffffffffffff821660009081526003602052604090205482906001600160a01b031680610893576040517f1f6a65b600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b336001600160a01b038216146108e5576040517fd8a3fb520000000000000000000000000000000000000000000000000000000081526001600160a01b03821660048201526024015b60405180910390fd5b600b546601000000000000900460ff161561092c576040517fed3ba6a600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b67ffffffffffffffff84166000908152600360205260409020600101546001600160a01b038481169116146109e55767ffffffffffffffff841660008181526003602090815260409182902060010180547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0388169081179091558251338152918201527f69436ea6df009049404f564eff6622cd00522b0bd6a89efd9e52a355c4a879be91015b60405180910390a25b50505050565b6109f36131ab565b604080518082018252600091610a229190849060029083908390808284376000920191909152506129db915050565b6000818152600660205260409020549091506001600160a01b031680610a77576040517f77f5b84c000000000000000000000000000000000000000000000000000000008152600481018390526024016108dc565b600082815260066020526040812080547fffffffffffffffffffffffff00000000000000000000000000000000000000001690555b600754811015610b67578260078281548110610aca57610aca615485565b90600052602060002001541415610b55576007805460009190610aef9060019061533f565b81548110610aff57610aff615485565b906000526020600020015490508060078381548110610b2057610b20615485565b6000918252602090912001556007805480610b3d57610b3d615456565b60019003818190600052602060002001600090559055505b80610b5f81615383565b915050610aac565b50806001600160a01b03167f72be339577868f868798bac2c93e52d6f034fef4689a9848996c14ebb7416c0d83604051610ba391815260200190565b60405180910390a2505050565b610bb86131ab565b60c861ffff87161115610c0b576040517fa738697600000000000000000000000000000000000000000000000000000000815261ffff871660048201819052602482015260c860448201526064016108dc565b60008213610c48576040517f43d4cf66000000000000000000000000000000000000000000000000000000008152600481018390526024016108dc565b6040805160a0808201835261ffff891680835263ffffffff89811660208086018290526000868801528a831660608088018290528b85166080988901819052600b80547fffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000001690971762010000909502949094177fffffffffffffffffffffffffffffffffff000000000000000000ffffffffffff166701000000000000009092027fffffffffffffffffffffffffffffffffff00000000ffffffffffffffffffffff16919091176b010000000000000000000000909302929092179093558651600c80549489015189890151938a0151978a0151968a015160c08b015160e08c01516101008d01519588167fffffffffffffffffffffffffffffffffffffffffffffffff00000000000000009099169890981764010000000093881693909302929092177fffffffffffffffffffffffffffffffff0000000000000000ffffffffffffffff1668010000000000000000958716959095027fffffffffffffffffffffffffffffffff00000000ffffffffffffffffffffffff16949094176c0100000000000000000000000098861698909802979097177fffffffffffffffffff00000000000000ffffffffffffffffffffffffffffffff1670010000000000000000000000000000000096909416959095027fffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffff16929092177401000000000000000000000000000000000000000062ffffff92831602177fffffff000000000000ffffffffffffffffffffffffffffffffffffffffffffff1677010000000000000000000000000000000000000000000000958216959095027fffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffff16949094177a01000000000000000000000000000000000000000000000000000092851692909202919091177cffffffffffffffffffffffffffffffffffffffffffffffffffffffffff167d0100000000000000000000000000000000000000000000000000000000009390911692909202919091178155600a84905590517fc21e3bd2e0b339d2848f0dd956947a88966c242c0c0c582a33137a5c1ceb5cb291610f97918991899189918991899190615099565b60405180910390a1505050505050565b600b546000906601000000000000900460ff1615610ff1576040517fed3ba6a600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b67ffffffffffffffff85166000908152600360205260409020546001600160a01b031661104a576040517f1f6a65b600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b33600090815260026020908152604080832067ffffffffffffffff808a16855292529091205416806110ba576040517ff0019fe600000000000000000000000000000000000000000000000000000000815267ffffffffffffffff871660048201523360248201526044016108dc565b600b5461ffff90811690861610806110d6575060c861ffff8616115b1561112657600b546040517fa738697600000000000000000000000000000000000000000000000000000000815261ffff8088166004830152909116602482015260c860448201526064016108dc565b600b5463ffffffff620100009091048116908516111561118d57600b546040517ff5d7e01e00000000000000000000000000000000000000000000000000000000815263ffffffff80871660048301526201000090920490911660248201526044016108dc565b6101f463ffffffff841611156111df576040517f47386bec00000000000000000000000000000000000000000000000000000000815263ffffffff841660048201526101f460248201526044016108dc565b60006111ec82600161529b565b6040805160208082018c9052338284015267ffffffffffffffff808c16606084015284166080808401919091528351808403909101815260a08301845280519082012060c083018d905260e080840182905284518085039091018152610100909301909352815191012091925060009182916040805160208101849052439181019190915267ffffffffffffffff8c16606082015263ffffffff808b166080830152891660a08201523360c0820152919350915060e00160408051808303601f19018152828252805160209182012060008681526009835283902055848352820183905261ffff8a169082015263ffffffff808916606083015287166080820152339067ffffffffffffffff8b16908c907f63373d1c4696214b898952999c9aaec57dac1ee2723cec59bea6888f489a97729060a00160405180910390a45033600090815260026020908152604080832067ffffffffffffffff808d16855292529091208054919093167fffffffffffffffffffffffffffffffffffffffffffffffff00000000000000009091161790915591505095945050505050565b600b546601000000000000900460ff16156113d1576040517fed3ba6a600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b336000908152600860205260409020546bffffffffffffffffffffffff8083169116101561142b576040517ff4d678b800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b33600090815260086020526040812080548392906114589084906bffffffffffffffffffffffff16615356565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff16021790555080600560088282829054906101000a90046bffffffffffffffffffffffff166114af9190615356565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff1602179055507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663a9059cbb83836040518363ffffffff1660e01b815260040161154d9291906001600160a01b039290921682526bffffffffffffffffffffffff16602082015260400190565b602060405180830381600087803b15801561156757600080fd5b505af115801561157b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061159f9190614bcf565b6115d5576040517ff4d678b800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5050565b6115e16131ab565b6040805180820182526000916116109190849060029083908390808284376000920191909152506129db915050565b6000818152600660205260409020549091506001600160a01b031615611665576040517f4a0b8fa7000000000000000000000000000000000000000000000000000000008152600481018290526024016108dc565b600081815260066020908152604080832080547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0388169081179091556007805460018101825594527fa66cc928b5edb82af9bd49922954155ab7b0942694bea4ce44661d9a8736c688909301849055518381527fe729ae16526293f74ade739043022254f1489f616295a25bf72dfb4511ed73b89101610ba3565b67ffffffffffffffff821660009081526003602052604090205482906001600160a01b031680611765576040517f1f6a65b600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b336001600160a01b038216146117b2576040517fd8a3fb520000000000000000000000000000000000000000000000000000000081526001600160a01b03821660048201526024016108dc565b600b546601000000000000900460ff16156117f9576040517fed3ba6a600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b67ffffffffffffffff841660009081526003602052604090206002015460641415611850576040517f05a48e0f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001600160a01b038316600090815260026020908152604080832067ffffffffffffffff8089168552925290912054161561188a576109e5565b6001600160a01b038316600081815260026020818152604080842067ffffffffffffffff8a1680865290835281852080547fffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000166001908117909155600384528286209094018054948501815585529382902090920180547fffffffffffffffffffffffff00000000000000000000000000000000000000001685179055905192835290917f43dc749a04ac8fb825cbd514f7c0e13f13bc6f2ee66043b76629d51776cff8e091016109dc565b6001546001600160a01b031633146119b05760405162461bcd60e51b815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e65720000000000000000000060448201526064016108dc565b60008054337fffffffffffffffffffffffff0000000000000000000000000000000000000000808316821784556001805490911690556040516001600160a01b0390921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b600b546601000000000000900460ff1615611a66576040517fed3ba6a600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b67ffffffffffffffff81166000908152600360205260409020546001600160a01b0316611abf576040517f1f6a65b600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b67ffffffffffffffff81166000908152600360205260409020600101546001600160a01b03163314611b475767ffffffffffffffff8116600090815260036020526040908190206001015490517fd084e9750000000000000000000000000000000000000000000000000000000081526001600160a01b0390911660048201526024016108dc565b67ffffffffffffffff81166000818152600360209081526040918290208054337fffffffffffffffffffffffff0000000000000000000000000000000000000000808316821784556001909301805490931690925583516001600160a01b03909116808252928101919091529092917f6f1dc65165ffffedfd8e507b4a0f1fcfdada045ed11f6c26ba27cedfe87802f0910160405180910390a25050565b67ffffffffffffffff821660009081526003602052604090205482906001600160a01b031680611c41576040517f1f6a65b600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b336001600160a01b03821614611c8e576040517fd8a3fb520000000000000000000000000000000000000000000000000000000081526001600160a01b03821660048201526024016108dc565b600b546601000000000000900460ff1615611cd5576040517fed3ba6a600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001600160a01b038316600090815260026020908152604080832067ffffffffffffffff808916855292529091205416611d56576040517ff0019fe600000000000000000000000000000000000000000000000000000000815267ffffffffffffffff851660048201526001600160a01b03841660248201526044016108dc565b67ffffffffffffffff8416600090815260036020908152604080832060020180548251818502810185019093528083529192909190830182828015611dc457602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311611da6575b50505050509050600060018251611ddb919061533f565b905060005b8251811015611f5357856001600160a01b0316838281518110611e0557611e05615485565b60200260200101516001600160a01b03161415611f41576000838381518110611e3057611e30615485565b6020026020010151905080600360008a67ffffffffffffffff1667ffffffffffffffff1681526020019081526020016000206002018381548110611e7657611e76615485565b600091825260208083209190910180547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b03949094169390931790925567ffffffffffffffff8a168152600390915260409020600201805480611ee357611ee3615456565b60008281526020902081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff90810180547fffffffffffffffffffffffff000000000000000000000000000000000000000016905501905550611f53565b80611f4b81615383565b915050611de0565b506001600160a01b038516600081815260026020908152604080832067ffffffffffffffff8b168085529083529281902080547fffffffffffffffffffffffffffffffffffffffffffffffff00000000000000001690555192835290917f182bff9831466789164ca77075fffd84916d35a8180ba73c27e45634549b445b91015b60405180910390a2505050505050565b600b546000906601000000000000900460ff161561202e576040517fed3ba6a600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6005805467ffffffffffffffff16906000612048836153bc565b82546101009290920a67ffffffffffffffff81810219909316918316021790915560055416905060008060405190808252806020026020018201604052801561209b578160200160208202803683370190505b506040805180820182526000808252602080830182815267ffffffffffffffff888116808552600484528685209551865493516bffffffffffffffffffffffff9091167fffffffffffffffffffffffff0000000000000000000000000000000000000000948516176c01000000000000000000000000919093160291909117909455845160608101865233815280830184815281870188815295855260038452959093208351815483166001600160a01b039182161782559551600182018054909316961695909517905591518051949550909361217f92600285019201906147d3565b505060405133815267ffffffffffffffff841691507f464722b4166576d3dcbba877b999bc35cf911f4eaf434b7eba68fa113951d0bf9060200160405180910390a250905090565b67ffffffffffffffff8116600090815260036020526040812054819081906060906001600160a01b0316612227576040517f1f6a65b600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b67ffffffffffffffff80861660009081526004602090815260408083205460038352928190208054600290910180548351818602810186019094528084526bffffffffffffffffffffffff8616966c01000000000000000000000000909604909516946001600160a01b039092169390929183918301828280156122d457602002820191906000526020600020905b81546001600160a01b031681526001909101906020018083116122b6575b5050505050905093509350935093509193509193565b600b546601000000000000900460ff1615612331576040517fed3ba6a600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614612393576040517f44b0e3c300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b602081146123cd576040517f8129bbcd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60006123db82840184614e86565b67ffffffffffffffff81166000908152600360205260409020549091506001600160a01b0316612437576040517f1f6a65b600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b67ffffffffffffffff8116600090815260046020526040812080546bffffffffffffffffffffffff169186919061246e83856152c7565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff16021790555084600560088282829054906101000a90046bffffffffffffffffffffffff166124c591906152c7565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff1602179055508167ffffffffffffffff167fd39ec07f4e209f627a4c427971473820dc129761ba28de8906bd56f57101d4f882878461252c9190615283565b60408051928352602083019190915201611fd4565b600b546000906601000000000000900460ff161561258b576040517fed3ba6a600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60005a9050600080600061259f878761362c565b9250925092506000866060015163ffffffff1667ffffffffffffffff8111156125ca576125ca6154b4565b6040519080825280602002602001820160405280156125f3578160200160208202803683370190505b50905060005b876060015163ffffffff168110156126675760408051602081018590529081018290526060016040516020818303038152906040528051906020012060001c82828151811061264a5761264a615485565b60209081029190910101528061265f81615383565b9150506125f9565b506000838152600960205260408082208290555181907f1fe543e300000000000000000000000000000000000000000000000000000000906126af908790869060240161518a565b60408051601f198184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff0000000000000000000000000000000000000000000000000000000090941693909317909252600b80547fffffffffffffffffffffffffffffffffffffffffffffffffff00ffffffffffff166601000000000000179055908a015160808b015191925060009161275f9163ffffffff169084613936565b600b80547fffffffffffffffffffffffffffffffffffffffffffffffffff00ffffffffffff1690556020808c01805167ffffffffffffffff9081166000908152600490935260408084205492518216845290922080549394506c01000000000000000000000000918290048316936001939192600c926127e392869290041661529b565b92506101000a81548167ffffffffffffffff021916908367ffffffffffffffff160217905550600061283a8a600b600001600b9054906101000a900463ffffffff1663ffffffff1661283485612a0b565b3a613984565b6020808e015167ffffffffffffffff166000908152600490915260409020549091506bffffffffffffffffffffffff808316911610156128a6576040517ff4d678b800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6020808d015167ffffffffffffffff16600090815260049091526040812080548392906128e29084906bffffffffffffffffffffffff16615356565b82546101009290920a6bffffffffffffffffffffffff81810219909316918316021790915560008b8152600660209081526040808320546001600160a01b03168352600890915281208054859450909261293e918591166152c7565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff160217905550877f7dffc5ae5ee4e2e4df1651cf6ad329a73cebdb728f37ea0187b9b17e036756e48883866040516129c1939291909283526bffffffffffffffffffffffff9190911660208301521515604082015260600190565b60405180910390a299505050505050505050505b92915050565b6000816040516020016129ee9190614fd7565b604051602081830303815290604052805190602001209050919050565b6040805161012081018252600c5463ffffffff80821683526401000000008204811660208401526801000000000000000082048116938301939093526c010000000000000000000000008104831660608301527001000000000000000000000000000000008104909216608082015262ffffff740100000000000000000000000000000000000000008304811660a08301819052770100000000000000000000000000000000000000000000008404821660c08401527a0100000000000000000000000000000000000000000000000000008404821660e08401527d0100000000000000000000000000000000000000000000000000000000009093041661010082015260009167ffffffffffffffff841611612b29575192915050565b8267ffffffffffffffff168160a0015162ffffff16108015612b5e57508060c0015162ffffff168367ffffffffffffffff1611155b15612b6d576020015192915050565b8267ffffffffffffffff168160c0015162ffffff16108015612ba257508060e0015162ffffff168367ffffffffffffffff1611155b15612bb1576040015192915050565b8267ffffffffffffffff168160e0015162ffffff16108015612be7575080610100015162ffffff168367ffffffffffffffff1611155b15612bf6576060015192915050565b6080015192915050565b67ffffffffffffffff821660009081526003602052604090205482906001600160a01b031680612c5c576040517f1f6a65b600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b336001600160a01b03821614612ca9576040517fd8a3fb520000000000000000000000000000000000000000000000000000000081526001600160a01b03821660048201526024016108dc565b600b546601000000000000900460ff1615612cf0576040517fed3ba6a600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b612cf984612f77565b15612d30576040517fb42f66e800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6109e58484613207565b612d426131ab565b6040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a082319060240160206040518083038186803b158015612dbd57600080fd5b505afa158015612dd1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612df59190614bf1565b6005549091506801000000000000000090046bffffffffffffffffffffffff1681811115612e59576040517fa99da30200000000000000000000000000000000000000000000000000000000815260048101829052602481018390526044016108dc565b81811015612f72576000612e6d828461533f565b6040517fa9059cbb0000000000000000000000000000000000000000000000000000000081526001600160a01b038681166004830152602482018390529192507f00000000000000000000000000000000000000000000000000000000000000009091169063a9059cbb90604401602060405180830381600087803b158015612ef557600080fd5b505af1158015612f09573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612f2d9190614bcf565b50604080516001600160a01b0386168152602081018390527f59bfc682b673f8cbf945f1e454df9334834abf7dfe7f92237ca29ecb9b436600910160405180910390a1505b505050565b67ffffffffffffffff81166000908152600360209081526040808320815160608101835281546001600160a01b039081168252600183015416818501526002820180548451818702810187018652818152879693958601939092919083018282801561300c57602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311612fee575b505050505081525050905060005b8160400151518110156131905760005b60075481101561317d5760006131466007838154811061304c5761304c615485565b90600052602060002001548560400151858151811061306d5761306d615485565b602002602001015188600260008960400151898151811061309057613090615485565b6020908102919091018101516001600160a01b03168252818101929092526040908101600090812067ffffffffffffffff808f16835293522054166040805160208082018790526001600160a01b03959095168183015267ffffffffffffffff9384166060820152919092166080808301919091528251808303909101815260a08201835280519084012060c082019490945260e080820185905282518083039091018152610100909101909152805191012091565b506000818152600960205260409020549091501561316a5750600195945050505050565b508061317581615383565b91505061302a565b508061318881615383565b91505061301a565b5060009392505050565b6131a26131ab565b61083481613a8c565b6000546001600160a01b031633146132055760405162461bcd60e51b815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e65720000000000000000000060448201526064016108dc565b565b600b546601000000000000900460ff161561324e576040517fed3ba6a600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b67ffffffffffffffff82166000908152600360209081526040808320815160608101835281546001600160a01b039081168252600183015416818501526002820180548451818702810187018652818152929593948601938301828280156132df57602002820191906000526020600020905b81546001600160a01b031681526001909101906020018083116132c1575b5050509190925250505067ffffffffffffffff80851660009081526004602090815260408083208151808301909252546bffffffffffffffffffffffff81168083526c01000000000000000000000000909104909416918101919091529293505b8360400151518110156133d957600260008560400151838151811061336757613367615485565b6020908102919091018101516001600160a01b03168252818101929092526040908101600090812067ffffffffffffffff8a168252909252902080547fffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000169055806133d181615383565b915050613340565b5067ffffffffffffffff8516600090815260036020526040812080547fffffffffffffffffffffffff000000000000000000000000000000000000000090811682556001820180549091169055906134346002830182614850565b505067ffffffffffffffff8516600090815260046020526040902080547fffffffffffffffffffffffff0000000000000000000000000000000000000000169055600580548291906008906134a49084906801000000000000000090046bffffffffffffffffffffffff16615356565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff1602179055507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663a9059cbb85836bffffffffffffffffffffffff166040518363ffffffff1660e01b81526004016135429291906001600160a01b03929092168252602082015260400190565b602060405180830381600087803b15801561355c57600080fd5b505af1158015613570573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906135949190614bcf565b6135ca576040517ff4d678b800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b604080516001600160a01b03861681526bffffffffffffffffffffffff8316602082015267ffffffffffffffff8716917fe8ed5b475a5b5987aa9165e8731bb78043f39eee32ec5a1169a89e27fcd49815910160405180910390a25050505050565b600080600061363e85600001516129db565b6000818152600660205260409020549093506001600160a01b031680613693576040517f77f5b84c000000000000000000000000000000000000000000000000000000008152600481018590526024016108dc565b60808601516040516136b2918691602001918252602082015260400190565b60408051601f1981840301815291815281516020928301206000818152600990935291205490935080613711576040517f3688124a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b85516020808801516040808a015160608b015160808c0151925161377d968b96909594910195865267ffffffffffffffff948516602087015292909316604085015263ffffffff90811660608501529190911660808301526001600160a01b031660a082015260c00190565b6040516020818303038152906040528051906020012081146137cb576040517fd529142c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b855167ffffffffffffffff1640806138e25786516040517fe9413d3800000000000000000000000000000000000000000000000000000000815267ffffffffffffffff90911660048201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063e9413d389060240160206040518083038186803b15801561386257600080fd5b505afa158015613876573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061389a9190614bf1565b9050806138e25786516040517f175dadad00000000000000000000000000000000000000000000000000000000815267ffffffffffffffff90911660048201526024016108dc565b6000886080015182604051602001613904929190918252602082015260400190565b6040516020818303038152906040528051906020012060001c90506139298982613b4e565b9450505050509250925092565b60005a61138881101561394857600080fd5b61138881039050846040820482031161396057600080fd5b50823b61396c57600080fd5b60008083516020850160008789f190505b9392505050565b60008061398f613bb9565b9050600081136139ce576040517f43d4cf66000000000000000000000000000000000000000000000000000000008152600481018290526024016108dc565b6000815a6139dc8989615283565b6139e6919061533f565b6139f886670de0b6b3a7640000615302565b613a029190615302565b613a0c91906152ee565b90506000613a2563ffffffff871664e8d4a51000615302565b9050613a3d816b033b2e3c9fd0803ce800000061533f565b821115613a76576040517fe80fa38100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b613a808183615283565b98975050505050505050565b6001600160a01b038116331415613ae55760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c6600000000000000000060448201526064016108dc565b600180547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b6000613b828360000151846020015185604001518660600151868860a001518960c001518a60e001518b6101000151613cc0565b60038360200151604051602001613b9a929190615176565b60408051601f1981840301815291905280516020909101209392505050565b600b54604080517ffeaf968c0000000000000000000000000000000000000000000000000000000081529051600092670100000000000000900463ffffffff169182151591849182917f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169163feaf968c9160048083019260a0929190829003018186803b158015613c5257600080fd5b505afa158015613c66573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613c8a9190614ecb565b509450909250849150508015613cae5750613ca5824261533f565b8463ffffffff16105b15613cb85750600a545b949350505050565b613cc989613efb565b613d155760405162461bcd60e51b815260206004820152601a60248201527f7075626c6963206b6579206973206e6f74206f6e20637572766500000000000060448201526064016108dc565b613d1e88613efb565b613d6a5760405162461bcd60e51b815260206004820152601560248201527f67616d6d61206973206e6f74206f6e206375727665000000000000000000000060448201526064016108dc565b613d7383613efb565b613dbf5760405162461bcd60e51b815260206004820152601d60248201527f6347616d6d615769746e657373206973206e6f74206f6e20637572766500000060448201526064016108dc565b613dc882613efb565b613e145760405162461bcd60e51b815260206004820152601c60248201527f73486173685769746e657373206973206e6f74206f6e2063757276650000000060448201526064016108dc565b613e20878a8887613fd4565b613e6c5760405162461bcd60e51b815260206004820152601960248201527f6164647228632a706b2b732a6729213d5f755769746e6573730000000000000060448201526064016108dc565b6000613e788a87614125565b90506000613e8b898b878b868989614189565b90506000613e9c838d8d8a866142a9565b9050808a14613eed5760405162461bcd60e51b815260206004820152600d60248201527f696e76616c69642070726f6f660000000000000000000000000000000000000060448201526064016108dc565b505050505050505050505050565b80516000906401000003d01911613f545760405162461bcd60e51b815260206004820152601260248201527f696e76616c696420782d6f7264696e617465000000000000000000000000000060448201526064016108dc565b60208201516401000003d01911613fad5760405162461bcd60e51b815260206004820152601260248201527f696e76616c696420792d6f7264696e617465000000000000000000000000000060448201526064016108dc565b60208201516401000003d019908009613fcd8360005b60200201516142e9565b1492915050565b60006001600160a01b03821661402c5760405162461bcd60e51b815260206004820152600b60248201527f626164207769746e65737300000000000000000000000000000000000000000060448201526064016108dc565b60208401516000906001161561404357601c614046565b601b5b905060007ffffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd03641418587600060200201510986517ffffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141918203925060009190890987516040805160008082526020820180845287905260ff88169282019290925260608101929092526080820183905291925060019060a0016020604051602081039080840390855afa1580156140fd573d6000803e3d6000fd5b5050604051601f1901516001600160a01b039081169088161495505050505050949350505050565b61412d61486e565b61415a6001848460405160200161414693929190614fb6565b60405160208183030381529060405261430d565b90505b61416681613efb565b6129d55780516040805160208101929092526141829101614146565b905061415d565b61419161486e565b825186516401000003d01990819006910614156141f05760405162461bcd60e51b815260206004820152601e60248201527f706f696e747320696e2073756d206d7573742062652064697374696e6374000060448201526064016108dc565b6141fb87898861435c565b6142475760405162461bcd60e51b815260206004820152601660248201527f4669727374206d756c20636865636b206661696c65640000000000000000000060448201526064016108dc565b61425284868561435c565b61429e5760405162461bcd60e51b815260206004820152601760248201527f5365636f6e64206d756c20636865636b206661696c656400000000000000000060448201526064016108dc565b613a808684846144a4565b6000600286868685876040516020016142c796959493929190614f44565b60408051601f1981840301815291905280516020909101209695505050505050565b6000806401000003d01980848509840990506401000003d019600782089392505050565b61431561486e565b61431e8261456b565b815261433361432e826000613fc3565b6145a6565b602082018190526002900660011415614357576020810180516401000003d0190390525b919050565b6000826143ab5760405162461bcd60e51b815260206004820152600b60248201527f7a65726f207363616c617200000000000000000000000000000000000000000060448201526064016108dc565b835160208501516000906143c1906002906153e4565b156143cd57601c6143d0565b601b5b905060007ffffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd03641418387096040805160008082526020820180845281905260ff86169282019290925260608101869052608081018390529192509060019060a0016020604051602081039080840390855afa158015614450573d6000803e3d6000fd5b50505060206040510351905060008660405160200161446f9190614f32565b60408051601f1981840301815291905280516020909101206001600160a01b0392831692169190911498975050505050505050565b6144ac61486e565b8351602080860151855191860151600093849384936144cd939091906145c6565b919450925090506401000003d01985820960011461452d5760405162461bcd60e51b815260206004820152601960248201527f696e765a206d75737420626520696e7665727365206f66207a0000000000000060448201526064016108dc565b60405180604001604052806401000003d0198061454c5761454c615427565b87860981526020016401000003d0198785099052979650505050505050565b805160208201205b6401000003d019811061435757604080516020808201939093528151808203840181529082019091528051910120614573565b60006129d58260026145bf6401000003d0196001615283565b901c6146a6565b60008080600180826401000003d019896401000003d019038808905060006401000003d0198b6401000003d019038a089050600061460683838585614766565b909850905061461788828e8861478a565b909850905061462888828c8761478a565b9098509050600061463b8d878b8561478a565b909850905061464c88828686614766565b909850905061465d88828e8961478a565b9098509050818114614692576401000003d019818a0998506401000003d01982890997506401000003d0198183099650614696565b8196505b5050505050509450945094915050565b6000806146b161488c565b6020808252818101819052604082015260608101859052608081018490526401000003d01960a08201526146e36148aa565b60208160c08460057ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa92508261475c5760405162461bcd60e51b815260206004820152601260248201527f6269674d6f64457870206661696c75726521000000000000000000000000000060448201526064016108dc565b5195945050505050565b6000806401000003d0198487096401000003d0198487099097909650945050505050565b600080806401000003d019878509905060006401000003d01987876401000003d019030990506401000003d0198183086401000003d01986890990999098509650505050505050565b828054828255906000526020600020908101928215614840579160200282015b8281111561484057825182547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b039091161782556020909201916001909101906147f3565b5061484c9291506148c8565b5090565b508054600082559060005260206000209081019061083491906148c8565b60405180604001604052806002906020820280368337509192915050565b6040518060c001604052806006906020820280368337509192915050565b60405180602001604052806001906020820280368337509192915050565b5b8082111561484c57600081556001016148c9565b80356001600160a01b038116811461435757600080fd5b80604081018310156129d557600080fd5b600082601f83011261491657600080fd5b6040516040810181811067ffffffffffffffff82111715614939576149396154b4565b806040525080838560408601111561495057600080fd5b60005b6002811015614972578135835260209283019290910190600101614953565b509195945050505050565b600060a0828403121561498f57600080fd5b60405160a0810181811067ffffffffffffffff821117156149b2576149b26154b4565b6040529050806149c183614a47565b81526149cf60208401614a47565b60208201526149e060408401614a33565b60408201526149f160608401614a33565b6060820152614a02608084016148dd565b60808201525092915050565b803561ffff8116811461435757600080fd5b803562ffffff8116811461435757600080fd5b803563ffffffff8116811461435757600080fd5b803567ffffffffffffffff8116811461435757600080fd5b805169ffffffffffffffffffff8116811461435757600080fd5b600060208284031215614a8b57600080fd5b61397d826148dd565b60008060608385031215614aa757600080fd5b614ab0836148dd565b9150614abf84602085016148f4565b90509250929050565b60008060008060608587031215614ade57600080fd5b614ae7856148dd565b935060208501359250604085013567ffffffffffffffff80821115614b0b57600080fd5b818701915087601f830112614b1f57600080fd5b813581811115614b2e57600080fd5b886020828501011115614b4057600080fd5b95989497505060200194505050565b60008060408385031215614b6257600080fd5b614b6b836148dd565b915060208301356bffffffffffffffffffffffff81168114614b8c57600080fd5b809150509250929050565b600060408284031215614ba957600080fd5b61397d83836148f4565b600060408284031215614bc557600080fd5b61397d8383614905565b600060208284031215614be157600080fd5b8151801515811461397d57600080fd5b600060208284031215614c0357600080fd5b5051919050565b600080600080600060a08688031215614c2257600080fd5b85359450614c3260208701614a47565b9350614c4060408701614a0e565b9250614c4e60608701614a33565b9150614c5c60808701614a33565b90509295509295909350565b600080828403610240811215614c7d57600080fd5b6101a080821215614c8d57600080fd5b614c95615259565b9150614ca18686614905565b8252614cb08660408701614905565b60208301526080850135604083015260a0850135606083015260c08501356080830152614cdf60e086016148dd565b60a0830152610100614cf387828801614905565b60c0840152614d06876101408801614905565b60e08401526101808601358184015250819350614d258682870161497d565b925050509250929050565b6000806000806000808688036101c0811215614d4b57600080fd5b614d5488614a0e565b9650614d6260208901614a33565b9550614d7060408901614a33565b9450614d7e60608901614a33565b935060808801359250610120807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6083011215614db957600080fd5b614dc1615259565b9150614dcf60a08a01614a33565b8252614ddd60c08a01614a33565b6020830152614dee60e08a01614a33565b6040830152610100614e01818b01614a33565b6060840152614e11828b01614a33565b6080840152614e236101408b01614a20565b60a0840152614e356101608b01614a20565b60c0840152614e476101808b01614a20565b60e0840152614e596101a08b01614a20565b818401525050809150509295509295509295565b600060208284031215614e7f57600080fd5b5035919050565b600060208284031215614e9857600080fd5b61397d82614a47565b60008060408385031215614eb457600080fd5b614ebd83614a47565b9150614abf602084016148dd565b600080600080600060a08688031215614ee357600080fd5b614eec86614a5f565b9450602086015193506040860151925060608601519150614c5c60808701614a5f565b8060005b60028110156109e5578151845260209384019390910190600101614f13565b614f3c8183614f0f565b604001919050565b868152614f546020820187614f0f565b614f616060820186614f0f565b614f6e60a0820185614f0f565b614f7b60e0820184614f0f565b60609190911b7fffffffffffffffffffffffffffffffffffffffff000000000000000000000000166101208201526101340195945050505050565b838152614fc66020820184614f0f565b606081019190915260800192915050565b604081016129d58284614f0f565b600060208083528351808285015260005b8181101561501257858101830151858201604001528201614ff6565b81811115615024576000604083870101525b50601f01601f1916929092016040019392505050565b60006060820161ffff86168352602063ffffffff86168185015260606040850152818551808452608086019150828701935060005b8181101561508b5784518352938301939183019160010161506f565b509098975050505050505050565b60006101c08201905061ffff8816825263ffffffff808816602084015280871660408401528086166060840152846080840152835481811660a08501526150ed60c08501838360201c1663ffffffff169052565b61510460e08501838360401c1663ffffffff169052565b61511c6101008501838360601c1663ffffffff169052565b6151346101208501838360801c1663ffffffff169052565b62ffffff60a082901c811661014086015260b882901c811661016086015260d082901c1661018085015260e81c6101a090930192909252979650505050505050565b8281526060810161397d6020830184614f0f565b6000604082018483526020604081850152818551808452606086019150828701935060005b818110156151cb578451835293830193918301916001016151af565b5090979650505050505050565b6000608082016bffffffffffffffffffffffff87168352602067ffffffffffffffff8716818501526001600160a01b0380871660408601526080606086015282865180855260a087019150838801945060005b8181101561524957855184168352948401949184019160010161522b565b50909a9950505050505050505050565b604051610120810167ffffffffffffffff8111828210171561527d5761527d6154b4565b60405290565b60008219821115615296576152966153f8565b500190565b600067ffffffffffffffff8083168185168083038211156152be576152be6153f8565b01949350505050565b60006bffffffffffffffffffffffff8083168185168083038211156152be576152be6153f8565b6000826152fd576152fd615427565b500490565b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff048311821515161561533a5761533a6153f8565b500290565b600082821015615351576153516153f8565b500390565b60006bffffffffffffffffffffffff8381169083168181101561537b5761537b6153f8565b039392505050565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8214156153b5576153b56153f8565b5060010190565b600067ffffffffffffffff808316818114156153da576153da6153f8565b6001019392505050565b6000826153f3576153f3615427565b500690565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fdfea164736f6c6343000806000a", +} + +var VRFCoordinatorTestV2ABI = VRFCoordinatorTestV2MetaData.ABI + +var VRFCoordinatorTestV2Bin = VRFCoordinatorTestV2MetaData.Bin + +func DeployVRFCoordinatorTestV2(auth *bind.TransactOpts, backend bind.ContractBackend, link common.Address, blockhashStore common.Address, linkEthFeed common.Address) (common.Address, *types.Transaction, *VRFCoordinatorTestV2, error) { + parsed, err := VRFCoordinatorTestV2MetaData.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(VRFCoordinatorTestV2Bin), backend, link, blockhashStore, linkEthFeed) + if err != nil { + return common.Address{}, nil, nil, err + } + return address, tx, &VRFCoordinatorTestV2{address: address, abi: *parsed, VRFCoordinatorTestV2Caller: VRFCoordinatorTestV2Caller{contract: contract}, VRFCoordinatorTestV2Transactor: VRFCoordinatorTestV2Transactor{contract: contract}, VRFCoordinatorTestV2Filterer: VRFCoordinatorTestV2Filterer{contract: contract}}, nil +} + +type VRFCoordinatorTestV2 struct { + address common.Address + abi abi.ABI + VRFCoordinatorTestV2Caller + VRFCoordinatorTestV2Transactor + VRFCoordinatorTestV2Filterer +} + +type VRFCoordinatorTestV2Caller struct { + contract *bind.BoundContract +} + +type VRFCoordinatorTestV2Transactor struct { + contract *bind.BoundContract +} + +type VRFCoordinatorTestV2Filterer struct { + contract *bind.BoundContract +} + +type VRFCoordinatorTestV2Session struct { + Contract *VRFCoordinatorTestV2 + CallOpts bind.CallOpts + TransactOpts bind.TransactOpts +} + +type VRFCoordinatorTestV2CallerSession struct { + Contract *VRFCoordinatorTestV2Caller + CallOpts bind.CallOpts +} + +type VRFCoordinatorTestV2TransactorSession struct { + Contract *VRFCoordinatorTestV2Transactor + TransactOpts bind.TransactOpts +} + +type VRFCoordinatorTestV2Raw struct { + Contract *VRFCoordinatorTestV2 +} + +type VRFCoordinatorTestV2CallerRaw struct { + Contract *VRFCoordinatorTestV2Caller +} + +type VRFCoordinatorTestV2TransactorRaw struct { + Contract *VRFCoordinatorTestV2Transactor +} + +func NewVRFCoordinatorTestV2(address common.Address, backend bind.ContractBackend) (*VRFCoordinatorTestV2, error) { + abi, err := abi.JSON(strings.NewReader(VRFCoordinatorTestV2ABI)) + if err != nil { + return nil, err + } + contract, err := bindVRFCoordinatorTestV2(address, backend, backend, backend) + if err != nil { + return nil, err + } + return &VRFCoordinatorTestV2{address: address, abi: abi, VRFCoordinatorTestV2Caller: VRFCoordinatorTestV2Caller{contract: contract}, VRFCoordinatorTestV2Transactor: VRFCoordinatorTestV2Transactor{contract: contract}, VRFCoordinatorTestV2Filterer: VRFCoordinatorTestV2Filterer{contract: contract}}, nil +} + +func NewVRFCoordinatorTestV2Caller(address common.Address, caller bind.ContractCaller) (*VRFCoordinatorTestV2Caller, error) { + contract, err := bindVRFCoordinatorTestV2(address, caller, nil, nil) + if err != nil { + return nil, err + } + return &VRFCoordinatorTestV2Caller{contract: contract}, nil +} + +func NewVRFCoordinatorTestV2Transactor(address common.Address, transactor bind.ContractTransactor) (*VRFCoordinatorTestV2Transactor, error) { + contract, err := bindVRFCoordinatorTestV2(address, nil, transactor, nil) + if err != nil { + return nil, err + } + return &VRFCoordinatorTestV2Transactor{contract: contract}, nil +} + +func NewVRFCoordinatorTestV2Filterer(address common.Address, filterer bind.ContractFilterer) (*VRFCoordinatorTestV2Filterer, error) { + contract, err := bindVRFCoordinatorTestV2(address, nil, nil, filterer) + if err != nil { + return nil, err + } + return &VRFCoordinatorTestV2Filterer{contract: contract}, nil +} + +func bindVRFCoordinatorTestV2(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) { + parsed, err := VRFCoordinatorTestV2MetaData.GetAbi() + if err != nil { + return nil, err + } + return bind.NewBoundContract(address, *parsed, caller, transactor, filterer), nil +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2Raw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _VRFCoordinatorTestV2.Contract.VRFCoordinatorTestV2Caller.contract.Call(opts, result, method, params...) +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2Raw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _VRFCoordinatorTestV2.Contract.VRFCoordinatorTestV2Transactor.contract.Transfer(opts) +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2Raw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _VRFCoordinatorTestV2.Contract.VRFCoordinatorTestV2Transactor.contract.Transact(opts, method, params...) +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2CallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _VRFCoordinatorTestV2.Contract.contract.Call(opts, result, method, params...) +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2TransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _VRFCoordinatorTestV2.Contract.contract.Transfer(opts) +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2TransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _VRFCoordinatorTestV2.Contract.contract.Transact(opts, method, params...) +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2Caller) BLOCKHASHSTORE(opts *bind.CallOpts) (common.Address, error) { + var out []interface{} + err := _VRFCoordinatorTestV2.contract.Call(opts, &out, "BLOCKHASH_STORE") + + if err != nil { + return *new(common.Address), err + } + + out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) + + return out0, err + +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2Session) BLOCKHASHSTORE() (common.Address, error) { + return _VRFCoordinatorTestV2.Contract.BLOCKHASHSTORE(&_VRFCoordinatorTestV2.CallOpts) +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2CallerSession) BLOCKHASHSTORE() (common.Address, error) { + return _VRFCoordinatorTestV2.Contract.BLOCKHASHSTORE(&_VRFCoordinatorTestV2.CallOpts) +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2Caller) LINK(opts *bind.CallOpts) (common.Address, error) { + var out []interface{} + err := _VRFCoordinatorTestV2.contract.Call(opts, &out, "LINK") + + if err != nil { + return *new(common.Address), err + } + + out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) + + return out0, err + +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2Session) LINK() (common.Address, error) { + return _VRFCoordinatorTestV2.Contract.LINK(&_VRFCoordinatorTestV2.CallOpts) +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2CallerSession) LINK() (common.Address, error) { + return _VRFCoordinatorTestV2.Contract.LINK(&_VRFCoordinatorTestV2.CallOpts) +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2Caller) LINKETHFEED(opts *bind.CallOpts) (common.Address, error) { + var out []interface{} + err := _VRFCoordinatorTestV2.contract.Call(opts, &out, "LINK_ETH_FEED") + + if err != nil { + return *new(common.Address), err + } + + out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) + + return out0, err + +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2Session) LINKETHFEED() (common.Address, error) { + return _VRFCoordinatorTestV2.Contract.LINKETHFEED(&_VRFCoordinatorTestV2.CallOpts) +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2CallerSession) LINKETHFEED() (common.Address, error) { + return _VRFCoordinatorTestV2.Contract.LINKETHFEED(&_VRFCoordinatorTestV2.CallOpts) +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2Caller) MAXCONSUMERS(opts *bind.CallOpts) (uint16, error) { + var out []interface{} + err := _VRFCoordinatorTestV2.contract.Call(opts, &out, "MAX_CONSUMERS") + + if err != nil { + return *new(uint16), err + } + + out0 := *abi.ConvertType(out[0], new(uint16)).(*uint16) + + return out0, err + +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2Session) MAXCONSUMERS() (uint16, error) { + return _VRFCoordinatorTestV2.Contract.MAXCONSUMERS(&_VRFCoordinatorTestV2.CallOpts) +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2CallerSession) MAXCONSUMERS() (uint16, error) { + return _VRFCoordinatorTestV2.Contract.MAXCONSUMERS(&_VRFCoordinatorTestV2.CallOpts) +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2Caller) MAXNUMWORDS(opts *bind.CallOpts) (uint32, error) { + var out []interface{} + err := _VRFCoordinatorTestV2.contract.Call(opts, &out, "MAX_NUM_WORDS") + + if err != nil { + return *new(uint32), err + } + + out0 := *abi.ConvertType(out[0], new(uint32)).(*uint32) + + return out0, err + +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2Session) MAXNUMWORDS() (uint32, error) { + return _VRFCoordinatorTestV2.Contract.MAXNUMWORDS(&_VRFCoordinatorTestV2.CallOpts) +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2CallerSession) MAXNUMWORDS() (uint32, error) { + return _VRFCoordinatorTestV2.Contract.MAXNUMWORDS(&_VRFCoordinatorTestV2.CallOpts) +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2Caller) MAXREQUESTCONFIRMATIONS(opts *bind.CallOpts) (uint16, error) { + var out []interface{} + err := _VRFCoordinatorTestV2.contract.Call(opts, &out, "MAX_REQUEST_CONFIRMATIONS") + + if err != nil { + return *new(uint16), err + } + + out0 := *abi.ConvertType(out[0], new(uint16)).(*uint16) + + return out0, err + +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2Session) MAXREQUESTCONFIRMATIONS() (uint16, error) { + return _VRFCoordinatorTestV2.Contract.MAXREQUESTCONFIRMATIONS(&_VRFCoordinatorTestV2.CallOpts) +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2CallerSession) MAXREQUESTCONFIRMATIONS() (uint16, error) { + return _VRFCoordinatorTestV2.Contract.MAXREQUESTCONFIRMATIONS(&_VRFCoordinatorTestV2.CallOpts) +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2Caller) GetCommitment(opts *bind.CallOpts, requestId *big.Int) ([32]byte, error) { + var out []interface{} + err := _VRFCoordinatorTestV2.contract.Call(opts, &out, "getCommitment", requestId) + + if err != nil { + return *new([32]byte), err + } + + out0 := *abi.ConvertType(out[0], new([32]byte)).(*[32]byte) + + return out0, err + +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2Session) GetCommitment(requestId *big.Int) ([32]byte, error) { + return _VRFCoordinatorTestV2.Contract.GetCommitment(&_VRFCoordinatorTestV2.CallOpts, requestId) +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2CallerSession) GetCommitment(requestId *big.Int) ([32]byte, error) { + return _VRFCoordinatorTestV2.Contract.GetCommitment(&_VRFCoordinatorTestV2.CallOpts, requestId) +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2Caller) GetConfig(opts *bind.CallOpts) (GetConfig, + + error) { + var out []interface{} + err := _VRFCoordinatorTestV2.contract.Call(opts, &out, "getConfig") + + outstruct := new(GetConfig) + if err != nil { + return *outstruct, err + } + + outstruct.MinimumRequestConfirmations = *abi.ConvertType(out[0], new(uint16)).(*uint16) + outstruct.MaxGasLimit = *abi.ConvertType(out[1], new(uint32)).(*uint32) + outstruct.StalenessSeconds = *abi.ConvertType(out[2], new(uint32)).(*uint32) + outstruct.GasAfterPaymentCalculation = *abi.ConvertType(out[3], new(uint32)).(*uint32) + + return *outstruct, err + +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2Session) GetConfig() (GetConfig, + + error) { + return _VRFCoordinatorTestV2.Contract.GetConfig(&_VRFCoordinatorTestV2.CallOpts) +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2CallerSession) GetConfig() (GetConfig, + + error) { + return _VRFCoordinatorTestV2.Contract.GetConfig(&_VRFCoordinatorTestV2.CallOpts) +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2Caller) GetCurrentSubId(opts *bind.CallOpts) (uint64, error) { + var out []interface{} + err := _VRFCoordinatorTestV2.contract.Call(opts, &out, "getCurrentSubId") + + if err != nil { + return *new(uint64), err + } + + out0 := *abi.ConvertType(out[0], new(uint64)).(*uint64) + + return out0, err + +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2Session) GetCurrentSubId() (uint64, error) { + return _VRFCoordinatorTestV2.Contract.GetCurrentSubId(&_VRFCoordinatorTestV2.CallOpts) +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2CallerSession) GetCurrentSubId() (uint64, error) { + return _VRFCoordinatorTestV2.Contract.GetCurrentSubId(&_VRFCoordinatorTestV2.CallOpts) +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2Caller) GetFallbackWeiPerUnitLink(opts *bind.CallOpts) (*big.Int, error) { + var out []interface{} + err := _VRFCoordinatorTestV2.contract.Call(opts, &out, "getFallbackWeiPerUnitLink") + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2Session) GetFallbackWeiPerUnitLink() (*big.Int, error) { + return _VRFCoordinatorTestV2.Contract.GetFallbackWeiPerUnitLink(&_VRFCoordinatorTestV2.CallOpts) +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2CallerSession) GetFallbackWeiPerUnitLink() (*big.Int, error) { + return _VRFCoordinatorTestV2.Contract.GetFallbackWeiPerUnitLink(&_VRFCoordinatorTestV2.CallOpts) +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2Caller) GetFeeConfig(opts *bind.CallOpts) (GetFeeConfig, + + error) { + var out []interface{} + err := _VRFCoordinatorTestV2.contract.Call(opts, &out, "getFeeConfig") + + outstruct := new(GetFeeConfig) + if err != nil { + return *outstruct, err + } + + outstruct.FulfillmentFlatFeeLinkPPMTier1 = *abi.ConvertType(out[0], new(uint32)).(*uint32) + outstruct.FulfillmentFlatFeeLinkPPMTier2 = *abi.ConvertType(out[1], new(uint32)).(*uint32) + outstruct.FulfillmentFlatFeeLinkPPMTier3 = *abi.ConvertType(out[2], new(uint32)).(*uint32) + outstruct.FulfillmentFlatFeeLinkPPMTier4 = *abi.ConvertType(out[3], new(uint32)).(*uint32) + outstruct.FulfillmentFlatFeeLinkPPMTier5 = *abi.ConvertType(out[4], new(uint32)).(*uint32) + outstruct.ReqsForTier2 = *abi.ConvertType(out[5], new(*big.Int)).(**big.Int) + outstruct.ReqsForTier3 = *abi.ConvertType(out[6], new(*big.Int)).(**big.Int) + outstruct.ReqsForTier4 = *abi.ConvertType(out[7], new(*big.Int)).(**big.Int) + outstruct.ReqsForTier5 = *abi.ConvertType(out[8], new(*big.Int)).(**big.Int) + + return *outstruct, err + +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2Session) GetFeeConfig() (GetFeeConfig, + + error) { + return _VRFCoordinatorTestV2.Contract.GetFeeConfig(&_VRFCoordinatorTestV2.CallOpts) +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2CallerSession) GetFeeConfig() (GetFeeConfig, + + error) { + return _VRFCoordinatorTestV2.Contract.GetFeeConfig(&_VRFCoordinatorTestV2.CallOpts) +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2Caller) GetFeeTier(opts *bind.CallOpts, reqCount uint64) (uint32, error) { + var out []interface{} + err := _VRFCoordinatorTestV2.contract.Call(opts, &out, "getFeeTier", reqCount) + + if err != nil { + return *new(uint32), err + } + + out0 := *abi.ConvertType(out[0], new(uint32)).(*uint32) + + return out0, err + +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2Session) GetFeeTier(reqCount uint64) (uint32, error) { + return _VRFCoordinatorTestV2.Contract.GetFeeTier(&_VRFCoordinatorTestV2.CallOpts, reqCount) +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2CallerSession) GetFeeTier(reqCount uint64) (uint32, error) { + return _VRFCoordinatorTestV2.Contract.GetFeeTier(&_VRFCoordinatorTestV2.CallOpts, reqCount) +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2Caller) GetRequestConfig(opts *bind.CallOpts) (uint16, uint32, [][32]byte, error) { + var out []interface{} + err := _VRFCoordinatorTestV2.contract.Call(opts, &out, "getRequestConfig") + + if err != nil { + return *new(uint16), *new(uint32), *new([][32]byte), err + } + + out0 := *abi.ConvertType(out[0], new(uint16)).(*uint16) + out1 := *abi.ConvertType(out[1], new(uint32)).(*uint32) + out2 := *abi.ConvertType(out[2], new([][32]byte)).(*[][32]byte) + + return out0, out1, out2, err + +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2Session) GetRequestConfig() (uint16, uint32, [][32]byte, error) { + return _VRFCoordinatorTestV2.Contract.GetRequestConfig(&_VRFCoordinatorTestV2.CallOpts) +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2CallerSession) GetRequestConfig() (uint16, uint32, [][32]byte, error) { + return _VRFCoordinatorTestV2.Contract.GetRequestConfig(&_VRFCoordinatorTestV2.CallOpts) +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2Caller) GetSubscription(opts *bind.CallOpts, subId uint64) (GetSubscription, + + error) { + var out []interface{} + err := _VRFCoordinatorTestV2.contract.Call(opts, &out, "getSubscription", subId) + + outstruct := new(GetSubscription) + if err != nil { + return *outstruct, err + } + + outstruct.Balance = *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + outstruct.ReqCount = *abi.ConvertType(out[1], new(uint64)).(*uint64) + outstruct.Owner = *abi.ConvertType(out[2], new(common.Address)).(*common.Address) + outstruct.Consumers = *abi.ConvertType(out[3], new([]common.Address)).(*[]common.Address) + + return *outstruct, err + +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2Session) GetSubscription(subId uint64) (GetSubscription, + + error) { + return _VRFCoordinatorTestV2.Contract.GetSubscription(&_VRFCoordinatorTestV2.CallOpts, subId) +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2CallerSession) GetSubscription(subId uint64) (GetSubscription, + + error) { + return _VRFCoordinatorTestV2.Contract.GetSubscription(&_VRFCoordinatorTestV2.CallOpts, subId) +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2Caller) GetTotalBalance(opts *bind.CallOpts) (*big.Int, error) { + var out []interface{} + err := _VRFCoordinatorTestV2.contract.Call(opts, &out, "getTotalBalance") + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2Session) GetTotalBalance() (*big.Int, error) { + return _VRFCoordinatorTestV2.Contract.GetTotalBalance(&_VRFCoordinatorTestV2.CallOpts) +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2CallerSession) GetTotalBalance() (*big.Int, error) { + return _VRFCoordinatorTestV2.Contract.GetTotalBalance(&_VRFCoordinatorTestV2.CallOpts) +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2Caller) HashOfKey(opts *bind.CallOpts, publicKey [2]*big.Int) ([32]byte, error) { + var out []interface{} + err := _VRFCoordinatorTestV2.contract.Call(opts, &out, "hashOfKey", publicKey) + + if err != nil { + return *new([32]byte), err + } + + out0 := *abi.ConvertType(out[0], new([32]byte)).(*[32]byte) + + return out0, err + +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2Session) HashOfKey(publicKey [2]*big.Int) ([32]byte, error) { + return _VRFCoordinatorTestV2.Contract.HashOfKey(&_VRFCoordinatorTestV2.CallOpts, publicKey) +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2CallerSession) HashOfKey(publicKey [2]*big.Int) ([32]byte, error) { + return _VRFCoordinatorTestV2.Contract.HashOfKey(&_VRFCoordinatorTestV2.CallOpts, publicKey) +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2Caller) Owner(opts *bind.CallOpts) (common.Address, error) { + var out []interface{} + err := _VRFCoordinatorTestV2.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 (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2Session) Owner() (common.Address, error) { + return _VRFCoordinatorTestV2.Contract.Owner(&_VRFCoordinatorTestV2.CallOpts) +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2CallerSession) Owner() (common.Address, error) { + return _VRFCoordinatorTestV2.Contract.Owner(&_VRFCoordinatorTestV2.CallOpts) +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2Caller) PendingRequestExists(opts *bind.CallOpts, subId uint64) (bool, error) { + var out []interface{} + err := _VRFCoordinatorTestV2.contract.Call(opts, &out, "pendingRequestExists", subId) + + if err != nil { + return *new(bool), err + } + + out0 := *abi.ConvertType(out[0], new(bool)).(*bool) + + return out0, err + +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2Session) PendingRequestExists(subId uint64) (bool, error) { + return _VRFCoordinatorTestV2.Contract.PendingRequestExists(&_VRFCoordinatorTestV2.CallOpts, subId) +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2CallerSession) PendingRequestExists(subId uint64) (bool, error) { + return _VRFCoordinatorTestV2.Contract.PendingRequestExists(&_VRFCoordinatorTestV2.CallOpts, subId) +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2Caller) TypeAndVersion(opts *bind.CallOpts) (string, error) { + var out []interface{} + err := _VRFCoordinatorTestV2.contract.Call(opts, &out, "typeAndVersion") + + if err != nil { + return *new(string), err + } + + out0 := *abi.ConvertType(out[0], new(string)).(*string) + + return out0, err + +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2Session) TypeAndVersion() (string, error) { + return _VRFCoordinatorTestV2.Contract.TypeAndVersion(&_VRFCoordinatorTestV2.CallOpts) +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2CallerSession) TypeAndVersion() (string, error) { + return _VRFCoordinatorTestV2.Contract.TypeAndVersion(&_VRFCoordinatorTestV2.CallOpts) +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2Transactor) AcceptOwnership(opts *bind.TransactOpts) (*types.Transaction, error) { + return _VRFCoordinatorTestV2.contract.Transact(opts, "acceptOwnership") +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2Session) AcceptOwnership() (*types.Transaction, error) { + return _VRFCoordinatorTestV2.Contract.AcceptOwnership(&_VRFCoordinatorTestV2.TransactOpts) +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2TransactorSession) AcceptOwnership() (*types.Transaction, error) { + return _VRFCoordinatorTestV2.Contract.AcceptOwnership(&_VRFCoordinatorTestV2.TransactOpts) +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2Transactor) AcceptSubscriptionOwnerTransfer(opts *bind.TransactOpts, subId uint64) (*types.Transaction, error) { + return _VRFCoordinatorTestV2.contract.Transact(opts, "acceptSubscriptionOwnerTransfer", subId) +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2Session) AcceptSubscriptionOwnerTransfer(subId uint64) (*types.Transaction, error) { + return _VRFCoordinatorTestV2.Contract.AcceptSubscriptionOwnerTransfer(&_VRFCoordinatorTestV2.TransactOpts, subId) +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2TransactorSession) AcceptSubscriptionOwnerTransfer(subId uint64) (*types.Transaction, error) { + return _VRFCoordinatorTestV2.Contract.AcceptSubscriptionOwnerTransfer(&_VRFCoordinatorTestV2.TransactOpts, subId) +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2Transactor) AddConsumer(opts *bind.TransactOpts, subId uint64, consumer common.Address) (*types.Transaction, error) { + return _VRFCoordinatorTestV2.contract.Transact(opts, "addConsumer", subId, consumer) +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2Session) AddConsumer(subId uint64, consumer common.Address) (*types.Transaction, error) { + return _VRFCoordinatorTestV2.Contract.AddConsumer(&_VRFCoordinatorTestV2.TransactOpts, subId, consumer) +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2TransactorSession) AddConsumer(subId uint64, consumer common.Address) (*types.Transaction, error) { + return _VRFCoordinatorTestV2.Contract.AddConsumer(&_VRFCoordinatorTestV2.TransactOpts, subId, consumer) +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2Transactor) CancelSubscription(opts *bind.TransactOpts, subId uint64, to common.Address) (*types.Transaction, error) { + return _VRFCoordinatorTestV2.contract.Transact(opts, "cancelSubscription", subId, to) +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2Session) CancelSubscription(subId uint64, to common.Address) (*types.Transaction, error) { + return _VRFCoordinatorTestV2.Contract.CancelSubscription(&_VRFCoordinatorTestV2.TransactOpts, subId, to) +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2TransactorSession) CancelSubscription(subId uint64, to common.Address) (*types.Transaction, error) { + return _VRFCoordinatorTestV2.Contract.CancelSubscription(&_VRFCoordinatorTestV2.TransactOpts, subId, to) +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2Transactor) CreateSubscription(opts *bind.TransactOpts) (*types.Transaction, error) { + return _VRFCoordinatorTestV2.contract.Transact(opts, "createSubscription") +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2Session) CreateSubscription() (*types.Transaction, error) { + return _VRFCoordinatorTestV2.Contract.CreateSubscription(&_VRFCoordinatorTestV2.TransactOpts) +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2TransactorSession) CreateSubscription() (*types.Transaction, error) { + return _VRFCoordinatorTestV2.Contract.CreateSubscription(&_VRFCoordinatorTestV2.TransactOpts) +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2Transactor) DeregisterProvingKey(opts *bind.TransactOpts, publicProvingKey [2]*big.Int) (*types.Transaction, error) { + return _VRFCoordinatorTestV2.contract.Transact(opts, "deregisterProvingKey", publicProvingKey) +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2Session) DeregisterProvingKey(publicProvingKey [2]*big.Int) (*types.Transaction, error) { + return _VRFCoordinatorTestV2.Contract.DeregisterProvingKey(&_VRFCoordinatorTestV2.TransactOpts, publicProvingKey) +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2TransactorSession) DeregisterProvingKey(publicProvingKey [2]*big.Int) (*types.Transaction, error) { + return _VRFCoordinatorTestV2.Contract.DeregisterProvingKey(&_VRFCoordinatorTestV2.TransactOpts, publicProvingKey) +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2Transactor) FulfillRandomWords(opts *bind.TransactOpts, proof VRFProof, rc VRFCoordinatorTestV2RequestCommitment) (*types.Transaction, error) { + return _VRFCoordinatorTestV2.contract.Transact(opts, "fulfillRandomWords", proof, rc) +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2Session) FulfillRandomWords(proof VRFProof, rc VRFCoordinatorTestV2RequestCommitment) (*types.Transaction, error) { + return _VRFCoordinatorTestV2.Contract.FulfillRandomWords(&_VRFCoordinatorTestV2.TransactOpts, proof, rc) +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2TransactorSession) FulfillRandomWords(proof VRFProof, rc VRFCoordinatorTestV2RequestCommitment) (*types.Transaction, error) { + return _VRFCoordinatorTestV2.Contract.FulfillRandomWords(&_VRFCoordinatorTestV2.TransactOpts, proof, rc) +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2Transactor) OnTokenTransfer(opts *bind.TransactOpts, arg0 common.Address, amount *big.Int, data []byte) (*types.Transaction, error) { + return _VRFCoordinatorTestV2.contract.Transact(opts, "onTokenTransfer", arg0, amount, data) +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2Session) OnTokenTransfer(arg0 common.Address, amount *big.Int, data []byte) (*types.Transaction, error) { + return _VRFCoordinatorTestV2.Contract.OnTokenTransfer(&_VRFCoordinatorTestV2.TransactOpts, arg0, amount, data) +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2TransactorSession) OnTokenTransfer(arg0 common.Address, amount *big.Int, data []byte) (*types.Transaction, error) { + return _VRFCoordinatorTestV2.Contract.OnTokenTransfer(&_VRFCoordinatorTestV2.TransactOpts, arg0, amount, data) +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2Transactor) OracleWithdraw(opts *bind.TransactOpts, recipient common.Address, amount *big.Int) (*types.Transaction, error) { + return _VRFCoordinatorTestV2.contract.Transact(opts, "oracleWithdraw", recipient, amount) +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2Session) OracleWithdraw(recipient common.Address, amount *big.Int) (*types.Transaction, error) { + return _VRFCoordinatorTestV2.Contract.OracleWithdraw(&_VRFCoordinatorTestV2.TransactOpts, recipient, amount) +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2TransactorSession) OracleWithdraw(recipient common.Address, amount *big.Int) (*types.Transaction, error) { + return _VRFCoordinatorTestV2.Contract.OracleWithdraw(&_VRFCoordinatorTestV2.TransactOpts, recipient, amount) +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2Transactor) OwnerCancelSubscription(opts *bind.TransactOpts, subId uint64) (*types.Transaction, error) { + return _VRFCoordinatorTestV2.contract.Transact(opts, "ownerCancelSubscription", subId) +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2Session) OwnerCancelSubscription(subId uint64) (*types.Transaction, error) { + return _VRFCoordinatorTestV2.Contract.OwnerCancelSubscription(&_VRFCoordinatorTestV2.TransactOpts, subId) +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2TransactorSession) OwnerCancelSubscription(subId uint64) (*types.Transaction, error) { + return _VRFCoordinatorTestV2.Contract.OwnerCancelSubscription(&_VRFCoordinatorTestV2.TransactOpts, subId) +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2Transactor) RecoverFunds(opts *bind.TransactOpts, to common.Address) (*types.Transaction, error) { + return _VRFCoordinatorTestV2.contract.Transact(opts, "recoverFunds", to) +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2Session) RecoverFunds(to common.Address) (*types.Transaction, error) { + return _VRFCoordinatorTestV2.Contract.RecoverFunds(&_VRFCoordinatorTestV2.TransactOpts, to) +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2TransactorSession) RecoverFunds(to common.Address) (*types.Transaction, error) { + return _VRFCoordinatorTestV2.Contract.RecoverFunds(&_VRFCoordinatorTestV2.TransactOpts, to) +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2Transactor) RegisterProvingKey(opts *bind.TransactOpts, oracle common.Address, publicProvingKey [2]*big.Int) (*types.Transaction, error) { + return _VRFCoordinatorTestV2.contract.Transact(opts, "registerProvingKey", oracle, publicProvingKey) +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2Session) RegisterProvingKey(oracle common.Address, publicProvingKey [2]*big.Int) (*types.Transaction, error) { + return _VRFCoordinatorTestV2.Contract.RegisterProvingKey(&_VRFCoordinatorTestV2.TransactOpts, oracle, publicProvingKey) +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2TransactorSession) RegisterProvingKey(oracle common.Address, publicProvingKey [2]*big.Int) (*types.Transaction, error) { + return _VRFCoordinatorTestV2.Contract.RegisterProvingKey(&_VRFCoordinatorTestV2.TransactOpts, oracle, publicProvingKey) +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2Transactor) RemoveConsumer(opts *bind.TransactOpts, subId uint64, consumer common.Address) (*types.Transaction, error) { + return _VRFCoordinatorTestV2.contract.Transact(opts, "removeConsumer", subId, consumer) +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2Session) RemoveConsumer(subId uint64, consumer common.Address) (*types.Transaction, error) { + return _VRFCoordinatorTestV2.Contract.RemoveConsumer(&_VRFCoordinatorTestV2.TransactOpts, subId, consumer) +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2TransactorSession) RemoveConsumer(subId uint64, consumer common.Address) (*types.Transaction, error) { + return _VRFCoordinatorTestV2.Contract.RemoveConsumer(&_VRFCoordinatorTestV2.TransactOpts, subId, consumer) +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2Transactor) RequestRandomWords(opts *bind.TransactOpts, keyHash [32]byte, subId uint64, requestConfirmations uint16, callbackGasLimit uint32, numWords uint32) (*types.Transaction, error) { + return _VRFCoordinatorTestV2.contract.Transact(opts, "requestRandomWords", keyHash, subId, requestConfirmations, callbackGasLimit, numWords) +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2Session) RequestRandomWords(keyHash [32]byte, subId uint64, requestConfirmations uint16, callbackGasLimit uint32, numWords uint32) (*types.Transaction, error) { + return _VRFCoordinatorTestV2.Contract.RequestRandomWords(&_VRFCoordinatorTestV2.TransactOpts, keyHash, subId, requestConfirmations, callbackGasLimit, numWords) +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2TransactorSession) RequestRandomWords(keyHash [32]byte, subId uint64, requestConfirmations uint16, callbackGasLimit uint32, numWords uint32) (*types.Transaction, error) { + return _VRFCoordinatorTestV2.Contract.RequestRandomWords(&_VRFCoordinatorTestV2.TransactOpts, keyHash, subId, requestConfirmations, callbackGasLimit, numWords) +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2Transactor) RequestSubscriptionOwnerTransfer(opts *bind.TransactOpts, subId uint64, newOwner common.Address) (*types.Transaction, error) { + return _VRFCoordinatorTestV2.contract.Transact(opts, "requestSubscriptionOwnerTransfer", subId, newOwner) +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2Session) RequestSubscriptionOwnerTransfer(subId uint64, newOwner common.Address) (*types.Transaction, error) { + return _VRFCoordinatorTestV2.Contract.RequestSubscriptionOwnerTransfer(&_VRFCoordinatorTestV2.TransactOpts, subId, newOwner) +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2TransactorSession) RequestSubscriptionOwnerTransfer(subId uint64, newOwner common.Address) (*types.Transaction, error) { + return _VRFCoordinatorTestV2.Contract.RequestSubscriptionOwnerTransfer(&_VRFCoordinatorTestV2.TransactOpts, subId, newOwner) +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2Transactor) SetConfig(opts *bind.TransactOpts, minimumRequestConfirmations uint16, maxGasLimit uint32, stalenessSeconds uint32, gasAfterPaymentCalculation uint32, fallbackWeiPerUnitLink *big.Int, feeConfig VRFCoordinatorTestV2FeeConfig) (*types.Transaction, error) { + return _VRFCoordinatorTestV2.contract.Transact(opts, "setConfig", minimumRequestConfirmations, maxGasLimit, stalenessSeconds, gasAfterPaymentCalculation, fallbackWeiPerUnitLink, feeConfig) +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2Session) SetConfig(minimumRequestConfirmations uint16, maxGasLimit uint32, stalenessSeconds uint32, gasAfterPaymentCalculation uint32, fallbackWeiPerUnitLink *big.Int, feeConfig VRFCoordinatorTestV2FeeConfig) (*types.Transaction, error) { + return _VRFCoordinatorTestV2.Contract.SetConfig(&_VRFCoordinatorTestV2.TransactOpts, minimumRequestConfirmations, maxGasLimit, stalenessSeconds, gasAfterPaymentCalculation, fallbackWeiPerUnitLink, feeConfig) +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2TransactorSession) SetConfig(minimumRequestConfirmations uint16, maxGasLimit uint32, stalenessSeconds uint32, gasAfterPaymentCalculation uint32, fallbackWeiPerUnitLink *big.Int, feeConfig VRFCoordinatorTestV2FeeConfig) (*types.Transaction, error) { + return _VRFCoordinatorTestV2.Contract.SetConfig(&_VRFCoordinatorTestV2.TransactOpts, minimumRequestConfirmations, maxGasLimit, stalenessSeconds, gasAfterPaymentCalculation, fallbackWeiPerUnitLink, feeConfig) +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2Transactor) TransferOwnership(opts *bind.TransactOpts, to common.Address) (*types.Transaction, error) { + return _VRFCoordinatorTestV2.contract.Transact(opts, "transferOwnership", to) +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2Session) TransferOwnership(to common.Address) (*types.Transaction, error) { + return _VRFCoordinatorTestV2.Contract.TransferOwnership(&_VRFCoordinatorTestV2.TransactOpts, to) +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2TransactorSession) TransferOwnership(to common.Address) (*types.Transaction, error) { + return _VRFCoordinatorTestV2.Contract.TransferOwnership(&_VRFCoordinatorTestV2.TransactOpts, to) +} + +type VRFCoordinatorTestV2ConfigSetIterator struct { + Event *VRFCoordinatorTestV2ConfigSet + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *VRFCoordinatorTestV2ConfigSetIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(VRFCoordinatorTestV2ConfigSet) + 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(VRFCoordinatorTestV2ConfigSet) + 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 *VRFCoordinatorTestV2ConfigSetIterator) Error() error { + return it.fail +} + +func (it *VRFCoordinatorTestV2ConfigSetIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type VRFCoordinatorTestV2ConfigSet struct { + MinimumRequestConfirmations uint16 + MaxGasLimit uint32 + StalenessSeconds uint32 + GasAfterPaymentCalculation uint32 + FallbackWeiPerUnitLink *big.Int + FeeConfig VRFCoordinatorTestV2FeeConfig + Raw types.Log +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2Filterer) FilterConfigSet(opts *bind.FilterOpts) (*VRFCoordinatorTestV2ConfigSetIterator, error) { + + logs, sub, err := _VRFCoordinatorTestV2.contract.FilterLogs(opts, "ConfigSet") + if err != nil { + return nil, err + } + return &VRFCoordinatorTestV2ConfigSetIterator{contract: _VRFCoordinatorTestV2.contract, event: "ConfigSet", logs: logs, sub: sub}, nil +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2Filterer) WatchConfigSet(opts *bind.WatchOpts, sink chan<- *VRFCoordinatorTestV2ConfigSet) (event.Subscription, error) { + + logs, sub, err := _VRFCoordinatorTestV2.contract.WatchLogs(opts, "ConfigSet") + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(VRFCoordinatorTestV2ConfigSet) + if err := _VRFCoordinatorTestV2.contract.UnpackLog(event, "ConfigSet", 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 (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2Filterer) ParseConfigSet(log types.Log) (*VRFCoordinatorTestV2ConfigSet, error) { + event := new(VRFCoordinatorTestV2ConfigSet) + if err := _VRFCoordinatorTestV2.contract.UnpackLog(event, "ConfigSet", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type VRFCoordinatorTestV2FundsRecoveredIterator struct { + Event *VRFCoordinatorTestV2FundsRecovered + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *VRFCoordinatorTestV2FundsRecoveredIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(VRFCoordinatorTestV2FundsRecovered) + 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(VRFCoordinatorTestV2FundsRecovered) + 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 *VRFCoordinatorTestV2FundsRecoveredIterator) Error() error { + return it.fail +} + +func (it *VRFCoordinatorTestV2FundsRecoveredIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type VRFCoordinatorTestV2FundsRecovered struct { + To common.Address + Amount *big.Int + Raw types.Log +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2Filterer) FilterFundsRecovered(opts *bind.FilterOpts) (*VRFCoordinatorTestV2FundsRecoveredIterator, error) { + + logs, sub, err := _VRFCoordinatorTestV2.contract.FilterLogs(opts, "FundsRecovered") + if err != nil { + return nil, err + } + return &VRFCoordinatorTestV2FundsRecoveredIterator{contract: _VRFCoordinatorTestV2.contract, event: "FundsRecovered", logs: logs, sub: sub}, nil +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2Filterer) WatchFundsRecovered(opts *bind.WatchOpts, sink chan<- *VRFCoordinatorTestV2FundsRecovered) (event.Subscription, error) { + + logs, sub, err := _VRFCoordinatorTestV2.contract.WatchLogs(opts, "FundsRecovered") + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(VRFCoordinatorTestV2FundsRecovered) + if err := _VRFCoordinatorTestV2.contract.UnpackLog(event, "FundsRecovered", 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 (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2Filterer) ParseFundsRecovered(log types.Log) (*VRFCoordinatorTestV2FundsRecovered, error) { + event := new(VRFCoordinatorTestV2FundsRecovered) + if err := _VRFCoordinatorTestV2.contract.UnpackLog(event, "FundsRecovered", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type VRFCoordinatorTestV2OwnershipTransferRequestedIterator struct { + Event *VRFCoordinatorTestV2OwnershipTransferRequested + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *VRFCoordinatorTestV2OwnershipTransferRequestedIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(VRFCoordinatorTestV2OwnershipTransferRequested) + 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(VRFCoordinatorTestV2OwnershipTransferRequested) + 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 *VRFCoordinatorTestV2OwnershipTransferRequestedIterator) Error() error { + return it.fail +} + +func (it *VRFCoordinatorTestV2OwnershipTransferRequestedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type VRFCoordinatorTestV2OwnershipTransferRequested struct { + From common.Address + To common.Address + Raw types.Log +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2Filterer) FilterOwnershipTransferRequested(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*VRFCoordinatorTestV2OwnershipTransferRequestedIterator, 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 := _VRFCoordinatorTestV2.contract.FilterLogs(opts, "OwnershipTransferRequested", fromRule, toRule) + if err != nil { + return nil, err + } + return &VRFCoordinatorTestV2OwnershipTransferRequestedIterator{contract: _VRFCoordinatorTestV2.contract, event: "OwnershipTransferRequested", logs: logs, sub: sub}, nil +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2Filterer) WatchOwnershipTransferRequested(opts *bind.WatchOpts, sink chan<- *VRFCoordinatorTestV2OwnershipTransferRequested, 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 := _VRFCoordinatorTestV2.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(VRFCoordinatorTestV2OwnershipTransferRequested) + if err := _VRFCoordinatorTestV2.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 (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2Filterer) ParseOwnershipTransferRequested(log types.Log) (*VRFCoordinatorTestV2OwnershipTransferRequested, error) { + event := new(VRFCoordinatorTestV2OwnershipTransferRequested) + if err := _VRFCoordinatorTestV2.contract.UnpackLog(event, "OwnershipTransferRequested", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type VRFCoordinatorTestV2OwnershipTransferredIterator struct { + Event *VRFCoordinatorTestV2OwnershipTransferred + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *VRFCoordinatorTestV2OwnershipTransferredIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(VRFCoordinatorTestV2OwnershipTransferred) + 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(VRFCoordinatorTestV2OwnershipTransferred) + 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 *VRFCoordinatorTestV2OwnershipTransferredIterator) Error() error { + return it.fail +} + +func (it *VRFCoordinatorTestV2OwnershipTransferredIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type VRFCoordinatorTestV2OwnershipTransferred struct { + From common.Address + To common.Address + Raw types.Log +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2Filterer) FilterOwnershipTransferred(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*VRFCoordinatorTestV2OwnershipTransferredIterator, 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 := _VRFCoordinatorTestV2.contract.FilterLogs(opts, "OwnershipTransferred", fromRule, toRule) + if err != nil { + return nil, err + } + return &VRFCoordinatorTestV2OwnershipTransferredIterator{contract: _VRFCoordinatorTestV2.contract, event: "OwnershipTransferred", logs: logs, sub: sub}, nil +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2Filterer) WatchOwnershipTransferred(opts *bind.WatchOpts, sink chan<- *VRFCoordinatorTestV2OwnershipTransferred, 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 := _VRFCoordinatorTestV2.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(VRFCoordinatorTestV2OwnershipTransferred) + if err := _VRFCoordinatorTestV2.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 (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2Filterer) ParseOwnershipTransferred(log types.Log) (*VRFCoordinatorTestV2OwnershipTransferred, error) { + event := new(VRFCoordinatorTestV2OwnershipTransferred) + if err := _VRFCoordinatorTestV2.contract.UnpackLog(event, "OwnershipTransferred", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type VRFCoordinatorTestV2ProvingKeyDeregisteredIterator struct { + Event *VRFCoordinatorTestV2ProvingKeyDeregistered + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *VRFCoordinatorTestV2ProvingKeyDeregisteredIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(VRFCoordinatorTestV2ProvingKeyDeregistered) + 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(VRFCoordinatorTestV2ProvingKeyDeregistered) + 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 *VRFCoordinatorTestV2ProvingKeyDeregisteredIterator) Error() error { + return it.fail +} + +func (it *VRFCoordinatorTestV2ProvingKeyDeregisteredIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type VRFCoordinatorTestV2ProvingKeyDeregistered struct { + KeyHash [32]byte + Oracle common.Address + Raw types.Log +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2Filterer) FilterProvingKeyDeregistered(opts *bind.FilterOpts, oracle []common.Address) (*VRFCoordinatorTestV2ProvingKeyDeregisteredIterator, error) { + + var oracleRule []interface{} + for _, oracleItem := range oracle { + oracleRule = append(oracleRule, oracleItem) + } + + logs, sub, err := _VRFCoordinatorTestV2.contract.FilterLogs(opts, "ProvingKeyDeregistered", oracleRule) + if err != nil { + return nil, err + } + return &VRFCoordinatorTestV2ProvingKeyDeregisteredIterator{contract: _VRFCoordinatorTestV2.contract, event: "ProvingKeyDeregistered", logs: logs, sub: sub}, nil +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2Filterer) WatchProvingKeyDeregistered(opts *bind.WatchOpts, sink chan<- *VRFCoordinatorTestV2ProvingKeyDeregistered, oracle []common.Address) (event.Subscription, error) { + + var oracleRule []interface{} + for _, oracleItem := range oracle { + oracleRule = append(oracleRule, oracleItem) + } + + logs, sub, err := _VRFCoordinatorTestV2.contract.WatchLogs(opts, "ProvingKeyDeregistered", oracleRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(VRFCoordinatorTestV2ProvingKeyDeregistered) + if err := _VRFCoordinatorTestV2.contract.UnpackLog(event, "ProvingKeyDeregistered", 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 (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2Filterer) ParseProvingKeyDeregistered(log types.Log) (*VRFCoordinatorTestV2ProvingKeyDeregistered, error) { + event := new(VRFCoordinatorTestV2ProvingKeyDeregistered) + if err := _VRFCoordinatorTestV2.contract.UnpackLog(event, "ProvingKeyDeregistered", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type VRFCoordinatorTestV2ProvingKeyRegisteredIterator struct { + Event *VRFCoordinatorTestV2ProvingKeyRegistered + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *VRFCoordinatorTestV2ProvingKeyRegisteredIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(VRFCoordinatorTestV2ProvingKeyRegistered) + 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(VRFCoordinatorTestV2ProvingKeyRegistered) + 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 *VRFCoordinatorTestV2ProvingKeyRegisteredIterator) Error() error { + return it.fail +} + +func (it *VRFCoordinatorTestV2ProvingKeyRegisteredIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type VRFCoordinatorTestV2ProvingKeyRegistered struct { + KeyHash [32]byte + Oracle common.Address + Raw types.Log +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2Filterer) FilterProvingKeyRegistered(opts *bind.FilterOpts, oracle []common.Address) (*VRFCoordinatorTestV2ProvingKeyRegisteredIterator, error) { + + var oracleRule []interface{} + for _, oracleItem := range oracle { + oracleRule = append(oracleRule, oracleItem) + } + + logs, sub, err := _VRFCoordinatorTestV2.contract.FilterLogs(opts, "ProvingKeyRegistered", oracleRule) + if err != nil { + return nil, err + } + return &VRFCoordinatorTestV2ProvingKeyRegisteredIterator{contract: _VRFCoordinatorTestV2.contract, event: "ProvingKeyRegistered", logs: logs, sub: sub}, nil +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2Filterer) WatchProvingKeyRegistered(opts *bind.WatchOpts, sink chan<- *VRFCoordinatorTestV2ProvingKeyRegistered, oracle []common.Address) (event.Subscription, error) { + + var oracleRule []interface{} + for _, oracleItem := range oracle { + oracleRule = append(oracleRule, oracleItem) + } + + logs, sub, err := _VRFCoordinatorTestV2.contract.WatchLogs(opts, "ProvingKeyRegistered", oracleRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(VRFCoordinatorTestV2ProvingKeyRegistered) + if err := _VRFCoordinatorTestV2.contract.UnpackLog(event, "ProvingKeyRegistered", 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 (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2Filterer) ParseProvingKeyRegistered(log types.Log) (*VRFCoordinatorTestV2ProvingKeyRegistered, error) { + event := new(VRFCoordinatorTestV2ProvingKeyRegistered) + if err := _VRFCoordinatorTestV2.contract.UnpackLog(event, "ProvingKeyRegistered", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type VRFCoordinatorTestV2RandomWordsFulfilledIterator struct { + Event *VRFCoordinatorTestV2RandomWordsFulfilled + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *VRFCoordinatorTestV2RandomWordsFulfilledIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(VRFCoordinatorTestV2RandomWordsFulfilled) + 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(VRFCoordinatorTestV2RandomWordsFulfilled) + 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 *VRFCoordinatorTestV2RandomWordsFulfilledIterator) Error() error { + return it.fail +} + +func (it *VRFCoordinatorTestV2RandomWordsFulfilledIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type VRFCoordinatorTestV2RandomWordsFulfilled struct { + RequestId *big.Int + OutputSeed *big.Int + Payment *big.Int + Success bool + Raw types.Log +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2Filterer) FilterRandomWordsFulfilled(opts *bind.FilterOpts, requestId []*big.Int) (*VRFCoordinatorTestV2RandomWordsFulfilledIterator, error) { + + var requestIdRule []interface{} + for _, requestIdItem := range requestId { + requestIdRule = append(requestIdRule, requestIdItem) + } + + logs, sub, err := _VRFCoordinatorTestV2.contract.FilterLogs(opts, "RandomWordsFulfilled", requestIdRule) + if err != nil { + return nil, err + } + return &VRFCoordinatorTestV2RandomWordsFulfilledIterator{contract: _VRFCoordinatorTestV2.contract, event: "RandomWordsFulfilled", logs: logs, sub: sub}, nil +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2Filterer) WatchRandomWordsFulfilled(opts *bind.WatchOpts, sink chan<- *VRFCoordinatorTestV2RandomWordsFulfilled, requestId []*big.Int) (event.Subscription, error) { + + var requestIdRule []interface{} + for _, requestIdItem := range requestId { + requestIdRule = append(requestIdRule, requestIdItem) + } + + logs, sub, err := _VRFCoordinatorTestV2.contract.WatchLogs(opts, "RandomWordsFulfilled", requestIdRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(VRFCoordinatorTestV2RandomWordsFulfilled) + if err := _VRFCoordinatorTestV2.contract.UnpackLog(event, "RandomWordsFulfilled", 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 (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2Filterer) ParseRandomWordsFulfilled(log types.Log) (*VRFCoordinatorTestV2RandomWordsFulfilled, error) { + event := new(VRFCoordinatorTestV2RandomWordsFulfilled) + if err := _VRFCoordinatorTestV2.contract.UnpackLog(event, "RandomWordsFulfilled", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type VRFCoordinatorTestV2RandomWordsRequestedIterator struct { + Event *VRFCoordinatorTestV2RandomWordsRequested + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *VRFCoordinatorTestV2RandomWordsRequestedIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(VRFCoordinatorTestV2RandomWordsRequested) + 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(VRFCoordinatorTestV2RandomWordsRequested) + 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 *VRFCoordinatorTestV2RandomWordsRequestedIterator) Error() error { + return it.fail +} + +func (it *VRFCoordinatorTestV2RandomWordsRequestedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type VRFCoordinatorTestV2RandomWordsRequested struct { + KeyHash [32]byte + RequestId *big.Int + PreSeed *big.Int + SubId uint64 + MinimumRequestConfirmations uint16 + CallbackGasLimit uint32 + NumWords uint32 + Sender common.Address + Raw types.Log +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2Filterer) FilterRandomWordsRequested(opts *bind.FilterOpts, keyHash [][32]byte, subId []uint64, sender []common.Address) (*VRFCoordinatorTestV2RandomWordsRequestedIterator, error) { + + var keyHashRule []interface{} + for _, keyHashItem := range keyHash { + keyHashRule = append(keyHashRule, keyHashItem) + } + + var subIdRule []interface{} + for _, subIdItem := range subId { + subIdRule = append(subIdRule, subIdItem) + } + + var senderRule []interface{} + for _, senderItem := range sender { + senderRule = append(senderRule, senderItem) + } + + logs, sub, err := _VRFCoordinatorTestV2.contract.FilterLogs(opts, "RandomWordsRequested", keyHashRule, subIdRule, senderRule) + if err != nil { + return nil, err + } + return &VRFCoordinatorTestV2RandomWordsRequestedIterator{contract: _VRFCoordinatorTestV2.contract, event: "RandomWordsRequested", logs: logs, sub: sub}, nil +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2Filterer) WatchRandomWordsRequested(opts *bind.WatchOpts, sink chan<- *VRFCoordinatorTestV2RandomWordsRequested, keyHash [][32]byte, subId []uint64, sender []common.Address) (event.Subscription, error) { + + var keyHashRule []interface{} + for _, keyHashItem := range keyHash { + keyHashRule = append(keyHashRule, keyHashItem) + } + + var subIdRule []interface{} + for _, subIdItem := range subId { + subIdRule = append(subIdRule, subIdItem) + } + + var senderRule []interface{} + for _, senderItem := range sender { + senderRule = append(senderRule, senderItem) + } + + logs, sub, err := _VRFCoordinatorTestV2.contract.WatchLogs(opts, "RandomWordsRequested", keyHashRule, subIdRule, senderRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(VRFCoordinatorTestV2RandomWordsRequested) + if err := _VRFCoordinatorTestV2.contract.UnpackLog(event, "RandomWordsRequested", 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 (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2Filterer) ParseRandomWordsRequested(log types.Log) (*VRFCoordinatorTestV2RandomWordsRequested, error) { + event := new(VRFCoordinatorTestV2RandomWordsRequested) + if err := _VRFCoordinatorTestV2.contract.UnpackLog(event, "RandomWordsRequested", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type VRFCoordinatorTestV2SubscriptionCanceledIterator struct { + Event *VRFCoordinatorTestV2SubscriptionCanceled + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *VRFCoordinatorTestV2SubscriptionCanceledIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(VRFCoordinatorTestV2SubscriptionCanceled) + 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(VRFCoordinatorTestV2SubscriptionCanceled) + 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 *VRFCoordinatorTestV2SubscriptionCanceledIterator) Error() error { + return it.fail +} + +func (it *VRFCoordinatorTestV2SubscriptionCanceledIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type VRFCoordinatorTestV2SubscriptionCanceled struct { + SubId uint64 + To common.Address + Amount *big.Int + Raw types.Log +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2Filterer) FilterSubscriptionCanceled(opts *bind.FilterOpts, subId []uint64) (*VRFCoordinatorTestV2SubscriptionCanceledIterator, error) { + + var subIdRule []interface{} + for _, subIdItem := range subId { + subIdRule = append(subIdRule, subIdItem) + } + + logs, sub, err := _VRFCoordinatorTestV2.contract.FilterLogs(opts, "SubscriptionCanceled", subIdRule) + if err != nil { + return nil, err + } + return &VRFCoordinatorTestV2SubscriptionCanceledIterator{contract: _VRFCoordinatorTestV2.contract, event: "SubscriptionCanceled", logs: logs, sub: sub}, nil +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2Filterer) WatchSubscriptionCanceled(opts *bind.WatchOpts, sink chan<- *VRFCoordinatorTestV2SubscriptionCanceled, subId []uint64) (event.Subscription, error) { + + var subIdRule []interface{} + for _, subIdItem := range subId { + subIdRule = append(subIdRule, subIdItem) + } + + logs, sub, err := _VRFCoordinatorTestV2.contract.WatchLogs(opts, "SubscriptionCanceled", subIdRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(VRFCoordinatorTestV2SubscriptionCanceled) + if err := _VRFCoordinatorTestV2.contract.UnpackLog(event, "SubscriptionCanceled", 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 (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2Filterer) ParseSubscriptionCanceled(log types.Log) (*VRFCoordinatorTestV2SubscriptionCanceled, error) { + event := new(VRFCoordinatorTestV2SubscriptionCanceled) + if err := _VRFCoordinatorTestV2.contract.UnpackLog(event, "SubscriptionCanceled", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type VRFCoordinatorTestV2SubscriptionConsumerAddedIterator struct { + Event *VRFCoordinatorTestV2SubscriptionConsumerAdded + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *VRFCoordinatorTestV2SubscriptionConsumerAddedIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(VRFCoordinatorTestV2SubscriptionConsumerAdded) + 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(VRFCoordinatorTestV2SubscriptionConsumerAdded) + 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 *VRFCoordinatorTestV2SubscriptionConsumerAddedIterator) Error() error { + return it.fail +} + +func (it *VRFCoordinatorTestV2SubscriptionConsumerAddedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type VRFCoordinatorTestV2SubscriptionConsumerAdded struct { + SubId uint64 + Consumer common.Address + Raw types.Log +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2Filterer) FilterSubscriptionConsumerAdded(opts *bind.FilterOpts, subId []uint64) (*VRFCoordinatorTestV2SubscriptionConsumerAddedIterator, error) { + + var subIdRule []interface{} + for _, subIdItem := range subId { + subIdRule = append(subIdRule, subIdItem) + } + + logs, sub, err := _VRFCoordinatorTestV2.contract.FilterLogs(opts, "SubscriptionConsumerAdded", subIdRule) + if err != nil { + return nil, err + } + return &VRFCoordinatorTestV2SubscriptionConsumerAddedIterator{contract: _VRFCoordinatorTestV2.contract, event: "SubscriptionConsumerAdded", logs: logs, sub: sub}, nil +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2Filterer) WatchSubscriptionConsumerAdded(opts *bind.WatchOpts, sink chan<- *VRFCoordinatorTestV2SubscriptionConsumerAdded, subId []uint64) (event.Subscription, error) { + + var subIdRule []interface{} + for _, subIdItem := range subId { + subIdRule = append(subIdRule, subIdItem) + } + + logs, sub, err := _VRFCoordinatorTestV2.contract.WatchLogs(opts, "SubscriptionConsumerAdded", subIdRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(VRFCoordinatorTestV2SubscriptionConsumerAdded) + if err := _VRFCoordinatorTestV2.contract.UnpackLog(event, "SubscriptionConsumerAdded", 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 (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2Filterer) ParseSubscriptionConsumerAdded(log types.Log) (*VRFCoordinatorTestV2SubscriptionConsumerAdded, error) { + event := new(VRFCoordinatorTestV2SubscriptionConsumerAdded) + if err := _VRFCoordinatorTestV2.contract.UnpackLog(event, "SubscriptionConsumerAdded", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type VRFCoordinatorTestV2SubscriptionConsumerRemovedIterator struct { + Event *VRFCoordinatorTestV2SubscriptionConsumerRemoved + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *VRFCoordinatorTestV2SubscriptionConsumerRemovedIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(VRFCoordinatorTestV2SubscriptionConsumerRemoved) + 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(VRFCoordinatorTestV2SubscriptionConsumerRemoved) + 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 *VRFCoordinatorTestV2SubscriptionConsumerRemovedIterator) Error() error { + return it.fail +} + +func (it *VRFCoordinatorTestV2SubscriptionConsumerRemovedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type VRFCoordinatorTestV2SubscriptionConsumerRemoved struct { + SubId uint64 + Consumer common.Address + Raw types.Log +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2Filterer) FilterSubscriptionConsumerRemoved(opts *bind.FilterOpts, subId []uint64) (*VRFCoordinatorTestV2SubscriptionConsumerRemovedIterator, error) { + + var subIdRule []interface{} + for _, subIdItem := range subId { + subIdRule = append(subIdRule, subIdItem) + } + + logs, sub, err := _VRFCoordinatorTestV2.contract.FilterLogs(opts, "SubscriptionConsumerRemoved", subIdRule) + if err != nil { + return nil, err + } + return &VRFCoordinatorTestV2SubscriptionConsumerRemovedIterator{contract: _VRFCoordinatorTestV2.contract, event: "SubscriptionConsumerRemoved", logs: logs, sub: sub}, nil +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2Filterer) WatchSubscriptionConsumerRemoved(opts *bind.WatchOpts, sink chan<- *VRFCoordinatorTestV2SubscriptionConsumerRemoved, subId []uint64) (event.Subscription, error) { + + var subIdRule []interface{} + for _, subIdItem := range subId { + subIdRule = append(subIdRule, subIdItem) + } + + logs, sub, err := _VRFCoordinatorTestV2.contract.WatchLogs(opts, "SubscriptionConsumerRemoved", subIdRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(VRFCoordinatorTestV2SubscriptionConsumerRemoved) + if err := _VRFCoordinatorTestV2.contract.UnpackLog(event, "SubscriptionConsumerRemoved", 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 (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2Filterer) ParseSubscriptionConsumerRemoved(log types.Log) (*VRFCoordinatorTestV2SubscriptionConsumerRemoved, error) { + event := new(VRFCoordinatorTestV2SubscriptionConsumerRemoved) + if err := _VRFCoordinatorTestV2.contract.UnpackLog(event, "SubscriptionConsumerRemoved", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type VRFCoordinatorTestV2SubscriptionCreatedIterator struct { + Event *VRFCoordinatorTestV2SubscriptionCreated + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *VRFCoordinatorTestV2SubscriptionCreatedIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(VRFCoordinatorTestV2SubscriptionCreated) + 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(VRFCoordinatorTestV2SubscriptionCreated) + 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 *VRFCoordinatorTestV2SubscriptionCreatedIterator) Error() error { + return it.fail +} + +func (it *VRFCoordinatorTestV2SubscriptionCreatedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type VRFCoordinatorTestV2SubscriptionCreated struct { + SubId uint64 + Owner common.Address + Raw types.Log +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2Filterer) FilterSubscriptionCreated(opts *bind.FilterOpts, subId []uint64) (*VRFCoordinatorTestV2SubscriptionCreatedIterator, error) { + + var subIdRule []interface{} + for _, subIdItem := range subId { + subIdRule = append(subIdRule, subIdItem) + } + + logs, sub, err := _VRFCoordinatorTestV2.contract.FilterLogs(opts, "SubscriptionCreated", subIdRule) + if err != nil { + return nil, err + } + return &VRFCoordinatorTestV2SubscriptionCreatedIterator{contract: _VRFCoordinatorTestV2.contract, event: "SubscriptionCreated", logs: logs, sub: sub}, nil +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2Filterer) WatchSubscriptionCreated(opts *bind.WatchOpts, sink chan<- *VRFCoordinatorTestV2SubscriptionCreated, subId []uint64) (event.Subscription, error) { + + var subIdRule []interface{} + for _, subIdItem := range subId { + subIdRule = append(subIdRule, subIdItem) + } + + logs, sub, err := _VRFCoordinatorTestV2.contract.WatchLogs(opts, "SubscriptionCreated", subIdRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(VRFCoordinatorTestV2SubscriptionCreated) + if err := _VRFCoordinatorTestV2.contract.UnpackLog(event, "SubscriptionCreated", 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 (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2Filterer) ParseSubscriptionCreated(log types.Log) (*VRFCoordinatorTestV2SubscriptionCreated, error) { + event := new(VRFCoordinatorTestV2SubscriptionCreated) + if err := _VRFCoordinatorTestV2.contract.UnpackLog(event, "SubscriptionCreated", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type VRFCoordinatorTestV2SubscriptionFundedIterator struct { + Event *VRFCoordinatorTestV2SubscriptionFunded + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *VRFCoordinatorTestV2SubscriptionFundedIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(VRFCoordinatorTestV2SubscriptionFunded) + 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(VRFCoordinatorTestV2SubscriptionFunded) + 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 *VRFCoordinatorTestV2SubscriptionFundedIterator) Error() error { + return it.fail +} + +func (it *VRFCoordinatorTestV2SubscriptionFundedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type VRFCoordinatorTestV2SubscriptionFunded struct { + SubId uint64 + OldBalance *big.Int + NewBalance *big.Int + Raw types.Log +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2Filterer) FilterSubscriptionFunded(opts *bind.FilterOpts, subId []uint64) (*VRFCoordinatorTestV2SubscriptionFundedIterator, error) { + + var subIdRule []interface{} + for _, subIdItem := range subId { + subIdRule = append(subIdRule, subIdItem) + } + + logs, sub, err := _VRFCoordinatorTestV2.contract.FilterLogs(opts, "SubscriptionFunded", subIdRule) + if err != nil { + return nil, err + } + return &VRFCoordinatorTestV2SubscriptionFundedIterator{contract: _VRFCoordinatorTestV2.contract, event: "SubscriptionFunded", logs: logs, sub: sub}, nil +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2Filterer) WatchSubscriptionFunded(opts *bind.WatchOpts, sink chan<- *VRFCoordinatorTestV2SubscriptionFunded, subId []uint64) (event.Subscription, error) { + + var subIdRule []interface{} + for _, subIdItem := range subId { + subIdRule = append(subIdRule, subIdItem) + } + + logs, sub, err := _VRFCoordinatorTestV2.contract.WatchLogs(opts, "SubscriptionFunded", subIdRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(VRFCoordinatorTestV2SubscriptionFunded) + if err := _VRFCoordinatorTestV2.contract.UnpackLog(event, "SubscriptionFunded", 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 (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2Filterer) ParseSubscriptionFunded(log types.Log) (*VRFCoordinatorTestV2SubscriptionFunded, error) { + event := new(VRFCoordinatorTestV2SubscriptionFunded) + if err := _VRFCoordinatorTestV2.contract.UnpackLog(event, "SubscriptionFunded", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type VRFCoordinatorTestV2SubscriptionOwnerTransferRequestedIterator struct { + Event *VRFCoordinatorTestV2SubscriptionOwnerTransferRequested + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *VRFCoordinatorTestV2SubscriptionOwnerTransferRequestedIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(VRFCoordinatorTestV2SubscriptionOwnerTransferRequested) + 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(VRFCoordinatorTestV2SubscriptionOwnerTransferRequested) + 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 *VRFCoordinatorTestV2SubscriptionOwnerTransferRequestedIterator) Error() error { + return it.fail +} + +func (it *VRFCoordinatorTestV2SubscriptionOwnerTransferRequestedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type VRFCoordinatorTestV2SubscriptionOwnerTransferRequested struct { + SubId uint64 + From common.Address + To common.Address + Raw types.Log +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2Filterer) FilterSubscriptionOwnerTransferRequested(opts *bind.FilterOpts, subId []uint64) (*VRFCoordinatorTestV2SubscriptionOwnerTransferRequestedIterator, error) { + + var subIdRule []interface{} + for _, subIdItem := range subId { + subIdRule = append(subIdRule, subIdItem) + } + + logs, sub, err := _VRFCoordinatorTestV2.contract.FilterLogs(opts, "SubscriptionOwnerTransferRequested", subIdRule) + if err != nil { + return nil, err + } + return &VRFCoordinatorTestV2SubscriptionOwnerTransferRequestedIterator{contract: _VRFCoordinatorTestV2.contract, event: "SubscriptionOwnerTransferRequested", logs: logs, sub: sub}, nil +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2Filterer) WatchSubscriptionOwnerTransferRequested(opts *bind.WatchOpts, sink chan<- *VRFCoordinatorTestV2SubscriptionOwnerTransferRequested, subId []uint64) (event.Subscription, error) { + + var subIdRule []interface{} + for _, subIdItem := range subId { + subIdRule = append(subIdRule, subIdItem) + } + + logs, sub, err := _VRFCoordinatorTestV2.contract.WatchLogs(opts, "SubscriptionOwnerTransferRequested", subIdRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(VRFCoordinatorTestV2SubscriptionOwnerTransferRequested) + if err := _VRFCoordinatorTestV2.contract.UnpackLog(event, "SubscriptionOwnerTransferRequested", 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 (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2Filterer) ParseSubscriptionOwnerTransferRequested(log types.Log) (*VRFCoordinatorTestV2SubscriptionOwnerTransferRequested, error) { + event := new(VRFCoordinatorTestV2SubscriptionOwnerTransferRequested) + if err := _VRFCoordinatorTestV2.contract.UnpackLog(event, "SubscriptionOwnerTransferRequested", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type VRFCoordinatorTestV2SubscriptionOwnerTransferredIterator struct { + Event *VRFCoordinatorTestV2SubscriptionOwnerTransferred + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *VRFCoordinatorTestV2SubscriptionOwnerTransferredIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(VRFCoordinatorTestV2SubscriptionOwnerTransferred) + 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(VRFCoordinatorTestV2SubscriptionOwnerTransferred) + 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 *VRFCoordinatorTestV2SubscriptionOwnerTransferredIterator) Error() error { + return it.fail +} + +func (it *VRFCoordinatorTestV2SubscriptionOwnerTransferredIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type VRFCoordinatorTestV2SubscriptionOwnerTransferred struct { + SubId uint64 + From common.Address + To common.Address + Raw types.Log +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2Filterer) FilterSubscriptionOwnerTransferred(opts *bind.FilterOpts, subId []uint64) (*VRFCoordinatorTestV2SubscriptionOwnerTransferredIterator, error) { + + var subIdRule []interface{} + for _, subIdItem := range subId { + subIdRule = append(subIdRule, subIdItem) + } + + logs, sub, err := _VRFCoordinatorTestV2.contract.FilterLogs(opts, "SubscriptionOwnerTransferred", subIdRule) + if err != nil { + return nil, err + } + return &VRFCoordinatorTestV2SubscriptionOwnerTransferredIterator{contract: _VRFCoordinatorTestV2.contract, event: "SubscriptionOwnerTransferred", logs: logs, sub: sub}, nil +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2Filterer) WatchSubscriptionOwnerTransferred(opts *bind.WatchOpts, sink chan<- *VRFCoordinatorTestV2SubscriptionOwnerTransferred, subId []uint64) (event.Subscription, error) { + + var subIdRule []interface{} + for _, subIdItem := range subId { + subIdRule = append(subIdRule, subIdItem) + } + + logs, sub, err := _VRFCoordinatorTestV2.contract.WatchLogs(opts, "SubscriptionOwnerTransferred", subIdRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(VRFCoordinatorTestV2SubscriptionOwnerTransferred) + if err := _VRFCoordinatorTestV2.contract.UnpackLog(event, "SubscriptionOwnerTransferred", 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 (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2Filterer) ParseSubscriptionOwnerTransferred(log types.Log) (*VRFCoordinatorTestV2SubscriptionOwnerTransferred, error) { + event := new(VRFCoordinatorTestV2SubscriptionOwnerTransferred) + if err := _VRFCoordinatorTestV2.contract.UnpackLog(event, "SubscriptionOwnerTransferred", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type GetConfig struct { + MinimumRequestConfirmations uint16 + MaxGasLimit uint32 + StalenessSeconds uint32 + GasAfterPaymentCalculation uint32 +} +type GetFeeConfig struct { + FulfillmentFlatFeeLinkPPMTier1 uint32 + FulfillmentFlatFeeLinkPPMTier2 uint32 + FulfillmentFlatFeeLinkPPMTier3 uint32 + FulfillmentFlatFeeLinkPPMTier4 uint32 + FulfillmentFlatFeeLinkPPMTier5 uint32 + ReqsForTier2 *big.Int + ReqsForTier3 *big.Int + ReqsForTier4 *big.Int + ReqsForTier5 *big.Int +} +type GetSubscription struct { + Balance *big.Int + ReqCount uint64 + Owner common.Address + Consumers []common.Address +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2) ParseLog(log types.Log) (generated.AbigenLog, error) { + switch log.Topics[0] { + case _VRFCoordinatorTestV2.abi.Events["ConfigSet"].ID: + return _VRFCoordinatorTestV2.ParseConfigSet(log) + case _VRFCoordinatorTestV2.abi.Events["FundsRecovered"].ID: + return _VRFCoordinatorTestV2.ParseFundsRecovered(log) + case _VRFCoordinatorTestV2.abi.Events["OwnershipTransferRequested"].ID: + return _VRFCoordinatorTestV2.ParseOwnershipTransferRequested(log) + case _VRFCoordinatorTestV2.abi.Events["OwnershipTransferred"].ID: + return _VRFCoordinatorTestV2.ParseOwnershipTransferred(log) + case _VRFCoordinatorTestV2.abi.Events["ProvingKeyDeregistered"].ID: + return _VRFCoordinatorTestV2.ParseProvingKeyDeregistered(log) + case _VRFCoordinatorTestV2.abi.Events["ProvingKeyRegistered"].ID: + return _VRFCoordinatorTestV2.ParseProvingKeyRegistered(log) + case _VRFCoordinatorTestV2.abi.Events["RandomWordsFulfilled"].ID: + return _VRFCoordinatorTestV2.ParseRandomWordsFulfilled(log) + case _VRFCoordinatorTestV2.abi.Events["RandomWordsRequested"].ID: + return _VRFCoordinatorTestV2.ParseRandomWordsRequested(log) + case _VRFCoordinatorTestV2.abi.Events["SubscriptionCanceled"].ID: + return _VRFCoordinatorTestV2.ParseSubscriptionCanceled(log) + case _VRFCoordinatorTestV2.abi.Events["SubscriptionConsumerAdded"].ID: + return _VRFCoordinatorTestV2.ParseSubscriptionConsumerAdded(log) + case _VRFCoordinatorTestV2.abi.Events["SubscriptionConsumerRemoved"].ID: + return _VRFCoordinatorTestV2.ParseSubscriptionConsumerRemoved(log) + case _VRFCoordinatorTestV2.abi.Events["SubscriptionCreated"].ID: + return _VRFCoordinatorTestV2.ParseSubscriptionCreated(log) + case _VRFCoordinatorTestV2.abi.Events["SubscriptionFunded"].ID: + return _VRFCoordinatorTestV2.ParseSubscriptionFunded(log) + case _VRFCoordinatorTestV2.abi.Events["SubscriptionOwnerTransferRequested"].ID: + return _VRFCoordinatorTestV2.ParseSubscriptionOwnerTransferRequested(log) + case _VRFCoordinatorTestV2.abi.Events["SubscriptionOwnerTransferred"].ID: + return _VRFCoordinatorTestV2.ParseSubscriptionOwnerTransferred(log) + + default: + return nil, fmt.Errorf("abigen wrapper received unknown log topic: %v", log.Topics[0]) + } +} + +func (VRFCoordinatorTestV2ConfigSet) Topic() common.Hash { + return common.HexToHash("0xc21e3bd2e0b339d2848f0dd956947a88966c242c0c0c582a33137a5c1ceb5cb2") +} + +func (VRFCoordinatorTestV2FundsRecovered) Topic() common.Hash { + return common.HexToHash("0x59bfc682b673f8cbf945f1e454df9334834abf7dfe7f92237ca29ecb9b436600") +} + +func (VRFCoordinatorTestV2OwnershipTransferRequested) Topic() common.Hash { + return common.HexToHash("0xed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae1278") +} + +func (VRFCoordinatorTestV2OwnershipTransferred) Topic() common.Hash { + return common.HexToHash("0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0") +} + +func (VRFCoordinatorTestV2ProvingKeyDeregistered) Topic() common.Hash { + return common.HexToHash("0x72be339577868f868798bac2c93e52d6f034fef4689a9848996c14ebb7416c0d") +} + +func (VRFCoordinatorTestV2ProvingKeyRegistered) Topic() common.Hash { + return common.HexToHash("0xe729ae16526293f74ade739043022254f1489f616295a25bf72dfb4511ed73b8") +} + +func (VRFCoordinatorTestV2RandomWordsFulfilled) Topic() common.Hash { + return common.HexToHash("0x7dffc5ae5ee4e2e4df1651cf6ad329a73cebdb728f37ea0187b9b17e036756e4") +} + +func (VRFCoordinatorTestV2RandomWordsRequested) Topic() common.Hash { + return common.HexToHash("0x63373d1c4696214b898952999c9aaec57dac1ee2723cec59bea6888f489a9772") +} + +func (VRFCoordinatorTestV2SubscriptionCanceled) Topic() common.Hash { + return common.HexToHash("0xe8ed5b475a5b5987aa9165e8731bb78043f39eee32ec5a1169a89e27fcd49815") +} + +func (VRFCoordinatorTestV2SubscriptionConsumerAdded) Topic() common.Hash { + return common.HexToHash("0x43dc749a04ac8fb825cbd514f7c0e13f13bc6f2ee66043b76629d51776cff8e0") +} + +func (VRFCoordinatorTestV2SubscriptionConsumerRemoved) Topic() common.Hash { + return common.HexToHash("0x182bff9831466789164ca77075fffd84916d35a8180ba73c27e45634549b445b") +} + +func (VRFCoordinatorTestV2SubscriptionCreated) Topic() common.Hash { + return common.HexToHash("0x464722b4166576d3dcbba877b999bc35cf911f4eaf434b7eba68fa113951d0bf") +} + +func (VRFCoordinatorTestV2SubscriptionFunded) Topic() common.Hash { + return common.HexToHash("0xd39ec07f4e209f627a4c427971473820dc129761ba28de8906bd56f57101d4f8") +} + +func (VRFCoordinatorTestV2SubscriptionOwnerTransferRequested) Topic() common.Hash { + return common.HexToHash("0x69436ea6df009049404f564eff6622cd00522b0bd6a89efd9e52a355c4a879be") +} + +func (VRFCoordinatorTestV2SubscriptionOwnerTransferred) Topic() common.Hash { + return common.HexToHash("0x6f1dc65165ffffedfd8e507b4a0f1fcfdada045ed11f6c26ba27cedfe87802f0") +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2) Address() common.Address { + return _VRFCoordinatorTestV2.address +} + +type VRFCoordinatorTestV2Interface interface { + BLOCKHASHSTORE(opts *bind.CallOpts) (common.Address, error) + + LINK(opts *bind.CallOpts) (common.Address, error) + + LINKETHFEED(opts *bind.CallOpts) (common.Address, error) + + MAXCONSUMERS(opts *bind.CallOpts) (uint16, error) + + MAXNUMWORDS(opts *bind.CallOpts) (uint32, error) + + MAXREQUESTCONFIRMATIONS(opts *bind.CallOpts) (uint16, error) + + GetCommitment(opts *bind.CallOpts, requestId *big.Int) ([32]byte, error) + + GetConfig(opts *bind.CallOpts) (GetConfig, + + error) + + GetCurrentSubId(opts *bind.CallOpts) (uint64, error) + + GetFallbackWeiPerUnitLink(opts *bind.CallOpts) (*big.Int, error) + + GetFeeConfig(opts *bind.CallOpts) (GetFeeConfig, + + error) + + GetFeeTier(opts *bind.CallOpts, reqCount uint64) (uint32, error) + + GetRequestConfig(opts *bind.CallOpts) (uint16, uint32, [][32]byte, error) + + GetSubscription(opts *bind.CallOpts, subId uint64) (GetSubscription, + + error) + + GetTotalBalance(opts *bind.CallOpts) (*big.Int, error) + + HashOfKey(opts *bind.CallOpts, publicKey [2]*big.Int) ([32]byte, error) + + Owner(opts *bind.CallOpts) (common.Address, error) + + PendingRequestExists(opts *bind.CallOpts, subId uint64) (bool, error) + + TypeAndVersion(opts *bind.CallOpts) (string, error) + + AcceptOwnership(opts *bind.TransactOpts) (*types.Transaction, error) + + AcceptSubscriptionOwnerTransfer(opts *bind.TransactOpts, subId uint64) (*types.Transaction, error) + + AddConsumer(opts *bind.TransactOpts, subId uint64, consumer common.Address) (*types.Transaction, error) + + CancelSubscription(opts *bind.TransactOpts, subId uint64, to common.Address) (*types.Transaction, error) + + CreateSubscription(opts *bind.TransactOpts) (*types.Transaction, error) + + DeregisterProvingKey(opts *bind.TransactOpts, publicProvingKey [2]*big.Int) (*types.Transaction, error) + + FulfillRandomWords(opts *bind.TransactOpts, proof VRFProof, rc VRFCoordinatorTestV2RequestCommitment) (*types.Transaction, error) + + OnTokenTransfer(opts *bind.TransactOpts, arg0 common.Address, amount *big.Int, data []byte) (*types.Transaction, error) + + OracleWithdraw(opts *bind.TransactOpts, recipient common.Address, amount *big.Int) (*types.Transaction, error) + + OwnerCancelSubscription(opts *bind.TransactOpts, subId uint64) (*types.Transaction, error) + + RecoverFunds(opts *bind.TransactOpts, to common.Address) (*types.Transaction, error) + + RegisterProvingKey(opts *bind.TransactOpts, oracle common.Address, publicProvingKey [2]*big.Int) (*types.Transaction, error) + + RemoveConsumer(opts *bind.TransactOpts, subId uint64, consumer common.Address) (*types.Transaction, error) + + RequestRandomWords(opts *bind.TransactOpts, keyHash [32]byte, subId uint64, requestConfirmations uint16, callbackGasLimit uint32, numWords uint32) (*types.Transaction, error) + + RequestSubscriptionOwnerTransfer(opts *bind.TransactOpts, subId uint64, newOwner common.Address) (*types.Transaction, error) + + SetConfig(opts *bind.TransactOpts, minimumRequestConfirmations uint16, maxGasLimit uint32, stalenessSeconds uint32, gasAfterPaymentCalculation uint32, fallbackWeiPerUnitLink *big.Int, feeConfig VRFCoordinatorTestV2FeeConfig) (*types.Transaction, error) + + TransferOwnership(opts *bind.TransactOpts, to common.Address) (*types.Transaction, error) + + FilterConfigSet(opts *bind.FilterOpts) (*VRFCoordinatorTestV2ConfigSetIterator, error) + + WatchConfigSet(opts *bind.WatchOpts, sink chan<- *VRFCoordinatorTestV2ConfigSet) (event.Subscription, error) + + ParseConfigSet(log types.Log) (*VRFCoordinatorTestV2ConfigSet, error) + + FilterFundsRecovered(opts *bind.FilterOpts) (*VRFCoordinatorTestV2FundsRecoveredIterator, error) + + WatchFundsRecovered(opts *bind.WatchOpts, sink chan<- *VRFCoordinatorTestV2FundsRecovered) (event.Subscription, error) + + ParseFundsRecovered(log types.Log) (*VRFCoordinatorTestV2FundsRecovered, error) + + FilterOwnershipTransferRequested(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*VRFCoordinatorTestV2OwnershipTransferRequestedIterator, error) + + WatchOwnershipTransferRequested(opts *bind.WatchOpts, sink chan<- *VRFCoordinatorTestV2OwnershipTransferRequested, from []common.Address, to []common.Address) (event.Subscription, error) + + ParseOwnershipTransferRequested(log types.Log) (*VRFCoordinatorTestV2OwnershipTransferRequested, error) + + FilterOwnershipTransferred(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*VRFCoordinatorTestV2OwnershipTransferredIterator, error) + + WatchOwnershipTransferred(opts *bind.WatchOpts, sink chan<- *VRFCoordinatorTestV2OwnershipTransferred, from []common.Address, to []common.Address) (event.Subscription, error) + + ParseOwnershipTransferred(log types.Log) (*VRFCoordinatorTestV2OwnershipTransferred, error) + + FilterProvingKeyDeregistered(opts *bind.FilterOpts, oracle []common.Address) (*VRFCoordinatorTestV2ProvingKeyDeregisteredIterator, error) + + WatchProvingKeyDeregistered(opts *bind.WatchOpts, sink chan<- *VRFCoordinatorTestV2ProvingKeyDeregistered, oracle []common.Address) (event.Subscription, error) + + ParseProvingKeyDeregistered(log types.Log) (*VRFCoordinatorTestV2ProvingKeyDeregistered, error) + + FilterProvingKeyRegistered(opts *bind.FilterOpts, oracle []common.Address) (*VRFCoordinatorTestV2ProvingKeyRegisteredIterator, error) + + WatchProvingKeyRegistered(opts *bind.WatchOpts, sink chan<- *VRFCoordinatorTestV2ProvingKeyRegistered, oracle []common.Address) (event.Subscription, error) + + ParseProvingKeyRegistered(log types.Log) (*VRFCoordinatorTestV2ProvingKeyRegistered, error) + + FilterRandomWordsFulfilled(opts *bind.FilterOpts, requestId []*big.Int) (*VRFCoordinatorTestV2RandomWordsFulfilledIterator, error) + + WatchRandomWordsFulfilled(opts *bind.WatchOpts, sink chan<- *VRFCoordinatorTestV2RandomWordsFulfilled, requestId []*big.Int) (event.Subscription, error) + + ParseRandomWordsFulfilled(log types.Log) (*VRFCoordinatorTestV2RandomWordsFulfilled, error) + + FilterRandomWordsRequested(opts *bind.FilterOpts, keyHash [][32]byte, subId []uint64, sender []common.Address) (*VRFCoordinatorTestV2RandomWordsRequestedIterator, error) + + WatchRandomWordsRequested(opts *bind.WatchOpts, sink chan<- *VRFCoordinatorTestV2RandomWordsRequested, keyHash [][32]byte, subId []uint64, sender []common.Address) (event.Subscription, error) + + ParseRandomWordsRequested(log types.Log) (*VRFCoordinatorTestV2RandomWordsRequested, error) + + FilterSubscriptionCanceled(opts *bind.FilterOpts, subId []uint64) (*VRFCoordinatorTestV2SubscriptionCanceledIterator, error) + + WatchSubscriptionCanceled(opts *bind.WatchOpts, sink chan<- *VRFCoordinatorTestV2SubscriptionCanceled, subId []uint64) (event.Subscription, error) + + ParseSubscriptionCanceled(log types.Log) (*VRFCoordinatorTestV2SubscriptionCanceled, error) + + FilterSubscriptionConsumerAdded(opts *bind.FilterOpts, subId []uint64) (*VRFCoordinatorTestV2SubscriptionConsumerAddedIterator, error) + + WatchSubscriptionConsumerAdded(opts *bind.WatchOpts, sink chan<- *VRFCoordinatorTestV2SubscriptionConsumerAdded, subId []uint64) (event.Subscription, error) + + ParseSubscriptionConsumerAdded(log types.Log) (*VRFCoordinatorTestV2SubscriptionConsumerAdded, error) + + FilterSubscriptionConsumerRemoved(opts *bind.FilterOpts, subId []uint64) (*VRFCoordinatorTestV2SubscriptionConsumerRemovedIterator, error) + + WatchSubscriptionConsumerRemoved(opts *bind.WatchOpts, sink chan<- *VRFCoordinatorTestV2SubscriptionConsumerRemoved, subId []uint64) (event.Subscription, error) + + ParseSubscriptionConsumerRemoved(log types.Log) (*VRFCoordinatorTestV2SubscriptionConsumerRemoved, error) + + FilterSubscriptionCreated(opts *bind.FilterOpts, subId []uint64) (*VRFCoordinatorTestV2SubscriptionCreatedIterator, error) + + WatchSubscriptionCreated(opts *bind.WatchOpts, sink chan<- *VRFCoordinatorTestV2SubscriptionCreated, subId []uint64) (event.Subscription, error) + + ParseSubscriptionCreated(log types.Log) (*VRFCoordinatorTestV2SubscriptionCreated, error) + + FilterSubscriptionFunded(opts *bind.FilterOpts, subId []uint64) (*VRFCoordinatorTestV2SubscriptionFundedIterator, error) + + WatchSubscriptionFunded(opts *bind.WatchOpts, sink chan<- *VRFCoordinatorTestV2SubscriptionFunded, subId []uint64) (event.Subscription, error) + + ParseSubscriptionFunded(log types.Log) (*VRFCoordinatorTestV2SubscriptionFunded, error) + + FilterSubscriptionOwnerTransferRequested(opts *bind.FilterOpts, subId []uint64) (*VRFCoordinatorTestV2SubscriptionOwnerTransferRequestedIterator, error) + + WatchSubscriptionOwnerTransferRequested(opts *bind.WatchOpts, sink chan<- *VRFCoordinatorTestV2SubscriptionOwnerTransferRequested, subId []uint64) (event.Subscription, error) + + ParseSubscriptionOwnerTransferRequested(log types.Log) (*VRFCoordinatorTestV2SubscriptionOwnerTransferRequested, error) + + FilterSubscriptionOwnerTransferred(opts *bind.FilterOpts, subId []uint64) (*VRFCoordinatorTestV2SubscriptionOwnerTransferredIterator, error) + + WatchSubscriptionOwnerTransferred(opts *bind.WatchOpts, sink chan<- *VRFCoordinatorTestV2SubscriptionOwnerTransferred, subId []uint64) (event.Subscription, error) + + ParseSubscriptionOwnerTransferred(log types.Log) (*VRFCoordinatorTestV2SubscriptionOwnerTransferred, error) + + ParseLog(log types.Log) (generated.AbigenLog, error) + + Address() common.Address +} 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 76b5e267d3..cbd84c86a6 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 @@ -31,8 +31,8 @@ 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: "0x60c0604052600060045560006005556103e760065534801561002057600080fd5b5060405161111138038061111183398101604081905261003f91610199565b6001600160601b0319606082901b1660805233806000816100a75760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b03848116919091179091558116156100d7576100d7816100ef565b50505060601b6001600160601b03191660a0526101c9565b6001600160a01b0381163314156101485760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c66000000000000000000604482015260640161009e565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b6000602082840312156101ab57600080fd5b81516001600160a01b03811681146101c257600080fd5b9392505050565b60805160601c60a05160601c610f0f6102026000396000818161014301526103da0152600081816102b7015261031f0152610f0f6000f3fe608060405234801561001057600080fd5b50600436106100f55760003560e01c806379ba509711610097578063d826f88f11610066578063d826f88f1461023f578063d8a4676f1461025e578063dc1670db14610283578063f2fde38b1461028c57600080fd5b806379ba5097146101a55780638da5cb5b146101ad578063a168fa89146101cb578063b1e217491461023657600080fd5b80633b2bcbf1116100d35780633b2bcbf11461013e578063557d2e921461018a578063737144bc1461019357806374dba1241461019c57600080fd5b80631757f11c146100fa5780631fe543e314610116578063271095ef1461012b575b600080fd5b61010360055481565b6040519081526020015b60405180910390f35b610129610124366004610bcb565b61029f565b005b610129610139366004610cba565b61035f565b6101657f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200161010d565b61010360035481565b61010360045481565b61010360065481565b610129610577565b60005473ffffffffffffffffffffffffffffffffffffffff16610165565b61020c6101d9366004610b99565b6009602052600090815260409020805460028201546003830154600484015460059094015460ff90931693919290919085565b6040805195151586526020860194909452928401919091526060830152608082015260a00161010d565b61010360075481565b6101296000600481905560058190556103e76006556003819055600255565b61027161026c366004610b99565b610674565b60405161010d96959493929190610d36565b61010360025481565b61012961029a366004610b5c565b610759565b3373ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001614610351576040517f1cf993f400000000000000000000000000000000000000000000000000000000815233600482015273ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001660248201526044015b60405180910390fd5b61035b828261076d565b5050565b610367610894565b60005b8161ffff168161ffff16101561056e576040517f5d3b1d300000000000000000000000000000000000000000000000000000000081526004810186905267ffffffffffffffff8816602482015261ffff8716604482015263ffffffff8086166064830152841660848201526000907f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1690635d3b1d309060a401602060405180830381600087803b15801561043357600080fd5b505af1158015610447573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061046b9190610bb2565b60078190559050600061047c610917565b6040805160c08101825260008082528251818152602080820185528084019182524284860152606084018390526080840186905260a084018390528783526009815293909120825181547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016901515178155905180519495509193909261050a926001850192910190610ad1565b506040820151600282015560608201516003808301919091556080830151600483015560a090920151600590910155805490600061054783610e6b565b9091555050600091825260086020526040909120558061056681610e49565b91505061036a565b50505050505050565b60015473ffffffffffffffffffffffffffffffffffffffff1633146105f8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e6572000000000000000000006044820152606401610348565b60008054337fffffffffffffffffffffffff00000000000000000000000000000000000000008083168217845560018054909116905560405173ffffffffffffffffffffffffffffffffffffffff90921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b6000818152600960209081526040808320815160c081018352815460ff16151581526001820180548451818702810187019095528085526060958795869586958695869591949293858401939092908301828280156106f257602002820191906000526020600020905b8154815260200190600101908083116106de575b505050505081526020016002820154815260200160038201548152602001600482015481526020016005820154815250509050806000015181602001518260400151836060015184608001518560a001519650965096509650965096505091939550919395565b610761610894565b61076a816109b4565b50565b6000610777610917565b600084815260086020526040812054919250906107949083610e32565b905060006107a582620f4240610df5565b90506005548211156107b75760058290555b60065482106107c8576006546107ca565b815b6006556002546107da578061080d565b6002546107e8906001610da2565b816002546004546107f99190610df5565b6108039190610da2565b61080d9190610dba565b600455600085815260096020908152604090912080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660019081178255865161085f939290910191870190610ad1565b506000858152600960205260408120426003820155600501849055600280549161088883610e6b565b91905055505050505050565b60005473ffffffffffffffffffffffffffffffffffffffff163314610915576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e6572000000000000000000006044820152606401610348565b565b60004661092381610aaa565b156109ad57606473ffffffffffffffffffffffffffffffffffffffff1663a3b1b31d6040518163ffffffff1660e01b815260040160206040518083038186803b15801561096f57600080fd5b505afa158015610983573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109a79190610bb2565b91505090565b4391505090565b73ffffffffffffffffffffffffffffffffffffffff8116331415610a34576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c660000000000000000006044820152606401610348565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b600061a4b1821480610abe575062066eed82145b80610acb575062066eee82145b92915050565b828054828255906000526020600020908101928215610b0c579160200282015b82811115610b0c578251825591602001919060010190610af1565b50610b18929150610b1c565b5090565b5b80821115610b185760008155600101610b1d565b803561ffff81168114610b4357600080fd5b919050565b803563ffffffff81168114610b4357600080fd5b600060208284031215610b6e57600080fd5b813573ffffffffffffffffffffffffffffffffffffffff81168114610b9257600080fd5b9392505050565b600060208284031215610bab57600080fd5b5035919050565b600060208284031215610bc457600080fd5b5051919050565b60008060408385031215610bde57600080fd5b8235915060208084013567ffffffffffffffff80821115610bfe57600080fd5b818601915086601f830112610c1257600080fd5b813581811115610c2457610c24610ed3565b8060051b6040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0603f83011681018181108582111715610c6757610c67610ed3565b604052828152858101935084860182860187018b1015610c8657600080fd5b600095505b83861015610ca9578035855260019590950194938601938601610c8b565b508096505050505050509250929050565b60008060008060008060c08789031215610cd357600080fd5b863567ffffffffffffffff81168114610ceb57600080fd5b9550610cf960208801610b31565b945060408701359350610d0e60608801610b48565b9250610d1c60808801610b48565b9150610d2a60a08801610b31565b90509295509295509295565b600060c082018815158352602060c08185015281895180845260e086019150828b01935060005b81811015610d7957845183529383019391830191600101610d5d565b505060408501989098525050506060810193909352608083019190915260a09091015292915050565b60008219821115610db557610db5610ea4565b500190565b600082610df0577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500490565b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0483118215151615610e2d57610e2d610ea4565b500290565b600082821015610e4457610e44610ea4565b500390565b600061ffff80831681811415610e6157610e61610ea4565b6001019392505050565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff821415610e9d57610e9d610ea4565b5060010190565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fdfea164736f6c6343000806000a", + 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\":false,\"internalType\":\"uint64\",\"name\":\"subId\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"consumer\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"SubscriptionCreatedFundedAndConsumerAdded\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"COORDINATOR\",\"outputs\":[{\"internalType\":\"contractVRFCoordinatorV2Interface\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"LINKTOKEN\",\"outputs\":[{\"internalType\":\"contractLinkTokenInterface\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"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\":[{\"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\":[{\"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\"},{\"internalType\":\"uint256\",\"name\":\"_subTopUpAmount\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"_link\",\"type\":\"address\"}],\"name\":\"requestRandomWordsWithForceFulfill\",\"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\":\"uint64\",\"name\":\"_subId\",\"type\":\"uint64\"},{\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"_link\",\"type\":\"address\"}],\"name\":\"topUpSubscription\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", + Bin: "0x60c0604052600060035560006004556103e760055534801561002057600080fd5b5060405161133038038061133083398101604081905261003f91610059565b60601b6001600160601b031916608081905260a052610089565b60006020828403121561006b57600080fd5b81516001600160a01b038116811461008257600080fd5b9392505050565b60805160601c60a05160601c61124b6100e560003960008181610156015281816103e00152818161048c0152818161056b0152818161067d0152818161072a0152610a250152600081816102c4015261032c015261124b6000f3fe608060405234801561001057600080fd5b50600436106100f55760003560e01c806362cce24411610097578063b1e2174911610066578063b1e2174914610256578063d826f88f1461025f578063d8a4676f1461027e578063dc1670db146102a357600080fd5b806362cce244146101c6578063737144bc146101d957806374dba124146101e2578063a168fa89146101eb57600080fd5b80632be555da116100d35780632be555da1461013e5780633b2bcbf11461015157806355380dfb1461019d578063557d2e92146101bd57600080fd5b80631757f11c146100fa5780631fe543e314610116578063271095ef1461012b575b600080fd5b61010360045481565b6040519081526020015b60405180910390f35b610129610124366004610e08565b6102ac565b005b610129610139366004610f14565b61036b565b61012961014c366004610f83565b610381565b6101787f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200161010d565b6000546101789073ffffffffffffffffffffffffffffffffffffffff1681565b61010360025481565b6101296101d4366004610d5e565b610488565b61010360035481565b61010360055481565b61022c6101f9366004610dd6565b6008602052600090815260409020805460028201546003830154600484015460059094015460ff90931693919290919085565b6040805195151586526020860194909452928401919091526060830152608082015260a00161010d565b61010360065481565b6101296000600381905560048190556103e76005556002819055600155565b61029161028c366004610dd6565b6107a7565b60405161010d96959493929190611059565b61010360015481565b3373ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000161461035d576040517f1cf993f400000000000000000000000000000000000000000000000000000000815233600482015273ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016602482015260440160405180910390fd5b610367828261088c565b5050565b6103798686868686866109b2565b505050505050565b600080547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040805167ffffffffffffffff86166020820152634000aea0917f0000000000000000000000000000000000000000000000000000000000000000918691016040516020818303038152906040526040518463ffffffff1660e01b815260040161043093929190610fc1565b602060405180830381600087803b15801561044a57600080fd5b505af115801561045e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104829190610d35565b50505050565b60007f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663a21a23e46040518163ffffffff1660e01b8152600401602060405180830381600087803b1580156104f257600080fd5b505af1158015610506573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061052a9190610ef7565b6040517f7341c10c00000000000000000000000000000000000000000000000000000000815267ffffffffffffffff821660048201523060248201529091507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1690637341c10c90604401600060405180830381600087803b1580156105c457600080fd5b505af11580156105d8573d6000803e3d6000fd5b505050506105e7818484610381565b6040805167ffffffffffffffff831681523060208201529081018490527f56c142509574e8340ca0190b029c74464b84037d2876278ea0ade3ffb1f0042c9060600160405180910390a161063f8189898989896109b2565b6040517f9f87fad700000000000000000000000000000000000000000000000000000000815267ffffffffffffffff821660048201523060248201527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1690639f87fad790604401600060405180830381600087803b1580156106d657600080fd5b505af11580156106ea573d6000803e3d6000fd5b50506040517fd7ae1d3000000000000000000000000000000000000000000000000000000000815267ffffffffffffffff841660048201523360248201527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16925063d7ae1d309150604401600060405180830381600087803b15801561078557600080fd5b505af1158015610799573d6000803e3d6000fd5b505050505050505050505050565b6000818152600860209081526040808320815160c081018352815460ff161515815260018201805484518187028101870190955280855260609587958695869586958695919492938584019390929083018282801561082557602002820191906000526020600020905b815481526020019060010190808311610811575b505050505081526020016002820154815260200160038201548152602001600482015481526020016005820154815250509050806000015181602001518260400151836060015184608001518560a001519650965096509650965096505091939550919395565b6000610896610bc2565b600084815260076020526040812054919250906108b39083611155565b905060006108c482620f4240611118565b90506004548211156108d65760048290555b60055482106108e7576005546108e9565b815b6005556001546108f9578061092b565b60018054610906916110c5565b816001546003546109179190611118565b61092191906110c5565b61092b91906110dd565b600355600085815260086020908152604090912080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660019081178255865161097d939290910191870190610c86565b50600085815260086020526040812042600382015560050184905560018054916109a68361118e565b91905055505050505050565b60005b8161ffff168161ffff161015610bb9576040517f5d3b1d300000000000000000000000000000000000000000000000000000000081526004810186905267ffffffffffffffff8816602482015261ffff8716604482015263ffffffff8086166064830152841660848201526000907f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1690635d3b1d309060a401602060405180830381600087803b158015610a7e57600080fd5b505af1158015610a92573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ab69190610def565b600681905590506000610ac7610bc2565b6040805160c08101825260008082528251818152602080820185528084019182524284860152606084018390526080840186905260a084018390528783526008815293909120825181547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169015151781559051805194955091939092610b55926001850192910190610c86565b506040820151600280830191909155606083015160038301556080830151600483015560a0909201516005909101558054906000610b928361118e565b90915550506000918252600760205260409091205580610bb18161116c565b9150506109b5565b50505050505050565b600046610bce81610c5f565b15610c5857606473ffffffffffffffffffffffffffffffffffffffff1663a3b1b31d6040518163ffffffff1660e01b815260040160206040518083038186803b158015610c1a57600080fd5b505afa158015610c2e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c529190610def565b91505090565b4391505090565b600061a4b1821480610c73575062066eed82145b80610c80575062066eee82145b92915050565b828054828255906000526020600020908101928215610cc1579160200282015b82811115610cc1578251825591602001919060010190610ca6565b50610ccd929150610cd1565b5090565b5b80821115610ccd5760008155600101610cd2565b803573ffffffffffffffffffffffffffffffffffffffff81168114610d0a57600080fd5b919050565b803561ffff81168114610d0a57600080fd5b803563ffffffff81168114610d0a57600080fd5b600060208284031215610d4757600080fd5b81518015158114610d5757600080fd5b9392505050565b600080600080600080600060e0888a031215610d7957600080fd5b610d8288610d0f565b965060208801359550610d9760408901610d21565b9450610da560608901610d21565b9350610db360808901610d0f565b925060a08801359150610dc860c08901610ce6565b905092959891949750929550565b600060208284031215610de857600080fd5b5035919050565b600060208284031215610e0157600080fd5b5051919050565b60008060408385031215610e1b57600080fd5b8235915060208084013567ffffffffffffffff80821115610e3b57600080fd5b818601915086601f830112610e4f57600080fd5b813581811115610e6157610e616111f6565b8060051b6040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0603f83011681018181108582111715610ea457610ea46111f6565b604052828152858101935084860182860187018b1015610ec357600080fd5b600095505b83861015610ee6578035855260019590950194938601938601610ec8565b508096505050505050509250929050565b600060208284031215610f0957600080fd5b8151610d5781611225565b60008060008060008060c08789031215610f2d57600080fd5b8635610f3881611225565b9550610f4660208801610d0f565b945060408701359350610f5b60608801610d21565b9250610f6960808801610d21565b9150610f7760a08801610d0f565b90509295509295509295565b600080600060608486031215610f9857600080fd5b8335610fa381611225565b925060208401359150610fb860408501610ce6565b90509250925092565b73ffffffffffffffffffffffffffffffffffffffff8416815260006020848184015260606040840152835180606085015260005b8181101561101157858101830151858201608001528201610ff5565b81811115611023576000608083870101525b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160800195945050505050565b600060c082018815158352602060c08185015281895180845260e086019150828b01935060005b8181101561109c57845183529383019391830191600101611080565b505060408501989098525050506060810193909352608083019190915260a09091015292915050565b600082198211156110d8576110d86111c7565b500190565b600082611113577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500490565b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0483118215151615611150576111506111c7565b500290565b600082821015611167576111676111c7565b500390565b600061ffff80831681811415611184576111846111c7565b6001019392505050565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8214156111c0576111c06111c7565b5060010190565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b67ffffffffffffffff8116811461123b57600080fd5b5056fea164736f6c6343000806000a", } var VRFV2LoadTestWithMetricsABI = VRFV2LoadTestWithMetricsMetaData.ABI @@ -193,6 +193,28 @@ func (_VRFV2LoadTestWithMetrics *VRFV2LoadTestWithMetricsCallerSession) COORDINA return _VRFV2LoadTestWithMetrics.Contract.COORDINATOR(&_VRFV2LoadTestWithMetrics.CallOpts) } +func (_VRFV2LoadTestWithMetrics *VRFV2LoadTestWithMetricsCaller) LINKTOKEN(opts *bind.CallOpts) (common.Address, error) { + var out []interface{} + err := _VRFV2LoadTestWithMetrics.contract.Call(opts, &out, "LINKTOKEN") + + if err != nil { + return *new(common.Address), err + } + + out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) + + return out0, err + +} + +func (_VRFV2LoadTestWithMetrics *VRFV2LoadTestWithMetricsSession) LINKTOKEN() (common.Address, error) { + return _VRFV2LoadTestWithMetrics.Contract.LINKTOKEN(&_VRFV2LoadTestWithMetrics.CallOpts) +} + +func (_VRFV2LoadTestWithMetrics *VRFV2LoadTestWithMetricsCallerSession) LINKTOKEN() (common.Address, error) { + return _VRFV2LoadTestWithMetrics.Contract.LINKTOKEN(&_VRFV2LoadTestWithMetrics.CallOpts) +} + func (_VRFV2LoadTestWithMetrics *VRFV2LoadTestWithMetricsCaller) GetRequestStatus(opts *bind.CallOpts, _requestId *big.Int) (GetRequestStatus, error) { @@ -227,28 +249,6 @@ func (_VRFV2LoadTestWithMetrics *VRFV2LoadTestWithMetricsCallerSession) GetReque return _VRFV2LoadTestWithMetrics.Contract.GetRequestStatus(&_VRFV2LoadTestWithMetrics.CallOpts, _requestId) } -func (_VRFV2LoadTestWithMetrics *VRFV2LoadTestWithMetricsCaller) Owner(opts *bind.CallOpts) (common.Address, error) { - var out []interface{} - err := _VRFV2LoadTestWithMetrics.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 (_VRFV2LoadTestWithMetrics *VRFV2LoadTestWithMetricsSession) Owner() (common.Address, error) { - return _VRFV2LoadTestWithMetrics.Contract.Owner(&_VRFV2LoadTestWithMetrics.CallOpts) -} - -func (_VRFV2LoadTestWithMetrics *VRFV2LoadTestWithMetricsCallerSession) Owner() (common.Address, error) { - return _VRFV2LoadTestWithMetrics.Contract.Owner(&_VRFV2LoadTestWithMetrics.CallOpts) -} - func (_VRFV2LoadTestWithMetrics *VRFV2LoadTestWithMetricsCaller) SAverageFulfillmentInMillions(opts *bind.CallOpts) (*big.Int, error) { var out []interface{} err := _VRFV2LoadTestWithMetrics.contract.Call(opts, &out, "s_averageFulfillmentInMillions") @@ -414,18 +414,6 @@ func (_VRFV2LoadTestWithMetrics *VRFV2LoadTestWithMetricsCallerSession) SSlowest return _VRFV2LoadTestWithMetrics.Contract.SSlowestFulfillment(&_VRFV2LoadTestWithMetrics.CallOpts) } -func (_VRFV2LoadTestWithMetrics *VRFV2LoadTestWithMetricsTransactor) AcceptOwnership(opts *bind.TransactOpts) (*types.Transaction, error) { - return _VRFV2LoadTestWithMetrics.contract.Transact(opts, "acceptOwnership") -} - -func (_VRFV2LoadTestWithMetrics *VRFV2LoadTestWithMetricsSession) AcceptOwnership() (*types.Transaction, error) { - return _VRFV2LoadTestWithMetrics.Contract.AcceptOwnership(&_VRFV2LoadTestWithMetrics.TransactOpts) -} - -func (_VRFV2LoadTestWithMetrics *VRFV2LoadTestWithMetricsTransactorSession) AcceptOwnership() (*types.Transaction, error) { - return _VRFV2LoadTestWithMetrics.Contract.AcceptOwnership(&_VRFV2LoadTestWithMetrics.TransactOpts) -} - func (_VRFV2LoadTestWithMetrics *VRFV2LoadTestWithMetricsTransactor) RawFulfillRandomWords(opts *bind.TransactOpts, requestId *big.Int, randomWords []*big.Int) (*types.Transaction, error) { return _VRFV2LoadTestWithMetrics.contract.Transact(opts, "rawFulfillRandomWords", requestId, randomWords) } @@ -450,168 +438,44 @@ func (_VRFV2LoadTestWithMetrics *VRFV2LoadTestWithMetricsTransactorSession) Requ return _VRFV2LoadTestWithMetrics.Contract.RequestRandomWords(&_VRFV2LoadTestWithMetrics.TransactOpts, _subId, _requestConfirmations, _keyHash, _callbackGasLimit, _numWords, _requestCount) } -func (_VRFV2LoadTestWithMetrics *VRFV2LoadTestWithMetricsTransactor) Reset(opts *bind.TransactOpts) (*types.Transaction, error) { - return _VRFV2LoadTestWithMetrics.contract.Transact(opts, "reset") +func (_VRFV2LoadTestWithMetrics *VRFV2LoadTestWithMetricsTransactor) RequestRandomWordsWithForceFulfill(opts *bind.TransactOpts, _requestConfirmations uint16, _keyHash [32]byte, _callbackGasLimit uint32, _numWords uint32, _requestCount uint16, _subTopUpAmount *big.Int, _link common.Address) (*types.Transaction, error) { + return _VRFV2LoadTestWithMetrics.contract.Transact(opts, "requestRandomWordsWithForceFulfill", _requestConfirmations, _keyHash, _callbackGasLimit, _numWords, _requestCount, _subTopUpAmount, _link) } -func (_VRFV2LoadTestWithMetrics *VRFV2LoadTestWithMetricsSession) Reset() (*types.Transaction, error) { - return _VRFV2LoadTestWithMetrics.Contract.Reset(&_VRFV2LoadTestWithMetrics.TransactOpts) -} - -func (_VRFV2LoadTestWithMetrics *VRFV2LoadTestWithMetricsTransactorSession) Reset() (*types.Transaction, error) { - return _VRFV2LoadTestWithMetrics.Contract.Reset(&_VRFV2LoadTestWithMetrics.TransactOpts) -} - -func (_VRFV2LoadTestWithMetrics *VRFV2LoadTestWithMetricsTransactor) TransferOwnership(opts *bind.TransactOpts, to common.Address) (*types.Transaction, error) { - return _VRFV2LoadTestWithMetrics.contract.Transact(opts, "transferOwnership", to) -} - -func (_VRFV2LoadTestWithMetrics *VRFV2LoadTestWithMetricsSession) TransferOwnership(to common.Address) (*types.Transaction, error) { - return _VRFV2LoadTestWithMetrics.Contract.TransferOwnership(&_VRFV2LoadTestWithMetrics.TransactOpts, to) -} - -func (_VRFV2LoadTestWithMetrics *VRFV2LoadTestWithMetricsTransactorSession) TransferOwnership(to common.Address) (*types.Transaction, error) { - return _VRFV2LoadTestWithMetrics.Contract.TransferOwnership(&_VRFV2LoadTestWithMetrics.TransactOpts, to) -} - -type VRFV2LoadTestWithMetricsOwnershipTransferRequestedIterator struct { - Event *VRFV2LoadTestWithMetricsOwnershipTransferRequested - - contract *bind.BoundContract - event string - - logs chan types.Log - sub ethereum.Subscription - done bool - fail error +func (_VRFV2LoadTestWithMetrics *VRFV2LoadTestWithMetricsSession) RequestRandomWordsWithForceFulfill(_requestConfirmations uint16, _keyHash [32]byte, _callbackGasLimit uint32, _numWords uint32, _requestCount uint16, _subTopUpAmount *big.Int, _link common.Address) (*types.Transaction, error) { + return _VRFV2LoadTestWithMetrics.Contract.RequestRandomWordsWithForceFulfill(&_VRFV2LoadTestWithMetrics.TransactOpts, _requestConfirmations, _keyHash, _callbackGasLimit, _numWords, _requestCount, _subTopUpAmount, _link) } -func (it *VRFV2LoadTestWithMetricsOwnershipTransferRequestedIterator) Next() bool { - - if it.fail != nil { - return false - } - - if it.done { - select { - case log := <-it.logs: - it.Event = new(VRFV2LoadTestWithMetricsOwnershipTransferRequested) - 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(VRFV2LoadTestWithMetricsOwnershipTransferRequested) - 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 (_VRFV2LoadTestWithMetrics *VRFV2LoadTestWithMetricsTransactorSession) RequestRandomWordsWithForceFulfill(_requestConfirmations uint16, _keyHash [32]byte, _callbackGasLimit uint32, _numWords uint32, _requestCount uint16, _subTopUpAmount *big.Int, _link common.Address) (*types.Transaction, error) { + return _VRFV2LoadTestWithMetrics.Contract.RequestRandomWordsWithForceFulfill(&_VRFV2LoadTestWithMetrics.TransactOpts, _requestConfirmations, _keyHash, _callbackGasLimit, _numWords, _requestCount, _subTopUpAmount, _link) } -func (it *VRFV2LoadTestWithMetricsOwnershipTransferRequestedIterator) Error() error { - return it.fail +func (_VRFV2LoadTestWithMetrics *VRFV2LoadTestWithMetricsTransactor) Reset(opts *bind.TransactOpts) (*types.Transaction, error) { + return _VRFV2LoadTestWithMetrics.contract.Transact(opts, "reset") } -func (it *VRFV2LoadTestWithMetricsOwnershipTransferRequestedIterator) Close() error { - it.sub.Unsubscribe() - return nil +func (_VRFV2LoadTestWithMetrics *VRFV2LoadTestWithMetricsSession) Reset() (*types.Transaction, error) { + return _VRFV2LoadTestWithMetrics.Contract.Reset(&_VRFV2LoadTestWithMetrics.TransactOpts) } -type VRFV2LoadTestWithMetricsOwnershipTransferRequested struct { - From common.Address - To common.Address - Raw types.Log +func (_VRFV2LoadTestWithMetrics *VRFV2LoadTestWithMetricsTransactorSession) Reset() (*types.Transaction, error) { + return _VRFV2LoadTestWithMetrics.Contract.Reset(&_VRFV2LoadTestWithMetrics.TransactOpts) } -func (_VRFV2LoadTestWithMetrics *VRFV2LoadTestWithMetricsFilterer) FilterOwnershipTransferRequested(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*VRFV2LoadTestWithMetricsOwnershipTransferRequestedIterator, 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 := _VRFV2LoadTestWithMetrics.contract.FilterLogs(opts, "OwnershipTransferRequested", fromRule, toRule) - if err != nil { - return nil, err - } - return &VRFV2LoadTestWithMetricsOwnershipTransferRequestedIterator{contract: _VRFV2LoadTestWithMetrics.contract, event: "OwnershipTransferRequested", logs: logs, sub: sub}, nil +func (_VRFV2LoadTestWithMetrics *VRFV2LoadTestWithMetricsTransactor) TopUpSubscription(opts *bind.TransactOpts, _subId uint64, _amount *big.Int, _link common.Address) (*types.Transaction, error) { + return _VRFV2LoadTestWithMetrics.contract.Transact(opts, "topUpSubscription", _subId, _amount, _link) } -func (_VRFV2LoadTestWithMetrics *VRFV2LoadTestWithMetricsFilterer) WatchOwnershipTransferRequested(opts *bind.WatchOpts, sink chan<- *VRFV2LoadTestWithMetricsOwnershipTransferRequested, 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 := _VRFV2LoadTestWithMetrics.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(VRFV2LoadTestWithMetricsOwnershipTransferRequested) - if err := _VRFV2LoadTestWithMetrics.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 (_VRFV2LoadTestWithMetrics *VRFV2LoadTestWithMetricsSession) TopUpSubscription(_subId uint64, _amount *big.Int, _link common.Address) (*types.Transaction, error) { + return _VRFV2LoadTestWithMetrics.Contract.TopUpSubscription(&_VRFV2LoadTestWithMetrics.TransactOpts, _subId, _amount, _link) } -func (_VRFV2LoadTestWithMetrics *VRFV2LoadTestWithMetricsFilterer) ParseOwnershipTransferRequested(log types.Log) (*VRFV2LoadTestWithMetricsOwnershipTransferRequested, error) { - event := new(VRFV2LoadTestWithMetricsOwnershipTransferRequested) - if err := _VRFV2LoadTestWithMetrics.contract.UnpackLog(event, "OwnershipTransferRequested", log); err != nil { - return nil, err - } - event.Raw = log - return event, nil +func (_VRFV2LoadTestWithMetrics *VRFV2LoadTestWithMetricsTransactorSession) TopUpSubscription(_subId uint64, _amount *big.Int, _link common.Address) (*types.Transaction, error) { + return _VRFV2LoadTestWithMetrics.Contract.TopUpSubscription(&_VRFV2LoadTestWithMetrics.TransactOpts, _subId, _amount, _link) } -type VRFV2LoadTestWithMetricsOwnershipTransferredIterator struct { - Event *VRFV2LoadTestWithMetricsOwnershipTransferred +type VRFV2LoadTestWithMetricsSubscriptionCreatedFundedAndConsumerAddedIterator struct { + Event *VRFV2LoadTestWithMetricsSubscriptionCreatedFundedAndConsumerAdded contract *bind.BoundContract event string @@ -622,7 +486,7 @@ type VRFV2LoadTestWithMetricsOwnershipTransferredIterator struct { fail error } -func (it *VRFV2LoadTestWithMetricsOwnershipTransferredIterator) Next() bool { +func (it *VRFV2LoadTestWithMetricsSubscriptionCreatedFundedAndConsumerAddedIterator) Next() bool { if it.fail != nil { return false @@ -631,7 +495,7 @@ func (it *VRFV2LoadTestWithMetricsOwnershipTransferredIterator) Next() bool { if it.done { select { case log := <-it.logs: - it.Event = new(VRFV2LoadTestWithMetricsOwnershipTransferred) + it.Event = new(VRFV2LoadTestWithMetricsSubscriptionCreatedFundedAndConsumerAdded) if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { it.fail = err return false @@ -646,7 +510,7 @@ func (it *VRFV2LoadTestWithMetricsOwnershipTransferredIterator) Next() bool { select { case log := <-it.logs: - it.Event = new(VRFV2LoadTestWithMetricsOwnershipTransferred) + it.Event = new(VRFV2LoadTestWithMetricsSubscriptionCreatedFundedAndConsumerAdded) if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { it.fail = err return false @@ -661,51 +525,34 @@ func (it *VRFV2LoadTestWithMetricsOwnershipTransferredIterator) Next() bool { } } -func (it *VRFV2LoadTestWithMetricsOwnershipTransferredIterator) Error() error { +func (it *VRFV2LoadTestWithMetricsSubscriptionCreatedFundedAndConsumerAddedIterator) Error() error { return it.fail } -func (it *VRFV2LoadTestWithMetricsOwnershipTransferredIterator) Close() error { +func (it *VRFV2LoadTestWithMetricsSubscriptionCreatedFundedAndConsumerAddedIterator) Close() error { it.sub.Unsubscribe() return nil } -type VRFV2LoadTestWithMetricsOwnershipTransferred struct { - From common.Address - To common.Address - Raw types.Log +type VRFV2LoadTestWithMetricsSubscriptionCreatedFundedAndConsumerAdded struct { + SubId uint64 + Consumer common.Address + Amount *big.Int + Raw types.Log } -func (_VRFV2LoadTestWithMetrics *VRFV2LoadTestWithMetricsFilterer) FilterOwnershipTransferred(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*VRFV2LoadTestWithMetricsOwnershipTransferredIterator, error) { +func (_VRFV2LoadTestWithMetrics *VRFV2LoadTestWithMetricsFilterer) FilterSubscriptionCreatedFundedAndConsumerAdded(opts *bind.FilterOpts) (*VRFV2LoadTestWithMetricsSubscriptionCreatedFundedAndConsumerAddedIterator, 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 := _VRFV2LoadTestWithMetrics.contract.FilterLogs(opts, "OwnershipTransferred", fromRule, toRule) + logs, sub, err := _VRFV2LoadTestWithMetrics.contract.FilterLogs(opts, "SubscriptionCreatedFundedAndConsumerAdded") if err != nil { return nil, err } - return &VRFV2LoadTestWithMetricsOwnershipTransferredIterator{contract: _VRFV2LoadTestWithMetrics.contract, event: "OwnershipTransferred", logs: logs, sub: sub}, nil + return &VRFV2LoadTestWithMetricsSubscriptionCreatedFundedAndConsumerAddedIterator{contract: _VRFV2LoadTestWithMetrics.contract, event: "SubscriptionCreatedFundedAndConsumerAdded", logs: logs, sub: sub}, nil } -func (_VRFV2LoadTestWithMetrics *VRFV2LoadTestWithMetricsFilterer) WatchOwnershipTransferred(opts *bind.WatchOpts, sink chan<- *VRFV2LoadTestWithMetricsOwnershipTransferred, 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) - } +func (_VRFV2LoadTestWithMetrics *VRFV2LoadTestWithMetricsFilterer) WatchSubscriptionCreatedFundedAndConsumerAdded(opts *bind.WatchOpts, sink chan<- *VRFV2LoadTestWithMetricsSubscriptionCreatedFundedAndConsumerAdded) (event.Subscription, error) { - logs, sub, err := _VRFV2LoadTestWithMetrics.contract.WatchLogs(opts, "OwnershipTransferred", fromRule, toRule) + logs, sub, err := _VRFV2LoadTestWithMetrics.contract.WatchLogs(opts, "SubscriptionCreatedFundedAndConsumerAdded") if err != nil { return nil, err } @@ -715,8 +562,8 @@ func (_VRFV2LoadTestWithMetrics *VRFV2LoadTestWithMetricsFilterer) WatchOwnershi select { case log := <-logs: - event := new(VRFV2LoadTestWithMetricsOwnershipTransferred) - if err := _VRFV2LoadTestWithMetrics.contract.UnpackLog(event, "OwnershipTransferred", log); err != nil { + event := new(VRFV2LoadTestWithMetricsSubscriptionCreatedFundedAndConsumerAdded) + if err := _VRFV2LoadTestWithMetrics.contract.UnpackLog(event, "SubscriptionCreatedFundedAndConsumerAdded", log); err != nil { return err } event.Raw = log @@ -737,9 +584,9 @@ func (_VRFV2LoadTestWithMetrics *VRFV2LoadTestWithMetricsFilterer) WatchOwnershi }), nil } -func (_VRFV2LoadTestWithMetrics *VRFV2LoadTestWithMetricsFilterer) ParseOwnershipTransferred(log types.Log) (*VRFV2LoadTestWithMetricsOwnershipTransferred, error) { - event := new(VRFV2LoadTestWithMetricsOwnershipTransferred) - if err := _VRFV2LoadTestWithMetrics.contract.UnpackLog(event, "OwnershipTransferred", log); err != nil { +func (_VRFV2LoadTestWithMetrics *VRFV2LoadTestWithMetricsFilterer) ParseSubscriptionCreatedFundedAndConsumerAdded(log types.Log) (*VRFV2LoadTestWithMetricsSubscriptionCreatedFundedAndConsumerAdded, error) { + event := new(VRFV2LoadTestWithMetricsSubscriptionCreatedFundedAndConsumerAdded) + if err := _VRFV2LoadTestWithMetrics.contract.UnpackLog(event, "SubscriptionCreatedFundedAndConsumerAdded", log); err != nil { return nil, err } event.Raw = log @@ -764,22 +611,16 @@ type SRequests struct { func (_VRFV2LoadTestWithMetrics *VRFV2LoadTestWithMetrics) ParseLog(log types.Log) (generated.AbigenLog, error) { switch log.Topics[0] { - case _VRFV2LoadTestWithMetrics.abi.Events["OwnershipTransferRequested"].ID: - return _VRFV2LoadTestWithMetrics.ParseOwnershipTransferRequested(log) - case _VRFV2LoadTestWithMetrics.abi.Events["OwnershipTransferred"].ID: - return _VRFV2LoadTestWithMetrics.ParseOwnershipTransferred(log) + case _VRFV2LoadTestWithMetrics.abi.Events["SubscriptionCreatedFundedAndConsumerAdded"].ID: + return _VRFV2LoadTestWithMetrics.ParseSubscriptionCreatedFundedAndConsumerAdded(log) default: return nil, fmt.Errorf("abigen wrapper received unknown log topic: %v", log.Topics[0]) } } -func (VRFV2LoadTestWithMetricsOwnershipTransferRequested) Topic() common.Hash { - return common.HexToHash("0xed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae1278") -} - -func (VRFV2LoadTestWithMetricsOwnershipTransferred) Topic() common.Hash { - return common.HexToHash("0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0") +func (VRFV2LoadTestWithMetricsSubscriptionCreatedFundedAndConsumerAdded) Topic() common.Hash { + return common.HexToHash("0x56c142509574e8340ca0190b029c74464b84037d2876278ea0ade3ffb1f0042c") } func (_VRFV2LoadTestWithMetrics *VRFV2LoadTestWithMetrics) Address() common.Address { @@ -789,12 +630,12 @@ func (_VRFV2LoadTestWithMetrics *VRFV2LoadTestWithMetrics) Address() common.Addr type VRFV2LoadTestWithMetricsInterface interface { COORDINATOR(opts *bind.CallOpts) (common.Address, error) + LINKTOKEN(opts *bind.CallOpts) (common.Address, error) + GetRequestStatus(opts *bind.CallOpts, _requestId *big.Int) (GetRequestStatus, error) - Owner(opts *bind.CallOpts) (common.Address, error) - SAverageFulfillmentInMillions(opts *bind.CallOpts) (*big.Int, error) SFastestFulfillment(opts *bind.CallOpts) (*big.Int, error) @@ -811,27 +652,21 @@ type VRFV2LoadTestWithMetricsInterface interface { SSlowestFulfillment(opts *bind.CallOpts) (*big.Int, 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, _requestConfirmations uint16, _keyHash [32]byte, _callbackGasLimit uint32, _numWords uint32, _requestCount uint16) (*types.Transaction, error) - Reset(opts *bind.TransactOpts) (*types.Transaction, error) - - TransferOwnership(opts *bind.TransactOpts, to common.Address) (*types.Transaction, error) + RequestRandomWordsWithForceFulfill(opts *bind.TransactOpts, _requestConfirmations uint16, _keyHash [32]byte, _callbackGasLimit uint32, _numWords uint32, _requestCount uint16, _subTopUpAmount *big.Int, _link common.Address) (*types.Transaction, error) - FilterOwnershipTransferRequested(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*VRFV2LoadTestWithMetricsOwnershipTransferRequestedIterator, error) - - WatchOwnershipTransferRequested(opts *bind.WatchOpts, sink chan<- *VRFV2LoadTestWithMetricsOwnershipTransferRequested, from []common.Address, to []common.Address) (event.Subscription, error) + Reset(opts *bind.TransactOpts) (*types.Transaction, error) - ParseOwnershipTransferRequested(log types.Log) (*VRFV2LoadTestWithMetricsOwnershipTransferRequested, error) + TopUpSubscription(opts *bind.TransactOpts, _subId uint64, _amount *big.Int, _link common.Address) (*types.Transaction, error) - FilterOwnershipTransferred(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*VRFV2LoadTestWithMetricsOwnershipTransferredIterator, error) + FilterSubscriptionCreatedFundedAndConsumerAdded(opts *bind.FilterOpts) (*VRFV2LoadTestWithMetricsSubscriptionCreatedFundedAndConsumerAddedIterator, error) - WatchOwnershipTransferred(opts *bind.WatchOpts, sink chan<- *VRFV2LoadTestWithMetricsOwnershipTransferred, from []common.Address, to []common.Address) (event.Subscription, error) + WatchSubscriptionCreatedFundedAndConsumerAdded(opts *bind.WatchOpts, sink chan<- *VRFV2LoadTestWithMetricsSubscriptionCreatedFundedAndConsumerAdded) (event.Subscription, error) - ParseOwnershipTransferred(log types.Log) (*VRFV2LoadTestWithMetricsOwnershipTransferred, error) + ParseSubscriptionCreatedFundedAndConsumerAdded(log types.Log) (*VRFV2LoadTestWithMetricsSubscriptionCreatedFundedAndConsumerAdded, error) ParseLog(log types.Log) (generated.AbigenLog, error) diff --git a/core/gethwrappers/generated/vrf_mock_ethlink_aggregator/vrf_mock_ethlink_aggregator.go b/core/gethwrappers/generated/vrf_mock_ethlink_aggregator/vrf_mock_ethlink_aggregator.go new file mode 100644 index 0000000000..d6736acfb9 --- /dev/null +++ b/core/gethwrappers/generated/vrf_mock_ethlink_aggregator/vrf_mock_ethlink_aggregator.go @@ -0,0 +1,377 @@ +// Code generated - DO NOT EDIT. +// This file is a generated binding and any manual changes will be lost. + +package vrf_mock_ethlink_aggregator + +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 VRFMockETHLINKAggregatorMetaData = &bind.MetaData{ + ABI: "[{\"inputs\":[{\"internalType\":\"int256\",\"name\":\"_answer\",\"type\":\"int256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"answer\",\"outputs\":[{\"internalType\":\"int256\",\"name\":\"\",\"type\":\"int256\"}],\"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\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint80\",\"name\":\"_roundId\",\"type\":\"uint80\"}],\"name\":\"getRoundData\",\"outputs\":[{\"internalType\":\"uint80\",\"name\":\"roundId\",\"type\":\"uint80\"},{\"internalType\":\"int256\",\"name\":\"ans\",\"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\":\"latestRoundData\",\"outputs\":[{\"internalType\":\"uint80\",\"name\":\"roundId\",\"type\":\"uint80\"},{\"internalType\":\"int256\",\"name\":\"ans\",\"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\":[{\"internalType\":\"uint256\",\"name\":\"_blockTimestampDeduction\",\"type\":\"uint256\"}],\"name\":\"setBlockTimestampDeduction\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"version\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"}]", + Bin: "0x6080604052600060015534801561001557600080fd5b506040516103383803806103388339810160408190526100349161003c565b600055610055565b60006020828403121561004e57600080fd5b5051919050565b6102d4806100646000396000f3fe608060405234801561001057600080fd5b506004361061007d5760003560e01c806385bb7d691161005b57806385bb7d69146100e65780639a6fc8f5146100ef578063f0ad37df14610139578063feaf968c1461014e57600080fd5b8063313ce5671461008257806354fd4d50146100965780637284e416146100a7575b600080fd5b604051601281526020015b60405180910390f35b60015b60405190815260200161008d565b604080518082018252601881527f5652464d6f636b4554484c494e4b41676772656761746f7200000000000000006020820152905161008d9190610216565b61009960005481565b6101026100fd3660046101e3565b610156565b6040805169ffffffffffffffffffff968716815260208101959095528401929092526060830152909116608082015260a00161008d565b61014c6101473660046101ca565b600155565b005b610102610186565b6000806000806000600160005461016b6101b5565b6101736101b5565b9299919850965090945060019350915050565b6000806000806000600160005461019b6101b5565b6101a36101b5565b92989197509550909350600192509050565b6000600154426101c59190610289565b905090565b6000602082840312156101dc57600080fd5b5035919050565b6000602082840312156101f557600080fd5b813569ffffffffffffffffffff8116811461020f57600080fd5b9392505050565b600060208083528351808285015260005b8181101561024357858101830151858201604001528201610227565b81811115610255576000604083870101525b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016929092016040019392505050565b6000828210156102c2577f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b50039056fea164736f6c6343000806000a", +} + +var VRFMockETHLINKAggregatorABI = VRFMockETHLINKAggregatorMetaData.ABI + +var VRFMockETHLINKAggregatorBin = VRFMockETHLINKAggregatorMetaData.Bin + +func DeployVRFMockETHLINKAggregator(auth *bind.TransactOpts, backend bind.ContractBackend, _answer *big.Int) (common.Address, *types.Transaction, *VRFMockETHLINKAggregator, error) { + parsed, err := VRFMockETHLINKAggregatorMetaData.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(VRFMockETHLINKAggregatorBin), backend, _answer) + if err != nil { + return common.Address{}, nil, nil, err + } + return address, tx, &VRFMockETHLINKAggregator{address: address, abi: *parsed, VRFMockETHLINKAggregatorCaller: VRFMockETHLINKAggregatorCaller{contract: contract}, VRFMockETHLINKAggregatorTransactor: VRFMockETHLINKAggregatorTransactor{contract: contract}, VRFMockETHLINKAggregatorFilterer: VRFMockETHLINKAggregatorFilterer{contract: contract}}, nil +} + +type VRFMockETHLINKAggregator struct { + address common.Address + abi abi.ABI + VRFMockETHLINKAggregatorCaller + VRFMockETHLINKAggregatorTransactor + VRFMockETHLINKAggregatorFilterer +} + +type VRFMockETHLINKAggregatorCaller struct { + contract *bind.BoundContract +} + +type VRFMockETHLINKAggregatorTransactor struct { + contract *bind.BoundContract +} + +type VRFMockETHLINKAggregatorFilterer struct { + contract *bind.BoundContract +} + +type VRFMockETHLINKAggregatorSession struct { + Contract *VRFMockETHLINKAggregator + CallOpts bind.CallOpts + TransactOpts bind.TransactOpts +} + +type VRFMockETHLINKAggregatorCallerSession struct { + Contract *VRFMockETHLINKAggregatorCaller + CallOpts bind.CallOpts +} + +type VRFMockETHLINKAggregatorTransactorSession struct { + Contract *VRFMockETHLINKAggregatorTransactor + TransactOpts bind.TransactOpts +} + +type VRFMockETHLINKAggregatorRaw struct { + Contract *VRFMockETHLINKAggregator +} + +type VRFMockETHLINKAggregatorCallerRaw struct { + Contract *VRFMockETHLINKAggregatorCaller +} + +type VRFMockETHLINKAggregatorTransactorRaw struct { + Contract *VRFMockETHLINKAggregatorTransactor +} + +func NewVRFMockETHLINKAggregator(address common.Address, backend bind.ContractBackend) (*VRFMockETHLINKAggregator, error) { + abi, err := abi.JSON(strings.NewReader(VRFMockETHLINKAggregatorABI)) + if err != nil { + return nil, err + } + contract, err := bindVRFMockETHLINKAggregator(address, backend, backend, backend) + if err != nil { + return nil, err + } + return &VRFMockETHLINKAggregator{address: address, abi: abi, VRFMockETHLINKAggregatorCaller: VRFMockETHLINKAggregatorCaller{contract: contract}, VRFMockETHLINKAggregatorTransactor: VRFMockETHLINKAggregatorTransactor{contract: contract}, VRFMockETHLINKAggregatorFilterer: VRFMockETHLINKAggregatorFilterer{contract: contract}}, nil +} + +func NewVRFMockETHLINKAggregatorCaller(address common.Address, caller bind.ContractCaller) (*VRFMockETHLINKAggregatorCaller, error) { + contract, err := bindVRFMockETHLINKAggregator(address, caller, nil, nil) + if err != nil { + return nil, err + } + return &VRFMockETHLINKAggregatorCaller{contract: contract}, nil +} + +func NewVRFMockETHLINKAggregatorTransactor(address common.Address, transactor bind.ContractTransactor) (*VRFMockETHLINKAggregatorTransactor, error) { + contract, err := bindVRFMockETHLINKAggregator(address, nil, transactor, nil) + if err != nil { + return nil, err + } + return &VRFMockETHLINKAggregatorTransactor{contract: contract}, nil +} + +func NewVRFMockETHLINKAggregatorFilterer(address common.Address, filterer bind.ContractFilterer) (*VRFMockETHLINKAggregatorFilterer, error) { + contract, err := bindVRFMockETHLINKAggregator(address, nil, nil, filterer) + if err != nil { + return nil, err + } + return &VRFMockETHLINKAggregatorFilterer{contract: contract}, nil +} + +func bindVRFMockETHLINKAggregator(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) { + parsed, err := VRFMockETHLINKAggregatorMetaData.GetAbi() + if err != nil { + return nil, err + } + return bind.NewBoundContract(address, *parsed, caller, transactor, filterer), nil +} + +func (_VRFMockETHLINKAggregator *VRFMockETHLINKAggregatorRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _VRFMockETHLINKAggregator.Contract.VRFMockETHLINKAggregatorCaller.contract.Call(opts, result, method, params...) +} + +func (_VRFMockETHLINKAggregator *VRFMockETHLINKAggregatorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _VRFMockETHLINKAggregator.Contract.VRFMockETHLINKAggregatorTransactor.contract.Transfer(opts) +} + +func (_VRFMockETHLINKAggregator *VRFMockETHLINKAggregatorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _VRFMockETHLINKAggregator.Contract.VRFMockETHLINKAggregatorTransactor.contract.Transact(opts, method, params...) +} + +func (_VRFMockETHLINKAggregator *VRFMockETHLINKAggregatorCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _VRFMockETHLINKAggregator.Contract.contract.Call(opts, result, method, params...) +} + +func (_VRFMockETHLINKAggregator *VRFMockETHLINKAggregatorTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _VRFMockETHLINKAggregator.Contract.contract.Transfer(opts) +} + +func (_VRFMockETHLINKAggregator *VRFMockETHLINKAggregatorTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _VRFMockETHLINKAggregator.Contract.contract.Transact(opts, method, params...) +} + +func (_VRFMockETHLINKAggregator *VRFMockETHLINKAggregatorCaller) Answer(opts *bind.CallOpts) (*big.Int, error) { + var out []interface{} + err := _VRFMockETHLINKAggregator.contract.Call(opts, &out, "answer") + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +func (_VRFMockETHLINKAggregator *VRFMockETHLINKAggregatorSession) Answer() (*big.Int, error) { + return _VRFMockETHLINKAggregator.Contract.Answer(&_VRFMockETHLINKAggregator.CallOpts) +} + +func (_VRFMockETHLINKAggregator *VRFMockETHLINKAggregatorCallerSession) Answer() (*big.Int, error) { + return _VRFMockETHLINKAggregator.Contract.Answer(&_VRFMockETHLINKAggregator.CallOpts) +} + +func (_VRFMockETHLINKAggregator *VRFMockETHLINKAggregatorCaller) Decimals(opts *bind.CallOpts) (uint8, error) { + var out []interface{} + err := _VRFMockETHLINKAggregator.contract.Call(opts, &out, "decimals") + + if err != nil { + return *new(uint8), err + } + + out0 := *abi.ConvertType(out[0], new(uint8)).(*uint8) + + return out0, err + +} + +func (_VRFMockETHLINKAggregator *VRFMockETHLINKAggregatorSession) Decimals() (uint8, error) { + return _VRFMockETHLINKAggregator.Contract.Decimals(&_VRFMockETHLINKAggregator.CallOpts) +} + +func (_VRFMockETHLINKAggregator *VRFMockETHLINKAggregatorCallerSession) Decimals() (uint8, error) { + return _VRFMockETHLINKAggregator.Contract.Decimals(&_VRFMockETHLINKAggregator.CallOpts) +} + +func (_VRFMockETHLINKAggregator *VRFMockETHLINKAggregatorCaller) Description(opts *bind.CallOpts) (string, error) { + var out []interface{} + err := _VRFMockETHLINKAggregator.contract.Call(opts, &out, "description") + + if err != nil { + return *new(string), err + } + + out0 := *abi.ConvertType(out[0], new(string)).(*string) + + return out0, err + +} + +func (_VRFMockETHLINKAggregator *VRFMockETHLINKAggregatorSession) Description() (string, error) { + return _VRFMockETHLINKAggregator.Contract.Description(&_VRFMockETHLINKAggregator.CallOpts) +} + +func (_VRFMockETHLINKAggregator *VRFMockETHLINKAggregatorCallerSession) Description() (string, error) { + return _VRFMockETHLINKAggregator.Contract.Description(&_VRFMockETHLINKAggregator.CallOpts) +} + +func (_VRFMockETHLINKAggregator *VRFMockETHLINKAggregatorCaller) GetRoundData(opts *bind.CallOpts, _roundId *big.Int) (GetRoundData, + + error) { + var out []interface{} + err := _VRFMockETHLINKAggregator.contract.Call(opts, &out, "getRoundData", _roundId) + + outstruct := new(GetRoundData) + if err != nil { + return *outstruct, err + } + + outstruct.RoundId = *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + outstruct.Ans = *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 (_VRFMockETHLINKAggregator *VRFMockETHLINKAggregatorSession) GetRoundData(_roundId *big.Int) (GetRoundData, + + error) { + return _VRFMockETHLINKAggregator.Contract.GetRoundData(&_VRFMockETHLINKAggregator.CallOpts, _roundId) +} + +func (_VRFMockETHLINKAggregator *VRFMockETHLINKAggregatorCallerSession) GetRoundData(_roundId *big.Int) (GetRoundData, + + error) { + return _VRFMockETHLINKAggregator.Contract.GetRoundData(&_VRFMockETHLINKAggregator.CallOpts, _roundId) +} + +func (_VRFMockETHLINKAggregator *VRFMockETHLINKAggregatorCaller) LatestRoundData(opts *bind.CallOpts) (LatestRoundData, + + error) { + var out []interface{} + err := _VRFMockETHLINKAggregator.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.Ans = *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 (_VRFMockETHLINKAggregator *VRFMockETHLINKAggregatorSession) LatestRoundData() (LatestRoundData, + + error) { + return _VRFMockETHLINKAggregator.Contract.LatestRoundData(&_VRFMockETHLINKAggregator.CallOpts) +} + +func (_VRFMockETHLINKAggregator *VRFMockETHLINKAggregatorCallerSession) LatestRoundData() (LatestRoundData, + + error) { + return _VRFMockETHLINKAggregator.Contract.LatestRoundData(&_VRFMockETHLINKAggregator.CallOpts) +} + +func (_VRFMockETHLINKAggregator *VRFMockETHLINKAggregatorCaller) Version(opts *bind.CallOpts) (*big.Int, error) { + var out []interface{} + err := _VRFMockETHLINKAggregator.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 (_VRFMockETHLINKAggregator *VRFMockETHLINKAggregatorSession) Version() (*big.Int, error) { + return _VRFMockETHLINKAggregator.Contract.Version(&_VRFMockETHLINKAggregator.CallOpts) +} + +func (_VRFMockETHLINKAggregator *VRFMockETHLINKAggregatorCallerSession) Version() (*big.Int, error) { + return _VRFMockETHLINKAggregator.Contract.Version(&_VRFMockETHLINKAggregator.CallOpts) +} + +func (_VRFMockETHLINKAggregator *VRFMockETHLINKAggregatorTransactor) SetBlockTimestampDeduction(opts *bind.TransactOpts, _blockTimestampDeduction *big.Int) (*types.Transaction, error) { + return _VRFMockETHLINKAggregator.contract.Transact(opts, "setBlockTimestampDeduction", _blockTimestampDeduction) +} + +func (_VRFMockETHLINKAggregator *VRFMockETHLINKAggregatorSession) SetBlockTimestampDeduction(_blockTimestampDeduction *big.Int) (*types.Transaction, error) { + return _VRFMockETHLINKAggregator.Contract.SetBlockTimestampDeduction(&_VRFMockETHLINKAggregator.TransactOpts, _blockTimestampDeduction) +} + +func (_VRFMockETHLINKAggregator *VRFMockETHLINKAggregatorTransactorSession) SetBlockTimestampDeduction(_blockTimestampDeduction *big.Int) (*types.Transaction, error) { + return _VRFMockETHLINKAggregator.Contract.SetBlockTimestampDeduction(&_VRFMockETHLINKAggregator.TransactOpts, _blockTimestampDeduction) +} + +type GetRoundData struct { + RoundId *big.Int + Ans *big.Int + StartedAt *big.Int + UpdatedAt *big.Int + AnsweredInRound *big.Int +} +type LatestRoundData struct { + RoundId *big.Int + Ans *big.Int + StartedAt *big.Int + UpdatedAt *big.Int + AnsweredInRound *big.Int +} + +func (_VRFMockETHLINKAggregator *VRFMockETHLINKAggregator) Address() common.Address { + return _VRFMockETHLINKAggregator.address +} + +type VRFMockETHLINKAggregatorInterface interface { + Answer(opts *bind.CallOpts) (*big.Int, error) + + Decimals(opts *bind.CallOpts) (uint8, error) + + Description(opts *bind.CallOpts) (string, error) + + GetRoundData(opts *bind.CallOpts, _roundId *big.Int) (GetRoundData, + + error) + + LatestRoundData(opts *bind.CallOpts) (LatestRoundData, + + error) + + Version(opts *bind.CallOpts) (*big.Int, error) + + SetBlockTimestampDeduction(opts *bind.TransactOpts, _blockTimestampDeduction *big.Int) (*types.Transaction, error) + + Address() common.Address +} 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 8a17b64378..333bb11562 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 @@ -31,15 +31,15 @@ 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: "0x60a0604052600060055560006006556103e76007553480156200002157600080fd5b50604051620013cc380380620013cc8339810160408190526200004491620002bf565b6001600160601b0319606082901b166080523380600081620000ad5760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b0384811691909117909155811615620000e057620000e08162000213565b5050600280546001600160a01b0319166001600160a01b0384169081179091556040805163288688f960e21b8152905191925063a21a23e49160048083019260209291908290030181600087803b1580156200013b57600080fd5b505af115801562000150573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620001769190620002f1565b600280546001600160401b03928316600160a01b908102600160a01b600160e01b03198316811793849055604051631cd0704360e21b81529190930490931660048401523060248401526001600160a01b0391821691161790637341c10c90604401600060405180830381600087803b158015620001f357600080fd5b505af115801562000208573d6000803e3d6000fd5b50505050506200031c565b6001600160a01b0381163314156200026e5760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c660000000000000000006044820152606401620000a4565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b600060208284031215620002d257600080fd5b81516001600160a01b0381168114620002ea57600080fd5b9392505050565b6000602082840312156200030457600080fd5b81516001600160401b0381168114620002ea57600080fd5b60805160601c61108a62000342600039600081816103000152610368015261108a6000f3fe608060405234801561001057600080fd5b50600436106101005760003560e01c8063a168fa8911610097578063d8a4676f11610066578063d8a4676f14610262578063dc1670db14610287578063eb1d28bb14610290578063f2fde38b146102d557600080fd5b8063a168fa89146101bc578063ad603ea214610227578063b1e217491461023a578063d826f88f1461024357600080fd5b8063737144bc116100d3578063737144bc1461018457806374dba1241461018d57806379ba5097146101965780638da5cb5b1461019e57600080fd5b80631757f11c146101055780631fe543e3146101215780633b2bcbf114610136578063557d2e921461017b575b600080fd5b61010e60065481565b6040519081526020015b60405180910390f35b61013461012f366004610dc2565b6102e8565b005b6002546101569073ffffffffffffffffffffffffffffffffffffffff1681565b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610118565b61010e60045481565b61010e60055481565b61010e60075481565b6101346103a8565b60005473ffffffffffffffffffffffffffffffffffffffff16610156565b6101fd6101ca366004610d90565b600a602052600090815260409020805460028201546003830154600484015460059094015460ff90931693919290919085565b6040805195151586526020860194909452928401919091526060830152608082015260a001610118565b610134610235366004610d32565b6104a5565b61010e60085481565b6101346000600581905560068190556103e76007556004819055600355565b610275610270366004610d90565b610809565b60405161011896959493929190610eb1565b61010e60035481565b6002546102bc9074010000000000000000000000000000000000000000900467ffffffffffffffff1681565b60405167ffffffffffffffff9091168152602001610118565b6101346102e3366004610cf5565b6108ee565b3373ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000161461039a576040517f1cf993f400000000000000000000000000000000000000000000000000000000815233600482015273ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001660248201526044015b60405180910390fd5b6103a48282610902565b5050565b60015473ffffffffffffffffffffffffffffffffffffffff163314610429576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e6572000000000000000000006044820152606401610391565b60008054337fffffffffffffffffffffffff00000000000000000000000000000000000000008083168217845560018054909116905560405173ffffffffffffffffffffffffffffffffffffffff90921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b6104ad610a2d565b60005b8161ffff168161ffff1610156106ad576002546040517f5d3b1d300000000000000000000000000000000000000000000000000000000081526004810187905274010000000000000000000000000000000000000000820467ffffffffffffffff16602482015261ffff8816604482015263ffffffff80871660648301528516608482015260009173ffffffffffffffffffffffffffffffffffffffff1690635d3b1d309060a401602060405180830381600087803b15801561057257600080fd5b505af1158015610586573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105aa9190610da9565b6008819055905060006105bb610ab0565b6040805160c08101825260008082528251818152602080820185528084019182524284860152606084018390526080840186905260a08401839052878352600a815293909120825181547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169015151781559051805194955091939092610649926001850192910190610c6a565b506040820151600282015560608201516003820155608082015160048083019190915560a090920151600590910155805490600061068683610fe6565b909155505060009182526009602052604090912055806106a581610fc4565b9150506104b0565b506002546040517f9f87fad700000000000000000000000000000000000000000000000000000000815274010000000000000000000000000000000000000000820467ffffffffffffffff16600482015230602482015273ffffffffffffffffffffffffffffffffffffffff90911690639f87fad790604401600060405180830381600087803b15801561074057600080fd5b505af1158015610754573d6000803e3d6000fd5b50506002546040517fd7ae1d3000000000000000000000000000000000000000000000000000000000815274010000000000000000000000000000000000000000820467ffffffffffffffff16600482015233602482015273ffffffffffffffffffffffffffffffffffffffff909116925063d7ae1d309150604401600060405180830381600087803b1580156107ea57600080fd5b505af11580156107fe573d6000803e3d6000fd5b505050505050505050565b6000818152600a60209081526040808320815160c081018352815460ff161515815260018201805484518187028101870190955280855260609587958695869586958695919492938584019390929083018282801561088757602002820191906000526020600020905b815481526020019060010190808311610873575b505050505081526020016002820154815260200160038201548152602001600482015481526020016005820154815250509050806000015181602001518260400151836060015184608001518560a001519650965096509650965096505091939550919395565b6108f6610a2d565b6108ff81610b4d565b50565b600061090c610ab0565b600084815260096020526040812054919250906109299083610fad565b9050600061093a82620f4240610f70565b905060065482111561094c5760068290555b600754821061095d5760075461095f565b815b60075560035461096f57806109a2565b60035461097d906001610f1d565b8160035460055461098e9190610f70565b6109989190610f1d565b6109a29190610f35565b6005556000858152600a6020908152604090912080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001908117825586516109f4939290910191870190610c6a565b506000858152600a60205260408120426003808301919091556005909101859055805491610a2183610fe6565b91905055505050505050565b60005473ffffffffffffffffffffffffffffffffffffffff163314610aae576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e6572000000000000000000006044820152606401610391565b565b600046610abc81610c43565b15610b4657606473ffffffffffffffffffffffffffffffffffffffff1663a3b1b31d6040518163ffffffff1660e01b815260040160206040518083038186803b158015610b0857600080fd5b505afa158015610b1c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b409190610da9565b91505090565b4391505090565b73ffffffffffffffffffffffffffffffffffffffff8116331415610bcd576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c660000000000000000006044820152606401610391565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b600061a4b1821480610c57575062066eed82145b80610c64575062066eee82145b92915050565b828054828255906000526020600020908101928215610ca5579160200282015b82811115610ca5578251825591602001919060010190610c8a565b50610cb1929150610cb5565b5090565b5b80821115610cb15760008155600101610cb6565b803561ffff81168114610cdc57600080fd5b919050565b803563ffffffff81168114610cdc57600080fd5b600060208284031215610d0757600080fd5b813573ffffffffffffffffffffffffffffffffffffffff81168114610d2b57600080fd5b9392505050565b600080600080600060a08688031215610d4a57600080fd5b610d5386610cca565b945060208601359350610d6860408701610ce1565b9250610d7660608701610ce1565b9150610d8460808701610cca565b90509295509295909350565b600060208284031215610da257600080fd5b5035919050565b600060208284031215610dbb57600080fd5b5051919050565b60008060408385031215610dd557600080fd5b8235915060208084013567ffffffffffffffff80821115610df557600080fd5b818601915086601f830112610e0957600080fd5b813581811115610e1b57610e1b61104e565b8060051b6040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0603f83011681018181108582111715610e5e57610e5e61104e565b604052828152858101935084860182860187018b1015610e7d57600080fd5b600095505b83861015610ea0578035855260019590950194938601938601610e82565b508096505050505050509250929050565b600060c082018815158352602060c08185015281895180845260e086019150828b01935060005b81811015610ef457845183529383019391830191600101610ed8565b505060408501989098525050506060810193909352608083019190915260a09091015292915050565b60008219821115610f3057610f3061101f565b500190565b600082610f6b577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500490565b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0483118215151615610fa857610fa861101f565b500290565b600082821015610fbf57610fbf61101f565b500390565b600061ffff80831681811415610fdc57610fdc61101f565b6001019392505050565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8214156110185761101861101f565b5060010190565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fdfea164736f6c6343000806000a", + 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\"},{\"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\":\"uint64\",\"name\":\"subId\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"consumer\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"SubscriptionCreatedFundedAndConsumerAdded\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"COORDINATOR\",\"outputs\":[{\"internalType\":\"contractVRFCoordinatorV2Interface\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"LINKTOKEN\",\"outputs\":[{\"internalType\":\"contractLinkTokenInterface\",\"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\"},{\"internalType\":\"uint256\",\"name\":\"_subTopUpAmount\",\"type\":\"uint256\"}],\"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\":\"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\"}]", + Bin: "0x60a0604052600060065560006007556103e76008553480156200002157600080fd5b50604051620016ee380380620016ee8339810160408190526200004491620001e2565b6001600160601b0319606083901b166080523380600081620000ad5760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b0384811691909117909155811615620000e057620000e08162000119565b5050600280546001600160a01b039485166001600160a01b0319918216179091556003805493909416921691909117909155506200021a565b6001600160a01b038116331415620001745760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c660000000000000000006044820152606401620000a4565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b80516001600160a01b0381168114620001dd57600080fd5b919050565b60008060408385031215620001f657600080fd5b6200020183620001c5565b91506200021160208401620001c5565b90509250929050565b60805160601c6114ae620002406000396000818161036901526103d101526114ae6000f3fe608060405234801561001057600080fd5b50600436106101365760003560e01c80638da5cb5b116100b2578063d8a4676f11610081578063eb1d28bb11610066578063eb1d28bb146102e6578063f2fde38b1461032b578063f82d24381461033e57600080fd5b8063d8a4676f146102b8578063dc1670db146102dd57600080fd5b80638da5cb5b14610207578063a168fa8914610225578063b1e2174914610290578063d826f88f1461029957600080fd5b8063557d2e921161010957806374dba124116100ee57806374dba124146101e357806379ba5097146101ec57806386850e93146101f457600080fd5b8063557d2e92146101d1578063737144bc146101da57600080fd5b80631757f11c1461013b5780631fe543e3146101575780633b2bcbf11461016c57806355380dfb146101b1575b600080fd5b61014460075481565b6040519081526020015b60405180910390f35b61016a610165366004611124565b610351565b005b60025461018c9073ffffffffffffffffffffffffffffffffffffffff1681565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200161014e565b60035461018c9073ffffffffffffffffffffffffffffffffffffffff1681565b61014460055481565b61014460065481565b61014460085481565b61016a610411565b61016a6102023660046110f2565b61050e565b60005473ffffffffffffffffffffffffffffffffffffffff1661018c565b6102666102333660046110f2565b600b602052600090815260409020805460028201546003830154600484015460059094015460ff90931693919290919085565b6040805195151586526020860194909452928401919091526060830152608082015260a00161014e565b61014460095481565b61016a6000600681905560078190556103e76008556005819055600455565b6102cb6102c63660046110f2565b6105ea565b60405161014e969594939291906112d5565b61014460045481565b6003546103129074010000000000000000000000000000000000000000900467ffffffffffffffff1681565b60405167ffffffffffffffff909116815260200161014e565b61016a61033936600461102d565b6106cf565b61016a61034c36600461108c565b6106e3565b3373ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001614610403576040517f1cf993f400000000000000000000000000000000000000000000000000000000815233600482015273ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001660248201526044015b60405180910390fd5b61040d8282610c3e565b5050565b60015473ffffffffffffffffffffffffffffffffffffffff163314610492576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e65720000000000000000000060448201526064016103fa565b60008054337fffffffffffffffffffffffff00000000000000000000000000000000000000008083168217845560018054909116905560405173ffffffffffffffffffffffffffffffffffffffff90921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b610516610d65565b6003546002546040805174010000000000000000000000000000000000000000840467ffffffffffffffff16602082015273ffffffffffffffffffffffffffffffffffffffff93841693634000aea09316918591016040516020818303038152906040526040518463ffffffff1660e01b81526004016105989392919061123d565b602060405180830381600087803b1580156105b257600080fd5b505af11580156105c6573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061040d919061106a565b6000818152600b60209081526040808320815160c081018352815460ff161515815260018201805484518187028101870190955280855260609587958695869586958695919492938584019390929083018282801561066857602002820191906000526020600020905b815481526020019060010190808311610654575b505050505081526020016002820154815260200160038201548152602001600482015481526020016005820154815250509050806000015181602001518260400151836060015184608001518560a001519650965096509650965096505091939550919395565b6106d7610d65565b6106e081610de8565b50565b6106eb610d65565b600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663a21a23e46040518163ffffffff1660e01b8152600401602060405180830381600087803b15801561075557600080fd5b505af1158015610769573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061078d9190611213565b600380547fffffffff0000000000000000ffffffffffffffffffffffffffffffffffffffff167401000000000000000000000000000000000000000067ffffffffffffffff938416810291909117918290556002546040517f7341c10c00000000000000000000000000000000000000000000000000000000815291909204909216600483015230602483015273ffffffffffffffffffffffffffffffffffffffff1690637341c10c90604401600060405180830381600087803b15801561085457600080fd5b505af1158015610868573d6000803e3d6000fd5b505050506108758161050e565b600354604080517401000000000000000000000000000000000000000090920467ffffffffffffffff16825230602083015281018290527f56c142509574e8340ca0190b029c74464b84037d2876278ea0ade3ffb1f0042c9060600160405180910390a160005b8261ffff168161ffff161015610ad9576002546003546040517f5d3b1d30000000000000000000000000000000000000000000000000000000008152600481018990527401000000000000000000000000000000000000000090910467ffffffffffffffff16602482015261ffff8916604482015263ffffffff80881660648301528616608482015260009173ffffffffffffffffffffffffffffffffffffffff1690635d3b1d309060a401602060405180830381600087803b1580156109a257600080fd5b505af11580156109b6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109da919061110b565b6009819055905060006109eb610ede565b6040805160c08101825260008082528251818152602080820185528084019182524284860152606084018390526080840186905260a08401839052878352600b815293909120825181547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169015151781559051805194955091939092610a79926001850192910190610fa2565b5060408201516002820155606082015160038201556080820151600482015560a0909101516005918201558054906000610ab28361140a565b90915550506000918252600a60205260409091205580610ad1816113e8565b9150506108dc565b506002546003546040517f9f87fad70000000000000000000000000000000000000000000000000000000081527401000000000000000000000000000000000000000090910467ffffffffffffffff16600482015230602482015273ffffffffffffffffffffffffffffffffffffffff90911690639f87fad790604401600060405180830381600087803b158015610b7057600080fd5b505af1158015610b84573d6000803e3d6000fd5b50506002546003546040517fd7ae1d300000000000000000000000000000000000000000000000000000000081527401000000000000000000000000000000000000000090910467ffffffffffffffff16600482015233602482015273ffffffffffffffffffffffffffffffffffffffff909116925063d7ae1d309150604401600060405180830381600087803b158015610c1e57600080fd5b505af1158015610c32573d6000803e3d6000fd5b50505050505050505050565b6000610c48610ede565b6000848152600a602052604081205491925090610c6590836113d1565b90506000610c7682620f4240611394565b9050600754821115610c885760078290555b6008548210610c9957600854610c9b565b815b600855600454610cab5780610cde565b600454610cb9906001611341565b81600454600654610cca9190611394565b610cd49190611341565b610cde9190611359565b6006556000858152600b6020908152604090912080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016600190811782558651610d30939290910191870190610fa2565b506000858152600b602052604081204260038201556005018490556004805491610d598361140a565b91905055505050505050565b60005473ffffffffffffffffffffffffffffffffffffffff163314610de6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e65720000000000000000000060448201526064016103fa565b565b73ffffffffffffffffffffffffffffffffffffffff8116331415610e68576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c6600000000000000000060448201526064016103fa565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b600046610eea81610f7b565b15610f7457606473ffffffffffffffffffffffffffffffffffffffff1663a3b1b31d6040518163ffffffff1660e01b815260040160206040518083038186803b158015610f3657600080fd5b505afa158015610f4a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f6e919061110b565b91505090565b4391505090565b600061a4b1821480610f8f575062066eed82145b80610f9c575062066eee82145b92915050565b828054828255906000526020600020908101928215610fdd579160200282015b82811115610fdd578251825591602001919060010190610fc2565b50610fe9929150610fed565b5090565b5b80821115610fe95760008155600101610fee565b803561ffff8116811461101457600080fd5b919050565b803563ffffffff8116811461101457600080fd5b60006020828403121561103f57600080fd5b813573ffffffffffffffffffffffffffffffffffffffff8116811461106357600080fd5b9392505050565b60006020828403121561107c57600080fd5b8151801515811461106357600080fd5b60008060008060008060c087890312156110a557600080fd5b6110ae87611002565b9550602087013594506110c360408801611019565b93506110d160608801611019565b92506110df60808801611002565b915060a087013590509295509295509295565b60006020828403121561110457600080fd5b5035919050565b60006020828403121561111d57600080fd5b5051919050565b6000806040838503121561113757600080fd5b8235915060208084013567ffffffffffffffff8082111561115757600080fd5b818601915086601f83011261116b57600080fd5b81358181111561117d5761117d611472565b8060051b6040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0603f830116810181811085821117156111c0576111c0611472565b604052828152858101935084860182860187018b10156111df57600080fd5b600095505b838610156112025780358552600195909501949386019386016111e4565b508096505050505050509250929050565b60006020828403121561122557600080fd5b815167ffffffffffffffff8116811461106357600080fd5b73ffffffffffffffffffffffffffffffffffffffff8416815260006020848184015260606040840152835180606085015260005b8181101561128d57858101830151858201608001528201611271565b8181111561129f576000608083870101525b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160800195945050505050565b600060c082018815158352602060c08185015281895180845260e086019150828b01935060005b81811015611318578451835293830193918301916001016112fc565b505060408501989098525050506060810193909352608083019190915260a09091015292915050565b6000821982111561135457611354611443565b500190565b60008261138f577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500490565b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff04831182151516156113cc576113cc611443565b500290565b6000828210156113e3576113e3611443565b500390565b600061ffff8083168181141561140057611400611443565b6001019392505050565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82141561143c5761143c611443565b5060010190565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fdfea164736f6c6343000806000a", } var VRFV2OwnerTestConsumerABI = VRFV2OwnerTestConsumerMetaData.ABI var VRFV2OwnerTestConsumerBin = VRFV2OwnerTestConsumerMetaData.Bin -func DeployVRFV2OwnerTestConsumer(auth *bind.TransactOpts, backend bind.ContractBackend, _vrfCoordinator common.Address) (common.Address, *types.Transaction, *VRFV2OwnerTestConsumer, error) { +func DeployVRFV2OwnerTestConsumer(auth *bind.TransactOpts, backend bind.ContractBackend, _vrfCoordinator common.Address, _link common.Address) (common.Address, *types.Transaction, *VRFV2OwnerTestConsumer, error) { parsed, err := VRFV2OwnerTestConsumerMetaData.GetAbi() if err != nil { return common.Address{}, nil, nil, err @@ -48,7 +48,7 @@ func DeployVRFV2OwnerTestConsumer(auth *bind.TransactOpts, backend bind.Contract return common.Address{}, nil, nil, errors.New("GetABI returned nil") } - address, tx, contract, err := bind.DeployContract(auth, *parsed, common.FromHex(VRFV2OwnerTestConsumerBin), backend, _vrfCoordinator) + address, tx, contract, err := bind.DeployContract(auth, *parsed, common.FromHex(VRFV2OwnerTestConsumerBin), backend, _vrfCoordinator, _link) if err != nil { return common.Address{}, nil, nil, err } @@ -193,6 +193,28 @@ func (_VRFV2OwnerTestConsumer *VRFV2OwnerTestConsumerCallerSession) COORDINATOR( return _VRFV2OwnerTestConsumer.Contract.COORDINATOR(&_VRFV2OwnerTestConsumer.CallOpts) } +func (_VRFV2OwnerTestConsumer *VRFV2OwnerTestConsumerCaller) LINKTOKEN(opts *bind.CallOpts) (common.Address, error) { + var out []interface{} + err := _VRFV2OwnerTestConsumer.contract.Call(opts, &out, "LINKTOKEN") + + if err != nil { + return *new(common.Address), err + } + + out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) + + return out0, err + +} + +func (_VRFV2OwnerTestConsumer *VRFV2OwnerTestConsumerSession) LINKTOKEN() (common.Address, error) { + return _VRFV2OwnerTestConsumer.Contract.LINKTOKEN(&_VRFV2OwnerTestConsumer.CallOpts) +} + +func (_VRFV2OwnerTestConsumer *VRFV2OwnerTestConsumerCallerSession) LINKTOKEN() (common.Address, error) { + return _VRFV2OwnerTestConsumer.Contract.LINKTOKEN(&_VRFV2OwnerTestConsumer.CallOpts) +} + func (_VRFV2OwnerTestConsumer *VRFV2OwnerTestConsumerCaller) GetRequestStatus(opts *bind.CallOpts, _requestId *big.Int) (GetRequestStatus, error) { @@ -460,16 +482,16 @@ func (_VRFV2OwnerTestConsumer *VRFV2OwnerTestConsumerTransactorSession) RawFulfi return _VRFV2OwnerTestConsumer.Contract.RawFulfillRandomWords(&_VRFV2OwnerTestConsumer.TransactOpts, requestId, randomWords) } -func (_VRFV2OwnerTestConsumer *VRFV2OwnerTestConsumerTransactor) RequestRandomWords(opts *bind.TransactOpts, _requestConfirmations uint16, _keyHash [32]byte, _callbackGasLimit uint32, _numWords uint32, _requestCount uint16) (*types.Transaction, error) { - return _VRFV2OwnerTestConsumer.contract.Transact(opts, "requestRandomWords", _requestConfirmations, _keyHash, _callbackGasLimit, _numWords, _requestCount) +func (_VRFV2OwnerTestConsumer *VRFV2OwnerTestConsumerTransactor) RequestRandomWords(opts *bind.TransactOpts, _requestConfirmations uint16, _keyHash [32]byte, _callbackGasLimit uint32, _numWords uint32, _requestCount uint16, _subTopUpAmount *big.Int) (*types.Transaction, error) { + return _VRFV2OwnerTestConsumer.contract.Transact(opts, "requestRandomWords", _requestConfirmations, _keyHash, _callbackGasLimit, _numWords, _requestCount, _subTopUpAmount) } -func (_VRFV2OwnerTestConsumer *VRFV2OwnerTestConsumerSession) RequestRandomWords(_requestConfirmations uint16, _keyHash [32]byte, _callbackGasLimit uint32, _numWords uint32, _requestCount uint16) (*types.Transaction, error) { - return _VRFV2OwnerTestConsumer.Contract.RequestRandomWords(&_VRFV2OwnerTestConsumer.TransactOpts, _requestConfirmations, _keyHash, _callbackGasLimit, _numWords, _requestCount) +func (_VRFV2OwnerTestConsumer *VRFV2OwnerTestConsumerSession) RequestRandomWords(_requestConfirmations uint16, _keyHash [32]byte, _callbackGasLimit uint32, _numWords uint32, _requestCount uint16, _subTopUpAmount *big.Int) (*types.Transaction, error) { + return _VRFV2OwnerTestConsumer.Contract.RequestRandomWords(&_VRFV2OwnerTestConsumer.TransactOpts, _requestConfirmations, _keyHash, _callbackGasLimit, _numWords, _requestCount, _subTopUpAmount) } -func (_VRFV2OwnerTestConsumer *VRFV2OwnerTestConsumerTransactorSession) RequestRandomWords(_requestConfirmations uint16, _keyHash [32]byte, _callbackGasLimit uint32, _numWords uint32, _requestCount uint16) (*types.Transaction, error) { - return _VRFV2OwnerTestConsumer.Contract.RequestRandomWords(&_VRFV2OwnerTestConsumer.TransactOpts, _requestConfirmations, _keyHash, _callbackGasLimit, _numWords, _requestCount) +func (_VRFV2OwnerTestConsumer *VRFV2OwnerTestConsumerTransactorSession) RequestRandomWords(_requestConfirmations uint16, _keyHash [32]byte, _callbackGasLimit uint32, _numWords uint32, _requestCount uint16, _subTopUpAmount *big.Int) (*types.Transaction, error) { + return _VRFV2OwnerTestConsumer.Contract.RequestRandomWords(&_VRFV2OwnerTestConsumer.TransactOpts, _requestConfirmations, _keyHash, _callbackGasLimit, _numWords, _requestCount, _subTopUpAmount) } func (_VRFV2OwnerTestConsumer *VRFV2OwnerTestConsumerTransactor) Reset(opts *bind.TransactOpts) (*types.Transaction, error) { @@ -484,6 +506,18 @@ func (_VRFV2OwnerTestConsumer *VRFV2OwnerTestConsumerTransactorSession) Reset() return _VRFV2OwnerTestConsumer.Contract.Reset(&_VRFV2OwnerTestConsumer.TransactOpts) } +func (_VRFV2OwnerTestConsumer *VRFV2OwnerTestConsumerTransactor) TopUpSubscription(opts *bind.TransactOpts, amount *big.Int) (*types.Transaction, error) { + return _VRFV2OwnerTestConsumer.contract.Transact(opts, "topUpSubscription", amount) +} + +func (_VRFV2OwnerTestConsumer *VRFV2OwnerTestConsumerSession) TopUpSubscription(amount *big.Int) (*types.Transaction, error) { + return _VRFV2OwnerTestConsumer.Contract.TopUpSubscription(&_VRFV2OwnerTestConsumer.TransactOpts, amount) +} + +func (_VRFV2OwnerTestConsumer *VRFV2OwnerTestConsumerTransactorSession) TopUpSubscription(amount *big.Int) (*types.Transaction, error) { + return _VRFV2OwnerTestConsumer.Contract.TopUpSubscription(&_VRFV2OwnerTestConsumer.TransactOpts, amount) +} + func (_VRFV2OwnerTestConsumer *VRFV2OwnerTestConsumerTransactor) TransferOwnership(opts *bind.TransactOpts, to common.Address) (*types.Transaction, error) { return _VRFV2OwnerTestConsumer.contract.Transact(opts, "transferOwnership", to) } @@ -768,6 +802,125 @@ func (_VRFV2OwnerTestConsumer *VRFV2OwnerTestConsumerFilterer) ParseOwnershipTra return event, nil } +type VRFV2OwnerTestConsumerSubscriptionCreatedFundedAndConsumerAddedIterator struct { + Event *VRFV2OwnerTestConsumerSubscriptionCreatedFundedAndConsumerAdded + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *VRFV2OwnerTestConsumerSubscriptionCreatedFundedAndConsumerAddedIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(VRFV2OwnerTestConsumerSubscriptionCreatedFundedAndConsumerAdded) + 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(VRFV2OwnerTestConsumerSubscriptionCreatedFundedAndConsumerAdded) + 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 *VRFV2OwnerTestConsumerSubscriptionCreatedFundedAndConsumerAddedIterator) Error() error { + return it.fail +} + +func (it *VRFV2OwnerTestConsumerSubscriptionCreatedFundedAndConsumerAddedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type VRFV2OwnerTestConsumerSubscriptionCreatedFundedAndConsumerAdded struct { + SubId uint64 + Consumer common.Address + Amount *big.Int + Raw types.Log +} + +func (_VRFV2OwnerTestConsumer *VRFV2OwnerTestConsumerFilterer) FilterSubscriptionCreatedFundedAndConsumerAdded(opts *bind.FilterOpts) (*VRFV2OwnerTestConsumerSubscriptionCreatedFundedAndConsumerAddedIterator, error) { + + logs, sub, err := _VRFV2OwnerTestConsumer.contract.FilterLogs(opts, "SubscriptionCreatedFundedAndConsumerAdded") + if err != nil { + return nil, err + } + return &VRFV2OwnerTestConsumerSubscriptionCreatedFundedAndConsumerAddedIterator{contract: _VRFV2OwnerTestConsumer.contract, event: "SubscriptionCreatedFundedAndConsumerAdded", logs: logs, sub: sub}, nil +} + +func (_VRFV2OwnerTestConsumer *VRFV2OwnerTestConsumerFilterer) WatchSubscriptionCreatedFundedAndConsumerAdded(opts *bind.WatchOpts, sink chan<- *VRFV2OwnerTestConsumerSubscriptionCreatedFundedAndConsumerAdded) (event.Subscription, error) { + + logs, sub, err := _VRFV2OwnerTestConsumer.contract.WatchLogs(opts, "SubscriptionCreatedFundedAndConsumerAdded") + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(VRFV2OwnerTestConsumerSubscriptionCreatedFundedAndConsumerAdded) + if err := _VRFV2OwnerTestConsumer.contract.UnpackLog(event, "SubscriptionCreatedFundedAndConsumerAdded", 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 (_VRFV2OwnerTestConsumer *VRFV2OwnerTestConsumerFilterer) ParseSubscriptionCreatedFundedAndConsumerAdded(log types.Log) (*VRFV2OwnerTestConsumerSubscriptionCreatedFundedAndConsumerAdded, error) { + event := new(VRFV2OwnerTestConsumerSubscriptionCreatedFundedAndConsumerAdded) + if err := _VRFV2OwnerTestConsumer.contract.UnpackLog(event, "SubscriptionCreatedFundedAndConsumerAdded", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + type GetRequestStatus struct { Fulfilled bool RandomWords []*big.Int @@ -790,6 +943,8 @@ func (_VRFV2OwnerTestConsumer *VRFV2OwnerTestConsumer) ParseLog(log types.Log) ( return _VRFV2OwnerTestConsumer.ParseOwnershipTransferRequested(log) case _VRFV2OwnerTestConsumer.abi.Events["OwnershipTransferred"].ID: return _VRFV2OwnerTestConsumer.ParseOwnershipTransferred(log) + case _VRFV2OwnerTestConsumer.abi.Events["SubscriptionCreatedFundedAndConsumerAdded"].ID: + return _VRFV2OwnerTestConsumer.ParseSubscriptionCreatedFundedAndConsumerAdded(log) default: return nil, fmt.Errorf("abigen wrapper received unknown log topic: %v", log.Topics[0]) @@ -804,6 +959,10 @@ func (VRFV2OwnerTestConsumerOwnershipTransferred) Topic() common.Hash { return common.HexToHash("0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0") } +func (VRFV2OwnerTestConsumerSubscriptionCreatedFundedAndConsumerAdded) Topic() common.Hash { + return common.HexToHash("0x56c142509574e8340ca0190b029c74464b84037d2876278ea0ade3ffb1f0042c") +} + func (_VRFV2OwnerTestConsumer *VRFV2OwnerTestConsumer) Address() common.Address { return _VRFV2OwnerTestConsumer.address } @@ -811,6 +970,8 @@ func (_VRFV2OwnerTestConsumer *VRFV2OwnerTestConsumer) Address() common.Address type VRFV2OwnerTestConsumerInterface interface { COORDINATOR(opts *bind.CallOpts) (common.Address, error) + LINKTOKEN(opts *bind.CallOpts) (common.Address, error) + GetRequestStatus(opts *bind.CallOpts, _requestId *big.Int) (GetRequestStatus, error) @@ -839,10 +1000,12 @@ type VRFV2OwnerTestConsumerInterface interface { RawFulfillRandomWords(opts *bind.TransactOpts, requestId *big.Int, randomWords []*big.Int) (*types.Transaction, error) - RequestRandomWords(opts *bind.TransactOpts, _requestConfirmations uint16, _keyHash [32]byte, _callbackGasLimit uint32, _numWords uint32, _requestCount uint16) (*types.Transaction, error) + RequestRandomWords(opts *bind.TransactOpts, _requestConfirmations uint16, _keyHash [32]byte, _callbackGasLimit uint32, _numWords uint32, _requestCount uint16, _subTopUpAmount *big.Int) (*types.Transaction, error) Reset(opts *bind.TransactOpts) (*types.Transaction, error) + TopUpSubscription(opts *bind.TransactOpts, amount *big.Int) (*types.Transaction, error) + TransferOwnership(opts *bind.TransactOpts, to common.Address) (*types.Transaction, error) FilterOwnershipTransferRequested(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*VRFV2OwnerTestConsumerOwnershipTransferRequestedIterator, error) @@ -857,6 +1020,12 @@ type VRFV2OwnerTestConsumerInterface interface { ParseOwnershipTransferred(log types.Log) (*VRFV2OwnerTestConsumerOwnershipTransferred, error) + FilterSubscriptionCreatedFundedAndConsumerAdded(opts *bind.FilterOpts) (*VRFV2OwnerTestConsumerSubscriptionCreatedFundedAndConsumerAddedIterator, error) + + WatchSubscriptionCreatedFundedAndConsumerAdded(opts *bind.WatchOpts, sink chan<- *VRFV2OwnerTestConsumerSubscriptionCreatedFundedAndConsumerAdded) (event.Subscription, error) + + ParseSubscriptionCreatedFundedAndConsumerAdded(log types.Log) (*VRFV2OwnerTestConsumerSubscriptionCreatedFundedAndConsumerAdded, error) + ParseLog(log types.Log) (generated.AbigenLog, error) Address() common.Address 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 0dd8e4cbb9..e967964daa 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,4 +1,4 @@ -GETH_VERSION: 1.12.2 +GETH_VERSION: 1.13.8 aggregator_v2v3_interface: ../../contracts/solc/v0.8.6/AggregatorV2V3Interface/AggregatorV2V3Interface.abi ../../contracts/solc/v0.8.6/AggregatorV2V3Interface/AggregatorV2V3Interface.bin 95e8814b408bb05bf21742ef580d98698b7db6a9bac6a35c3de12b23aec4ee28 aggregator_v3_interface: ../../contracts/solc/v0.8.6/AggregatorV2V3Interface/AggregatorV3Interface.abi ../../contracts/solc/v0.8.6/AggregatorV2V3Interface/AggregatorV3Interface.bin 351b55d3b0f04af67db6dfb5c92f1c64479400ca1fec77afc20bc0ce65cb49ab authorized_forwarder: ../../contracts/solc/v0.8.19/AuthorizedForwarder/AuthorizedForwarder.abi ../../contracts/solc/v0.8.19/AuthorizedForwarder/AuthorizedForwarder.bin 8ea76c883d460f8353a45a493f2aebeb5a2d9a7b4619d1bc4fff5fb590bb3e10 @@ -6,11 +6,14 @@ authorized_receiver: ../../contracts/solc/v0.8.19/AuthorizedReceiver/AuthorizedR automation_consumer_benchmark: ../../contracts/solc/v0.8.16/AutomationConsumerBenchmark/AutomationConsumerBenchmark.abi ../../contracts/solc/v0.8.16/AutomationConsumerBenchmark/AutomationConsumerBenchmark.bin f52c76f1aaed4be541d82d97189d70f5aa027fc9838037dd7a7d21910c8c488e automation_forwarder_logic: ../../contracts/solc/v0.8.16/AutomationForwarderLogic/AutomationForwarderLogic.abi ../../contracts/solc/v0.8.16/AutomationForwarderLogic/AutomationForwarderLogic.bin 15ae0c367297955fdab4b552dbb10e1f2be80a8fde0efec4a4d398693e9d72b5 automation_registrar_wrapper2_1: ../../contracts/solc/v0.8.16/AutomationRegistrar2_1/AutomationRegistrar2_1.abi ../../contracts/solc/v0.8.16/AutomationRegistrar2_1/AutomationRegistrar2_1.bin eb06d853aab39d3196c593b03e555851cbe8386e0fe54a74c2479f62d14b3c42 +automation_registrar_wrapper2_2: ../../contracts/solc/v0.8.16/AutomationRegistrar2_2/AutomationRegistrar2_2.abi ../../contracts/solc/v0.8.16/AutomationRegistrar2_2/AutomationRegistrar2_2.bin 1da3ede9459c097482de224a47025ef7d578c7a73bafdbe4d471989ca4ecb608 automation_utils_2_1: ../../contracts/solc/v0.8.16/AutomationUtils2_1/AutomationUtils2_1.abi ../../contracts/solc/v0.8.16/AutomationUtils2_1/AutomationUtils2_1.bin 331bfa79685aee6ddf63b64c0747abee556c454cae3fb8175edff425b615d8aa +automation_utils_2_2: ../../contracts/solc/v0.8.16/AutomationUtils2_2/AutomationUtils2_2.abi ../../contracts/solc/v0.8.16/AutomationUtils2_2/AutomationUtils2_2.bin 4f8055e0d47c0fa88f545d0160b04666a0d7720da8fd1206405da0bcf410b426 batch_blockhash_store: ../../contracts/solc/v0.8.6/BatchBlockhashStore/BatchBlockhashStore.abi ../../contracts/solc/v0.8.6/BatchBlockhashStore/BatchBlockhashStore.bin 14356c48ef70f66ef74f22f644450dbf3b2a147c1b68deaa7e7d1eb8ffab15db batch_vrf_coordinator_v2: ../../contracts/solc/v0.8.6/BatchVRFCoordinatorV2/BatchVRFCoordinatorV2.abi ../../contracts/solc/v0.8.6/BatchVRFCoordinatorV2/BatchVRFCoordinatorV2.bin d0a54963260d8c1f1bbd984b758285e6027cfb5a7e42701bcb562ab123219332 batch_vrf_coordinator_v2plus: ../../contracts/solc/v0.8.6/BatchVRFCoordinatorV2Plus/BatchVRFCoordinatorV2Plus.abi ../../contracts/solc/v0.8.6/BatchVRFCoordinatorV2Plus/BatchVRFCoordinatorV2Plus.bin 7bb76ae241cf1b37b41920830b836cb99f1ad33efd7435ca2398ff6cd2fe5d48 blockhash_store: ../../contracts/solc/v0.8.6/BlockhashStore/BlockhashStore.abi ../../contracts/solc/v0.8.6/BlockhashStore/BlockhashStore.bin 12b0662f1636a341c8863bdec7a20f2ddd97c3a4fd1a7ae353fe316609face4e +chain_reader_example: ../../contracts/solc/v0.8.19/ChainReaderTestContract/LatestValueHolder.abi ../../contracts/solc/v0.8.19/ChainReaderTestContract/LatestValueHolder.bin de88c7e68de36b96aa2bec844bdc96fcd7c9017b38e25062b3b9f9cec42c814f chain_specific_util_helper: ../../contracts/solc/v0.8.6/ChainSpecificUtilHelper/ChainSpecificUtilHelper.abi ../../contracts/solc/v0.8.6/ChainSpecificUtilHelper/ChainSpecificUtilHelper.bin 5f10664e31abc768f4a37901cae7a3bef90146180f97303e5a1bde5a08d84595 consumer_wrapper: ../../contracts/solc/v0.7/Consumer/Consumer.abi ../../contracts/solc/v0.7/Consumer/Consumer.bin 894d1cbd920dccbd36d92918c1037c6ded34f66f417ccb18ec3f33c64ef83ec5 cron_upkeep_factory_wrapper: ../../contracts/solc/v0.8.6/CronUpkeepFactory/CronUpkeepFactory.abi - dacb0f8cdf54ae9d2781c5e720fc314b32ed5e58eddccff512c75d6067292cd7 @@ -21,6 +24,7 @@ flux_aggregator_wrapper: ../../contracts/solc/v0.6/FluxAggregator/FluxAggregator gas_wrapper: ../../contracts/solc/v0.8.6/KeeperRegistryCheckUpkeepGasUsageWrapper1_2/KeeperRegistryCheckUpkeepGasUsageWrapper1_2.abi ../../contracts/solc/v0.8.6/KeeperRegistryCheckUpkeepGasUsageWrapper1_2/KeeperRegistryCheckUpkeepGasUsageWrapper1_2.bin 4a5dcdac486d18fcd58e3488c15c1710ae76b977556a3f3191bd269a4bc75723 gas_wrapper_mock: ../../contracts/solc/v0.8.6/KeeperRegistryCheckUpkeepGasUsageWrapper1_2Mock/KeeperRegistryCheckUpkeepGasUsageWrapper1_2Mock.abi ../../contracts/solc/v0.8.6/KeeperRegistryCheckUpkeepGasUsageWrapper1_2Mock/KeeperRegistryCheckUpkeepGasUsageWrapper1_2Mock.bin a9b08f18da59125c6fc305855710241f3d35161b8b9f3e3f635a7b1d5c6da9c8 i_keeper_registry_master_wrapper_2_1: ../../contracts/solc/v0.8.16/IKeeperRegistryMaster/IKeeperRegistryMaster.abi ../../contracts/solc/v0.8.16/IKeeperRegistryMaster/IKeeperRegistryMaster.bin 6501bb9bcf5048bab2737b00685c6984a24867e234ddf5b60a65904eee9a4ebc +i_keeper_registry_master_wrapper_2_2: ../../contracts/solc/v0.8.16/IAutomationRegistryMaster/IAutomationRegistryMaster.abi ../../contracts/solc/v0.8.16/IAutomationRegistryMaster/IAutomationRegistryMaster.bin 69fe8b127b71739606600760fc8fb01b3af1e8dba786ba0d047d766416acf83b i_log_automation: ../../contracts/solc/v0.8.16/ILogAutomation/ILogAutomation.abi ../../contracts/solc/v0.8.16/ILogAutomation/ILogAutomation.bin 296beccb6af655d6fc3a6e676b244831cce2da6688d3afc4f21f8738ae59e03e keeper_consumer_performance_wrapper: ../../contracts/solc/v0.8.16/KeeperConsumerPerformance/KeeperConsumerPerformance.abi ../../contracts/solc/v0.8.16/KeeperConsumerPerformance/KeeperConsumerPerformance.bin eeda39f5d3e1c8ffa0fb6cd1803731b98a4bc262d41833458e3fe8b40933ae90 keeper_consumer_wrapper: ../../contracts/solc/v0.8.16/KeeperConsumer/KeeperConsumer.abi ../../contracts/solc/v0.8.16/KeeperConsumer/KeeperConsumer.bin 2c6163b145082fbab74b7343577a9cec8fda8b0da9daccf2a82581b1f5a84b83 @@ -30,13 +34,16 @@ keeper_registrar_wrapper2_0: ../../contracts/solc/v0.8.6/KeeperRegistrar2_0/Keep keeper_registry_logic1_3: ../../contracts/solc/v0.8.6/KeeperRegistryLogic1_3/KeeperRegistryLogic1_3.abi ../../contracts/solc/v0.8.6/KeeperRegistryLogic1_3/KeeperRegistryLogic1_3.bin 903f8b9c8e25425ca6d0b81b89e339d695a83630bfbfa24a6f3b38869676bc5a keeper_registry_logic2_0: ../../contracts/solc/v0.8.6/KeeperRegistryLogic2_0/KeeperRegistryLogic2_0.abi ../../contracts/solc/v0.8.6/KeeperRegistryLogic2_0/KeeperRegistryLogic2_0.bin d69d2bc8e4844293dbc2d45abcddc50b84c88554ecccfa4fa77c0ca45ec80871 keeper_registry_logic_a_wrapper_2_1: ../../contracts/solc/v0.8.16/KeeperRegistryLogicA2_1/KeeperRegistryLogicA2_1.abi ../../contracts/solc/v0.8.16/KeeperRegistryLogicA2_1/KeeperRegistryLogicA2_1.bin 77481ab75c9aa86a62a7b2a708599b5ea1a6346ed1c0def6d4826e7ae523f1ee +keeper_registry_logic_a_wrapper_2_2: ../../contracts/solc/v0.8.16/AutomationRegistryLogicA2_2/AutomationRegistryLogicA2_2.abi ../../contracts/solc/v0.8.16/AutomationRegistryLogicA2_2/AutomationRegistryLogicA2_2.bin 202d0d7829daa0e6cb7b2cf55bacf5f0b0ea7d17ffe3d8241e5bf96a37f1b416 keeper_registry_logic_b_wrapper_2_1: ../../contracts/solc/v0.8.16/KeeperRegistryLogicB2_1/KeeperRegistryLogicB2_1.abi ../../contracts/solc/v0.8.16/KeeperRegistryLogicB2_1/KeeperRegistryLogicB2_1.bin 467d10741a04601b136553a2b1c6ab37f2a65d809366faf03180a22ff26be215 +keeper_registry_logic_b_wrapper_2_2: ../../contracts/solc/v0.8.16/AutomationRegistryLogicB2_2/AutomationRegistryLogicB2_2.abi ../../contracts/solc/v0.8.16/AutomationRegistryLogicB2_2/AutomationRegistryLogicB2_2.bin b1cca74805530042f1255b4cf50115c47e4186603d3f9d276bbe3773ad1d8285 keeper_registry_wrapper1_1: ../../contracts/solc/v0.7/KeeperRegistry1_1/KeeperRegistry1_1.abi ../../contracts/solc/v0.7/KeeperRegistry1_1/KeeperRegistry1_1.bin 6ce079f2738f015f7374673a2816e8e9787143d00b780ea7652c8aa9ad9e1e20 keeper_registry_wrapper1_1_mock: ../../contracts/solc/v0.7/KeeperRegistry1_1Mock/KeeperRegistry1_1Mock.abi ../../contracts/solc/v0.7/KeeperRegistry1_1Mock/KeeperRegistry1_1Mock.bin 98ddb3680e86359de3b5d17e648253ba29a84703f087a1b52237824003a8c6df keeper_registry_wrapper1_2: ../../contracts/solc/v0.8.6/KeeperRegistry1_2/KeeperRegistry1_2.abi ../../contracts/solc/v0.8.6/KeeperRegistry1_2/KeeperRegistry1_2.bin a40ff877dd7c280f984cbbb2b428e160662b0c295e881d5f778f941c0088ca22 keeper_registry_wrapper1_3: ../../contracts/solc/v0.8.6/KeeperRegistry1_3/KeeperRegistry1_3.abi ../../contracts/solc/v0.8.6/KeeperRegistry1_3/KeeperRegistry1_3.bin d4dc760b767ae274ee25c4a604ea371e1fa603a7b6421b69efb2088ad9e8abb3 keeper_registry_wrapper2_0: ../../contracts/solc/v0.8.6/KeeperRegistry2_0/KeeperRegistry2_0.abi ../../contracts/solc/v0.8.6/KeeperRegistry2_0/KeeperRegistry2_0.bin c32dea7d5ef66b7c58ddc84ddf69aa44df1b3ae8601fbc271c95be4ff5853056 keeper_registry_wrapper_2_1: ../../contracts/solc/v0.8.16/KeeperRegistry2_1/KeeperRegistry2_1.abi ../../contracts/solc/v0.8.16/KeeperRegistry2_1/KeeperRegistry2_1.bin 604e4a0cd980c713929b523b999462a3aa0ed06f96ff563a4c8566cf59c8445b +keeper_registry_wrapper_2_2: ../../contracts/solc/v0.8.16/AutomationRegistry2_2/AutomationRegistry2_2.abi ../../contracts/solc/v0.8.16/AutomationRegistry2_2/AutomationRegistry2_2.bin 9242df418f129e08d4e2eb0ee02a67781d3261f9c303035d87864765eed35b9b keepers_vrf_consumer: ../../contracts/solc/v0.8.6/KeepersVRFConsumer/KeepersVRFConsumer.abi ../../contracts/solc/v0.8.6/KeepersVRFConsumer/KeepersVRFConsumer.bin fa75572e689c9e84705c63e8dbe1b7b8aa1a8fe82d66356c4873d024bb9166e8 log_emitter: ../../contracts/solc/v0.8.19/LogEmitter/LogEmitter.abi ../../contracts/solc/v0.8.19/LogEmitter/LogEmitter.bin 4b129ab93432c95ff9143f0631323e189887668889e0b36ccccf18a571e41ccf log_triggered_streams_lookup_wrapper: ../../contracts/solc/v0.8.16/LogTriggeredStreamsLookup/LogTriggeredStreamsLookup.abi ../../contracts/solc/v0.8.16/LogTriggeredStreamsLookup/LogTriggeredStreamsLookup.bin f8da43a927c1a66238a9f4fd5d5dd7e280e361daa0444da1f7f79498ace901e1 @@ -74,6 +81,7 @@ vrf_consumer_v2: ../../contracts/solc/v0.8.6/VRFConsumerV2/VRFConsumerV2.abi ../ vrf_consumer_v2_plus_upgradeable_example: ../../contracts/solc/v0.8.6/VRFConsumerV2PlusUpgradeableExample/VRFConsumerV2PlusUpgradeableExample.abi ../../contracts/solc/v0.8.6/VRFConsumerV2PlusUpgradeableExample/VRFConsumerV2PlusUpgradeableExample.bin 3155c611e4d6882e9324b6e975033b31356776ea8b031ca63d63da37589d583b vrf_consumer_v2_upgradeable_example: ../../contracts/solc/v0.8.6/VRFConsumerV2UpgradeableExample/VRFConsumerV2UpgradeableExample.abi ../../contracts/solc/v0.8.6/VRFConsumerV2UpgradeableExample/VRFConsumerV2UpgradeableExample.bin f1790a9a2f2a04c730593e483459709cb89e897f8a19d7a3ac0cfe6a97265e6e vrf_coordinator_mock: ../../contracts/solc/v0.8.6/VRFCoordinatorMock/VRFCoordinatorMock.abi ../../contracts/solc/v0.8.6/VRFCoordinatorMock/VRFCoordinatorMock.bin 5c495cf8df1f46d8736b9150cdf174cce358cb8352f60f0d5bb9581e23920501 +vrf_coordinator_test_v2: ../../contracts/solc/v0.8.6/VRFCoordinatorTestV2/VRFCoordinatorTestV2.abi ../../contracts/solc/v0.8.6/VRFCoordinatorTestV2/VRFCoordinatorTestV2.bin eaefd785c38bac67fb11a7fc2737ab2da68c988ca170e7db8ff235c80893e01c vrf_coordinator_v2: ../../contracts/solc/v0.8.6/VRFCoordinatorV2/VRFCoordinatorV2.abi ../../contracts/solc/v0.8.6/VRFCoordinatorV2/VRFCoordinatorV2.bin 295f35ce282060317dfd01f45959f5a2b05ba26913e422fbd4fb6bf90b107006 vrf_coordinator_v2_5: ../../contracts/solc/v0.8.6/VRFCoordinatorV2_5/VRFCoordinatorV2_5.abi ../../contracts/solc/v0.8.6/VRFCoordinatorV2_5/VRFCoordinatorV2_5.bin bcad64e1b41278998c94867370fd9c4809b1376ccc004955bc7ed33fe716408c vrf_coordinator_v2_plus_v2_example: ../../contracts/solc/v0.8.6/VRFCoordinatorV2Plus_V2Example/VRFCoordinatorV2Plus_V2Example.abi ../../contracts/solc/v0.8.6/VRFCoordinatorV2Plus_V2Example/VRFCoordinatorV2Plus_V2Example.bin 4a5b86701983b1b65f0a8dfa116b3f6d75f8f706fa274004b57bdf5992e4cec3 @@ -81,12 +89,13 @@ vrf_coordinator_v2plus_interface: ../../contracts/solc/v0.8.6/IVRFCoordinatorV2P vrf_external_sub_owner_example: ../../contracts/solc/v0.8.6/VRFExternalSubOwnerExample/VRFExternalSubOwnerExample.abi ../../contracts/solc/v0.8.6/VRFExternalSubOwnerExample/VRFExternalSubOwnerExample.bin 14f888eb313930b50233a6f01ea31eba0206b7f41a41f6311670da8bb8a26963 vrf_load_test_external_sub_owner: ../../contracts/solc/v0.8.6/VRFLoadTestExternalSubOwner/VRFLoadTestExternalSubOwner.abi ../../contracts/solc/v0.8.6/VRFLoadTestExternalSubOwner/VRFLoadTestExternalSubOwner.bin 2097faa70265e420036cc8a3efb1f1e0836ad2d7323b295b9a26a125dbbe6c7d vrf_load_test_ownerless_consumer: ../../contracts/solc/v0.8.6/VRFLoadTestOwnerlessConsumer/VRFLoadTestOwnerlessConsumer.abi ../../contracts/solc/v0.8.6/VRFLoadTestOwnerlessConsumer/VRFLoadTestOwnerlessConsumer.bin 74f914843cbc70b9c3079c3e1c709382ce415225e8bb40113e7ac018bfcb0f5c -vrf_load_test_with_metrics: ../../contracts/solc/v0.8.6/VRFV2LoadTestWithMetrics/VRFV2LoadTestWithMetrics.abi ../../contracts/solc/v0.8.6/VRFV2LoadTestWithMetrics/VRFV2LoadTestWithMetrics.bin 8ab9de5816fbdf93a2865e2711b85a39a6fc9c413a4b336578c485be1158d430 +vrf_load_test_with_metrics: ../../contracts/solc/v0.8.6/VRFV2LoadTestWithMetrics/VRFV2LoadTestWithMetrics.abi ../../contracts/solc/v0.8.6/VRFV2LoadTestWithMetrics/VRFV2LoadTestWithMetrics.bin c9621c52d216a090ff6bbe942f1b75d2bce8658a27323c3789e5e14b523277ee vrf_log_emitter: ../../contracts/solc/v0.8.19/VRFLogEmitter/VRFLogEmitter.abi ../../contracts/solc/v0.8.19/VRFLogEmitter/VRFLogEmitter.bin 15f491d445ac4d0c712d1cbe4e5054c759b080bf20de7d54bfe2a82cde4dcf06 vrf_malicious_consumer_v2: ../../contracts/solc/v0.8.6/VRFMaliciousConsumerV2/VRFMaliciousConsumerV2.abi ../../contracts/solc/v0.8.6/VRFMaliciousConsumerV2/VRFMaliciousConsumerV2.bin 9755fa8ffc7f5f0b337d5d413d77b0c9f6cd6f68c31727d49acdf9d4a51bc522 vrf_malicious_consumer_v2_plus: ../../contracts/solc/v0.8.6/VRFMaliciousConsumerV2Plus/VRFMaliciousConsumerV2Plus.abi ../../contracts/solc/v0.8.6/VRFMaliciousConsumerV2Plus/VRFMaliciousConsumerV2Plus.bin e2a72638e11da807b6533d037e7e5aaeed695efd5035777b8e20d2f8973a574c +vrf_mock_ethlink_aggregator: ../../contracts/solc/v0.8.6/VRFMockETHLINKAggregator/VRFMockETHLINKAggregator.abi ../../contracts/solc/v0.8.6/VRFMockETHLINKAggregator/VRFMockETHLINKAggregator.bin a6e753984eeec8107e205ae517f74d4616bf23cffda50a25538ffc16ac4b036f vrf_owner: ../../contracts/solc/v0.8.6/VRFOwner/VRFOwner.abi ../../contracts/solc/v0.8.6/VRFOwner/VRFOwner.bin eccfae5ee295b5850e22f61240c469f79752b8d9a3bac5d64aec7ac8def2f6cb -vrf_owner_test_consumer: ../../contracts/solc/v0.8.6/VRFV2OwnerTestConsumer/VRFV2OwnerTestConsumer.abi ../../contracts/solc/v0.8.6/VRFV2OwnerTestConsumer/VRFV2OwnerTestConsumer.bin 0537bbe96c5a8bbd44d0a65fbb7e51f6a9f9e75f4673225845ac1ba33f4e7974 +vrf_owner_test_consumer: ../../contracts/solc/v0.8.6/VRFV2OwnerTestConsumer/VRFV2OwnerTestConsumer.abi ../../contracts/solc/v0.8.6/VRFV2OwnerTestConsumer/VRFV2OwnerTestConsumer.bin 6969de242efe8f366ae4097fc279d9375c8e2d0307aaa322e31f2ce6b8c1909a vrf_ownerless_consumer_example: ../../contracts/solc/v0.8.6/VRFOwnerlessConsumerExample/VRFOwnerlessConsumerExample.abi ../../contracts/solc/v0.8.6/VRFOwnerlessConsumerExample/VRFOwnerlessConsumerExample.bin 9893b3805863273917fb282eed32274e32aa3d5c2a67a911510133e1218132be vrf_single_consumer_example: ../../contracts/solc/v0.8.6/VRFSingleConsumerExample/VRFSingleConsumerExample.abi ../../contracts/solc/v0.8.6/VRFSingleConsumerExample/VRFSingleConsumerExample.bin 892a5ed35da2e933f7fd7835cd6f7f70ef3aa63a9c03a22c5b1fd026711b0ece vrf_v2_consumer_wrapper: ../../contracts/solc/v0.8.6/VRFv2Consumer/VRFv2Consumer.abi ../../contracts/solc/v0.8.6/VRFv2Consumer/VRFv2Consumer.bin 12368b3b5e06392440143a13b94c0ea2f79c4c897becc3b060982559e10ace40 diff --git a/core/gethwrappers/go_generate.go b/core/gethwrappers/go_generate.go index 9b47de2510..082821de08 100644 --- a/core/gethwrappers/go_generate.go +++ b/core/gethwrappers/go_generate.go @@ -55,8 +55,14 @@ package gethwrappers //go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.16/KeeperRegistryLogicA2_1/KeeperRegistryLogicA2_1.abi ../../contracts/solc/v0.8.16/KeeperRegistryLogicA2_1/KeeperRegistryLogicA2_1.bin KeeperRegistryLogicA keeper_registry_logic_a_wrapper_2_1 //go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.16/KeeperRegistryLogicB2_1/KeeperRegistryLogicB2_1.abi ../../contracts/solc/v0.8.16/KeeperRegistryLogicB2_1/KeeperRegistryLogicB2_1.bin KeeperRegistryLogicB keeper_registry_logic_b_wrapper_2_1 //go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.16/IKeeperRegistryMaster/IKeeperRegistryMaster.abi ../../contracts/solc/v0.8.16/IKeeperRegistryMaster/IKeeperRegistryMaster.bin IKeeperRegistryMaster i_keeper_registry_master_wrapper_2_1 -//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.16/ILogAutomation/ILogAutomation.abi ../../contracts/solc/v0.8.16/ILogAutomation/ILogAutomation.bin ILogAutomation i_log_automation //go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.16/AutomationUtils2_1/AutomationUtils2_1.abi ../../contracts/solc/v0.8.16/AutomationUtils2_1/AutomationUtils2_1.bin AutomationUtils automation_utils_2_1 +//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.16/AutomationRegistrar2_2/AutomationRegistrar2_2.abi ../../contracts/solc/v0.8.16/AutomationRegistrar2_2/AutomationRegistrar2_2.bin AutomationRegistrar automation_registrar_wrapper2_2 +//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.16/AutomationRegistry2_2/AutomationRegistry2_2.abi ../../contracts/solc/v0.8.16/AutomationRegistry2_2/AutomationRegistry2_2.bin AutomationRegistry keeper_registry_wrapper_2_2 +//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.16/AutomationRegistryLogicA2_2/AutomationRegistryLogicA2_2.abi ../../contracts/solc/v0.8.16/AutomationRegistryLogicA2_2/AutomationRegistryLogicA2_2.bin AutomationRegistryLogicA keeper_registry_logic_a_wrapper_2_2 +//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.16/AutomationRegistryLogicB2_2/AutomationRegistryLogicB2_2.abi ../../contracts/solc/v0.8.16/AutomationRegistryLogicB2_2/AutomationRegistryLogicB2_2.bin AutomationRegistryLogicB keeper_registry_logic_b_wrapper_2_2 +//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.16/IAutomationRegistryMaster/IAutomationRegistryMaster.abi ../../contracts/solc/v0.8.16/IAutomationRegistryMaster/IAutomationRegistryMaster.bin IAutomationRegistryMaster i_keeper_registry_master_wrapper_2_2 +//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.16/AutomationUtils2_2/AutomationUtils2_2.abi ../../contracts/solc/v0.8.16/AutomationUtils2_2/AutomationUtils2_2.bin AutomationUtils automation_utils_2_2 +//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.16/ILogAutomation/ILogAutomation.abi ../../contracts/solc/v0.8.16/ILogAutomation/ILogAutomation.bin ILogAutomation i_log_automation //go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.16/AutomationForwarderLogic/AutomationForwarderLogic.abi ../../contracts/solc/v0.8.16/AutomationForwarderLogic/AutomationForwarderLogic.bin AutomationForwarderLogic automation_forwarder_logic //go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.6/LogUpkeepCounter/LogUpkeepCounter.abi ../../contracts/solc/v0.8.6/LogUpkeepCounter/LogUpkeepCounter.bin LogUpkeepCounter log_upkeep_counter_wrapper //go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.6/SimpleLogUpkeepCounter/SimpleLogUpkeepCounter.abi ../../contracts/solc/v0.8.6/SimpleLogUpkeepCounter/SimpleLogUpkeepCounter.bin SimpleLogUpkeepCounter simple_log_upkeep_counter_wrapper @@ -103,6 +109,8 @@ package gethwrappers //go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.6/VRFV2TransparentUpgradeableProxy/VRFV2TransparentUpgradeableProxy.abi ../../contracts/solc/v0.8.6/VRFV2TransparentUpgradeableProxy/VRFV2TransparentUpgradeableProxy.bin VRFV2TransparentUpgradeableProxy vrfv2_transparent_upgradeable_proxy //go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.6/VRFV2ProxyAdmin/VRFV2ProxyAdmin.abi ../../contracts/solc/v0.8.6/VRFV2ProxyAdmin/VRFV2ProxyAdmin.bin VRFV2ProxyAdmin vrfv2_proxy_admin //go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.6/ChainSpecificUtilHelper/ChainSpecificUtilHelper.abi ../../contracts/solc/v0.8.6/ChainSpecificUtilHelper/ChainSpecificUtilHelper.bin ChainSpecificUtilHelper chain_specific_util_helper +//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.6/VRFCoordinatorTestV2/VRFCoordinatorTestV2.abi ../../contracts/solc/v0.8.6/VRFCoordinatorTestV2/VRFCoordinatorTestV2.bin VRFCoordinatorTestV2 vrf_coordinator_test_v2 +//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.6/VRFMockETHLINKAggregator/VRFMockETHLINKAggregator.abi ../../contracts/solc/v0.8.6/VRFMockETHLINKAggregator/VRFMockETHLINKAggregator.bin VRFMockETHLINKAggregator vrf_mock_ethlink_aggregator // VRF V2 Wrapper //go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.6/VRFV2Wrapper/VRFV2Wrapper.abi ../../contracts/solc/v0.8.6/VRFV2Wrapper/VRFV2Wrapper.bin VRFV2Wrapper vrfv2_wrapper @@ -139,7 +147,9 @@ package gethwrappers //go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.6/MockAggregatorProxy/MockAggregatorProxy.abi ../../contracts/solc/v0.8.6/MockAggregatorProxy/MockAggregatorProxy.bin MockAggregatorProxy mock_aggregator_proxy // Log tester -//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.19/LogEmitter/LogEmitter.abi ../../contracts/solc/v0.8.19/LogEmitter/LogEmitter.bin LogEmitter log_emitter + +// ChainReader test contract +//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.19/ChainReaderTestContract/LatestValueHolder.abi ../../contracts/solc/v0.8.19/ChainReaderTestContract/LatestValueHolder.bin LatestValueHolder chain_reader_example // Chainlink Functions //go:generate go generate ./functions 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 29f0deb7b2..d54d3fb8cd 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 @@ -1,4 +1,4 @@ -GETH_VERSION: 1.12.2 +GETH_VERSION: 1.13.8 errored_verifier: ../../../contracts/solc/v0.8.16/ErroredVerifier/ErroredVerifier.abi ../../../contracts/solc/v0.8.16/ErroredVerifier/ErroredVerifier.bin 510d18a58bfda646be35e46491baf73041eb333a349615465b20e2b5b41c5f73 exposed_verifier: ../../../contracts/solc/v0.8.16/ExposedVerifier/ExposedVerifier.abi ../../../contracts/solc/v0.8.16/ExposedVerifier/ExposedVerifier.bin 6932cea8f2738e874d3ec9e1a4231d2421704030c071d9e15dd2f7f08482c246 fee_manager: ../../../contracts/solc/v0.8.16/FeeManager/FeeManager.abi ../../../contracts/solc/v0.8.16/FeeManager/FeeManager.bin 1b852df75bfabcc2b57539e84309cd57f9e693a2bb6b25a50e4a6101ccf32c49 diff --git a/core/gethwrappers/rebalancer/generation/generated-wrapper-dependency-versions-do-not-edit.txt b/core/gethwrappers/rebalancer/generation/generated-wrapper-dependency-versions-do-not-edit.txt index 3788b69601..2661d28e84 100644 --- a/core/gethwrappers/rebalancer/generation/generated-wrapper-dependency-versions-do-not-edit.txt +++ b/core/gethwrappers/rebalancer/generation/generated-wrapper-dependency-versions-do-not-edit.txt @@ -1,4 +1,4 @@ -GETH_VERSION: 1.12.2 +GETH_VERSION: 1.13.8 arbitrum_l1_bridge_adapter: ../../../contracts/solc/v0.8.19/ArbitrumL1BridgeAdapter/ArbitrumL1BridgeAdapter.abi ../../../contracts/solc/v0.8.19/ArbitrumL1BridgeAdapter/ArbitrumL1BridgeAdapter.bin e9bb45c4dcf326361c896eda07a7ea85e1c36915b71ea6185d15db917221d9c3 arbitrum_l2_bridge_adapter: ../../../contracts/solc/v0.8.19/ArbitrumL2BridgeAdapter/ArbitrumL2BridgeAdapter.abi ../../../contracts/solc/v0.8.19/ArbitrumL2BridgeAdapter/ArbitrumL2BridgeAdapter.bin c84764c7ba0b3db99dd12df2e3f5dfe668f921d9f27e7d10a95334618b2128b1 mock_l2_bridge_adapter: ../../../contracts/solc/v0.8.19/MockBridgeAdapter/MockL2BridgeAdapter.abi ../../../contracts/solc/v0.8.19/MockBridgeAdapter/MockL2BridgeAdapter.bin a2e93e04c96f1f893decc90b283dbb5a14f1dcce2dc1c4ff07f1e8ba564f7b43 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 ff9bfa2fea..3268bb55bd 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 @@ -1,4 +1,4 @@ -GETH_VERSION: 1.12.2 +GETH_VERSION: 1.13.8 burn_mint_erc677: ../../../contracts/solc/v0.8.19/BurnMintERC677/BurnMintERC677.abi ../../../contracts/solc/v0.8.19/BurnMintERC677/BurnMintERC677.bin 405c9016171e614b17e10588653ef8d33dcea21dd569c3fddc596a46fcff68a3 erc20: ../../../contracts/solc/v0.8.19/ERC20/ERC20.abi ../../../contracts/solc/v0.8.19/ERC20/ERC20.bin 5b1a93d9b24f250e49a730c96335a8113c3f7010365cba578f313b483001d4fc link_token: ../../../contracts/solc/v0.8.19/LinkToken/LinkToken.abi ../../../contracts/solc/v0.8.19/LinkToken/LinkToken.bin c0ef9b507103aae541ebc31d87d051c2764ba9d843076b30ec505d37cdfffaba 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 cded1f0c5e..6d5b5c22c5 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 @@ -1,4 +1,4 @@ -GETH_VERSION: 1.12.2 +GETH_VERSION: 1.13.8 entry_point: ../../../contracts/solc/v0.8.15/EntryPoint/EntryPoint.abi ../../../contracts/solc/v0.8.15/EntryPoint/EntryPoint.bin 2cb4bb2ba3efa8df3dfb0a57eb3727d17b68fe202682024fa7cfb4faf026833e greeter: ../../../contracts/solc/v0.8.15/Greeter.abi ../../../contracts/solc/v0.8.15/Greeter.bin 653dcba5c33a46292073939ce1e639372cf521c0ec2814d4c9f20c72f796f18c greeter_wrapper: ../../../contracts/solc/v0.8.15/Greeter/Greeter.abi ../../../contracts/solc/v0.8.15/Greeter/Greeter.bin 653dcba5c33a46292073939ce1e639372cf521c0ec2814d4c9f20c72f796f18c diff --git a/core/internal/features/ocr2/features_ocr2_plugin_test.go b/core/internal/features/ocr2/features_ocr2_plugin_test.go new file mode 100644 index 0000000000..96a9f32e95 --- /dev/null +++ b/core/internal/features/ocr2/features_ocr2_plugin_test.go @@ -0,0 +1,14 @@ +//go:build integration + +package ocr2_test + +import ( + "testing" + + "github.com/smartcontractkit/chainlink/v2/core/config/env" +) + +func TestIntegration_OCR2_plugins(t *testing.T) { + t.Setenv(string(env.MedianPlugin.Cmd), "chainlink-feeds") + testIntegration_OCR2(t) +} diff --git a/core/internal/features/ocr2/features_ocr2_test.go b/core/internal/features/ocr2/features_ocr2_test.go index 863451de73..938b7aa2a6 100644 --- a/core/internal/features/ocr2/features_ocr2_test.go +++ b/core/internal/features/ocr2/features_ocr2_test.go @@ -35,6 +35,7 @@ import ( ocrtypes2 "github.com/smartcontractkit/libocr/offchainreporting2plus/types" commonconfig "github.com/smartcontractkit/chainlink-common/pkg/config" + "github.com/smartcontractkit/chainlink/v2/core/bridges" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/forwarders" @@ -188,50 +189,63 @@ func setupNodeOCR2( func TestIntegration_OCR2(t *testing.T) { t.Parallel() - owner, b, ocrContractAddress, ocrContract := setupOCR2Contracts(t) - - lggr := logger.TestLogger(t) - bootstrapNodePort := freeport.GetOne(t) - bootstrapNode := setupNodeOCR2(t, owner, bootstrapNodePort, false /* useForwarders */, b, nil) - - var ( - oracles []confighelper2.OracleIdentityExtra - transmitters []common.Address - kbs []ocr2key.KeyBundle - apps []*cltest.TestApplication - ) - ports := freeport.GetN(t, 4) - for i := 0; i < 4; i++ { - node := setupNodeOCR2(t, owner, ports[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)}}, - }) - - kbs = append(kbs, node.keybundle) - apps = append(apps, node.app) - transmitters = append(transmitters, node.transmitter) + testIntegration_OCR2(t) +} - oracles = append(oracles, confighelper2.OracleIdentityExtra{ - OracleIdentity: confighelper2.OracleIdentity{ - OnchainPublicKey: node.keybundle.PublicKey(), - TransmitAccount: ocrtypes2.Account(node.transmitter.String()), - OffchainPublicKey: node.keybundle.OffchainPublicKey(), - PeerID: node.peerID, - }, - ConfigEncryptionPublicKey: node.keybundle.ConfigEncryptionPublicKey(), - }) - } +func testIntegration_OCR2(t *testing.T) { + for _, test := range []struct { + name string + chainReaderAndCodec bool + }{ + {"legacy", false}, + {"chain-reader", true}, + } { + test := test + t.Run(test.name, func(t *testing.T) { + owner, b, ocrContractAddress, ocrContract := setupOCR2Contracts(t) + + lggr := logger.TestLogger(t) + bootstrapNodePort := freeport.GetOne(t) + bootstrapNode := setupNodeOCR2(t, owner, bootstrapNodePort, false /* useForwarders */, b, nil) + + var ( + oracles []confighelper2.OracleIdentityExtra + transmitters []common.Address + kbs []ocr2key.KeyBundle + apps []*cltest.TestApplication + ) + ports := freeport.GetN(t, 4) + for i := 0; i < 4; i++ { + node := setupNodeOCR2(t, owner, ports[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)}}, + }) + + kbs = append(kbs, node.keybundle) + apps = append(apps, node.app) + transmitters = append(transmitters, node.transmitter) + + oracles = append(oracles, confighelper2.OracleIdentityExtra{ + OracleIdentity: confighelper2.OracleIdentity{ + OnchainPublicKey: node.keybundle.PublicKey(), + TransmitAccount: ocrtypes2.Account(node.transmitter.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() - } - }() + 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, transmitters, transmitters, func(blockNum int64) string { - return 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" @@ -241,54 +255,189 @@ contractID = "%s" chainID = 1337 fromBlock = %d `, ocrContractAddress, blockNum) - }) - - var jids []int32 - var servers, slowServers = make([]*httptest.Server, 4), make([]*httptest.Server, 4) - // We expect metadata of: - // latestAnswer:nil // First call - // latestAnswer:0 - // latestAnswer:10 - // latestAnswer:20 - // latestAnswer:30 - var metaLock sync.Mutex - expectedMeta := map[string]struct{}{ - "0": {}, "10": {}, "20": {}, "30": {}, - } - for i := 0; i < 4; i++ { - s := i - 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) { - time.Sleep(5 * time.Second) - res.WriteHeader(http.StatusOK) - _, err := res.Write([]byte(`{"data":10}`)) - require.NoError(t, err) - })) - 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) - var m bridges.BridgeMetaDataJSON - require.NoError(t, json.Unmarshal(b, &m)) - if m.Meta.LatestAnswer != nil && m.Meta.UpdatedAt != nil { - metaLock.Lock() - delete(expectedMeta, m.Meta.LatestAnswer.String()) - metaLock.Unlock() + }) + + var jids []int32 + var servers, slowServers = make([]*httptest.Server, 4), make([]*httptest.Server, 4) + // We expect metadata of: + // latestAnswer:nil // First call + // latestAnswer:0 + // latestAnswer:10 + // latestAnswer:20 + // latestAnswer:30 + var metaLock sync.Mutex + expectedMeta := map[string]struct{}{ + "0": {}, "10": {}, "20": {}, "30": {}, } - res.WriteHeader(http.StatusOK) - _, err = res.Write([]byte(`{"data":10}`)) - require.NoError(t, err) - })) - 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)), - URL: models.WebURL(*u), - })) - - ocrJob, err := validate.ValidatedOracleSpecToml(apps[i].Config.OCR2(), apps[i].Config.Insecure(), fmt.Sprintf(` + returnData := int(10) + for i := 0; i < 4; i++ { + s := i + 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) { + time.Sleep(5 * time.Second) + var result string + metaLock.Lock() + result = fmt.Sprintf(`{"data":%d}`, returnData) + metaLock.Unlock() + res.WriteHeader(http.StatusOK) + t.Logf("Slow Bridge %d returning data:10", s) + _, err := res.Write([]byte(result)) + require.NoError(t, err) + })) + 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) + var m bridges.BridgeMetaDataJSON + require.NoError(t, json.Unmarshal(b, &m)) + var result string + metaLock.Lock() + result = fmt.Sprintf(`{"data":%d}`, returnData) + metaLock.Unlock() + if m.Meta.LatestAnswer != nil && m.Meta.UpdatedAt != nil { + t.Logf("Bridge %d deleting %s, from request body: %s", s, m.Meta.LatestAnswer, b) + metaLock.Lock() + delete(expectedMeta, m.Meta.LatestAnswer.String()) + metaLock.Unlock() + } + res.WriteHeader(http.StatusOK) + _, err = res.Write([]byte(result)) + require.NoError(t, err) + })) + 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)), + URL: models.WebURL(*u), + })) + + var chainReaderSpec string + if test.chainReaderAndCodec { + chainReaderSpec = ` +[relayConfig.chainReader.contracts.median] +contractABI = ''' +[ + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "requester", + "type": "address" + }, + { + "indexed": false, + "internalType": "bytes32", + "name": "configDigest", + "type": "bytes32" + }, + { + "indexed": false, + "internalType": "uint32", + "name": "epoch", + "type": "uint32" + }, + { + "indexed": false, + "internalType": "uint8", + "name": "round", + "type": "uint8" + } + ], + "name": "RoundRequested", + "type": "event" + }, + { + "inputs": [], + "name": "latestTransmissionDetails", + "outputs": [ + { + "internalType": "bytes32", + "name": "configDigest", + "type": "bytes32" + }, + { + "internalType": "uint32", + "name": "epoch", + "type": "uint32" + }, + { + "internalType": "uint8", + "name": "round", + "type": "uint8" + }, + { + "internalType": "int192", + "name": "latestAnswer_", + "type": "int192" + }, + { + "internalType": "uint64", + "name": "latestTimestamp_", + "type": "uint64" + } + ], + "stateMutability": "view", + "type": "function" + } +] +''' + +[relayConfig.chainReader.contracts.median.configs] +LatestRoundRequested = ''' +{ + "chainSpecificName": "RoundRequested", + "readType": "event" +} +''' +LatestTransmissionDetails = ''' +{ + "chainSpecificName": "latestTransmissionDetails", + "outputModifications": [ + { + "Fields": [ + "LatestTimestamp_" + ], + "type": "epoch to time" + }, + { + "Fields": { + "LatestAnswer_": "LatestAnswer", + "LatestTimestamp_": "LatestTimestamp" + }, + "type": "rename" + } + ] +} +''' + +[relayConfig.codec.configs.MedianReport] +typeABI = ''' +[ + { + "Name": "Timestamp", + "Type": "uint32" + }, + { + "Name": "Observers", + "Type": "bytes32" + }, + { + "Name": "Observations", + "Type": "int192[]" + }, + { + "Name": "JuelsPerFeeCoin", + "Type": "int192" + } +] +''' +` + } + ocrJob, err := validate.ValidatedOracleSpecToml(apps[i].Config.OCR2(), apps[i].Config.Insecure(), fmt.Sprintf(` type = "offchainreporting2" relay = "evm" schemaVersion = 1 @@ -315,9 +464,12 @@ observationSource = """ answer1 [type=median index=0]; """ + [relayConfig] chainID = 1337 fromBlock = %d +%s + [pluginConfig] juelsPerFeeCoinSource = """ // data source 1 @@ -335,72 +487,131 @@ juelsPerFeeCoinSource = """ answer1 [type=median index=0]; """ -`, ocrContractAddress, kbs[i].ID(), transmitters[i], fmt.Sprintf("bridge%d", i), i, slowServers[i].URL, i, blockBeforeConfig.Number().Int64(), fmt.Sprintf("bridge%d", i), i, slowServers[i].URL, i)) - require.NoError(t, err) - err = apps[i].AddJobV2(testutils.Context(t), &ocrJob) - require.NoError(t, err) - jids = append(jids, ocrJob.ID) - } +`, ocrContractAddress, kbs[i].ID(), transmitters[i], fmt.Sprintf("bridge%d", i), i, slowServers[i].URL, i, blockBeforeConfig.Number().Int64(), chainReaderSpec, fmt.Sprintf("bridge%d", i), i, slowServers[i].URL, i)) + require.NoError(t, err) + err = apps[i].AddJobV2(testutils.Context(t), &ocrJob) + require.NoError(t, err) + jids = append(jids, ocrJob.ID) + } - // Assert that all the OCR jobs get a run with valid values eventually. - var wg sync.WaitGroup - for i := 0; i < 4; i++ { - ic := i - wg.Add(1) - go func() { - defer wg.Done() - // Want at least 2 runs so we see all the metadata. - pr := cltest.WaitForPipelineComplete(t, ic, jids[ic], 2, 7, apps[ic].JobORM(), 2*time.Minute, 5*time.Second) - jb, err := pr[0].Outputs.MarshalJSON() + // Watch for OCR2AggregatorTransmitted events + start := uint64(0) + txEvents := make(chan *ocr2aggregator.OCR2AggregatorTransmitted) + _, err := ocrContract.WatchTransmitted(&bind.WatchOpts{Start: &start, Context: testutils.Context(t)}, txEvents) require.NoError(t, err) - assert.Equal(t, []byte(fmt.Sprintf("[\"%d\"]", 10*ic)), jb, "pr[0] %+v pr[1] %+v", pr[0], pr[1]) + newTxEvents := make(chan *ocr2aggregator.OCR2AggregatorNewTransmission) + _, err = ocrContract.WatchNewTransmission(&bind.WatchOpts{Start: &start, Context: testutils.Context(t)}, newTxEvents, []uint32{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}) require.NoError(t, err) - }() - } - wg.Wait() - // 4 oracles reporting 0, 10, 20, 30. Answer should be 20 (results[4/2]). - gomega.NewGomegaWithT(t).Eventually(func() string { - answer, err := ocrContract.LatestAnswer(nil) - require.NoError(t, err) - return answer.String() - }, 1*time.Minute, 200*time.Millisecond).Should(gomega.Equal("20")) + go func() { + var newTxEvent *ocr2aggregator.OCR2AggregatorNewTransmission + select { + case txEvent := <-txEvents: + t.Logf("txEvent: %v", txEvent) + if newTxEvent != nil { + assert.Equal(t, txEvent.Epoch, uint32(newTxEvent.EpochAndRound.Uint64())) + } + case newTxEvent = <-newTxEvents: + t.Logf("newTxEvent: %v", newTxEvent) + } + }() - for _, app := range apps { - jobs, _, err := app.JobORM().FindJobs(0, 1000) - require.NoError(t, err) - // No spec errors - for _, j := range jobs { - ignore := 0 - for i := range j.JobSpecErrors { - // Non-fatal timing related error, ignore for testing. - if strings.Contains(j.JobSpecErrors[i].Description, "leader's phase conflicts tGrace timeout") { - ignore++ + for trial := 0; trial < 2; trial++ { + var retVal int + + metaLock.Lock() + returnData = 10 * (trial + 1) + retVal = returnData + for i := 0; i < 4; i++ { + expectedMeta[fmt.Sprintf("%d", returnData*i)] = struct{}{} + } + metaLock.Unlock() + + // Assert that all the OCR jobs get a run with valid values eventually. + var wg sync.WaitGroup + for i := 0; i < 4; i++ { + ic := i + wg.Add(1) + go func() { + defer wg.Done() + completedRuns, err2 := apps[ic].JobORM().FindPipelineRunIDsByJobID(jids[ic], 0, 1000) + require.NoError(t, err2) + // Want at least 2 runs so we see all the metadata. + pr := cltest.WaitForPipelineComplete(t, ic, jids[ic], len(completedRuns)+2, 7, apps[ic].JobORM(), 2*time.Minute, 5*time.Second) + jb, err2 := pr[0].Outputs.MarshalJSON() + require.NoError(t, err2) + assert.Equal(t, []byte(fmt.Sprintf("[\"%d\"]", retVal*ic)), jb, "pr[0] %+v pr[1] %+v", pr[0], pr[1]) + require.NoError(t, err2) + }() + } + wg.Wait() + + // Trail #1: 4 oracles reporting 0, 10, 20, 30. Answer should be 20 (results[4/2]). + // Trial #2: 4 oracles reporting 0, 20, 40, 60. Answer should be 40 (results[4/2]). + gomega.NewGomegaWithT(t).Eventually(func() string { + answer, err2 := ocrContract.LatestAnswer(nil) + require.NoError(t, err2) + return answer.String() + }, 1*time.Minute, 200*time.Millisecond).Should(gomega.Equal(fmt.Sprintf("%d", 2*retVal))) + + for _, app := range apps { + jobs, _, err2 := app.JobORM().FindJobs(0, 1000) + require.NoError(t, err2) + // No spec errors + for _, j := range jobs { + ignore := 0 + for i := range j.JobSpecErrors { + // Non-fatal timing related error, ignore for testing. + if strings.Contains(j.JobSpecErrors[i].Description, "leader's phase conflicts tGrace timeout") { + ignore++ + } + } + require.Len(t, j.JobSpecErrors, ignore) + } + } + em := map[string]struct{}{} + metaLock.Lock() + maps.Copy(em, expectedMeta) + metaLock.Unlock() + assert.Len(t, em, 0, "expected metadata %v", em) + + t.Logf("======= Summary =======") + roundId, err2 := ocrContract.LatestRound(nil) + require.NoError(t, err2) + for i := 0; i <= int(roundId.Int64()); i++ { + roundData, err3 := ocrContract.GetRoundData(nil, big.NewInt(int64(i))) + require.NoError(t, err3) + t.Logf("RoundId: %d, AnsweredInRound: %d, Answer: %d, StartedAt: %v, UpdatedAt: %v", roundData.RoundId, roundData.AnsweredInRound, roundData.Answer, roundData.StartedAt, roundData.UpdatedAt) + } + + expectedAnswer := big.NewInt(2 * int64(retVal)) + + // Assert we can read the latest config digest and epoch after a report has been submitted. + contractABI, err2 := abi.JSON(strings.NewReader(ocr2aggregator.OCR2AggregatorABI)) + require.NoError(t, err2) + apps[0].GetRelayers().LegacyEVMChains().Slice() + ct, err2 := evm.NewOCRContractTransmitter(ocrContractAddress, apps[0].GetRelayers().LegacyEVMChains().Slice()[0].Client(), contractABI, nil, apps[0].GetRelayers().LegacyEVMChains().Slice()[0].LogPoller(), lggr, nil) + require.NoError(t, err2) + configDigest, epoch, err2 := ct.LatestConfigDigestAndEpoch(testutils.Context(t)) + require.NoError(t, err2) + details, err2 := ocrContract.LatestConfigDetails(nil) + require.NoError(t, err2) + assert.True(t, bytes.Equal(configDigest[:], details.ConfigDigest[:])) + digestAndEpoch, err2 := ocrContract.LatestConfigDigestAndEpoch(nil) + require.NoError(t, err2) + assert.Equal(t, digestAndEpoch.Epoch, epoch) + latestTransmissionDetails, err2 := ocrContract.LatestTransmissionDetails(nil) + require.NoError(t, err2) + assert.Equal(t, expectedAnswer, latestTransmissionDetails.LatestAnswer) + require.NoError(t, err2) + newTransmissionEvents, err2 := ocrContract.FilterTransmitted(&bind.FilterOpts{Start: 0, End: nil}) + require.NoError(t, err2) + for newTransmissionEvents.Next() { + assert.Equal(t, 3, newTransmissionEvents.Event.Epoch) } } - require.Len(t, j.JobSpecErrors, ignore) - } + }) } - em := map[string]struct{}{} - metaLock.Lock() - maps.Copy(em, expectedMeta) - metaLock.Unlock() - assert.Len(t, em, 0, "expected metadata %v", em) - - // Assert we can read the latest config digest and epoch after a report has been submitted. - contractABI, err := abi.JSON(strings.NewReader(ocr2aggregator.OCR2AggregatorABI)) - require.NoError(t, err) - apps[0].GetRelayers().LegacyEVMChains().Slice() - ct, err := evm.NewOCRContractTransmitter(ocrContractAddress, apps[0].GetRelayers().LegacyEVMChains().Slice()[0].Client(), contractABI, nil, apps[0].GetRelayers().LegacyEVMChains().Slice()[0].LogPoller(), lggr, nil) - require.NoError(t, err) - configDigest, epoch, err := ct.LatestConfigDigestAndEpoch(testutils.Context(t)) - require.NoError(t, err) - details, err := ocrContract.LatestConfigDetails(nil) - require.NoError(t, err) - assert.True(t, bytes.Equal(configDigest[:], details.ConfigDigest[:])) - digestAndEpoch, err := ocrContract.LatestConfigDigestAndEpoch(nil) - require.NoError(t, err) - assert.Equal(t, digestAndEpoch.Epoch, epoch) } func initOCR2(t *testing.T, lggr logger.Logger, b *backends.SimulatedBackend, diff --git a/core/scripts/chaincli/.env.debugging.example b/core/scripts/chaincli/.env.debugging.example index 6934bb107f..c2942b9907 100644 --- a/core/scripts/chaincli/.env.debugging.example +++ b/core/scripts/chaincli/.env.debugging.example @@ -8,8 +8,8 @@ KEEPER_REGISTRY_ADDRESS= #TENDERLY_ACCOUNT_NAME= #TENDERLY_PROJECT_NAME= -# [Optional] add mercury info only if your upkeep uses mercury -#MERCURY_ID= -#MERCURY_KEY= -#MERCURY_LEGACY_URL= -#MERCURY_URL= \ No newline at end of file +# [Optional] add data streams (https://docs.chain.link/data-streams) info only if your upkeep uses data streams +#DATA_STREAMS_ID= +#DATA_STREAMS_KEY= +#DATA_STREAMS_URL= +#DATA_STREAMS_LEGACY_URL= \ No newline at end of file diff --git a/core/scripts/chaincli/DEBUGGING.md b/core/scripts/chaincli/DEBUGGING.md new file mode 100644 index 0000000000..6466a40fc3 --- /dev/null +++ b/core/scripts/chaincli/DEBUGGING.md @@ -0,0 +1,95 @@ +## Automation Debugging Script + +### Context + +The debugging script is a tool within ChainCLI designed to facilitate the debugging of upkeeps in Automation v21, covering both conditional and log-based scenarios. + +### Setup + +Before starting, you will need: +1. Git clone this chainlink [repo](https://github.com/smartcontractkit/chainlink) +2. A working [Go](https://go.dev/doc/install) installation +2. Change directory to `core/scripts/chaincli` and create a `.env` file based on the example `.env.debugging.example` + +### Configuration in `.env` File + +#### Mandatory Fields + +Ensure the following fields are provided in your `.env` file: + +- `NODE_URL`: Archival node URL +- `KEEPER_REGISTRY_ADDRESS`: Address of the Keeper Registry contract. Refer to the [Supported Networks](https://docs.chain.link/chainlink-automation/overview/supported-networks#configurations) doc for addresses. + +#### Optional Fields (Streams Lookup) + +If your targeted upkeep involves streams lookup, please provide the following details. If you are using Data Streams v0.3 (which is likely), only provide the DATA_STREAMS_URL. The DATA_STREAMS_LEGACY_URL is specifically for Data Streams v0.2. + +- `DATA_STREAMS_ID` +- `DATA_STREAMS_KEY` +- `DATA_STREAMS_LEGACY_URL` +- `DATA_STREAMS_URL` + +#### Optional Fields (Tenderly Integration) + +For detailed transaction simulation logs, set up Tenderly credentials. Refer to the [Tenderly Documentation](https://docs.tenderly.co/other/platform-access/how-to-generate-api-access-tokens) for creating an API key, account name, and project name. + +- `TENDERLY_KEY` +- `TENDERLY_ACCOUNT_NAME` +- `TENDERLY_PROJECT_NAME` + +### Usage + +Execute the following command based on your upkeep type: + +- For conditional upkeep, if a block number is given we use that block, otherwise we use the latest block: + + ```bash + go run main.go keeper debug UPKEEP_ID [OPTIONAL BLOCK_NUMBER] + ``` + +- For log trigger upkeep: + + ```bash + go run main.go keeper debug UPKEEP_ID TX_HASH LOG_INDEX + ``` + +### Checks Performed by the Debugging Script + +1. **Fetch and Sanity Check Upkeep:** + - Verify upkeep status: active, paused, or canceled + - Check upkeep balance + +2. **For Conditional Upkeep:** + - Check conditional upkeep + - Simulate `performUpkeep` + +3. **For Log Trigger Upkeep:** + - Check if the upkeep has already run for log-trigger-based upkeep + - Verify if log matches trigger configuration + - Check upkeep + - If check result indicates a streams lookup is required (TargetCheckReverted): + - Verify if the upkeep is allowed to use Mercury + - Execute Mercury request + - Execute check callback + + - Simulate `performUpkeep` + +### Examples +- Eligible and log trigger based and using mercury lookup v0.3: + + ```bash + go run main.go keeper debug 5591498142036749453487419299781783197030971023186134955311257372668222176389 0xdc6d0e547a5aa85fefa5b0f3a37e3493eafb5aeba8b5f3071ce53c9e9a539e9c 0 + ``` + +- Ineligible and conditional upkeep: + + ```bash + go run main.go keeper debug 52635131310730056105456985154251306793887717546629785340977553840883117540096 + ``` + +- Ineligible and Log does not match trigger config: + + ```bash + go run main.go keeper debug 5591498142036749453487419299781783197030971023186134955311257372668222176389 0xc0686ae85d2a7a976ef46df6c613517b9fd46f23340ac583be4e44f5c8b7a186 1 + ``` +--- \ No newline at end of file diff --git a/core/scripts/chaincli/README.md b/core/scripts/chaincli/README.md index bcf407b684..992250ae77 100644 --- a/core/scripts/chaincli/README.md +++ b/core/scripts/chaincli/README.md @@ -123,93 +123,4 @@ You can use the `grep` and `grepv` flags to filter log lines, e.g. to only show ./chaincli keeper logs --grep keepers-plugin ``` ---- - -## ChainCLI Automation Debugging Script - -### Context - -The debugging script is a tool within ChainCLI designed to facilitate the debugging of upkeeps in Automation v21, covering both conditional and log-based scenarios. - -### Configuration - -#### Mandatory Fields - -Ensure the following fields are provided in your `.env` file: - -- `NODE_URL`: Archival node URL -- `KEEPER_REGISTRY_ADDRESS`: Address of the Keeper Registry contract. Refer to the [Supported Networks](https://docs.chain.link/chainlink-automation/overview/supported-networks#configurations) doc for addresses. - -#### Additional Fields (Streams Lookup) - -If your targeted upkeep involves streams lookup, include the following information: - -- `MERCURY_ID` -- `MERCURY_KEY` -- `MERCURY_LEGACY_URL` -- `MERCURY_URL` - -#### Tenderly Integration - -For detailed transaction simulation logs, set up Tenderly credentials. Refer to the [Tenderly Documentation](https://docs.tenderly.co/other/platform-access/how-to-generate-api-access-tokens) for creating an API key, account name, and project name. - -- `TENDERLY_KEY` -- `TENDERLY_ACCOUNT_NAME` -- `TENDERLY_PROJECT_NAME` - -### Usage - -Execute the following command based on your upkeep type: - -- For conditional upkeep: - - ```bash - go run main.go keeper debug UPKEEP_ID - ``` - -- For log trigger upkeep: - - ```bash - go run main.go keeper debug UPKEEP_ID TX_HASH LOG_INDEX - ``` - -### Checks Performed by the Debugging Script - -1. **Fetch and Sanity Check Upkeep:** - - Verify upkeep status: active, paused, or canceled - - Check upkeep balance - -2. **For Conditional Upkeep:** - - Check conditional upkeep - - Simulate `performUpkeep` - -3. **For Log Trigger Upkeep:** - - Check if the upkeep has already run for log-trigger-based upkeep - - Verify if log matches trigger configuration - - Check upkeep - - If check result indicates a streams lookup is required (TargetCheckReverted): - - Verify if the upkeep is allowed to use Mercury - - Execute Mercury request - - Execute check callback - - - Simulate `performUpkeep` - -### Examples -- Eligible and log trigger based and using mercury lookup v0.3: - - ```bash - go run main.go keeper debug 5591498142036749453487419299781783197030971023186134955311257372668222176389 0xdc6d0e547a5aa85fefa5b0f3a37e3493eafb5aeba8b5f3071ce53c9e9a539e9c 0 - ``` - -- Ineligible and conditional upkeep: - - ```bash - go run main.go keeper debug 52635131310730056105456985154251306793887717546629785340977553840883117540096 - ``` - -- Ineligible and Log does not match trigger config: - - ```bash - go run main.go keeper debug 5591498142036749453487419299781783197030971023186134955311257372668222176389 0xc0686ae85d2a7a976ef46df6c613517b9fd46f23340ac583be4e44f5c8b7a186 1 - ``` --- \ No newline at end of file diff --git a/core/scripts/chaincli/config/config.go b/core/scripts/chaincli/config/config.go index d227aa2e29..a17671bf8a 100644 --- a/core/scripts/chaincli/config/config.go +++ b/core/scripts/chaincli/config/config.go @@ -90,12 +90,12 @@ type Config struct { FeedQuoteAddr string `mapstructure:"FEED_QUOTE_ADDR"` FeedDecimals uint8 `mapstructure:"FEED_DECIMALS"` - // Mercury Config - 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"` + // Data Streams Config + DataStreamsURL string `mapstructure:"DATA_STREAMS_URL"` + DataStreamsLegacyURL string `mapstructure:"DATA_STREAMS_LEGACY_URL"` + DataStreamsID string `mapstructure:"DATA_STREAMS_ID"` + DataStreamsKey string `mapstructure:"DATA_STREAMS_KEY"` + DataStreamsCredName string `mapstructure:"DATA_STREAMS_CRED_NAME"` // Tenderly TenderlyKey string `mapstructure:"TENDERLY_KEY"` diff --git a/core/scripts/chaincli/handler/debug.go b/core/scripts/chaincli/handler/debug.go index c317edcac3..8b06937fc2 100644 --- a/core/scripts/chaincli/handler/debug.go +++ b/core/scripts/chaincli/handler/debug.go @@ -14,13 +14,15 @@ import ( "os" "strconv" + types2 "github.com/smartcontractkit/chainlink-common/pkg/types" + "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/ethereum/go-ethereum/ethclient" - ocr2keepers "github.com/smartcontractkit/chainlink-automation/pkg/v3/types" + ocr2keepers "github.com/smartcontractkit/chainlink-common/pkg/types/automation" evm21 "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21" @@ -31,7 +33,6 @@ import ( "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/logger" - "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/models" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/core" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/encoding" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mercury" @@ -67,14 +68,16 @@ func (k *Keeper) Debug(ctx context.Context, args []string) { } chainID := chainIDBig.Int64() - var triggerCallOpts *bind.CallOpts // use latest block for conditionals, but use block from tx for log triggers - latestCallOpts := &bind.CallOpts{Context: ctx} // always use latest block + // Log triggers: always use block from tx + // Conditional: use latest block if no block number is provided, otherwise use block from user input + var triggerCallOpts *bind.CallOpts // use a certain block + latestCallOpts := &bind.CallOpts{Context: ctx} // use the latest block // connect to registry contract registryAddress := gethcommon.HexToAddress(k.cfg.RegistryAddress) keeperRegistry21, err := iregistry21.NewIKeeperRegistryMaster(registryAddress, k.client) if err != nil { - failUnknown("failed to connect to registry contract", err) + failUnknown("failed to connect to the registry contract", err) } // verify contract is correct @@ -138,8 +141,21 @@ func (k *Keeper) Debug(ctx context.Context, args []string) { // check upkeep if triggerType == ConditionTrigger { message("upkeep identified as conditional trigger") + + if len(args) > 1 { + // if a block number is provided, use that block for both checkUpkeep and simulatePerformUpkeep + blockNum, err = strconv.ParseUint(args[1], 10, 64) + if err != nil { + failCheckArgs("unable to parse block number", err) + } + triggerCallOpts = &bind.CallOpts{Context: ctx, BlockNumber: new(big.Int).SetUint64(blockNum)} + } else { + // if no block number is provided, use latest block for both checkUpkeep and simulatePerformUpkeep + triggerCallOpts = latestCallOpts + } + var tmpCheckResult iregistry21.CheckUpkeep0 - tmpCheckResult, err = keeperRegistry21.CheckUpkeep0(latestCallOpts, upkeepID) + tmpCheckResult, err = keeperRegistry21.CheckUpkeep0(triggerCallOpts, upkeepID) if err != nil { failUnknown("failed to check upkeep: ", err) } @@ -250,13 +266,14 @@ func (k *Keeper) Debug(ctx context.Context, args []string) { 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)) + message(fmt.Sprintf("checkUpkeep failed with UpkeepFailureReason %s", getCheckUpkeepFailureReason(checkResult.UpkeepFailureReason))) } + // handle data streams lookup if checkResult.UpkeepFailureReason == uint8(encoding.UpkeepFailureReasonTargetCheckReverted) { - mc := &models.MercuryCredentials{LegacyURL: k.cfg.MercuryLegacyURL, URL: k.cfg.MercuryURL, Username: k.cfg.MercuryID, Password: k.cfg.MercuryKey} + mc := &types2.MercuryCredentials{LegacyURL: k.cfg.DataStreamsLegacyURL, URL: k.cfg.DataStreamsURL, Username: k.cfg.DataStreamsID, Password: k.cfg.DataStreamsKey} mercuryConfig := evm21.NewMercuryConfig(mc, core.StreamsCompatibleABI) lggr, _ := logger.NewLogger() blockSub := &blockSubscriber{k.client} @@ -281,25 +298,25 @@ func (k *Keeper) Debug(ctx context.Context, args []string) { } if streamsLookup.IsMercuryV02() { - message("using mercury lookup v0.2") + message("using data streams lookup v0.2") // check if upkeep is allowed to use mercury v0.2 var allowed bool _, _, _, allowed, err = streams.AllowedToUseMercury(triggerCallOpts, upkeepID) if err != nil { - failUnknown("failed to check if upkeep is allowed to use mercury", err) + failUnknown("failed to check if upkeep is allowed to use data streams", err) } if !allowed { resolveIneligible("upkeep reverted with StreamsLookup but is not allowed to access streams") } } else if streamsLookup.IsMercuryV03() { // handle v0.3 - message("using mercury lookup v0.3") + message("using data streams lookup v0.3") } else { resolveIneligible("upkeep reverted with StreamsLookup but the configuration is invalid") } - if k.cfg.MercuryLegacyURL == "" || k.cfg.MercuryURL == "" || k.cfg.MercuryID == "" || k.cfg.MercuryKey == "" { - failCheckConfig("Mercury configs not set properly, check your MERCURY_LEGACY_URL, MERCURY_URL, MERCURY_ID and MERCURY_KEY", nil) + if k.cfg.DataStreamsLegacyURL == "" || k.cfg.DataStreamsURL == "" || k.cfg.DataStreamsID == "" || k.cfg.DataStreamsKey == "" { + failCheckConfig("Data streams configs not set properly, check your DATA_STREAMS_LEGACY_URL, DATA_STREAMS_URL, DATA_STREAMS_ID and DATA_STREAMS_KEY", nil) } // do mercury request @@ -313,16 +330,16 @@ func (k *Keeper) Debug(ctx context.Context, args []string) { resolveIneligible("upkeep used invalid revert data") } if checkResults[0].PipelineExecutionState == uint8(encoding.InvalidMercuryRequest) { - resolveIneligible("the mercury request data is invalid") + resolveIneligible("the data streams request data is invalid") } if err != nil { - failCheckConfig("failed to do mercury request ", err) + failCheckConfig("failed to do data streams request ", err) } // do checkCallback err = streams.CheckCallback(ctx, values, streamsLookup, checkResults, 0) if err != nil { - failUnknown("failed to execute mercury callback ", err) + failUnknown("failed to execute data streams callback ", err) } if checkResults[0].IneligibilityReason != 0 { message(fmt.Sprintf("checkCallback failed with UpkeepFailureReason %d", checkResults[0].IneligibilityReason)) @@ -377,6 +394,28 @@ func (k *Keeper) Debug(ctx context.Context, args []string) { } } +func getCheckUpkeepFailureReason(reasonIndex uint8) string { + // Copied from KeeperRegistryBase2_1.sol + reasonStrings := []string{ + "NONE", + "UPKEEP_CANCELLED", + "UPKEEP_PAUSED", + "TARGET_CHECK_REVERTED", + "UPKEEP_NOT_NEEDED", + "PERFORM_DATA_EXCEEDS_LIMIT", + "INSUFFICIENT_BALANCE", + "CALLBACK_REVERTED", + "REVERT_DATA_EXCEEDS_LIMIT", + "REGISTRY_PAUSED", + } + + if int(reasonIndex) < len(reasonStrings) { + return reasonStrings[reasonIndex] + } + + return fmt.Sprintf("Unknown : %d", reasonIndex) +} + func mustAutomationCheckResult(upkeepID *big.Int, checkResult iregistry21.CheckUpkeep, trigger ocr2keepers.Trigger) ocr2keepers.CheckResult { upkeepIdentifier := mustUpkeepIdentifier(upkeepID) checkResult2 := ocr2keepers.CheckResult{ diff --git a/core/scripts/chaincli/handler/handler.go b/core/scripts/chaincli/handler/handler.go index 591431555a..a5b6798836 100644 --- a/core/scripts/chaincli/handler/handler.go +++ b/core/scripts/chaincli/handler/handler.go @@ -333,7 +333,7 @@ func (h *baseHandler) launchChainlinkNode(ctx context.Context, port int, contain if err != nil { return "", nil, fmt.Errorf("failed to create toml file: %w", err) } - var secretTOMLStr = fmt.Sprintf(secretTOML, h.cfg.MercuryURL, h.cfg.MercuryID, h.cfg.MercuryKey) + var secretTOMLStr = fmt.Sprintf(secretTOML, h.cfg.DataStreamsURL, h.cfg.DataStreamsID, h.cfg.DataStreamsKey) secretFile, secretTOMLFileCleanup, err := createTomlFile(secretTOMLStr) if err != nil { return "", nil, fmt.Errorf("failed to create secret toml file: %w", err) diff --git a/core/scripts/chaincli/handler/keeper_launch.go b/core/scripts/chaincli/handler/keeper_launch.go index 25af77f1d5..1db3884ae4 100644 --- a/core/scripts/chaincli/handler/keeper_launch.go +++ b/core/scripts/chaincli/handler/keeper_launch.go @@ -19,6 +19,7 @@ import ( "github.com/ethereum/go-ethereum/crypto" "github.com/smartcontractkit/chainlink-common/pkg/utils/hex" + "github.com/smartcontractkit/chainlink/v2/core/cmd" iregistry21 "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/i_keeper_registry_master_wrapper_2_1" registry12 "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/keeper_registry_wrapper1_2" @@ -377,13 +378,13 @@ func (k *Keeper) createOCR2KeeperJob(ctx context.Context, client cmd.HTTPClient, request, err := json.Marshal(web.CreateJobRequest{ TOML: fmt.Sprintf(ocr2keeperJobTemplate, - contractAddr, // contractID - ocr2KeyConfig.ID, // ocrKeyBundleID - nodeAddr, // transmitterID - node wallet address - k.cfg.BootstrapNodeAddr, // bootstrap node key and address - k.cfg.ChainID, // chainID - contractVersion, // contractVersion - k.cfg.MercuryCredName, // mercury credential name + contractAddr, // contractID + ocr2KeyConfig.ID, // ocrKeyBundleID + nodeAddr, // transmitterID - node wallet address + k.cfg.BootstrapNodeAddr, // bootstrap node key and address + k.cfg.ChainID, // chainID + contractVersion, // contractVersion + k.cfg.DataStreamsCredName, // mercury credential name ), }) if err != nil { diff --git a/core/scripts/common/vrf/jobs/jobs.go b/core/scripts/common/vrf/jobs/jobs.go index 674cca175c..7e304f431b 100644 --- a/core/scripts/common/vrf/jobs/jobs.go +++ b/core/scripts/common/vrf/jobs/jobs.go @@ -7,13 +7,14 @@ schemaVersion = 1 coordinatorAddress = "%s" batchCoordinatorAddress = "%s" batchFulfillmentEnabled = %t -batchFulfillmentGasMultiplier = 1.1 +batchFulfillmentGasMultiplier = %f +customRevertsPipelineEnabled = %t publicKey = "%s" minIncomingConfirmations = %d evmChainID = "%d" fromAddresses = ["%s"] -pollPeriod = "300ms" -requestTimeout = "30m0s" +pollPeriod = "%s" +requestTimeout = "%s" 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)" @@ -25,7 +26,7 @@ vrf [type=vrfv2 topics="$(jobRun.logTopics)"] estimate_gas [type=estimategaslimit to="%s" - multiplier="1.1" + multiplier="%f" data="$(vrf.output)"] simulate [type=ethcall from="%s" @@ -45,13 +46,13 @@ schemaVersion = 1 coordinatorAddress = "%s" batchCoordinatorAddress = "%s" batchFulfillmentEnabled = %t -batchFulfillmentGasMultiplier = 1.1 +batchFulfillmentGasMultiplier = %f publicKey = "%s" minIncomingConfirmations = %d evmChainID = "%d" fromAddresses = ["%s"] -pollPeriod = "300ms" -requestTimeout = "30m0s" +pollPeriod = "%s" +requestTimeout = "%s" 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)" @@ -64,7 +65,7 @@ generate_proof [type=vrfv2plus topics="$(jobRun.logTopics)"] estimate_gas [type=estimategaslimit to="%s" - multiplier="1.1" + multiplier="%f" data="$(generate_proof.output)"] simulate_fulfillment [type=ethcall from="%s" @@ -91,6 +92,20 @@ runTimeout = "1m0s" evmChainID = "%d" fromAddresses = ["%s"] ` + BHSPlusJobFormatted = `type = "blockhashstore" +schemaVersion = 1 +name = "blockhashstore" +forwardingAllowed = false +coordinatorV2PlusAddress = "%s" +waitBlocks = %d +lookbackBlocks = %d +blockhashStoreAddress = "%s" +pollPeriod = "30s" +runTimeout = "1m0s" +evmChainID = "%d" +fromAddresses = ["%s"] +` + BHFJobFormatted = `type = "blockheaderfeeder" schemaVersion = 1 name = "blockheaderfeeder" @@ -106,5 +121,22 @@ evmChainID = "%d" fromAddresses = ["%s"] getBlockhashesBatchSize = 50 storeBlockhashesBatchSize = 10 +` + + BHFPlusJobFormatted = `type = "blockheaderfeeder" +schemaVersion = 1 +name = "blockheaderfeeder" +forwardingAllowed = false +coordinatorV2PlusAddress = "%s" +waitBlocks = 256 +lookbackBlocks = 1_000 +blockhashStoreAddress = "%s" +batchBlockhashStoreAddress = "%s" +pollPeriod = "10s" +runTimeout = "30s" +evmChainID = "%d" +fromAddresses = ["%s"] +getBlockhashesBatchSize = 50 +storeBlockhashesBatchSize = 10 ` ) diff --git a/core/scripts/common/vrf/model/model.go b/core/scripts/common/vrf/model/model.go index 1b4e59fe4f..ba919eb3c4 100644 --- a/core/scripts/common/vrf/model/model.go +++ b/core/scripts/common/vrf/model/model.go @@ -49,3 +49,12 @@ type VRFKeyRegistrationConfig struct { VRFKeyUncompressedPubKey string RegisterAgainstAddress string } + +type CoordinatorJobSpecConfig struct { + BatchFulfillmentEnabled bool + BatchFulfillmentGasMultiplier float64 + EstimateGasMultiplier float64 + PollPeriod string + RequestTimeout string + RevertsPipelineEnabled bool +} diff --git a/core/scripts/common/vrf/setup-envs/README.md b/core/scripts/common/vrf/setup-envs/README.md index 5aa6aa4754..372e735844 100644 --- a/core/scripts/common/vrf/setup-envs/README.md +++ b/core/scripts/common/vrf/setup-envs/README.md @@ -15,10 +15,12 @@ export ETH_CHAIN_ID= export ACCOUNT_KEY= ``` 5. execute from `core/scripts/common/vrf/setup-envs` folder - * `--vrf-version` - "v2" or "v2plus" + * `--vrf-version` - "v2" or "v2plus" + +#### VRF V2 ``` go run . \ ---vrf-version="v2plus" \ +--vrf-version="v2" \ --vrf-primary-node-url=http://localhost:6610 \ --vrf-primary-creds-file \ --vrf-backup-node-url=http://localhost:6611 \ @@ -36,10 +38,48 @@ go run . \ --subscription-balance="1e19" \ --subscription-balance-native="1e18" \ --batch-fulfillment-enabled="true" \ +--batch-fulfillment-gas-multiplier=1.1 \ +--estimate-gas-multiplier=1.1 \ +--poll-period="5s" \ +--request-timeout="30m0s" \ +--reverts-pipeline-enabled="true" \ --min-confs=3 \ --register-vrf-key-against-address= \ ---deploy-vrfv2-owner="true" +--deploy-vrfv2-owner="true" \ +--use-test-coordinator="true" +``` +#### VRF V2 Plus +* does not need to register VRF key against address +* does not need to deploy VRFV2Owner contract +* does not need to use test coordinator + +VRF V2 Plus example: +``` +go run . \ +--vrf-version="v2plus" \ +--vrf-primary-node-url=http://localhost:6610 \ +--vrf-primary-creds-file \ +--vrf-backup-node-url=http://localhost:6611 \ +--vrf-bk-creds-file \ +--bhs-node-url=http://localhost:6612 \ +--bhs-creds-file \ +--bhs-backup-node-url=http://localhost:6613 \ +--bhs-bk-creds-file \ +--bhf-node-url=http://localhost:6614 \ +--bhf-creds-file \ +--num-eth-keys=1 \ +--num-vrf-keys=1 \ +--sending-key-funding-amount="1e17" \ +--deploy-contracts-and-create-jobs="true" \ +--subscription-balance="1e19" \ +--subscription-balance-native="1e18" \ +--batch-fulfillment-enabled="true" \ +--batch-fulfillment-gas-multiplier=1.1 \ +--estimate-gas-multiplier=1.1 \ +--poll-period="5s" \ +--request-timeout="30m0s" \ +--min-confs=3 ``` Optional parameters - will not be deployed if specified diff --git a/core/scripts/common/vrf/setup-envs/main.go b/core/scripts/common/vrf/setup-envs/main.go index 598238bebe..57e4817d80 100644 --- a/core/scripts/common/vrf/setup-envs/main.go +++ b/core/scripts/common/vrf/setup-envs/main.go @@ -70,7 +70,12 @@ 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") + batchFulfillmentEnabled := flag.Bool("batch-fulfillment-enabled", constants.BatchFulfillmentEnabled, "whether send randomness fulfillments in batches inside one tx from CL node") + batchFulfillmentGasMultiplier := flag.Float64("batch-fulfillment-gas-multiplier", 1.1, "") + estimateGasMultiplier := flag.Float64("estimate-gas-multiplier", 1.1, "") + pollPeriod := flag.String("poll-period", "300ms", "") + requestTimeout := flag.String("request-timeout", "30m0s", "") + revertsPipelineEnabled := flag.Bool("reverts-pipeline-enabled", true, "") 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") @@ -88,6 +93,7 @@ func main() { registerVRFKeyAgainstAddress := flag.String("register-vrf-key-against-address", "", "VRF Key registration against address - "+ "from this address you can perform `coordinator.oracleWithdraw` to withdraw earned funds from rand request fulfilments") deployVRFOwner := flag.Bool("deploy-vrfv2-owner", true, "whether to deploy VRF owner contracts") + useTestCoordinator := flag.Bool("use-test-coordinator", true, "whether to use test coordinator contract or use the normal one") e := helpers.SetupEnv(false) flag.Parse() @@ -204,15 +210,25 @@ func main() { FeeConfig: feeConfigV2, } + coordinatorJobSpecConfig := model.CoordinatorJobSpecConfig{ + BatchFulfillmentEnabled: *batchFulfillmentEnabled, + BatchFulfillmentGasMultiplier: *batchFulfillmentGasMultiplier, + EstimateGasMultiplier: *estimateGasMultiplier, + PollPeriod: *pollPeriod, + RequestTimeout: *requestTimeout, + RevertsPipelineEnabled: *revertsPipelineEnabled, + } + jobSpecs = v2scripts.VRFV2DeployUniverse( e, subscriptionBalanceJuels, vrfKeyRegistrationConfig, contractAddresses, coordinatorConfigV2, - *batchFulfillmentEnabled, nodesMap, *deployVRFOwner, + coordinatorJobSpecConfig, + *useTestCoordinator, ) case "v2plus": feeConfigV2Plus := vrf_coordinator_v2_5.VRFCoordinatorV25FeeConfig{ @@ -228,6 +244,14 @@ func main() { FeeConfig: feeConfigV2Plus, } + coordinatorJobSpecConfig := model.CoordinatorJobSpecConfig{ + BatchFulfillmentEnabled: *batchFulfillmentEnabled, + BatchFulfillmentGasMultiplier: *batchFulfillmentGasMultiplier, + EstimateGasMultiplier: *estimateGasMultiplier, + PollPeriod: *pollPeriod, + RequestTimeout: *requestTimeout, + } + jobSpecs = v2plusscripts.VRFV2PlusDeployUniverse( e, subscriptionBalanceJuels, @@ -235,8 +259,8 @@ func main() { vrfKeyRegistrationConfig, contractAddresses, coordinatorConfigV2Plus, - *batchFulfillmentEnabled, nodesMap, + coordinatorJobSpecConfig, ) } diff --git a/core/scripts/go.mod b/core/scripts/go.mod index 23a9289469..f5290d1d85 100644 --- a/core/scripts/go.mod +++ b/core/scripts/go.mod @@ -8,7 +8,7 @@ replace github.com/smartcontractkit/chainlink/v2 => ../../ require ( github.com/docker/docker v24.0.7+incompatible github.com/docker/go-connections v0.4.0 - github.com/ethereum/go-ethereum v1.12.2 + github.com/ethereum/go-ethereum v1.13.8 github.com/google/go-cmp v0.6.0 github.com/google/uuid v1.4.0 github.com/jmoiron/sqlx v1.3.5 @@ -19,11 +19,11 @@ require ( github.com/pelletier/go-toml/v2 v2.1.1 github.com/pkg/errors v0.9.1 github.com/shopspring/decimal v1.3.1 - github.com/smartcontractkit/chainlink-automation v1.0.1 - github.com/smartcontractkit/chainlink-common v0.1.7-0.20240108182329-237f56daad6b + github.com/smartcontractkit/chainlink-automation v1.0.2-0.20240118014648-1ab6a88c9429 + github.com/smartcontractkit/chainlink-common v0.1.7-0.20240123141952-a879db9d23b3 github.com/smartcontractkit/chainlink-vrf v0.0.0-20231120191722-fef03814f868 github.com/smartcontractkit/chainlink/v2 v2.0.0-00010101000000-000000000000 - github.com/smartcontractkit/libocr v0.0.0-20231130143053-c5102a9c0fb7 + github.com/smartcontractkit/libocr v0.0.0-20240112202000-6359502d2ff1 github.com/spf13/cobra v1.7.0 github.com/spf13/viper v1.16.0 github.com/stretchr/testify v1.8.4 @@ -51,14 +51,14 @@ require ( github.com/Depado/ginprom v1.8.0 // indirect github.com/Masterminds/semver/v3 v3.2.1 // indirect github.com/Microsoft/go-winio v0.6.1 // indirect - github.com/VictoriaMetrics/fastcache v1.10.0 // indirect + github.com/VictoriaMetrics/fastcache v1.12.1 // indirect github.com/andres-erbsen/clock v0.0.0-20160526145045-9e14626cd129 // indirect github.com/armon/go-metrics v0.4.1 // indirect github.com/avast/retry-go/v4 v4.5.1 // indirect github.com/aybabtme/rgbterm v0.0.0-20170906152045-cc83f3b3ce59 // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/bgentry/speakeasy v0.1.1-0.20220910012023-760eaf8b6816 // indirect - github.com/bits-and-blooms/bitset v1.7.0 // indirect + github.com/bits-and-blooms/bitset v1.10.0 // indirect github.com/blendle/zapdriver v1.3.1 // indirect github.com/btcsuite/btcd/btcec/v2 v2.3.2 // indirect github.com/btcsuite/btcd/btcutil v1.1.3 // indirect @@ -71,13 +71,14 @@ require ( github.com/chenzhuoyu/iasm v0.9.0 // indirect github.com/cockroachdb/errors v1.9.1 // indirect github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b // indirect - github.com/cockroachdb/pebble v0.0.0-20230906160148-46873a6a7a06 // indirect + github.com/cockroachdb/pebble v0.0.0-20230928194634-aa077af62593 // indirect github.com/cockroachdb/redact v1.1.3 // indirect + github.com/cockroachdb/tokenbucket v0.0.0-20230807174530-cc333fc44b06 // indirect github.com/cometbft/cometbft v0.37.2 // indirect github.com/cometbft/cometbft-db v0.8.0 // indirect github.com/confio/ics23/go v0.9.0 // indirect github.com/consensys/bavard v0.1.13 // indirect - github.com/consensys/gnark-crypto v0.10.0 // indirect + github.com/consensys/gnark-crypto v0.12.1 // indirect github.com/cosmos/btcutil v1.0.5 // indirect github.com/cosmos/cosmos-proto v1.0.0-beta.2 // indirect github.com/cosmos/cosmos-sdk v0.47.4 // indirect @@ -88,7 +89,8 @@ require ( github.com/cosmos/ics23/go v0.10.0 // indirect github.com/cosmos/ledger-cosmos-go v0.12.1 // indirect github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect - github.com/crate-crypto/go-kzg-4844 v0.3.0 // indirect + github.com/crate-crypto/go-ipa v0.0.0-20231025140028-3c0104f4b233 // indirect + github.com/crate-crypto/go-kzg-4844 v0.7.0 // indirect github.com/danieljoos/wincred v1.1.2 // indirect github.com/danielkov/gin-helmet v0.0.0-20171108135313-1387e224435e // indirect github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect @@ -103,7 +105,7 @@ require ( github.com/dustin/go-humanize v1.0.1 // indirect github.com/dvsekhvalnov/jose2go v1.5.0 // indirect github.com/esote/minmaxheap v1.0.0 // indirect - github.com/ethereum/c-kzg-4844 v0.3.1 // indirect + github.com/ethereum/c-kzg-4844 v0.4.0 // indirect github.com/fatih/color v1.16.0 // indirect github.com/fsnotify/fsnotify v1.6.0 // indirect github.com/fxamacker/cbor/v2 v2.5.0 // indirect @@ -112,6 +114,7 @@ require ( github.com/gagliardetto/solana-go v1.4.1-0.20220428092759-5250b4abbb27 // indirect github.com/gagliardetto/treeout v0.1.4 // indirect github.com/gballet/go-libpcsclite v0.0.0-20191108122812-4678299bea08 // indirect + github.com/gballet/go-verkle v0.1.1-0.20231031103413-a67434b50f46 // indirect github.com/gedex/inflector v0.0.0-20170307190818-16278e9db813 // indirect github.com/getsentry/sentry-go v0.19.0 // indirect github.com/gin-contrib/cors v1.5.0 // indirect @@ -132,7 +135,6 @@ require ( github.com/go-playground/locales v0.14.1 // indirect github.com/go-playground/universal-translator v0.18.1 // indirect github.com/go-playground/validator/v10 v10.15.5 // indirect - github.com/go-stack/stack v1.8.1 // indirect github.com/go-webauthn/webauthn v0.9.4 // indirect github.com/go-webauthn/x v0.1.5 // indirect github.com/goccy/go-json v0.10.2 // indirect @@ -165,6 +167,8 @@ require ( 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/sdk v0.14.1 // indirect + github.com/hashicorp/go-envparse v0.1.0 // indirect github.com/hashicorp/go-hclog v1.5.0 // indirect github.com/hashicorp/go-immutable-radix v1.3.1 // indirect github.com/hashicorp/go-plugin v1.5.2 // indirect @@ -173,7 +177,7 @@ require ( github.com/hashicorp/yamux v0.0.0-20200609203250-aecfd211c9ce // indirect github.com/hdevalence/ed25519consensus v0.1.0 // indirect github.com/holiman/bloomfilter/v2 v2.0.3 // indirect - github.com/holiman/uint256 v1.2.3 // indirect + github.com/holiman/uint256 v1.2.4 // indirect github.com/huandu/skiplist v1.2.0 // indirect github.com/huin/goupnp v1.3.0 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect @@ -244,11 +248,11 @@ require ( github.com/sirupsen/logrus v1.9.3 // indirect github.com/smartcontractkit/caigo v0.0.0-20230621050857-b29a4ca8c704 // indirect github.com/smartcontractkit/chain-selectors v1.0.9 // indirect - github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20231218175426-6e0427c661e5 // indirect + github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20240120192246-4bb04c997ca0 // indirect github.com/smartcontractkit/chainlink-data-streams v0.0.0-20231204152908-a6e3fe8ff2a1 // indirect - github.com/smartcontractkit/chainlink-feeds v0.0.0-20231127231053-2232d3a6766d // indirect - github.com/smartcontractkit/chainlink-solana v1.0.3-0.20231219140448-151a4725f312 // indirect - github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20231219014050-0c4a7831293a // indirect + github.com/smartcontractkit/chainlink-feeds v0.0.0-20240119021347-3c541a78cdb8 // indirect + github.com/smartcontractkit/chainlink-solana v1.0.3-0.20240122152632-38444d2ad8ba // indirect + github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20240119162652-3a7274645007 // 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 @@ -284,6 +288,7 @@ 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/github.com/gin-gonic/gin/otelgin v0.46.1 // indirect go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.46.1 // indirect go.opentelemetry.io/otel v1.21.0 // indirect go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.21.0 // indirect @@ -296,7 +301,7 @@ require ( go.uber.org/ratelimit v0.2.0 // indirect go.uber.org/zap v1.26.0 // indirect golang.org/x/arch v0.6.0 // indirect - golang.org/x/crypto v0.16.0 // indirect + golang.org/x/crypto v0.17.0 // indirect golang.org/x/exp v0.0.0-20231127185646-65229373498e // indirect golang.org/x/mod v0.14.0 // indirect golang.org/x/net v0.19.0 // indirect @@ -316,7 +321,6 @@ require ( gopkg.in/guregu/null.v4 v4.0.0 // indirect gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect - gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce // indirect gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect pgregory.net/rapid v0.5.5 // indirect diff --git a/core/scripts/go.sum b/core/scripts/go.sum index d4e29ad029..478c1da3fa 100644 --- a/core/scripts/go.sum +++ b/core/scripts/go.sum @@ -111,11 +111,11 @@ github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5 github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5 h1:TngWCqHvy9oXAN6lEVMRuU21PR1EtLVZJmdB18Gu3Rw= github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5/go.mod h1:lmUJ/7eu/Q8D7ML55dXQrVaamCz2vxCfdQBasLZfHKk= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= -github.com/OneOfOne/xxhash v1.2.8 h1:31czK/TI9sNkxIKfaUfGlU47BAxQ0ztGgd9vPyqimf8= -github.com/OneOfOne/xxhash v1.2.8/go.mod h1:eZbhyaAYD41SGSSsnmcpxVoRiQ/MPUTjUdIIOT9Um7Q= +github.com/OneOfOne/xxhash v1.2.5 h1:zl/OfRA6nftbBK9qTohYBJ5xvw6C/oNKizR7cZGl3cI= +github.com/OneOfOne/xxhash v1.2.5/go.mod h1:eZbhyaAYD41SGSSsnmcpxVoRiQ/MPUTjUdIIOT9Um7Q= github.com/Shopify/goreferrer v0.0.0-20181106222321-ec9c9a553398/go.mod h1:a1uqRtAwp2Xwc6WNPJEufxJ7fx3npB4UV/JOLmbu5I0= -github.com/VictoriaMetrics/fastcache v1.10.0 h1:5hDJnLsKLpnUEToub7ETuRu8RCkb40woBZAUiKonXzY= -github.com/VictoriaMetrics/fastcache v1.10.0/go.mod h1:tjiYeEfYXCqacuvYw/7UoDIeJaNxq6132xHICNP77w8= +github.com/VictoriaMetrics/fastcache v1.12.1 h1:i0mICQuojGDL3KblA7wUNlY5lOK6a4bwt3uRKnkZU40= +github.com/VictoriaMetrics/fastcache v1.12.1/go.mod h1:tX04vaqcNoQeGLD+ra5pU5sWkuxnzWhEzLwhP9w653o= github.com/VividCortex/gohistogram v1.0.0 h1:6+hBz+qvs0JOrrNhhmR7lFxo5sINxBCGXrdtl/UvroE= github.com/VividCortex/gohistogram v1.0.0/go.mod h1:Pf5mBqqDxYaXu3hDrrU+w6nw50o/4+TcAqDqk/vUH7g= github.com/aead/siphash v1.0.1/go.mod h1:Nywa3cDsYNNK3gaciGTWPwHt0wlpNV15vwmswBAUSII= @@ -164,8 +164,8 @@ github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d/go.mod h1:6QX/PXZ github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= github.com/bgentry/speakeasy v0.1.1-0.20220910012023-760eaf8b6816 h1:41iFGWnSlI2gVpmOtVTJZNodLdLQLn/KsJqFvXwnd/s= github.com/bgentry/speakeasy v0.1.1-0.20220910012023-760eaf8b6816/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= -github.com/bits-and-blooms/bitset v1.7.0 h1:YjAGVd3XmtK9ktAbX8Zg2g2PwLIMjGREZJHlV4j7NEo= -github.com/bits-and-blooms/bitset v1.7.0/go.mod h1:gIdJ4wp64HaoK2YrL1Q5/N7Y16edYb8uY+O0FJTyyDA= +github.com/bits-and-blooms/bitset v1.10.0 h1:ePXTeiPEazB5+opbv5fr8umg2R/1NlzgDsyepwsSr88= +github.com/bits-and-blooms/bitset v1.10.0/go.mod h1:7hO7Gc7Pp1vODcmWvKMRA9BNmbv6a/7QIWpPxHddWR8= github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJmJgSg28kpZDP6UIiPt0e0Oz0kqKNGyRaWEPv84= github.com/blendle/zapdriver v1.3.1 h1:C3dydBOWYRiOk+B8X9IVZ5IOe+7cl+tGOexN4QqHfpE= github.com/blendle/zapdriver v1.3.1/go.mod h1:mdXfREi6u5MArG4j9fewC+FGnXaBR+T4Ox4J2u4eHCc= @@ -211,7 +211,6 @@ github.com/cespare/cp v1.1.1/go.mod h1:SOGHArjBr4JWaSDEVpWpo/hNg6RoKrls6Oh40hiwW github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko= github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= -github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/chenzhuoyu/base64x v0.0.0-20211019084208-fb5309c8db06/go.mod h1:DH46F32mSOjUmXrMHnKwZdA8wcEefY7UVqBKYGjpdQY= @@ -240,17 +239,19 @@ github.com/cockroachdb/apd/v2 v2.0.2/go.mod h1:DDxRlzC2lo3/vSlmSoS7JkqbbrARPuFOG github.com/cockroachdb/apd/v3 v3.1.0 h1:MK3Ow7LH0W8zkd5GMKA1PvS9qG3bWFI95WaVNfyZJ/w= github.com/cockroachdb/apd/v3 v3.1.0/go.mod h1:6qgPBMXjATAdD/VefbRP9NoSLKjbB4LCoA7gN4LpHs4= github.com/cockroachdb/datadriven v1.0.2/go.mod h1:a9RdTaap04u637JoCzcUoIcDmvwSUtcUFtT/C3kJlTU= -github.com/cockroachdb/datadriven v1.0.3-0.20230801171734-e384cf455877 h1:1MLK4YpFtIEo3ZtMA5C795Wtv5VuUnrXX7mQG+aHg6o= -github.com/cockroachdb/datadriven v1.0.3-0.20230801171734-e384cf455877/go.mod h1:a9RdTaap04u637JoCzcUoIcDmvwSUtcUFtT/C3kJlTU= +github.com/cockroachdb/datadriven v1.0.3-0.20230413201302-be42291fc80f h1:otljaYPt5hWxV3MUfO5dFPFiOXg9CyG5/kCfayTqsJ4= +github.com/cockroachdb/datadriven v1.0.3-0.20230413201302-be42291fc80f/go.mod h1:a9RdTaap04u637JoCzcUoIcDmvwSUtcUFtT/C3kJlTU= github.com/cockroachdb/errors v1.9.1 h1:yFVvsI0VxmRShfawbt/laCIDy/mtTqqnvoNgiy5bEV8= github.com/cockroachdb/errors v1.9.1/go.mod h1:2sxOtL2WIc096WSZqZ5h8fa17rdDq9HZOZLBCor4mBk= github.com/cockroachdb/logtags v0.0.0-20211118104740-dabe8e521a4f/go.mod h1:Vz9DsVWQQhf3vs21MhPMZpMGSht7O/2vFW2xusFUVOs= github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b h1:r6VH0faHjZeQy818SGhaone5OnYfxFR/+AzdY3sf5aE= github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b/go.mod h1:Vz9DsVWQQhf3vs21MhPMZpMGSht7O/2vFW2xusFUVOs= -github.com/cockroachdb/pebble v0.0.0-20230906160148-46873a6a7a06 h1:T+Np/xtzIjYM/P5NAw0e2Rf1FGvzDau1h54MKvx8G7w= -github.com/cockroachdb/pebble v0.0.0-20230906160148-46873a6a7a06/go.mod h1:bynZ3gvVyhlvjLI7PT6dmZ7g76xzJ7HpxfjgkzCGz6s= +github.com/cockroachdb/pebble v0.0.0-20230928194634-aa077af62593 h1:aPEJyR4rPBvDmeyi+l/FS/VtA00IWvjeFvjen1m1l1A= +github.com/cockroachdb/pebble v0.0.0-20230928194634-aa077af62593/go.mod h1:6hk1eMY/u5t+Cf18q5lFMUA1Rc+Sm5I6Ra1QuPyxXCo= github.com/cockroachdb/redact v1.1.3 h1:AKZds10rFSIj7qADf0g46UixK8NNLwWTNdCIGS5wfSQ= github.com/cockroachdb/redact v1.1.3/go.mod h1:BVNblN9mBWFyMyqK1k3AAiSxhvhfK2oOZZ2lK+dpvRg= +github.com/cockroachdb/tokenbucket v0.0.0-20230807174530-cc333fc44b06 h1:zuQyyAKVxetITBuuhv3BI9cMrmStnpT18zmgmTxunpo= +github.com/cockroachdb/tokenbucket v0.0.0-20230807174530-cc333fc44b06/go.mod h1:7nc4anLGjupUW/PeY5qiNYsdNXj7zopG+eqsS7To5IQ= github.com/codegangsta/inject v0.0.0-20150114235600-33e0aa1cb7c0/go.mod h1:4Zcjuz89kmFXt9morQgcfYZAYZ5n8WHjt81YYWIwtTM= github.com/coinbase/rosetta-sdk-go/types v1.0.0 h1:jpVIwLcPoOeCR6o1tU+Xv7r5bMONNbHU7MuEHboiFuA= github.com/coinbase/rosetta-sdk-go/types v1.0.0/go.mod h1:eq7W2TMRH22GTW0N0beDnN931DW0/WOI1R2sdHNHG4c= @@ -262,8 +263,8 @@ github.com/confio/ics23/go v0.9.0 h1:cWs+wdbS2KRPZezoaaj+qBleXgUk5WOQFMP3CQFGTr4 github.com/confio/ics23/go v0.9.0/go.mod h1:4LPZ2NYqnYIVRklaozjNR1FScgDJ2s5Xrp+e/mYVRak= github.com/consensys/bavard v0.1.13 h1:oLhMLOFGTLdlda/kma4VOJazblc7IM5y5QPd2A/YjhQ= github.com/consensys/bavard v0.1.13/go.mod h1:9ItSMtA/dXMAiL7BG6bqW2m3NdSEObYWoH223nGHukI= -github.com/consensys/gnark-crypto v0.10.0 h1:zRh22SR7o4K35SoNqouS9J/TKHTyU2QWaj5ldehyXtA= -github.com/consensys/gnark-crypto v0.10.0/go.mod h1:Iq/P3HHl0ElSjsg2E1gsMwhAyxnxoKK5nVyZKd+/KhU= +github.com/consensys/gnark-crypto v0.12.1 h1:lHH39WuuFgVHONRl3J0LRBtuYdQTumFSDtJF7HpyG8M= +github.com/consensys/gnark-crypto v0.12.1/go.mod h1:v2Gy7L/4ZRosZ7Ivs+9SfUDr0f5UlG+EM5t7MPHiLuY= github.com/containerd/continuity v0.4.3 h1:6HVkalIp+2u1ZLH1J/pYX2oBVXlJZvh1X1A7bEZ9Su8= github.com/containerd/continuity v0.4.3/go.mod h1:F6PTNCKepoxEaXLQp3wDAjygEnImnZ/7o4JzpodfroQ= github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= @@ -302,8 +303,10 @@ github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwc github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/cpuguy83/go-md2man/v2 v2.0.2 h1:p1EgwI/C7NhT0JmVkwCD2ZBK8j4aeHQX2pMHHBfMQ6w= github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= -github.com/crate-crypto/go-kzg-4844 v0.3.0 h1:UBlWE0CgyFqqzTI+IFyCzA7A3Zw4iip6uzRv5NIXG0A= -github.com/crate-crypto/go-kzg-4844 v0.3.0/go.mod h1:SBP7ikXEgDnUPONgm33HtuDZEDtWa3L4QtN1ocJSEQ4= +github.com/crate-crypto/go-ipa v0.0.0-20231025140028-3c0104f4b233 h1:d28BXYi+wUpz1KBmiF9bWrjEMacUEREV6MBi2ODnrfQ= +github.com/crate-crypto/go-ipa v0.0.0-20231025140028-3c0104f4b233/go.mod h1:geZJZH3SzKCqnz5VT0q/DyIG/tvu/dZk+VIfXicupJs= +github.com/crate-crypto/go-kzg-4844 v0.7.0 h1:C0vgZRk4q4EZ/JgPfzuSoxdCq3C3mOZMBShovmncxvA= +github.com/crate-crypto/go-kzg-4844 v0.7.0/go.mod h1:1kMhvPgI0Ky3yIa+9lFySEBUBXkYxeOi8ZF1sYioxhc= github.com/creachadair/taskgroup v0.4.2 h1:jsBLdAJE42asreGss2xZGZ8fJra7WtwnHWeJFxv2Li8= github.com/creachadair/taskgroup v0.4.2/go.mod h1:qiXUOSrbwAY3u0JPGTzObbE3yf9hcXHDKBZ2ZjpCbgM= github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= @@ -379,10 +382,10 @@ github.com/envoyproxy/protoc-gen-validate v1.0.2/go.mod h1:GpiZQP3dDbg4JouG/NNS7 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= -github.com/ethereum/c-kzg-4844 v0.3.1 h1:sR65+68+WdnMKxseNWxSJuAv2tsUrihTpVBTfM/U5Zg= -github.com/ethereum/c-kzg-4844 v0.3.1/go.mod h1:VewdlzQmpT5QSrVhbBuGoCdFJkpaJlO1aQputP83wc0= -github.com/ethereum/go-ethereum v1.12.2 h1:eGHJ4ij7oyVqUQn48LBz3B7pvQ8sV0wGJiIE6gDq/6Y= -github.com/ethereum/go-ethereum v1.12.2/go.mod h1:1cRAEV+rp/xX0zraSCBnu9Py3HQ+geRMj3HdR+k0wfI= +github.com/ethereum/c-kzg-4844 v0.4.0 h1:3MS1s4JtA868KpJxroZoepdV0ZKBp3u/O5HcZ7R3nlY= +github.com/ethereum/c-kzg-4844 v0.4.0/go.mod h1:VewdlzQmpT5QSrVhbBuGoCdFJkpaJlO1aQputP83wc0= +github.com/ethereum/go-ethereum v1.13.8 h1:1od+thJel3tM52ZUNQwvpYOeRHlbkVFZ5S8fhi0Lgsg= +github.com/ethereum/go-ethereum v1.13.8/go.mod h1:sc48XYQxCzH3fG9BcrXCOOgQk2JfZzNAmIKnceogzsA= github.com/fasthttp-contrib/websocket v0.0.0-20160511215533-1f3b11f56072/go.mod h1:duJ4Jxv5lDcvg4QuQr0oowTf7dz4/CR8NtyCooz9HL8= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU= @@ -419,6 +422,8 @@ github.com/gagliardetto/treeout v0.1.4/go.mod h1:loUefvXTrlRG5rYmJmExNryyBRh8f89 github.com/gavv/httpexpect v2.0.0+incompatible/go.mod h1:x+9tiU1YnrOvnB725RkpoLv1M62hOWzwo5OXotisrKc= github.com/gballet/go-libpcsclite v0.0.0-20191108122812-4678299bea08 h1:f6D9Hr8xV8uYKlyuj8XIruxlh9WjVjdh1gIicAS7ays= github.com/gballet/go-libpcsclite v0.0.0-20191108122812-4678299bea08/go.mod h1:x7DCsMOv1taUwEWCzT4cmDeAkigA5/QCwUodaVOe8Ww= +github.com/gballet/go-verkle v0.1.1-0.20231031103413-a67434b50f46 h1:BAIP2GihuqhwdILrV+7GJel5lyPV3u1+PgzrWLc0TkE= +github.com/gballet/go-verkle v0.1.1-0.20231031103413-a67434b50f46/go.mod h1:QNpY22eby74jVhqH4WhDLDwxc/vqsern6pW+u2kbkpc= github.com/gedex/inflector v0.0.0-20170307190818-16278e9db813 h1:Uc+IZ7gYqAf/rSGFplbWBSHaGolEQlNLgMgSE3ccnIQ= github.com/gedex/inflector v0.0.0-20170307190818-16278e9db813/go.mod h1:P+oSoE9yhSRvsmYyZsshflcR6ePWYLql6UU1amW13IM= github.com/getsentry/sentry-go v0.12.0/go.mod h1:NSap0JBYWzHND8oMbyi0+XZhUalc1TBdRL1M71JZW2c= @@ -493,8 +498,6 @@ github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LB github.com/go-sql-driver/mysql v1.7.1 h1:lUIinVbN1DY0xBg0eMOzmmtGoHwWBbvnWubQUrtU8EI= github.com/go-sql-driver/mysql v1.7.1/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= -github.com/go-stack/stack v1.8.1 h1:ntEHSVwIt7PNXNpgPmVfMrNhLtgjlmnZha2kOpuRiDw= -github.com/go-stack/stack v1.8.1/go.mod h1:dcoOX6HbPZSZptuspn9bctJ+N/CnF5gGygcUP3XYfe4= github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= github.com/go-webauthn/webauthn v0.9.4 h1:YxvHSqgUyc5AK2pZbqkWWR55qKeDPhP8zLDr6lpIc2g= github.com/go-webauthn/webauthn v0.9.4/go.mod h1:LqupCtzSef38FcxzaklmOn7AykGKhAhr9xlRbdbgnTw= @@ -685,6 +688,8 @@ github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtng github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ= github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48= +github.com/hashicorp/go-envparse v0.1.0 h1:bE++6bhIsNCPLvgDZkYqo3nA+/PFI51pkrHdmPSDFPY= +github.com/hashicorp/go-envparse v0.1.0/go.mod h1:OHheN1GoygLlAkTlXLXvAdnXdZxy8JUweQ1rAXx1xnc= github.com/hashicorp/go-getter v1.7.1 h1:SWiSWN/42qdpR0MdhaOc/bLR48PLuP1ZQtYLRlM69uY= github.com/hashicorp/go-getter v1.7.1/go.mod h1:W7TalhMmbPmsSMdNjD0ZskARur/9GJ17cfHTRtXV744= github.com/hashicorp/go-hclog v1.5.0 h1:bI2ocEMgcVlz55Oj1xZNBsVi900c7II+fWDyV9o+13c= @@ -702,8 +707,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= @@ -727,8 +732,8 @@ github.com/holiman/billy v0.0.0-20230718173358-1c7e68d277a7 h1:3JQNjnMRil1yD0IfZ github.com/holiman/billy v0.0.0-20230718173358-1c7e68d277a7/go.mod h1:5GuXa7vkL8u9FkFuWdVvfR5ix8hRB7DbOAaYULamFpc= github.com/holiman/bloomfilter/v2 v2.0.3 h1:73e0e/V0tCydx14a0SCYS/EWCxgwLZ18CZcZKVu0fao= github.com/holiman/bloomfilter/v2 v2.0.3/go.mod h1:zpoh+gs7qcpqrHr3dB55AMiJwo0iURXE7ZOP9L9hSkA= -github.com/holiman/uint256 v1.2.3 h1:K8UWO1HUJpRMXBxbmaY1Y8IAMZC/RsKB+ArEnnK4l5o= -github.com/holiman/uint256 v1.2.3/go.mod h1:SC8Ryt4n+UBbPbIBKaG9zbbDlp4jOru9xFZmPzLUTxw= +github.com/holiman/uint256 v1.2.4 h1:jUc4Nk8fm9jZabQuqr2JzednajVmBpC+oiTiXZJEApU= +github.com/holiman/uint256 v1.2.4/go.mod h1:EOMSn4q6Nyt9P6efbI3bueV4e1b3dGlUCXeiRV4ng7E= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/huandu/go-assert v1.1.5 h1:fjemmA7sSfYHJD7CUqs9qTwwfdNAx7/j2/ZlHXzNB3c= github.com/huandu/go-assert v1.1.5/go.mod h1:yOLvuqZwmcHIC5rIzrBhT7D3Q9c3GFnd0JrPVhn/06U= @@ -1159,28 +1164,28 @@ 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/chain-selectors v1.0.9 h1:Zof8tl3Huvv/Yi0q1CKVg1iAx9J39IUPaQOZUq5Qmps= github.com/smartcontractkit/chain-selectors v1.0.9/go.mod h1:d4Hi+E1zqjy9HqMkjBE5q1vcG9VGgxf5VxiRHfzi2kE= -github.com/smartcontractkit/chainlink-automation v1.0.1 h1:vVjBFq2Zsz21kPy1Pb0wpjF9zrbJX+zjXphDeeR4XZk= -github.com/smartcontractkit/chainlink-automation v1.0.1/go.mod h1:INSchkV3ntyDdlZKGWA030MPDpp6pbeuiRkRKYFCm2k= -github.com/smartcontractkit/chainlink-common v0.1.7-0.20240108182329-237f56daad6b h1:PRuvHgPka1gIGPKASuJHvqUvYWhZO7z5B/kKapjkZaM= -github.com/smartcontractkit/chainlink-common v0.1.7-0.20240108182329-237f56daad6b/go.mod h1:f+0ei9N4PlTJHu7pbGzEjTnBUr45syPdGFu5+31lS5Q= -github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20231218175426-6e0427c661e5 h1:kBnmjv3fxU7krVIqZFvo1m4F6qBc4vPURQFX/mcChhI= -github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20231218175426-6e0427c661e5/go.mod h1:EoM7wQ81mov7wsUzG4zEnnr0EH0POEo/I0hRDg433TU= +github.com/smartcontractkit/chainlink-automation v1.0.2-0.20240118014648-1ab6a88c9429 h1:xkejUBZhcBpBrTSfxc91Iwzadrb6SXw8ks69bHIQ9Ww= +github.com/smartcontractkit/chainlink-automation v1.0.2-0.20240118014648-1ab6a88c9429/go.mod h1:wJmVvDf4XSjsahWtfUq3wvIAYEAuhr7oxmxYnEL/LGQ= +github.com/smartcontractkit/chainlink-common v0.1.7-0.20240123141952-a879db9d23b3 h1:uSLn+JbClhldYn7zm0GEALGvi6KAfrY5Kp46IX9sy0E= +github.com/smartcontractkit/chainlink-common v0.1.7-0.20240123141952-a879db9d23b3/go.mod h1:05rRF84QKlIOF5LfTBPkHdw4UpBI2G3zxRcuZ65bPjk= +github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20240120192246-4bb04c997ca0 h1:NALwENz6vQ972DuD9AZjqRjyNSxH9ptNapizQGLI+2s= +github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20240120192246-4bb04c997ca0/go.mod h1:NcVAT/GETDBvIoAej5K6OYqAtDOkF6vO5pYw/hLuYVU= github.com/smartcontractkit/chainlink-data-streams v0.0.0-20231204152908-a6e3fe8ff2a1 h1:xYqRgZO0nMSO8CBCMR0r3WA+LZ4kNL8a6bnbyk/oBtQ= github.com/smartcontractkit/chainlink-data-streams v0.0.0-20231204152908-a6e3fe8ff2a1/go.mod h1:GuPvyXryvbiUZIHmPeLBz4L+yJKeyGUjrDfd1KNne+o= -github.com/smartcontractkit/chainlink-feeds v0.0.0-20231127231053-2232d3a6766d h1:w4MsbOtNk6nD/mcXLstHWk9hB6g7QLtcAfhPjhwvOaQ= -github.com/smartcontractkit/chainlink-feeds v0.0.0-20231127231053-2232d3a6766d/go.mod h1:YPAfLNowdBwiKiYOwgwtbJHi8AJWbcxkbOY0ItAvkfc= -github.com/smartcontractkit/chainlink-solana v1.0.3-0.20231219140448-151a4725f312 h1:ziqC+WW/2/UI6w3DShy7HGzJMWWLIYHT5ev2Qaa3h6I= -github.com/smartcontractkit/chainlink-solana v1.0.3-0.20231219140448-151a4725f312/go.mod h1:vqnojBNdzHNI6asWezJlottUiVEXudMEGf2Mz5R+xps= -github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20231219014050-0c4a7831293a h1:atCXqF8e5U2zfEaA87cKJs+K1MAbOVh3V05gEd60fR0= -github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20231219014050-0c4a7831293a/go.mod h1:YWKpf+hO9XMlzIWQT8yGoky3aeFLzMUVsjbs80LD77M= +github.com/smartcontractkit/chainlink-feeds v0.0.0-20240119021347-3c541a78cdb8 h1:1BcjXuviSAKttOX7BZoVHRZZGfxqoA2+AL8tykmkdoc= +github.com/smartcontractkit/chainlink-feeds v0.0.0-20240119021347-3c541a78cdb8/go.mod h1:vy1L7NybTy2F/Yv7BOh+oZBa1MACD6gzd1+DkcSkfp8= +github.com/smartcontractkit/chainlink-solana v1.0.3-0.20240122152632-38444d2ad8ba h1:6rnQrD8NaLfLOPHszW1hbpviqpU8011gzdZk6wKP1xY= +github.com/smartcontractkit/chainlink-solana v1.0.3-0.20240122152632-38444d2ad8ba/go.mod h1:OZfzyayUdwsVBqxvbEMqwUntQT8HbFbgyqoudvwfVN0= +github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20240119162652-3a7274645007 h1:KwB0H2P/gxJgt823Ku1fTcFLDKMj6zsP3wbQGlBOm4U= +github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20240119162652-3a7274645007/go.mod h1:EbZAlb/2K6mKr26u3+3cLBe/caJaqCHw786On94C43g= github.com/smartcontractkit/chainlink-vrf v0.0.0-20231120191722-fef03814f868 h1:FFdvEzlYwcuVHkdZ8YnZR/XomeMGbz5E2F2HZI3I3w8= github.com/smartcontractkit/chainlink-vrf v0.0.0-20231120191722-fef03814f868/go.mod h1:Kn1Hape05UzFZ7bOUnm3GVsHzP0TNrVmpfXYNHdqGGs= 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-20231130143053-c5102a9c0fb7 h1:AA7vf29c6lFsZm+MtIEtXtg6VUOQV6waJo5MUuHfRjQ= -github.com/smartcontractkit/libocr v0.0.0-20231130143053-c5102a9c0fb7/go.mod h1:WcuWFMskcGK0MYZuH5hEhGJOzdJRUFeNEM4PAKlejI4= +github.com/smartcontractkit/libocr v0.0.0-20240112202000-6359502d2ff1 h1:3y9WsXkZ5lxFrmfH7DQHs/q308lylKId5l/3VC0QAdM= +github.com/smartcontractkit/libocr v0.0.0-20240112202000-6359502d2ff1/go.mod h1:kC0qmVPUaVkFqGiZMNhmRmjdphuUmeyLEdlWFOQzFWI= github.com/smartcontractkit/tdh2/go/ocr2/decryptionplugin v0.0.0-20230906073235-9e478e5e19f1 h1:yiKnypAqP8l0OX0P3klzZ7SCcBUxy5KqTAKZmQOvSQE= github.com/smartcontractkit/tdh2/go/ocr2/decryptionplugin v0.0.0-20230906073235-9e478e5e19f1/go.mod h1:q6f4fe39oZPdsh1i57WznEZgxd8siidMaSFq3wdPmVg= github.com/smartcontractkit/tdh2/go/tdh2 v0.0.0-20230906073235-9e478e5e19f1 h1:Dai1bn+Q5cpeGMQwRdjOdVjG8mmFFROVkSKuUgBErRQ= @@ -1359,8 +1364,12 @@ 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/github.com/gin-gonic/gin/otelgin v0.46.1 h1:mMv2jG58h6ZI5t5S9QCVGdzCmAsTakMa3oxVgpSD44g= +go.opentelemetry.io/contrib/instrumentation/github.com/gin-gonic/gin/otelgin v0.46.1/go.mod h1:oqRuNKG0upTaDPbLVCG8AD0G2ETrfDtmh7jViy7ox6M= go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.46.1 h1:SpGay3w+nEwMpfVnbqOLH5gY52/foP8RE8UzTZ1pdSE= go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.46.1/go.mod h1:4UoMYEZOC0yN/sPGH76KPkkU7zgiEWYWL9vwmbnTJPE= +go.opentelemetry.io/contrib/propagators/b3 v1.21.1 h1:WPYiUgmw3+b7b3sQ1bFBFAf0q+Di9dvNc3AtYfnT4RQ= +go.opentelemetry.io/contrib/propagators/b3 v1.21.1/go.mod h1:EmzokPoSqsYMBVK4nRnhsfm5mbn8J1eDuz/U1UaQaWg= go.opentelemetry.io/otel v1.21.0 h1:hzLeKBZEL7Okw2mGzZ0cc4k/A7Fta0uoPgaJCr8fsFc= go.opentelemetry.io/otel v1.21.0/go.mod h1:QZzNPQPm1zLX4gZK4cMi+71eaorMSGT3A4znnUvNNEo= go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.21.0 h1:cl5P5/GIfFh4t6xyruOgJP5QiA1pw4fYYdv6nc6CBWw= @@ -1432,8 +1441,8 @@ golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5y golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc= -golang.org/x/crypto v0.16.0 h1:mMMrFzRSCF0GvB7Ne27XVtVAaXLrPmgPC7/v0tkwHaY= -golang.org/x/crypto v0.16.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4= +golang.org/x/crypto v0.17.0 h1:r8bRNjWL3GshPW3gkd+RpvzWrZAwPS49OmTGZ/uhM4k= +golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4= 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= @@ -1635,7 +1644,6 @@ golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220209214540-3681064d5158/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220405052023-b1e9470b6e64/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -1906,8 +1914,6 @@ gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/mgo.v2 v2.0.0-20180705113604-9856a29383ce/go.mod h1:yeKp02qBN3iKW1OzL3MGk2IdtZzaj7SFntXj72NppTA= gopkg.in/natefinch/lumberjack.v2 v2.2.1 h1:bBRl1b0OH9s/DuPhuXpNl+VtCaJXFZ5/uEFST95x9zc= gopkg.in/natefinch/lumberjack.v2 v2.2.1/go.mod h1:YD8tP3GAjkrDg1eZH7EGmyESg/lsYskCTPBJVb9jqSc= -gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce h1:+JknDZhAj8YMt7GC73Ei8pv4MzjDUNPHgQWJdtMAaDU= -gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce/go.mod h1:5AcXVHNjg+BDxry382+8OKon8SEWiKktQR07RKPsv1c= gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= diff --git a/core/scripts/vrfv2/testnet/main.go b/core/scripts/vrfv2/testnet/main.go index 100440d6fb..34070c90d8 100644 --- a/core/scripts/vrfv2/testnet/main.go +++ b/core/scripts/vrfv2/testnet/main.go @@ -10,6 +10,7 @@ import ( "math/big" "os" "strings" + "sync" "github.com/smartcontractkit/chainlink/core/scripts/vrfv2/testnet/v2scripts" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/vrf_owner_test_consumer" @@ -721,14 +722,19 @@ func main() { 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") - helpers.ParseArgs(loadTestConsumerDeployCmd, os.Args[2:], "coordinator-address") + consumerLinkAddress := loadTestConsumerDeployCmd.String("link-address", "", "link-address") + + helpers.ParseArgs(loadTestConsumerDeployCmd, os.Args[2:], "coordinator-address", "link-address") + _, tx, _, err := vrf_owner_test_consumer.DeployVRFV2OwnerTestConsumer( e.Owner, e.Ec, common.HexToAddress(*consumerCoordinator), + common.HexToAddress(*consumerLinkAddress), ) helpers.PanicErr(err) helpers.ConfirmContractDeployed(context.Background(), e.Ec, tx, e.ChainID) + case "eoa-create-sub": createSubCmd := flag.NewFlagSet("eoa-create-sub", flag.ExitOnError) coordinatorAddress := createSubCmd.String("coordinator-address", "", "coordinator address") @@ -853,57 +859,103 @@ func main() { keyHash := request.String("key-hash", "", "key hash") cbGasLimit := request.Uint("cb-gas-limit", 100_000, "request callback gas limit") numWords := request.Uint("num-words", 1, "num words to request") - requests := request.Uint("requests", 10, "number of randomness requests to make per run") + requests := request.Uint("requests", 1, "number of randomness requests to make per run") runs := request.Uint("runs", 1, "number of runs to do. total randomness requests will be (requests * runs).") + subFundingAmountJuels := request.String("sub-funding-amount-juels", "0", "amount of Juels to fund subscription with") + vrfOwnerAddress := request.String("vrf-owner-address", "", "vrf owner address") + linkAddress := request.String("link-address", "", "link-address") + helpers.ParseArgs(request, os.Args[2:], "consumer-address", "key-hash") keyHashBytes := common.HexToHash(*keyHash) + link, err := link_token_interface.NewLinkToken(common.HexToAddress(*linkAddress), e.Ec) + helpers.PanicErr(err) + + linkTransferTX, err := link.Transfer(e.Owner, common.HexToAddress(*consumerAddress), decimal.RequireFromString(*subFundingAmountJuels).BigInt()) + helpers.PanicErr(err) + helpers.ConfirmTXMined(context.Background(), e.Ec, linkTransferTX, e.ChainID, "transfer", *subFundingAmountJuels, "juels to", *consumerAddress) + + consumerBalanceJuels, err := link.BalanceOf(nil, common.HexToAddress(*consumerAddress)) + helpers.PanicErr(err) + fmt.Println("Consumer Balance:", consumerBalanceJuels.String(), "juels") + consumer, err := vrf_owner_test_consumer.NewVRFV2OwnerTestConsumer( common.HexToAddress(*consumerAddress), e.Ec) helpers.PanicErr(err) var txes []*types.Transaction for i := 0; i < int(*runs); i++ { - tx, err := consumer.RequestRandomWords( + requestRandTX, errRequestRandomWords := consumer.RequestRandomWords( e.Owner, uint16(*requestConfirmations), keyHashBytes, uint32(*cbGasLimit), uint32(*numWords), uint16(*requests), + decimal.RequireFromString(*subFundingAmountJuels).BigInt(), ) - helpers.PanicErr(err) - fmt.Printf("TX %d: %s\n", i+1, helpers.ExplorerLink(e.ChainID, tx.Hash())) - txes = append(txes, tx) + helpers.PanicErr(errRequestRandomWords) + fmt.Printf("TX %d: %s\n", i+1, helpers.ExplorerLink(e.ChainID, requestRandTX.Hash())) + txes = append(txes, requestRandTX) } - fmt.Println("Total number of requests sent:", (*requests)*(*runs)) + + coordinatorAddress, err := consumer.COORDINATOR(nil) + helpers.PanicErr(err) + coordinator, err := vrf_coordinator_v2.NewVRFCoordinatorV2(coordinatorAddress, e.Ec) + helpers.PanicErr(err) + + coordinatorOwnerAddress, err := coordinator.Owner(nil) + helpers.PanicErr(err) + + fmt.Println("Actual Coordinator Owner Address:", coordinatorOwnerAddress.String()) + fmt.Println("Provided VRF Owner Address:", *vrfOwnerAddress) + if coordinatorOwnerAddress.String() != *vrfOwnerAddress { + panic("Actual Coordinator Owner and provided Coordinator Owner Addresses does not match") + } + + var subId uint64 + var wg sync.WaitGroup + + wg.Add(1) + + go func() { + subCreatedChan := make(chan *vrf_coordinator_v2.VRFCoordinatorV2SubscriptionCreated) + subCreatedSubscription, errw := coordinator.WatchSubscriptionCreated(nil, subCreatedChan, nil) + helpers.PanicErr(errw) + defer subCreatedSubscription.Unsubscribe() + subscriptionCreatedEvent := <-subCreatedChan + subId = subscriptionCreatedEvent.SubId + fmt.Println("VRF Owner Test Consumer's Sub ID:", subId) + defer wg.Done() + }() + + wg.Wait() + + totalNumberOfRequests := (*requests) * (*runs) + fmt.Println("Total number of requests sent:", totalNumberOfRequests) fmt.Println("fetching receipts for all transactions") + + var receipt *types.Receipt for i, tx := range txes { - helpers.ConfirmTXMined(context.Background(), e.Ec, tx, e.ChainID, fmt.Sprintf("load test %d", i+1)) + receipt = helpers.ConfirmTXMined(context.Background(), e.Ec, tx, e.ChainID, fmt.Sprintf("load test %d", i+1)) + } + blockNumber := receipt.BlockNumber.Uint64() + fmt.Println("subId", subId) + subFundedIterator, err := coordinator.FilterSubscriptionFunded(&bind.FilterOpts{End: &blockNumber}, []uint64{subId}) + helpers.PanicErr(err) + + if !subFundedIterator.Next() { + panic("Sub Funded Event not found") } + + fmt.Println("Sub Funded, sub ID:", subFundedIterator.Event.SubId, ", Old Balance:", subFundedIterator.Event.OldBalance, ", New Balance:", subFundedIterator.Event.NewBalance) case "eoa-vrf-owner-test-read-metrics": request := flag.NewFlagSet("eoa-load-test-read-metrics", flag.ExitOnError) consumerAddress := request.String("consumer-address", "", "consumer address") helpers.ParseArgs(request, os.Args[2:], "consumer-address") - consumer, err := vrf_owner_test_consumer.NewVRFV2OwnerTestConsumer( - common.HexToAddress(*consumerAddress), - e.Ec) - helpers.PanicErr(err) - responseCount, err := consumer.SResponseCount(nil) - helpers.PanicErr(err) - fmt.Println("Response Count: ", responseCount) - requestCount, err := consumer.SRequestCount(nil) - helpers.PanicErr(err) - fmt.Println("Request Count: ", requestCount) - averageFulfillmentInMillions, err := consumer.SAverageFulfillmentInMillions(nil) - helpers.PanicErr(err) - fmt.Println("Average Fulfillment In Millions: ", averageFulfillmentInMillions) - slowestFulfillment, err := consumer.SSlowestFulfillment(nil) - helpers.PanicErr(err) - fmt.Println("Slowest Fulfillment: ", slowestFulfillment) - fastestFulfillment, err := consumer.SFastestFulfillment(nil) - helpers.PanicErr(err) - fmt.Println("Fastest Fulfillment: ", fastestFulfillment) + metrics := getVRFOwnerTestConsumerMetrics(*consumerAddress, e) + printLoadTestMetrics(metrics) + case "eoa-vrf-owner-test-reset-metrics": request := flag.NewFlagSet("eoa-vrf-owner-test-reset-metrics", flag.ExitOnError) consumerAddress := request.String("consumer-address", "", "consumer address") @@ -1352,3 +1404,45 @@ func main() { panic("unrecognized subcommand: " + os.Args[1]) } } + +func getVRFOwnerTestConsumerMetrics(consumerAddress string, e helpers.Environment) LoadTestMetrics { + consumer, err := vrf_owner_test_consumer.NewVRFV2OwnerTestConsumer( + common.HexToAddress(consumerAddress), + e.Ec) + helpers.PanicErr(err) + responseCount, err := consumer.SResponseCount(nil) + helpers.PanicErr(err) + requestCount, err := consumer.SRequestCount(nil) + helpers.PanicErr(err) + averageFulfillmentInMillions, err := consumer.SAverageFulfillmentInMillions(nil) + helpers.PanicErr(err) + slowestFulfillment, err := consumer.SSlowestFulfillment(nil) + helpers.PanicErr(err) + fastestFulfillment, err := consumer.SFastestFulfillment(nil) + helpers.PanicErr(err) + + metrics := LoadTestMetrics{ + ResponseCount: responseCount, + RequestCount: requestCount, + AverageFulfillmentInMillions: averageFulfillmentInMillions, + SlowestFulfillment: slowestFulfillment, + FastestFulfillment: fastestFulfillment, + } + return metrics +} + +func printLoadTestMetrics(metrics LoadTestMetrics) { + fmt.Println("Response Count: ", metrics.ResponseCount) + fmt.Println("Request Count: ", metrics.RequestCount) + fmt.Println("Average Fulfillment In Millions: ", metrics.AverageFulfillmentInMillions) + fmt.Println("Slowest Fulfillment: ", metrics.SlowestFulfillment) + fmt.Println("Fastest Fulfillment: ", metrics.FastestFulfillment) +} + +type LoadTestMetrics struct { + ResponseCount *big.Int + RequestCount *big.Int + AverageFulfillmentInMillions *big.Int + SlowestFulfillment *big.Int + FastestFulfillment *big.Int +} diff --git a/core/scripts/vrfv2/testnet/v2scripts/super_scripts.go b/core/scripts/vrfv2/testnet/v2scripts/super_scripts.go index 2608873fcf..1397274656 100644 --- a/core/scripts/vrfv2/testnet/v2scripts/super_scripts.go +++ b/core/scripts/vrfv2/testnet/v2scripts/super_scripts.go @@ -52,8 +52,14 @@ func DeployUniverseViaCLI(e helpers.Environment) { 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") + batchFulfillmentGasMultiplier := deployCmd.Float64("batch-fulfillment-gas-multiplier", 1.1, "") + estimateGasMultiplier := deployCmd.Float64("estimate-gas-multiplier", 1.1, "") + pollPeriod := deployCmd.String("poll-period", "300ms", "") + requestTimeout := deployCmd.String("request-timeout", "30m0s", "") + revertsPipelineEnabled := deployCmd.Bool("reverts-pipeline-enabled", true, "") - deployVRFOwner := deployCmd.Bool("deploy-vrf-owner", false, "whether to deploy VRF owner contracts") + deployVRFOwner := deployCmd.Bool("deploy-vrf-owner", true, "whether to deploy VRF owner contracts") + useTestCoordinator := deployCmd.Bool("use-test-coordinator", true, "whether to use test coordinator") // optional flags fallbackWeiPerUnitLinkString := deployCmd.String("fallback-wei-per-unit-link", constants.FallbackWeiPerUnitLink.String(), "fallback wei/link ratio") @@ -137,15 +143,25 @@ func DeployUniverseViaCLI(e helpers.Environment) { RegisterAgainstAddress: *registerVRFKeyAgainstAddress, } + coordinatorJobSpecConfig := model.CoordinatorJobSpecConfig{ + BatchFulfillmentEnabled: *batchFulfillmentEnabled, + BatchFulfillmentGasMultiplier: *batchFulfillmentGasMultiplier, + EstimateGasMultiplier: *estimateGasMultiplier, + PollPeriod: *pollPeriod, + RequestTimeout: *requestTimeout, + RevertsPipelineEnabled: *revertsPipelineEnabled, + } + VRFV2DeployUniverse( e, subscriptionBalanceJuels, vrfKeyRegistrationConfig, contractAddresses, coordinatorConfig, - *batchFulfillmentEnabled, nodesMap, *deployVRFOwner, + coordinatorJobSpecConfig, + *useTestCoordinator, ) vrfPrimaryNode := nodesMap[model.VRFPrimaryNodeName] @@ -161,9 +177,10 @@ func VRFV2DeployUniverse( vrfKeyRegistrationConfig model.VRFKeyRegistrationConfig, contractAddresses model.ContractAddresses, coordinatorConfig CoordinatorConfigV2, - batchFulfillmentEnabled bool, nodesMap map[string]model.Node, deployVRFOwner bool, + coordinatorJobSpecConfig model.CoordinatorJobSpecConfig, + useTestCoordinator bool, ) model.JobSpecs { var compressedPkHex string var keyHash common.Hash @@ -212,9 +229,16 @@ func VRFV2DeployUniverse( contractAddresses.BatchBHSAddress = DeployBatchBHS(e, contractAddresses.BhsContractAddress) } - if contractAddresses.CoordinatorAddress.String() == "0x0000000000000000000000000000000000000000" { - fmt.Println("\nDeploying Coordinator...") - contractAddresses.CoordinatorAddress = DeployCoordinator(e, contractAddresses.LinkAddress, contractAddresses.BhsContractAddress.String(), contractAddresses.LinkEthAddress) + if useTestCoordinator { + if contractAddresses.CoordinatorAddress.String() == "0x0000000000000000000000000000000000000000" { + fmt.Println("\nDeploying Test Coordinator...") + contractAddresses.CoordinatorAddress = DeployTestCoordinator(e, contractAddresses.LinkAddress, contractAddresses.BhsContractAddress.String(), contractAddresses.LinkEthAddress) + } + } else { + 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.NewVRFCoordinatorV2(contractAddresses.CoordinatorAddress, e.Ec) @@ -310,14 +334,19 @@ func VRFV2DeployUniverse( formattedVrfPrimaryJobSpec := fmt.Sprintf( jobs.VRFV2JobFormatted, - contractAddresses.CoordinatorAddress, //coordinatorAddress - contractAddresses.BatchCoordinatorAddress, //batchCoordinatorAddress - batchFulfillmentEnabled, //batchFulfillmentEnabled - compressedPkHex, //publicKey - coordinatorConfig.MinConfs, //minIncomingConfirmations - e.ChainID, //evmChainID + contractAddresses.CoordinatorAddress, //coordinatorAddress + contractAddresses.BatchCoordinatorAddress, //batchCoordinatorAddress + coordinatorJobSpecConfig.BatchFulfillmentEnabled, //batchFulfillmentEnabled + coordinatorJobSpecConfig.BatchFulfillmentGasMultiplier, //batchFulfillmentGasMultiplier + coordinatorJobSpecConfig.RevertsPipelineEnabled, //revertsPipelineEnabled + compressedPkHex, //publicKey + coordinatorConfig.MinConfs, //minIncomingConfirmations + e.ChainID, //evmChainID strings.Join(util.MapToAddressArr(nodesMap[model.VRFPrimaryNodeName].SendingKeys), "\",\""), //fromAddresses + coordinatorJobSpecConfig.PollPeriod, //pollPeriod + coordinatorJobSpecConfig.RequestTimeout, //requestTimeout contractAddresses.CoordinatorAddress, + coordinatorJobSpecConfig.EstimateGasMultiplier, //estimateGasMultiplier func() string { if keys := nodesMap[model.VRFPrimaryNodeName].SendingKeys; len(keys) > 0 { return keys[0].Address @@ -336,14 +365,19 @@ func VRFV2DeployUniverse( formattedVrfBackupJobSpec := fmt.Sprintf( jobs.VRFV2JobFormatted, - contractAddresses.CoordinatorAddress, //coordinatorAddress - contractAddresses.BatchCoordinatorAddress, //batchCoordinatorAddress - batchFulfillmentEnabled, //batchFulfillmentEnabled - compressedPkHex, //publicKey - 100, //minIncomingConfirmations - e.ChainID, //evmChainID + contractAddresses.CoordinatorAddress, //coordinatorAddress + contractAddresses.BatchCoordinatorAddress, //batchCoordinatorAddress + coordinatorJobSpecConfig.BatchFulfillmentEnabled, //batchFulfillmentEnabled + coordinatorJobSpecConfig.BatchFulfillmentGasMultiplier, //batchFulfillmentGasMultiplier + coordinatorJobSpecConfig.RevertsPipelineEnabled, //revertsPipelineEnabled + compressedPkHex, //publicKey + 100, //minIncomingConfirmations + e.ChainID, //evmChainID strings.Join(util.MapToAddressArr(nodesMap[model.VRFBackupNodeName].SendingKeys), "\",\""), //fromAddresses + coordinatorJobSpecConfig.PollPeriod, //pollPeriod + coordinatorJobSpecConfig.RequestTimeout, //requestTimeout contractAddresses.CoordinatorAddress, + coordinatorJobSpecConfig.EstimateGasMultiplier, //estimateGasMultiplier func() string { if keys := nodesMap[model.VRFPrimaryNodeName].SendingKeys; len(keys) > 0 { return keys[0].Address diff --git a/core/scripts/vrfv2/testnet/v2scripts/util.go b/core/scripts/vrfv2/testnet/v2scripts/util.go index 45cda3d2aa..325ced2ab2 100644 --- a/core/scripts/vrfv2/testnet/v2scripts/util.go +++ b/core/scripts/vrfv2/testnet/v2scripts/util.go @@ -7,6 +7,8 @@ import ( "fmt" "math/big" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/vrf_coordinator_test_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" "github.com/ethereum/go-ethereum/common" @@ -19,7 +21,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/batch_vrf_coordinator_v2" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/blockhash_store" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/link_token_interface" - "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/vrf_coordinator_v2" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/vrf_external_sub_owner_example" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/vrfv2_wrapper" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/vrfv2_wrapper_consumer_example" @@ -53,6 +54,22 @@ func DeployCoordinator( return helpers.ConfirmContractDeployed(context.Background(), e.Ec, tx, e.ChainID) } +func DeployTestCoordinator( + e helpers.Environment, + linkAddress string, + bhsAddress string, + linkEthAddress string, +) (coordinatorAddress common.Address) { + _, tx, _, err := vrf_coordinator_test_v2.DeployVRFCoordinatorTestV2( + e.Owner, + e.Ec, + common.HexToAddress(linkAddress), + common.HexToAddress(bhsAddress), + common.HexToAddress(linkEthAddress)) + helpers.PanicErr(err) + return helpers.ConfirmContractDeployed(context.Background(), e.Ec, tx, e.ChainID) +} + 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) diff --git a/core/scripts/vrfv2plus/testnet/main.go b/core/scripts/vrfv2plus/testnet/main.go index 97d987dac2..320576055b 100644 --- a/core/scripts/vrfv2plus/testnet/main.go +++ b/core/scripts/vrfv2plus/testnet/main.go @@ -564,7 +564,6 @@ func main() { coordinatorRegisterKey := flag.NewFlagSet("coordinator-register-key", flag.ExitOnError) registerKeyAddress := coordinatorRegisterKey.String("address", "", "coordinator address") registerKeyUncompressedPubKey := coordinatorRegisterKey.String("pubkey", "", "uncompressed pubkey") - registerKeyOracleAddress := coordinatorRegisterKey.String("oracle-address", "", "oracle address") helpers.ParseArgs(coordinatorRegisterKey, os.Args[2:], "address", "pubkey", "oracle-address") coordinator, err := vrf_coordinator_v2_5.NewVRFCoordinatorV25(common.HexToAddress(*registerKeyAddress), e.Ec) helpers.PanicErr(err) @@ -574,7 +573,7 @@ func main() { *registerKeyUncompressedPubKey = strings.Replace(*registerKeyUncompressedPubKey, "0x", "04", 1) } - v2plusscripts.RegisterCoordinatorProvingKey(e, *coordinator, *registerKeyUncompressedPubKey, *registerKeyOracleAddress) + v2plusscripts.RegisterCoordinatorProvingKey(e, *coordinator, *registerKeyUncompressedPubKey) case "coordinator-deregister-key": coordinatorDeregisterKey := flag.NewFlagSet("coordinator-deregister-key", flag.ExitOnError) deregisterKeyAddress := coordinatorDeregisterKey.String("address", "", "coordinator address") diff --git a/core/scripts/vrfv2plus/testnet/v2plusscripts/super_scripts.go b/core/scripts/vrfv2plus/testnet/v2plusscripts/super_scripts.go index 65e4cca2ab..09c93ff879 100644 --- a/core/scripts/vrfv2plus/testnet/v2plusscripts/super_scripts.go +++ b/core/scripts/vrfv2plus/testnet/v2plusscripts/super_scripts.go @@ -476,12 +476,14 @@ func DeployUniverseViaCLI(e helpers.Environment) { 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") + batchFulfillmentGasMultiplier := deployCmd.Float64("batch-fulfillment-gas-multiplier", 1.1, "") + estimateGasMultiplier := deployCmd.Float64("estimate-gas-multiplier", 1.1, "") + pollPeriod := deployCmd.String("poll-period", "300ms", "") + requestTimeout := deployCmd.String("request-timeout", "30m0s", "") // optional flags fallbackWeiPerUnitLinkString := deployCmd.String("fallback-wei-per-unit-link", "6e16", "fallback wei/link ratio") registerVRFKeyUncompressedPubKey := deployCmd.String("uncompressed-pub-key", "", "uncompressed public key") - registerVRFKeyAgainstAddress := deployCmd.String("register-vrf-key-against-address", "", "VRF Key registration against address - "+ - "from this address you can perform `coordinator.oracleWithdraw` to withdraw earned funds from rand request fulfilments") vrfPrimaryNodeSendingKeysString := deployCmd.String("vrf-primary-node-sending-keys", "", "VRF Primary Node sending keys") minConfs := deployCmd.Int("min-confs", constants.MinConfs, "min confs") @@ -512,10 +514,7 @@ func DeployUniverseViaCLI(e helpers.Environment) { nodesMap := make(map[string]model.Node) - fundingAmount, ok := new(big.Int).SetString(*nodeSendingKeyFundingAmount, 10) - if !ok { - panic(fmt.Sprintf("failed to parse node sending key funding amount '%s'", *nodeSendingKeyFundingAmount)) - } + fundingAmount := decimal.RequireFromString(*nodeSendingKeyFundingAmount).BigInt() nodesMap[model.VRFPrimaryNodeName] = model.Node{ SendingKeys: util.MapToSendingKeyArr(vrfPrimaryNodeSendingKeys), SendingKeyFundingAmount: fundingAmount, @@ -546,7 +545,14 @@ func DeployUniverseViaCLI(e helpers.Environment) { vrfKeyRegistrationConfig := model.VRFKeyRegistrationConfig{ VRFKeyUncompressedPubKey: *registerVRFKeyUncompressedPubKey, - RegisterAgainstAddress: *registerVRFKeyAgainstAddress, + } + + coordinatorJobSpecConfig := model.CoordinatorJobSpecConfig{ + BatchFulfillmentEnabled: *batchFulfillmentEnabled, + BatchFulfillmentGasMultiplier: *batchFulfillmentGasMultiplier, + EstimateGasMultiplier: *estimateGasMultiplier, + PollPeriod: *pollPeriod, + RequestTimeout: *requestTimeout, } VRFV2PlusDeployUniverse( @@ -556,8 +562,8 @@ func DeployUniverseViaCLI(e helpers.Environment) { vrfKeyRegistrationConfig, contractAddresses, coordinatorConfig, - *batchFulfillmentEnabled, nodesMap, + coordinatorJobSpecConfig, ) vrfPrimaryNode := nodesMap[model.VRFPrimaryNodeName] @@ -573,8 +579,8 @@ func VRFV2PlusDeployUniverse(e helpers.Environment, vrfKeyRegistrationConfig model.VRFKeyRegistrationConfig, contractAddresses model.ContractAddresses, coordinatorConfig CoordinatorConfigV2Plus, - batchFulfillmentEnabled bool, nodesMap map[string]model.Node, + coordinatorJobSpecConfig model.CoordinatorJobSpecConfig, ) model.JobSpecs { var compressedPkHex string var keyHash common.Hash @@ -656,7 +662,7 @@ func VRFV2PlusDeployUniverse(e helpers.Environment, //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, vrfKeyRegistrationConfig.VRFKeyUncompressedPubKey, vrfKeyRegistrationConfig.RegisterAgainstAddress) + RegisterCoordinatorProvingKey(e, *coordinator, vrfKeyRegistrationConfig.VRFKeyUncompressedPubKey) fmt.Println("\nProving key registered, getting proving key hashes from deployed contract...") _, _, provingKeyHashes, configErr := coordinator.GetRequestConfig(nil) @@ -698,14 +704,19 @@ func VRFV2PlusDeployUniverse(e helpers.Environment, formattedVrfV2PlusPrimaryJobSpec := fmt.Sprintf( jobs.VRFV2PlusJobFormatted, - contractAddresses.CoordinatorAddress, //coordinatorAddress - contractAddresses.BatchCoordinatorAddress, //batchCoordinatorAddress - batchFulfillmentEnabled, //batchFulfillmentEnabled - compressedPkHex, //publicKey - coordinatorConfig.MinConfs, //minIncomingConfirmations - e.ChainID, //evmChainID + contractAddresses.CoordinatorAddress, //coordinatorAddress + contractAddresses.BatchCoordinatorAddress, //batchCoordinatorAddress + coordinatorJobSpecConfig.BatchFulfillmentEnabled, //batchFulfillmentEnabled + coordinatorJobSpecConfig.BatchFulfillmentGasMultiplier, //batchFulfillmentGasMultiplier + strings.Join(util.MapToAddressArr(nodesMap[model.VRFPrimaryNodeName].SendingKeys), "\",\""), //fromAddresses + compressedPkHex, //publicKey + coordinatorConfig.MinConfs, //minIncomingConfirmations + e.ChainID, //evmChainID strings.Join(util.MapToAddressArr(nodesMap[model.VRFPrimaryNodeName].SendingKeys), "\",\""), //fromAddresses + coordinatorJobSpecConfig.PollPeriod, //pollPeriod + coordinatorJobSpecConfig.RequestTimeout, //requestTimeout contractAddresses.CoordinatorAddress, + coordinatorJobSpecConfig.EstimateGasMultiplier, //estimateGasMultiplier func() string { if keys := nodesMap[model.VRFPrimaryNodeName].SendingKeys; len(keys) > 0 { return keys[0].Address @@ -718,14 +729,18 @@ func VRFV2PlusDeployUniverse(e helpers.Environment, formattedVrfV2PlusBackupJobSpec := fmt.Sprintf( jobs.VRFV2PlusJobFormatted, - contractAddresses.CoordinatorAddress, //coordinatorAddress - contractAddresses.BatchCoordinatorAddress, //batchCoordinatorAddress - batchFulfillmentEnabled, //batchFulfillmentEnabled - compressedPkHex, //publicKey - 100, //minIncomingConfirmations - e.ChainID, //evmChainID + contractAddresses.CoordinatorAddress, //coordinatorAddress + contractAddresses.BatchCoordinatorAddress, //batchCoordinatorAddress + coordinatorJobSpecConfig.BatchFulfillmentEnabled, //batchFulfillmentEnabled + coordinatorJobSpecConfig.BatchFulfillmentGasMultiplier, //batchFulfillmentGasMultiplier + compressedPkHex, //publicKey + 100, //minIncomingConfirmations + e.ChainID, //evmChainID strings.Join(util.MapToAddressArr(nodesMap[model.VRFBackupNodeName].SendingKeys), "\",\""), //fromAddresses + coordinatorJobSpecConfig.PollPeriod, //pollPeriod + coordinatorJobSpecConfig.RequestTimeout, //requestTimeout contractAddresses.CoordinatorAddress, + coordinatorJobSpecConfig.EstimateGasMultiplier, //estimateGasMultiplier func() string { if keys := nodesMap[model.VRFPrimaryNodeName].SendingKeys; len(keys) > 0 { return keys[0].Address @@ -737,7 +752,7 @@ func VRFV2PlusDeployUniverse(e helpers.Environment, ) formattedBHSJobSpec := fmt.Sprintf( - jobs.BHSJobFormatted, + jobs.BHSPlusJobFormatted, contractAddresses.CoordinatorAddress, //coordinatorAddress 30, //waitBlocks 200, //lookbackBlocks @@ -747,7 +762,7 @@ func VRFV2PlusDeployUniverse(e helpers.Environment, ) formattedBHSBackupJobSpec := fmt.Sprintf( - jobs.BHSJobFormatted, + jobs.BHSPlusJobFormatted, contractAddresses.CoordinatorAddress, //coordinatorAddress 100, //waitBlocks 200, //lookbackBlocks @@ -757,7 +772,7 @@ func VRFV2PlusDeployUniverse(e helpers.Environment, ) formattedBHFJobSpec := fmt.Sprintf( - jobs.BHFJobFormatted, + jobs.BHFPlusJobFormatted, contractAddresses.CoordinatorAddress, //coordinatorAddress contractAddresses.BhsContractAddress, //bhs adreess contractAddresses.BatchBHSAddress, //batchBHS diff --git a/core/scripts/vrfv2plus/testnet/v2plusscripts/util.go b/core/scripts/vrfv2plus/testnet/v2plusscripts/util.go index 48b196b409..7b38dc7b39 100644 --- a/core/scripts/vrfv2plus/testnet/v2plusscripts/util.go +++ b/core/scripts/vrfv2plus/testnet/v2plusscripts/util.go @@ -176,7 +176,7 @@ func SetCoordinatorConfig( } func RegisterCoordinatorProvingKey(e helpers.Environment, - coordinator vrf_coordinator_v2_5.VRFCoordinatorV25, uncompressed string, oracleAddress string) { + coordinator vrf_coordinator_v2_5.VRFCoordinatorV25, uncompressed string) { pubBytes, err := hex.DecodeString(uncompressed) helpers.PanicErr(err) pk, err := crypto.UnmarshalPubkey(pubBytes) @@ -190,7 +190,6 @@ func RegisterCoordinatorProvingKey(e helpers.Environment, tx, e.ChainID, fmt.Sprintf("Uncompressed public key: %s,", uncompressed), - fmt.Sprintf("Oracle address: %s,", oracleAddress), ) } diff --git a/core/services/chainlink/config_mercury.go b/core/services/chainlink/config_mercury.go index 49f1cf0a5f..27303a6889 100644 --- a/core/services/chainlink/config_mercury.go +++ b/core/services/chainlink/config_mercury.go @@ -3,9 +3,10 @@ package chainlink import ( "time" + "github.com/smartcontractkit/chainlink-common/pkg/types" + "github.com/smartcontractkit/chainlink/v2/core/config" "github.com/smartcontractkit/chainlink/v2/core/config/toml" - "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/models" ) var _ config.MercuryCache = (*mercuryCacheConfig)(nil) @@ -37,9 +38,9 @@ type mercuryConfig struct { s toml.MercurySecrets } -func (m *mercuryConfig) Credentials(credName string) *models.MercuryCredentials { +func (m *mercuryConfig) Credentials(credName string) *types.MercuryCredentials { if mc, ok := m.s.Credentials[credName]; ok { - c := &models.MercuryCredentials{ + c := &types.MercuryCredentials{ URL: mc.URL.URL().String(), Password: string(*mc.Password), Username: string(*mc.Username), diff --git a/core/services/chainlink/config_mercury_test.go b/core/services/chainlink/config_mercury_test.go index 71dfb2a01c..1ae8dc0ba2 100644 --- a/core/services/chainlink/config_mercury_test.go +++ b/core/services/chainlink/config_mercury_test.go @@ -3,11 +3,11 @@ package chainlink import ( "testing" + "github.com/smartcontractkit/chainlink-common/pkg/types" + "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/models" - "github.com/smartcontractkit/chainlink/v2/core/config/toml" ) @@ -33,8 +33,8 @@ func TestMercuryConfig(t *testing.T) { require.NoError(t, err) m := cfg.Mercury() - assert.Equal(t, &models.MercuryCredentials{URL: "https://chain1.link", Username: "username1", Password: "password1"}, m.Credentials("cred1")) - assert.Equal(t, &models.MercuryCredentials{URL: "https://chain2.link", Username: "username2", Password: "password2"}, m.Credentials("cred2")) + assert.Equal(t, &types.MercuryCredentials{URL: "https://chain1.link", Username: "username1", Password: "password1"}, m.Credentials("cred1")) + assert.Equal(t, &types.MercuryCredentials{URL: "https://chain2.link", Username: "username2", Password: "password2"}, m.Credentials("cred2")) } func TestMercuryTLS(t *testing.T) { diff --git a/core/services/chainlink/config_telemetry_ingress.go b/core/services/chainlink/config_telemetry_ingress.go index 5126833134..3ad721ad30 100644 --- a/core/services/chainlink/config_telemetry_ingress.go +++ b/core/services/chainlink/config_telemetry_ingress.go @@ -46,16 +46,6 @@ 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 { diff --git a/core/services/chainlink/config_test.go b/core/services/chainlink/config_test.go index 9545c85d65..269ba1e035 100644 --- a/core/services/chainlink/config_test.go +++ b/core/services/chainlink/config_test.go @@ -294,8 +294,6 @@ func TestConfig_Marshal(t *testing.T) { SendInterval: commonconfig.MustNewDuration(time.Minute), SendTimeout: commonconfig.MustNewDuration(5 * time.Second), UseBatchSend: ptr(true), - URL: ptr(commonconfig.URL{}), - ServerPubKey: ptr(""), Endpoints: []toml.TelemetryIngressEndpoint{{ Network: ptr("EVM"), ChainID: ptr("1"), @@ -746,8 +744,6 @@ MaxBatchSize = 4321 SendInterval = '1m0s' SendTimeout = '5s' UseBatchSend = true -URL = '' -ServerPubKey = '' [[TelemetryIngress.Endpoints]] Network = 'EVM' @@ -1143,17 +1139,6 @@ 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(commonconfig.URL) - } - cfgtest.AssertFieldsNotNil(t, got) } @@ -1198,7 +1183,7 @@ func TestConfig_Validate(t *testing.T) { - 1: 6 errors: - ChainType: invalid value (Foo): must not be set with this chain id - Nodes: missing: must have at least one node - - ChainType: invalid value (Foo): must be one of arbitrum, metis, xdai, optimismBedrock, celo, kroma, wemix, zksync or omitted + - ChainType: invalid value (Foo): must be one of arbitrum, metis, xdai, optimismBedrock, celo, kroma, wemix, zksync, scroll or omitted - HeadTracker.HistoryDepth: invalid value (30): must be equal to or greater than FinalityDepth - GasEstimator: 2 errors: - FeeCapDefault: invalid value (101 wei): must be equal to PriceMax (99 wei) since you are using FixedPrice estimation with gas bumping disabled in EIP1559 mode - PriceMax will be used as the FeeCap for transactions instead of FeeCapDefault @@ -1207,7 +1192,7 @@ func TestConfig_Validate(t *testing.T) { - 2: 5 errors: - ChainType: invalid value (Arbitrum): only "optimismBedrock" can be used with this chain id - Nodes: missing: must have at least one node - - ChainType: invalid value (Arbitrum): must be one of arbitrum, metis, xdai, optimismBedrock, celo, kroma, wemix, zksync or omitted + - ChainType: invalid value (Arbitrum): must be one of arbitrum, metis, xdai, optimismBedrock, celo, kroma, wemix, zksync, scroll or omitted - FinalityDepth: invalid value (0): must be greater than or equal to 1 - MinIncomingConfirmations: invalid value (0): must be greater than or equal to 1 - 3.Nodes: 5 errors: diff --git a/core/services/chainlink/relayer_factory.go b/core/services/chainlink/relayer_factory.go index 49582e2d52..c42ca77dc3 100644 --- a/core/services/chainlink/relayer_factory.go +++ b/core/services/chainlink/relayer_factory.go @@ -116,7 +116,7 @@ func (r *RelayerFactory) NewSolana(ks keystore.Solana, chainCfgs solana.TOMLConf lggr := solLggr.Named(relayID.ChainID) - if cmdName := env.SolanaPluginCmd.Get(); cmdName != "" { + if cmdName := env.SolanaPlugin.Cmd.Get(); cmdName != "" { // setup the solana relayer to be a LOOP cfgTOML, err := toml.Marshal(struct { @@ -126,10 +126,14 @@ func (r *RelayerFactory) NewSolana(ks keystore.Solana, chainCfgs solana.TOMLConf if err != nil { return nil, fmt.Errorf("failed to marshal Solana configs: %w", err) } - + envVars, err := plugins.ParseEnvFile(env.SolanaPlugin.Env.Get()) + if err != nil { + return nil, fmt.Errorf("failed to parse Solana env file: %w", err) + } solCmdFn, err := plugins.NewCmdFactory(r.Register, plugins.CmdConfig{ ID: relayID.Name(), Cmd: cmdName, + Env: envVars, }) if err != nil { return nil, fmt.Errorf("failed to create Solana LOOP command: %w", err) @@ -187,7 +191,7 @@ func (r *RelayerFactory) NewStarkNet(ks keystore.StarkNet, chainCfgs config.TOML lggr := starkLggr.Named(relayID.ChainID) - if cmdName := env.StarknetPluginCmd.Get(); cmdName != "" { + if cmdName := env.StarknetPlugin.Cmd.Get(); cmdName != "" { // setup the starknet relayer to be a LOOP cfgTOML, err := toml.Marshal(struct { Starknet config.TOMLConfig @@ -196,9 +200,14 @@ func (r *RelayerFactory) NewStarkNet(ks keystore.StarkNet, chainCfgs config.TOML return nil, fmt.Errorf("failed to marshal StarkNet configs: %w", err) } + envVars, err := plugins.ParseEnvFile(env.StarknetPlugin.Env.Get()) + if err != nil { + return nil, fmt.Errorf("failed to parse Starknet env file: %w", err) + } starknetCmdFn, err := plugins.NewCmdFactory(r.Register, plugins.CmdConfig{ ID: relayID.Name(), Cmd: cmdName, + Env: envVars, }) if err != nil { return nil, fmt.Errorf("failed to create StarkNet LOOP command: %w", err) diff --git a/core/services/chainlink/testdata/config-empty-effective.toml b/core/services/chainlink/testdata/config-empty-effective.toml index 7afef95e19..1c2e7b1b4b 100644 --- a/core/services/chainlink/testdata/config-empty-effective.toml +++ b/core/services/chainlink/testdata/config-empty-effective.toml @@ -41,8 +41,6 @@ MaxBatchSize = 50 SendInterval = '500ms' SendTimeout = '10s' UseBatchSend = true -URL = '' -ServerPubKey = '' [AuditLogger] Enabled = false diff --git a/core/services/chainlink/testdata/config-full.toml b/core/services/chainlink/testdata/config-full.toml index 4a2379d6d9..d4a2492b4a 100644 --- a/core/services/chainlink/testdata/config-full.toml +++ b/core/services/chainlink/testdata/config-full.toml @@ -41,8 +41,6 @@ MaxBatchSize = 4321 SendInterval = '1m0s' SendTimeout = '5s' UseBatchSend = true -URL = '' -ServerPubKey = '' [[TelemetryIngress.Endpoints]] Network = 'EVM' diff --git a/core/services/chainlink/testdata/config-multi-chain-effective.toml b/core/services/chainlink/testdata/config-multi-chain-effective.toml index f4cb6c1612..4e1a433733 100644 --- a/core/services/chainlink/testdata/config-multi-chain-effective.toml +++ b/core/services/chainlink/testdata/config-multi-chain-effective.toml @@ -41,8 +41,6 @@ MaxBatchSize = 50 SendInterval = '500ms' SendTimeout = '10s' UseBatchSend = true -URL = '' -ServerPubKey = '' [AuditLogger] Enabled = true diff --git a/core/services/functions/connector_handler.go b/core/services/functions/connector_handler.go index 1594dc6eb5..c8c522e6a6 100644 --- a/core/services/functions/connector_handler.go +++ b/core/services/functions/connector_handler.go @@ -6,6 +6,7 @@ import ( "crypto/ecdsa" "encoding/json" "fmt" + "strings" "sync" "time" @@ -25,34 +26,36 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/services/gateway/connector" hc "github.com/smartcontractkit/chainlink/v2/core/services/gateway/handlers/common" "github.com/smartcontractkit/chainlink/v2/core/services/gateway/handlers/functions" + fallow "github.com/smartcontractkit/chainlink/v2/core/services/gateway/handlers/functions/allowlist" + fsub "github.com/smartcontractkit/chainlink/v2/core/services/gateway/handlers/functions/subscriptions" + "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/functions/config" "github.com/smartcontractkit/chainlink/v2/core/services/s4" ) type functionsConnectorHandler struct { services.StateMachine - connector connector.GatewayConnector - signerKey *ecdsa.PrivateKey - nodeAddress string - storage s4.Storage - allowlist functions.OnchainAllowlist - rateLimiter *hc.RateLimiter - subscriptions functions.OnchainSubscriptions - minimumBalance assets.Link - listener FunctionsListener - offchainTransmitter OffchainTransmitter - heartbeatRequests map[RequestID]*HeartbeatResponse - orderedRequests []RequestID - mu sync.Mutex - chStop services.StopChan - shutdownWaitGroup sync.WaitGroup - lggr logger.Logger + connector connector.GatewayConnector + signerKey *ecdsa.PrivateKey + nodeAddress string + storage s4.Storage + allowlist fallow.OnchainAllowlist + rateLimiter *hc.RateLimiter + subscriptions fsub.OnchainSubscriptions + minimumBalance assets.Link + listener FunctionsListener + offchainTransmitter OffchainTransmitter + allowedHeartbeatInitiators map[string]struct{} + heartbeatRequests map[RequestID]*HeartbeatResponse + requestTimeoutSec uint32 + orderedRequests []RequestID + mu sync.Mutex + chStop services.StopChan + shutdownWaitGroup sync.WaitGroup + lggr logger.Logger } -const ( - HeartbeatRequestTimeoutSec = 240 - HeartbeatCacheSize = 1000 -) +const HeartbeatCacheSize = 1000 var ( _ connector.Signer = &functionsConnectorHandler{} @@ -71,23 +74,29 @@ func InternalId(sender []byte, requestId []byte) RequestID { return RequestID(crypto.Keccak256Hash(append(sender, requestId...)).Bytes()) } -func NewFunctionsConnectorHandler(nodeAddress string, signerKey *ecdsa.PrivateKey, storage s4.Storage, allowlist functions.OnchainAllowlist, rateLimiter *hc.RateLimiter, subscriptions functions.OnchainSubscriptions, listener FunctionsListener, offchainTransmitter OffchainTransmitter, minimumBalance assets.Link, lggr logger.Logger) (*functionsConnectorHandler, error) { +func NewFunctionsConnectorHandler(pluginConfig *config.PluginConfig, signerKey *ecdsa.PrivateKey, storage s4.Storage, allowlist fallow.OnchainAllowlist, rateLimiter *hc.RateLimiter, subscriptions fsub.OnchainSubscriptions, listener FunctionsListener, offchainTransmitter OffchainTransmitter, lggr logger.Logger) (*functionsConnectorHandler, error) { if signerKey == nil || storage == nil || allowlist == nil || rateLimiter == nil || subscriptions == nil || listener == nil || offchainTransmitter == nil { return nil, fmt.Errorf("all dependencies must be non-nil") } + allowedHeartbeatInitiators := make(map[string]struct{}) + for _, initiator := range pluginConfig.AllowedHeartbeatInitiators { + allowedHeartbeatInitiators[strings.ToLower(initiator)] = struct{}{} + } return &functionsConnectorHandler{ - nodeAddress: nodeAddress, - signerKey: signerKey, - storage: storage, - allowlist: allowlist, - rateLimiter: rateLimiter, - subscriptions: subscriptions, - minimumBalance: minimumBalance, - listener: listener, - offchainTransmitter: offchainTransmitter, - heartbeatRequests: make(map[RequestID]*HeartbeatResponse), - chStop: make(services.StopChan), - lggr: lggr.Named("FunctionsConnectorHandler"), + nodeAddress: pluginConfig.GatewayConnectorConfig.NodeAddress, + signerKey: signerKey, + storage: storage, + allowlist: allowlist, + rateLimiter: rateLimiter, + subscriptions: subscriptions, + minimumBalance: pluginConfig.MinimumSubscriptionBalance, + listener: listener, + offchainTransmitter: offchainTransmitter, + allowedHeartbeatInitiators: allowedHeartbeatInitiators, + heartbeatRequests: make(map[RequestID]*HeartbeatResponse), + requestTimeoutSec: pluginConfig.RequestTimeoutSec, + chStop: make(services.StopChan), + lggr: lggr.Named("FunctionsConnectorHandler"), }, nil } @@ -211,6 +220,10 @@ func (h *functionsConnectorHandler) handleHeartbeat(ctx context.Context, gateway h.sendResponseAndLog(ctx, gatewayId, requestBody, internalErrorResponse(fmt.Sprintf("failed to unmarshal request: %v", err))) return } + if _, ok := h.allowedHeartbeatInitiators[requestBody.Sender]; !ok { + h.sendResponseAndLog(ctx, gatewayId, requestBody, internalErrorResponse("sender not allowed to send heartbeat requests")) + return + } if !bytes.Equal(request.RequestInitiator, fromAddr.Bytes()) { h.sendResponseAndLog(ctx, gatewayId, requestBody, internalErrorResponse("RequestInitiator doesn't match sender")) return @@ -219,6 +232,10 @@ func (h *functionsConnectorHandler) handleHeartbeat(ctx context.Context, gateway h.sendResponseAndLog(ctx, gatewayId, requestBody, internalErrorResponse("SubscriptionOwner doesn't match sender")) return } + if request.Timestamp < uint64(time.Now().Unix())-uint64(h.requestTimeoutSec) { + h.sendResponseAndLog(ctx, gatewayId, requestBody, internalErrorResponse("Request is too old")) + return + } internalId := InternalId(fromAddr.Bytes(), request.RequestId) request.RequestId = internalId[:] @@ -250,7 +267,7 @@ func internalErrorResponse(internalError string) HeartbeatResponse { func (h *functionsConnectorHandler) handleOffchainRequest(request *OffchainRequest) { defer h.shutdownWaitGroup.Done() stopCtx, _ := h.chStop.NewCtx() - ctx, cancel := context.WithTimeout(stopCtx, time.Duration(HeartbeatRequestTimeoutSec)*time.Second) + ctx, cancel := context.WithTimeout(stopCtx, time.Duration(h.requestTimeoutSec)*time.Second) defer cancel() err := h.listener.HandleOffchainRequest(ctx, request) if err != nil { diff --git a/core/services/functions/connector_handler_test.go b/core/services/functions/connector_handler_test.go index 409f9cdcc5..aadc84ba96 100644 --- a/core/services/functions/connector_handler_test.go +++ b/core/services/functions/connector_handler_test.go @@ -10,6 +10,7 @@ import ( "time" geth_common "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/crypto" "github.com/onsi/gomega" "github.com/smartcontractkit/chainlink-common/pkg/assets" @@ -19,9 +20,12 @@ import ( sfmocks "github.com/smartcontractkit/chainlink/v2/core/services/functions/mocks" "github.com/smartcontractkit/chainlink/v2/core/services/gateway/api" "github.com/smartcontractkit/chainlink/v2/core/services/gateway/common" + gwconnector "github.com/smartcontractkit/chainlink/v2/core/services/gateway/connector" gcmocks "github.com/smartcontractkit/chainlink/v2/core/services/gateway/connector/mocks" hc "github.com/smartcontractkit/chainlink/v2/core/services/gateway/handlers/common" - gfmocks "github.com/smartcontractkit/chainlink/v2/core/services/gateway/handlers/functions/mocks" + fallowMocks "github.com/smartcontractkit/chainlink/v2/core/services/gateway/handlers/functions/allowlist/mocks" + fsubMocks "github.com/smartcontractkit/chainlink/v2/core/services/gateway/handlers/functions/subscriptions/mocks" + "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/functions/config" "github.com/smartcontractkit/chainlink/v2/core/services/s4" s4mocks "github.com/smartcontractkit/chainlink/v2/core/services/s4/mocks" @@ -30,7 +34,7 @@ import ( "github.com/stretchr/testify/require" ) -func newOffchainRequest(t *testing.T, sender []byte) (*api.Message, functions.RequestID) { +func newOffchainRequest(t *testing.T, sender []byte, ageSec uint64) (*api.Message, functions.RequestID) { requestId := make([]byte, 32) _, err := rand.Read(requestId) require.NoError(t, err) @@ -39,6 +43,7 @@ func newOffchainRequest(t *testing.T, sender []byte) (*api.Message, functions.Re RequestInitiator: sender, SubscriptionId: 1, SubscriptionOwner: sender, + Timestamp: uint64(time.Now().Unix()) - ageSec, } internalId := functions.InternalId(request.RequestInitiator, request.RequestId) @@ -62,9 +67,9 @@ func TestFunctionsConnectorHandler(t *testing.T) { privateKey, addr := testutils.NewPrivateKeyAndAddress(t) storage := s4mocks.NewStorage(t) connector := gcmocks.NewGatewayConnector(t) - allowlist := gfmocks.NewOnchainAllowlist(t) + allowlist := fallowMocks.NewOnchainAllowlist(t) rateLimiter, err := hc.NewRateLimiter(hc.RateLimiterConfig{GlobalRPS: 100.0, GlobalBurst: 100, PerSenderRPS: 100.0, PerSenderBurst: 100}) - subscriptions := gfmocks.NewOnchainSubscriptions(t) + subscriptions := fsubMocks.NewOnchainSubscriptions(t) reportCh := make(chan *functions.OffchainResponse) offchainTransmitter := sfmocks.NewOffchainTransmitter(t) offchainTransmitter.On("ReportChannel", mock.Anything).Return(reportCh) @@ -74,7 +79,15 @@ func TestFunctionsConnectorHandler(t *testing.T) { allowlist.On("Close", mock.Anything).Return(nil) subscriptions.On("Start", mock.Anything).Return(nil) subscriptions.On("Close", mock.Anything).Return(nil) - handler, err := functions.NewFunctionsConnectorHandler(addr.Hex(), privateKey, storage, allowlist, rateLimiter, subscriptions, listener, offchainTransmitter, *assets.NewLinkFromJuels(100), logger) + config := &config.PluginConfig{ + GatewayConnectorConfig: &gwconnector.ConnectorConfig{ + NodeAddress: addr.Hex(), + }, + MinimumSubscriptionBalance: *assets.NewLinkFromJuels(100), + RequestTimeoutSec: 1_000, + AllowedHeartbeatInitiators: []string{crypto.PubkeyToAddress(privateKey.PublicKey).Hex()}, + } + handler, err := functions.NewFunctionsConnectorHandler(config, privateKey, storage, allowlist, rateLimiter, subscriptions, listener, offchainTransmitter, logger) require.NoError(t, err) handler.SetConnector(connector) @@ -257,7 +270,7 @@ func TestFunctionsConnectorHandler(t *testing.T) { t.Run("heartbeat success", func(t *testing.T) { ctx := testutils.Context(t) - msg, internalId := newOffchainRequest(t, addr.Bytes()) + msg, internalId := newOffchainRequest(t, addr.Bytes(), 0) require.NoError(t, msg.Sign(privateKey)) // first call to trigger the request @@ -292,7 +305,7 @@ func TestFunctionsConnectorHandler(t *testing.T) { t.Run("heartbeat internal error", func(t *testing.T) { ctx := testutils.Context(t) - msg, _ := newOffchainRequest(t, addr.Bytes()) + msg, _ := newOffchainRequest(t, addr.Bytes(), 0) require.NoError(t, msg.Sign(privateKey)) // first call to trigger the request @@ -319,7 +332,23 @@ func TestFunctionsConnectorHandler(t *testing.T) { t.Run("heartbeat sender address doesn't match", func(t *testing.T) { ctx := testutils.Context(t) - msg, _ := newOffchainRequest(t, geth_common.BytesToAddress([]byte("0x1234")).Bytes()) + msg, _ := newOffchainRequest(t, geth_common.BytesToAddress([]byte("0x1234")).Bytes(), 0) + require.NoError(t, msg.Sign(privateKey)) + + var response functions.HeartbeatResponse + allowlist.On("Allow", addr).Return(true).Once() + connector.On("SendToGateway", mock.Anything, "gw1", mock.Anything).Run(func(args mock.Arguments) { + respMsg, ok := args[2].(*api.Message) + require.True(t, ok) + require.NoError(t, json.Unmarshal(respMsg.Body.Payload, &response)) + require.Equal(t, functions.RequestStateInternalError, response.Status) + }).Return(nil).Once() + handler.HandleGatewayMessage(ctx, "gw1", msg) + }) + + t.Run("heartbeat request too old", func(t *testing.T) { + ctx := testutils.Context(t) + msg, _ := newOffchainRequest(t, addr.Bytes(), 10_000) require.NoError(t, msg.Sign(privateKey)) var response functions.HeartbeatResponse diff --git a/core/services/functions/orm_test.go b/core/services/functions/orm_test.go index 459b1f56a6..ca92aafcb0 100644 --- a/core/services/functions/orm_test.go +++ b/core/services/functions/orm_test.go @@ -8,6 +8,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/stretchr/testify/require" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest" "github.com/smartcontractkit/chainlink/v2/core/logger" @@ -47,7 +48,7 @@ func createRequest(t *testing.T, orm functions.ORM) (functions.RequestID, common func createRequestWithTimestamp(t *testing.T, orm functions.ORM, ts time.Time) (functions.RequestID, common.Hash) { id := newRequestID() - txHash := testutils.NewAddress().Hash() + txHash := utils.RandomHash() newReq := &functions.Request{ RequestID: id, RequestTxHash: &txHash, diff --git a/core/services/gateway/api/message.go b/core/services/gateway/api/message.go index c01d3bb9f2..5e6c8e4924 100644 --- a/core/services/gateway/api/message.go +++ b/core/services/gateway/api/message.go @@ -20,6 +20,7 @@ const ( MessageMethodMaxLen = 64 MessageDonIdMaxLen = 64 MessageReceiverLen = 2 + 2*20 + NullChar = "\x00" ) /* @@ -56,12 +57,21 @@ func (m *Message) Validate() error { if len(m.Body.MessageId) == 0 || len(m.Body.MessageId) > MessageIdMaxLen { return errors.New("invalid message ID length") } + if strings.HasSuffix(m.Body.MessageId, NullChar) { + return errors.New("message ID ending with null bytes") + } if len(m.Body.Method) == 0 || len(m.Body.Method) > MessageMethodMaxLen { return errors.New("invalid method name length") } + if strings.HasSuffix(m.Body.Method, NullChar) { + return errors.New("method name ending with null bytes") + } if len(m.Body.DonId) == 0 || len(m.Body.DonId) > MessageDonIdMaxLen { return errors.New("invalid DON ID length") } + if strings.HasSuffix(m.Body.DonId, NullChar) { + return errors.New("DON ID ending with null bytes") + } if len(m.Body.Receiver) != 0 && len(m.Body.Receiver) != MessageReceiverLen { return errors.New("invalid Receiver length") } diff --git a/core/services/gateway/api/message_test.go b/core/services/gateway/api/message_test.go index a0835ea24b..1f292db26b 100644 --- a/core/services/gateway/api/message_test.go +++ b/core/services/gateway/api/message_test.go @@ -31,22 +31,38 @@ func TestMessage_Validate(t *testing.T) { // missing message ID msg.Body.MessageId = "" require.Error(t, msg.Validate()) + // message ID ending with null bytes + msg.Body.MessageId = "myid\x00\x00" + require.Error(t, msg.Validate()) msg.Body.MessageId = "abcd" + require.NoError(t, msg.Validate()) // missing DON ID msg.Body.DonId = "" require.Error(t, msg.Validate()) + // DON ID ending with null bytes + msg.Body.DonId = "mydon\x00\x00" + require.Error(t, msg.Validate()) msg.Body.DonId = "donA" + require.NoError(t, msg.Validate()) - // method too long + // method name too long msg.Body.Method = string(bytes.Repeat([]byte("a"), api.MessageMethodMaxLen+1)) require.Error(t, msg.Validate()) + // empty method name + msg.Body.Method = "" + require.Error(t, msg.Validate()) + // method name ending with null bytes + msg.Body.Method = "method\x00" + require.Error(t, msg.Validate()) msg.Body.Method = "request" + require.NoError(t, msg.Validate()) // incorrect receiver msg.Body.Receiver = "blah" require.Error(t, msg.Validate()) msg.Body.Receiver = "0x0000000000000000000000000000000000000000" + require.NoError(t, msg.Validate()) // invalid signature msg.Signature = "0x00" diff --git a/core/services/gateway/connectionmanager.go b/core/services/gateway/connectionmanager.go index 9f88b51e7b..e5f7fb13af 100644 --- a/core/services/gateway/connectionmanager.go +++ b/core/services/gateway/connectionmanager.go @@ -287,6 +287,10 @@ func (m *donConnectionManager) readLoop(nodeAddress string, nodeState *nodeState m.lggr.Errorw("message validation error when reading from node", "nodeAddress", nodeAddress, "err", err) break } + if msg.Body.Sender != nodeAddress { + m.lggr.Errorw("message sender mismatch when reading from node", "nodeAddress", nodeAddress, "sender", msg.Body.Sender) + break + } err = m.handler.HandleNodeMessage(ctx, msg, nodeAddress) if err != nil { m.lggr.Error("error when calling HandleNodeMessage ", err) diff --git a/core/services/gateway/handlers/functions/allowlist.go b/core/services/gateway/handlers/functions/allowlist/allowlist.go similarity index 51% rename from core/services/gateway/handlers/functions/allowlist.go rename to core/services/gateway/handlers/functions/allowlist/allowlist.go index 0a18d6e6d8..20dc92ced7 100644 --- a/core/services/gateway/handlers/functions/allowlist.go +++ b/core/services/gateway/handlers/functions/allowlist/allowlist.go @@ -1,4 +1,4 @@ -package functions +package allowlist import ( "context" @@ -22,14 +22,26 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/utils" ) +const ( + defaultStoredAllowlistBatchSize = 1000 + defaultOnchainAllowlistBatchSize = 100 + defaultFetchingDelayInRangeSec = 1 +) + type OnchainAllowlistConfig struct { // ContractAddress is required ContractAddress common.Address `json:"contractAddress"` ContractVersion uint32 `json:"contractVersion"` BlockConfirmations uint `json:"blockConfirmations"` // UpdateFrequencySec can be zero to disable periodic updates - UpdateFrequencySec uint `json:"updateFrequencySec"` - UpdateTimeoutSec uint `json:"updateTimeoutSec"` + UpdateFrequencySec uint `json:"updateFrequencySec"` + UpdateTimeoutSec uint `json:"updateTimeoutSec"` + StoredAllowlistBatchSize uint `json:"storedAllowlistBatchSize"` + OnchainAllowlistBatchSize uint `json:"onchainAllowlistBatchSize"` + // StoreAllowedSendersEnabled is a feature flag that enables storing in db a copy of the allowlist. + StoreAllowedSendersEnabled bool `json:"storeAllowedSendersEnabled"` + // FetchingDelayInRangeSec prevents RPC client being rate limited when fetching the allowlist in ranges. + FetchingDelayInRangeSec uint `json:"fetchingDelayInRangeSec"` } // OnchainAllowlist maintains an allowlist of addresses fetched from the blockchain (EVM-only). @@ -50,6 +62,7 @@ type onchainAllowlist struct { config OnchainAllowlistConfig allowlist atomic.Pointer[map[common.Address]struct{}] + orm ORM client evmclient.Client contractV1 *functions_router.FunctionsRouter blockConfirmations *big.Int @@ -58,7 +71,7 @@ type onchainAllowlist struct { stopCh services.StopChan } -func NewOnchainAllowlist(client evmclient.Client, config OnchainAllowlistConfig, lggr logger.Logger) (OnchainAllowlist, error) { +func NewOnchainAllowlist(client evmclient.Client, config OnchainAllowlistConfig, orm ORM, lggr logger.Logger) (OnchainAllowlist, error) { if client == nil { return nil, errors.New("client is nil") } @@ -68,12 +81,33 @@ func NewOnchainAllowlist(client evmclient.Client, config OnchainAllowlistConfig, if config.ContractVersion != 1 { return nil, fmt.Errorf("unsupported contract version %d", config.ContractVersion) } + + if config.StoredAllowlistBatchSize == 0 { + lggr.Info("StoredAllowlistBatchSize not specified, using default size: ", defaultStoredAllowlistBatchSize) + config.StoredAllowlistBatchSize = defaultStoredAllowlistBatchSize + } + + if config.OnchainAllowlistBatchSize == 0 { + lggr.Info("OnchainAllowlistBatchSize not specified, using default size: ", defaultOnchainAllowlistBatchSize) + config.OnchainAllowlistBatchSize = defaultOnchainAllowlistBatchSize + } + + if config.FetchingDelayInRangeSec == 0 { + lggr.Info("FetchingDelayInRangeSec not specified, using default delay: ", defaultFetchingDelayInRangeSec) + config.FetchingDelayInRangeSec = defaultFetchingDelayInRangeSec + } + + if config.UpdateFrequencySec != 0 && config.FetchingDelayInRangeSec >= config.UpdateFrequencySec { + return nil, fmt.Errorf("to avoid updates overlapping FetchingDelayInRangeSec:%d should be less than UpdateFrequencySec:%d", config.FetchingDelayInRangeSec, config.UpdateFrequencySec) + } + contractV1, err := functions_router.NewFunctionsRouter(config.ContractAddress, client) if err != nil { return nil, fmt.Errorf("unexpected error during functions_router.NewFunctionsRouter: %s", err) } allowlist := &onchainAllowlist{ config: config, + orm: orm, client: client, contractV1: contractV1, blockConfirmations: big.NewInt(int64(config.BlockConfirmations)), @@ -93,6 +127,8 @@ func (a *onchainAllowlist) Start(ctx context.Context) error { return nil } + a.loadStoredAllowedSenderList() + updateOnce := func() { timeoutCtx, cancel := utils.ContextFromChanWithTimeout(a.stopCh, time.Duration(a.config.UpdateTimeoutSec)*time.Second) if err := a.UpdateFromContract(timeoutCtx); err != nil { @@ -172,17 +208,113 @@ func (a *onchainAllowlist) updateFromContractV1(ctx context.Context, blockNum *b if err != nil { return errors.Wrap(err, "unexpected error during functions_allow_list.NewTermsOfServiceAllowList") } - addrList, err := tosContract.GetAllAllowedSenders(&bind.CallOpts{ + + var allowedSenderList []common.Address + if !a.config.StoreAllowedSendersEnabled { + allowedSenderList, err = tosContract.GetAllAllowedSenders(&bind.CallOpts{ + Pending: false, + BlockNumber: blockNum, + Context: ctx, + }) + if err != nil { + return errors.Wrap(err, "error calling GetAllAllowedSenders") + } + } else { + err = a.syncBlockedSenders(ctx, tosContract, blockNum) + if err != nil { + return errors.Wrap(err, "failed to sync the stored allowed and blocked senders") + } + + allowedSenderList, err = a.getAllowedSendersBatched(ctx, tosContract, blockNum) + if err != nil { + return errors.Wrap(err, "failed to get allowed senders in rage") + } + } + + a.update(allowedSenderList) + return nil +} + +func (a *onchainAllowlist) getAllowedSendersBatched(ctx context.Context, tosContract *functions_allow_list.TermsOfServiceAllowList, blockNum *big.Int) ([]common.Address, error) { + allowedSenderList := make([]common.Address, 0) + count, err := tosContract.GetAllowedSendersCount(&bind.CallOpts{ Pending: false, BlockNumber: blockNum, Context: ctx, }) if err != nil { - return errors.Wrap(err, "error calling GetAllAllowedSenders") + return nil, errors.Wrap(err, "unexpected error during functions_allow_list.GetAllowedSendersCount") } - a.update(addrList) + + throttleTicker := time.NewTicker(time.Duration(a.config.FetchingDelayInRangeSec) * time.Second) + for idxStart := uint64(0); idxStart < count; idxStart += uint64(a.config.OnchainAllowlistBatchSize) { + <-throttleTicker.C + + idxEnd := idxStart + uint64(a.config.OnchainAllowlistBatchSize) + if idxEnd >= count { + idxEnd = count - 1 + } + + allowedSendersBatch, err := tosContract.GetAllowedSendersInRange(&bind.CallOpts{ + Pending: false, + BlockNumber: blockNum, + Context: ctx, + }, idxStart, idxEnd) + if err != nil { + return nil, errors.Wrap(err, "error calling GetAllowedSendersInRange") + } + + allowedSenderList = append(allowedSenderList, allowedSendersBatch...) + err = a.orm.CreateAllowedSenders(allowedSendersBatch) + if err != nil { + a.lggr.Errorf("failed to update stored allowedSenderList: %w", err) + } + } + throttleTicker.Stop() + + return allowedSenderList, nil +} + +// syncBlockedSenders fetches the list of blocked addresses from the contract in batches +// and removes the addresses from the functions_allowlist table if present +func (a *onchainAllowlist) syncBlockedSenders(ctx context.Context, tosContract *functions_allow_list.TermsOfServiceAllowList, blockNum *big.Int) error { + count, err := tosContract.GetBlockedSendersCount(&bind.CallOpts{ + Pending: false, + BlockNumber: blockNum, + Context: ctx, + }) + if err != nil { + return errors.Wrap(err, "unexpected error during functions_allow_list.GetBlockedSendersCount") + } + + throttleTicker := time.NewTicker(time.Duration(a.config.FetchingDelayInRangeSec) * time.Second) + for idxStart := uint64(0); idxStart < count; idxStart += uint64(a.config.OnchainAllowlistBatchSize) { + <-throttleTicker.C + + idxEnd := idxStart + uint64(a.config.OnchainAllowlistBatchSize) + if idxEnd >= count { + idxEnd = count - 1 + } + + blockedSendersBatch, err := tosContract.GetBlockedSendersInRange(&bind.CallOpts{ + Pending: false, + BlockNumber: blockNum, + Context: ctx, + }, idxStart, idxEnd) + if err != nil { + return errors.Wrap(err, "error calling GetAllowedSendersInRange") + } + + err = a.orm.DeleteAllowedSenders(blockedSendersBatch) + if err != nil { + a.lggr.Errorf("failed to delete blocked address from allowed list in storage: %w", err) + } + } + throttleTicker.Stop() + return nil } + func (a *onchainAllowlist) update(addrList []common.Address) { newAllowlist := make(map[common.Address]struct{}) for _, addr := range addrList { @@ -191,3 +323,24 @@ func (a *onchainAllowlist) update(addrList []common.Address) { a.allowlist.Store(&newAllowlist) a.lggr.Infow("allowlist updated successfully", "len", len(addrList)) } + +func (a *onchainAllowlist) loadStoredAllowedSenderList() { + allowedList := make([]common.Address, 0) + offset := uint(0) + for { + asBatch, err := a.orm.GetAllowedSenders(offset, a.config.StoredAllowlistBatchSize) + if err != nil { + a.lggr.Errorf("failed to get stored allowed senders: %w", err) + break + } + + allowedList = append(allowedList, asBatch...) + + if len(asBatch) < int(a.config.StoredAllowlistBatchSize) { + break + } + offset += a.config.StoredAllowlistBatchSize + } + + a.update(allowedList) +} diff --git a/core/services/gateway/handlers/functions/allowlist/allowlist_test.go b/core/services/gateway/handlers/functions/allowlist/allowlist_test.go new file mode 100644 index 0000000000..e8cbca80b9 --- /dev/null +++ b/core/services/gateway/handlers/functions/allowlist/allowlist_test.go @@ -0,0 +1,184 @@ +package allowlist_test + +import ( + "context" + "encoding/hex" + "math/big" + "testing" + "time" + + "github.com/ethereum/go-ethereum/common" + "github.com/onsi/gomega" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/mock" + "github.com/stretchr/testify/require" + + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client/mocks" + "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" + "github.com/smartcontractkit/chainlink/v2/core/logger" + "github.com/smartcontractkit/chainlink/v2/core/services/gateway/handlers/functions/allowlist" + amocks "github.com/smartcontractkit/chainlink/v2/core/services/gateway/handlers/functions/allowlist/mocks" +) + +const ( + addr1 = "9ed925d8206a4f88a2f643b28b3035b315753cd6" + addr2 = "ea6721ac65bced841b8ec3fc5fedea6141a0ade4" + addr3 = "84689acc87ff22841b8ec378300da5e141a99911" +) + +func sampleEncodedAllowlist(t *testing.T) []byte { + abiEncodedAddresses := + "0000000000000000000000000000000000000000000000000000000000000020" + + "0000000000000000000000000000000000000000000000000000000000000002" + + "000000000000000000000000" + addr1 + + "000000000000000000000000" + addr2 + rawData, err := hex.DecodeString(abiEncodedAddresses) + require.NoError(t, err) + return rawData +} + +func TestAllowlist_UpdateAndCheck(t *testing.T) { + t.Parallel() + + 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 := allowlist.OnchainAllowlistConfig{ + ContractVersion: 1, + ContractAddress: common.Address{}, + BlockConfirmations: 1, + } + + orm := amocks.NewORM(t) + allowlist, err := allowlist.NewOnchainAllowlist(client, config, orm, 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))) +} + +func TestAllowlist_UnsupportedVersion(t *testing.T) { + t.Parallel() + + client := mocks.NewClient(t) + config := allowlist.OnchainAllowlistConfig{ + ContractVersion: 0, + ContractAddress: common.Address{}, + BlockConfirmations: 1, + } + + orm := amocks.NewORM(t) + _, err := allowlist.NewOnchainAllowlist(client, config, orm, logger.TestLogger(t)) + require.Error(t, err) +} + +func TestAllowlist_UpdatePeriodically(t *testing.T) { + t.Parallel() + + ctx, cancel := context.WithCancel(testutils.Context(t)) + client := mocks.NewClient(t) + client.On("LatestBlockHeight", mock.Anything).Return(big.NewInt(42), nil) + client.On("CallContract", mock.Anything, mock.Anything, mock.Anything).Run(func(args mock.Arguments) { + cancel() + }).Return(sampleEncodedAllowlist(t), nil) + config := allowlist.OnchainAllowlistConfig{ + ContractAddress: common.Address{}, + ContractVersion: 1, + BlockConfirmations: 1, + UpdateFrequencySec: 2, + UpdateTimeoutSec: 1, + } + + orm := amocks.NewORM(t) + orm.On("GetAllowedSenders", uint(0), uint(1000)).Return([]common.Address{}, nil) + + allowlist, err := allowlist.NewOnchainAllowlist(client, config, orm, logger.TestLogger(t)) + require.NoError(t, err) + + err = allowlist.Start(ctx) + require.NoError(t, err) + t.Cleanup(func() { + assert.NoError(t, allowlist.Close()) + }) + + gomega.NewGomegaWithT(t).Eventually(func() bool { + return allowlist.Allow(common.HexToAddress(addr1)) && !allowlist.Allow(common.HexToAddress(addr3)) + }, testutils.WaitTimeout(t), time.Second).Should(gomega.BeTrue()) +} +func TestAllowlist_UpdateFromContract(t *testing.T) { + t.Parallel() + + t.Run("OK-iterate_over_list_of_allowed_senders", func(t *testing.T) { + ctx, cancel := context.WithCancel(testutils.Context(t)) + client := mocks.NewClient(t) + client.On("LatestBlockHeight", mock.Anything).Return(big.NewInt(42), nil) + client.On("CallContract", mock.Anything, mock.Anything, mock.Anything).Run(func(args mock.Arguments) { + cancel() + }).Return(sampleEncodedAllowlist(t), nil) + config := allowlist.OnchainAllowlistConfig{ + ContractAddress: common.HexToAddress(addr3), + ContractVersion: 1, + BlockConfirmations: 1, + UpdateFrequencySec: 2, + UpdateTimeoutSec: 1, + StoredAllowlistBatchSize: 2, + OnchainAllowlistBatchSize: 16, + StoreAllowedSendersEnabled: true, + FetchingDelayInRangeSec: 0, + } + + orm := amocks.NewORM(t) + orm.On("DeleteAllowedSenders", []common.Address{common.HexToAddress(addr1), common.HexToAddress(addr2)}).Times(2).Return(nil) + orm.On("CreateAllowedSenders", []common.Address{common.HexToAddress(addr1), common.HexToAddress(addr2)}).Times(2).Return(nil) + + allowlist, err := allowlist.NewOnchainAllowlist(client, config, orm, logger.TestLogger(t)) + require.NoError(t, err) + + err = allowlist.UpdateFromContract(ctx) + require.NoError(t, err) + + gomega.NewGomegaWithT(t).Eventually(func() bool { + return allowlist.Allow(common.HexToAddress(addr1)) && !allowlist.Allow(common.HexToAddress(addr3)) + }, testutils.WaitTimeout(t), time.Second).Should(gomega.BeTrue()) + }) + + t.Run("OK-fetch_complete_list_of_allowed_senders_without_storing", func(t *testing.T) { + ctx, cancel := context.WithCancel(testutils.Context(t)) + client := mocks.NewClient(t) + client.On("LatestBlockHeight", mock.Anything).Return(big.NewInt(42), nil) + client.On("CallContract", mock.Anything, mock.Anything, mock.Anything).Run(func(args mock.Arguments) { + cancel() + }).Return(sampleEncodedAllowlist(t), nil) + config := allowlist.OnchainAllowlistConfig{ + ContractAddress: common.HexToAddress(addr3), + ContractVersion: 1, + BlockConfirmations: 1, + UpdateFrequencySec: 2, + UpdateTimeoutSec: 1, + StoredAllowlistBatchSize: 2, + OnchainAllowlistBatchSize: 16, + StoreAllowedSendersEnabled: false, + FetchingDelayInRangeSec: 0, + } + + orm := amocks.NewORM(t) + allowlist, err := allowlist.NewOnchainAllowlist(client, config, orm, logger.TestLogger(t)) + require.NoError(t, err) + + err = allowlist.UpdateFromContract(ctx) + require.NoError(t, err) + + gomega.NewGomegaWithT(t).Eventually(func() bool { + return allowlist.Allow(common.HexToAddress(addr1)) && !allowlist.Allow(common.HexToAddress(addr3)) + }, testutils.WaitTimeout(t), time.Second).Should(gomega.BeTrue()) + }) +} diff --git a/core/services/gateway/handlers/functions/mocks/onchain_allowlist.go b/core/services/gateway/handlers/functions/allowlist/mocks/onchain_allowlist.go similarity index 100% rename from core/services/gateway/handlers/functions/mocks/onchain_allowlist.go rename to core/services/gateway/handlers/functions/allowlist/mocks/onchain_allowlist.go diff --git a/core/services/gateway/handlers/functions/allowlist/mocks/orm.go b/core/services/gateway/handlers/functions/allowlist/mocks/orm.go new file mode 100644 index 0000000000..c2ba27c3a2 --- /dev/null +++ b/core/services/gateway/handlers/functions/allowlist/mocks/orm.go @@ -0,0 +1,116 @@ +// Code generated by mockery v2.38.0. DO NOT EDIT. + +package mocks + +import ( + common "github.com/ethereum/go-ethereum/common" + mock "github.com/stretchr/testify/mock" + + pg "github.com/smartcontractkit/chainlink/v2/core/services/pg" +) + +// ORM is an autogenerated mock type for the ORM type +type ORM struct { + mock.Mock +} + +// CreateAllowedSenders provides a mock function with given fields: allowedSenders, qopts +func (_m *ORM) CreateAllowedSenders(allowedSenders []common.Address, qopts ...pg.QOpt) error { + _va := make([]interface{}, len(qopts)) + for _i := range qopts { + _va[_i] = qopts[_i] + } + var _ca []interface{} + _ca = append(_ca, allowedSenders) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + if len(ret) == 0 { + panic("no return value specified for CreateAllowedSenders") + } + + var r0 error + if rf, ok := ret.Get(0).(func([]common.Address, ...pg.QOpt) error); ok { + r0 = rf(allowedSenders, qopts...) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// DeleteAllowedSenders provides a mock function with given fields: blockedSenders, qopts +func (_m *ORM) DeleteAllowedSenders(blockedSenders []common.Address, qopts ...pg.QOpt) error { + _va := make([]interface{}, len(qopts)) + for _i := range qopts { + _va[_i] = qopts[_i] + } + var _ca []interface{} + _ca = append(_ca, blockedSenders) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + if len(ret) == 0 { + panic("no return value specified for DeleteAllowedSenders") + } + + var r0 error + if rf, ok := ret.Get(0).(func([]common.Address, ...pg.QOpt) error); ok { + r0 = rf(blockedSenders, qopts...) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// GetAllowedSenders provides a mock function with given fields: offset, limit, qopts +func (_m *ORM) GetAllowedSenders(offset uint, limit uint, qopts ...pg.QOpt) ([]common.Address, error) { + _va := make([]interface{}, len(qopts)) + for _i := range qopts { + _va[_i] = qopts[_i] + } + var _ca []interface{} + _ca = append(_ca, offset, limit) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + if len(ret) == 0 { + panic("no return value specified for GetAllowedSenders") + } + + var r0 []common.Address + var r1 error + if rf, ok := ret.Get(0).(func(uint, uint, ...pg.QOpt) ([]common.Address, error)); ok { + return rf(offset, limit, qopts...) + } + if rf, ok := ret.Get(0).(func(uint, uint, ...pg.QOpt) []common.Address); ok { + r0 = rf(offset, limit, qopts...) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).([]common.Address) + } + } + + if rf, ok := ret.Get(1).(func(uint, uint, ...pg.QOpt) error); ok { + r1 = rf(offset, limit, qopts...) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// 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()) +}) *ORM { + mock := &ORM{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/core/services/gateway/handlers/functions/allowlist/orm.go b/core/services/gateway/handlers/functions/allowlist/orm.go new file mode 100644 index 0000000000..07ee1ea3b3 --- /dev/null +++ b/core/services/gateway/handlers/functions/allowlist/orm.go @@ -0,0 +1,123 @@ +package allowlist + +import ( + "fmt" + "strings" + + "github.com/ethereum/go-ethereum/common" + "github.com/pkg/errors" + + "github.com/jmoiron/sqlx" + + "github.com/smartcontractkit/chainlink/v2/core/logger" + "github.com/smartcontractkit/chainlink/v2/core/services/pg" +) + +//go:generate mockery --quiet --name ORM --output ./mocks/ --case=underscore +type ORM interface { + GetAllowedSenders(offset, limit uint, qopts ...pg.QOpt) ([]common.Address, error) + CreateAllowedSenders(allowedSenders []common.Address, qopts ...pg.QOpt) error + DeleteAllowedSenders(blockedSenders []common.Address, qopts ...pg.QOpt) error +} + +type orm struct { + q pg.Q + lggr logger.Logger + routerContractAddress common.Address +} + +var _ ORM = (*orm)(nil) +var ( + ErrInvalidParameters = errors.New("invalid parameters provided to create a functions contract cache ORM") +) + +const ( + tableName = "functions_allowlist" +) + +func NewORM(db *sqlx.DB, lggr logger.Logger, cfg pg.QConfig, routerContractAddress common.Address) (ORM, error) { + if db == nil || cfg == nil || lggr == nil || routerContractAddress == (common.Address{}) { + return nil, ErrInvalidParameters + } + + return &orm{ + q: pg.NewQ(db, lggr, cfg), + lggr: lggr, + routerContractAddress: routerContractAddress, + }, nil +} + +func (o *orm) GetAllowedSenders(offset, limit uint, qopts ...pg.QOpt) ([]common.Address, error) { + var addresses []common.Address + stmt := fmt.Sprintf(` + SELECT allowed_address + FROM %s + WHERE router_contract_address = $1 + ORDER BY id ASC + OFFSET $2 + LIMIT $3; + `, tableName) + err := o.q.WithOpts(qopts...).Select(&addresses, stmt, o.routerContractAddress, offset, limit) + if err != nil { + return addresses, err + } + o.lggr.Debugf("Successfully fetched allowed sender list from DB. offset: %d, limit: %d, length: %d", offset, limit, len(addresses)) + + return addresses, nil +} + +func (o *orm) CreateAllowedSenders(allowedSenders []common.Address, qopts ...pg.QOpt) error { + var valuesPlaceholder []string + for i := 1; i <= len(allowedSenders)*2; i += 2 { + valuesPlaceholder = append(valuesPlaceholder, fmt.Sprintf("($%d, $%d)", i, i+1)) + } + + stmt := fmt.Sprintf(` + INSERT INTO %s (allowed_address, router_contract_address) + VALUES %s ON CONFLICT (allowed_address, router_contract_address) DO NOTHING;`, tableName, strings.Join(valuesPlaceholder, ", ")) + + var args []interface{} + for _, as := range allowedSenders { + args = append(args, as, o.routerContractAddress) + } + + _, err := o.q.WithOpts(qopts...).Exec(stmt, args...) + if err != nil { + return err + } + + o.lggr.Debugf("Successfully stored allowed senders: %v for routerContractAddress: %s", allowedSenders, o.routerContractAddress) + + return nil +} + +func (o *orm) DeleteAllowedSenders(blockedSenders []common.Address, qopts ...pg.QOpt) error { + var valuesPlaceholder []string + for i := 1; i <= len(blockedSenders); i++ { + valuesPlaceholder = append(valuesPlaceholder, fmt.Sprintf("$%d", i+1)) + } + + stmt := fmt.Sprintf(` + DELETE FROM %s + WHERE router_contract_address = $1 + AND allowed_address IN (%s);`, tableName, strings.Join(valuesPlaceholder, ", ")) + + args := []interface{}{o.routerContractAddress} + for _, bs := range blockedSenders { + args = append(args, bs) + } + + res, err := o.q.WithOpts(qopts...).Exec(stmt, args...) + if err != nil { + return err + } + + rowsAffected, err := res.RowsAffected() + if err != nil { + return err + } + + o.lggr.Debugf("Successfully removed blocked senders from the allowed list: %v for routerContractAddress: %s. rowsAffected: %d", blockedSenders, o.routerContractAddress, rowsAffected) + + return nil +} diff --git a/core/services/gateway/handlers/functions/allowlist/orm_test.go b/core/services/gateway/handlers/functions/allowlist/orm_test.go new file mode 100644 index 0000000000..0f63e83cd5 --- /dev/null +++ b/core/services/gateway/handlers/functions/allowlist/orm_test.go @@ -0,0 +1,190 @@ +package allowlist_test + +import ( + "testing" + + "github.com/ethereum/go-ethereum/common" + "github.com/stretchr/testify/require" + + "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/gateway/handlers/functions/allowlist" +) + +func setupORM(t *testing.T) (allowlist.ORM, error) { + t.Helper() + + var ( + db = pgtest.NewSqlxDB(t) + lggr = logger.TestLogger(t) + ) + + return allowlist.NewORM(db, lggr, pgtest.NewQConfig(true), testutils.NewAddress()) +} + +func seedAllowedSenders(t *testing.T, orm allowlist.ORM, amount int) []common.Address { + storedAllowedSenders := make([]common.Address, amount) + for i := 0; i < amount; i++ { + address := testutils.NewAddress() + storedAllowedSenders[i] = address + } + + err := orm.CreateAllowedSenders(storedAllowedSenders) + require.NoError(t, err) + + return storedAllowedSenders +} +func TestORM_GetAllowedSenders(t *testing.T) { + t.Parallel() + t.Run("fetch first page", func(t *testing.T) { + orm, err := setupORM(t) + require.NoError(t, err) + storedAllowedSenders := seedAllowedSenders(t, orm, 2) + results, err := orm.GetAllowedSenders(0, 1) + require.NoError(t, err) + require.Equal(t, 1, len(results), "incorrect results length") + require.Equal(t, storedAllowedSenders[0], results[0]) + }) + + t.Run("fetch second page", func(t *testing.T) { + orm, err := setupORM(t) + require.NoError(t, err) + storedAllowedSenders := seedAllowedSenders(t, orm, 2) + results, err := orm.GetAllowedSenders(1, 5) + require.NoError(t, err) + require.Equal(t, 1, len(results), "incorrect results length") + require.Equal(t, storedAllowedSenders[1], results[0]) + }) +} + +func TestORM_CreateAllowedSenders(t *testing.T) { + t.Parallel() + + t.Run("OK-create_an_allowed_sender", func(t *testing.T) { + orm, err := setupORM(t) + require.NoError(t, err) + expected := testutils.NewAddress() + err = orm.CreateAllowedSenders([]common.Address{expected}) + require.NoError(t, err) + + results, err := orm.GetAllowedSenders(0, 1) + require.NoError(t, err) + require.Equal(t, 1, len(results), "incorrect results length") + require.Equal(t, expected, results[0]) + }) + + t.Run("OK-create_an_existing_allowed_sender", func(t *testing.T) { + orm, err := setupORM(t) + require.NoError(t, err) + expected := testutils.NewAddress() + err = orm.CreateAllowedSenders([]common.Address{expected}) + require.NoError(t, err) + + err = orm.CreateAllowedSenders([]common.Address{expected}) + require.NoError(t, err) + + results, err := orm.GetAllowedSenders(0, 5) + require.NoError(t, err) + require.Equal(t, 1, len(results), "incorrect results length") + require.Equal(t, expected, results[0]) + }) + + t.Run("OK-create_multiple_allowed_senders_in_one_query", func(t *testing.T) { + orm, err := setupORM(t) + require.NoError(t, err) + expected := []common.Address{testutils.NewAddress(), testutils.NewAddress()} + err = orm.CreateAllowedSenders(expected) + require.NoError(t, err) + + results, err := orm.GetAllowedSenders(0, 2) + require.NoError(t, err) + require.Equal(t, 2, len(results), "incorrect results length") + require.Equal(t, expected[0], results[0]) + require.Equal(t, expected[1], results[1]) + }) + + t.Run("OK-create_multiple_allowed_senders_with_duplicates", func(t *testing.T) { + orm, err := setupORM(t) + require.NoError(t, err) + addr1 := testutils.NewAddress() + addr2 := testutils.NewAddress() + expected := []common.Address{addr1, addr2} + + duplicatedAddressInput := []common.Address{addr1, addr1, addr1, addr2} + err = orm.CreateAllowedSenders(duplicatedAddressInput) + require.NoError(t, err) + + results, err := orm.GetAllowedSenders(0, 10) + require.NoError(t, err) + require.Equal(t, 2, len(results), "incorrect results length") + require.Equal(t, expected[0], results[0]) + require.Equal(t, expected[1], results[1]) + }) +} + +func TestORM_DeleteAllowedSenders(t *testing.T) { + t.Parallel() + + t.Run("OK-delete_blocked_sender_from_allowed_list", func(t *testing.T) { + orm, err := setupORM(t) + require.NoError(t, err) + add1 := testutils.NewAddress() + add2 := testutils.NewAddress() + add3 := testutils.NewAddress() + err = orm.CreateAllowedSenders([]common.Address{add1, add2, add3}) + require.NoError(t, err) + + results, err := orm.GetAllowedSenders(0, 10) + require.NoError(t, err) + require.Equal(t, 3, len(results), "incorrect results length") + require.Equal(t, add1, results[0]) + + err = orm.DeleteAllowedSenders([]common.Address{add1, add3}) + require.NoError(t, err) + + results, err = orm.GetAllowedSenders(0, 10) + require.NoError(t, err) + require.Equal(t, 1, len(results), "incorrect results length") + require.Equal(t, add2, results[0]) + }) + + t.Run("OK-delete_non_existing_blocked_sender_from_allowed_list", func(t *testing.T) { + orm, err := setupORM(t) + require.NoError(t, err) + add1 := testutils.NewAddress() + add2 := testutils.NewAddress() + err = orm.CreateAllowedSenders([]common.Address{add1, add2}) + require.NoError(t, err) + + results, err := orm.GetAllowedSenders(0, 10) + require.NoError(t, err) + require.Equal(t, 2, len(results), "incorrect results length") + require.Equal(t, add1, results[0]) + + add3 := testutils.NewAddress() + err = orm.DeleteAllowedSenders([]common.Address{add3}) + require.NoError(t, err) + + results, err = orm.GetAllowedSenders(0, 10) + require.NoError(t, err) + require.Equal(t, 2, len(results), "incorrect results length") + require.Equal(t, add1, results[0]) + require.Equal(t, add2, results[1]) + }) +} + +func Test_NewORM(t *testing.T) { + t.Run("OK-create_ORM", func(t *testing.T) { + _, err := allowlist.NewORM(pgtest.NewSqlxDB(t), logger.TestLogger(t), pgtest.NewQConfig(true), testutils.NewAddress()) + require.NoError(t, err) + }) + t.Run("NOK-create_ORM_with_nil_fields", func(t *testing.T) { + _, err := allowlist.NewORM(nil, nil, nil, common.Address{}) + require.Error(t, err) + }) + t.Run("NOK-create_ORM_with_empty_address", func(t *testing.T) { + _, err := allowlist.NewORM(pgtest.NewSqlxDB(t), logger.TestLogger(t), pgtest.NewQConfig(true), common.Address{}) + require.Error(t, err) + }) +} diff --git a/core/services/gateway/handlers/functions/allowlist_test.go b/core/services/gateway/handlers/functions/allowlist_test.go deleted file mode 100644 index fdaea81b2c..0000000000 --- a/core/services/gateway/handlers/functions/allowlist_test.go +++ /dev/null @@ -1,107 +0,0 @@ -package functions_test - -import ( - "context" - "encoding/hex" - "math/big" - "testing" - "time" - - "github.com/ethereum/go-ethereum/common" - "github.com/onsi/gomega" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/mock" - "github.com/stretchr/testify/require" - - "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client/mocks" - "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" - "github.com/smartcontractkit/chainlink/v2/core/logger" - "github.com/smartcontractkit/chainlink/v2/core/services/gateway/handlers/functions" -) - -const ( - addr1 = "9ed925d8206a4f88a2f643b28b3035b315753cd6" - addr2 = "ea6721ac65bced841b8ec3fc5fedea6141a0ade4" - addr3 = "84689acc87ff22841b8ec378300da5e141a99911" -) - -func sampleEncodedAllowlist(t *testing.T) []byte { - abiEncodedAddresses := - "0000000000000000000000000000000000000000000000000000000000000020" + - "0000000000000000000000000000000000000000000000000000000000000002" + - "000000000000000000000000" + addr1 + - "000000000000000000000000" + addr2 - rawData, err := hex.DecodeString(abiEncodedAddresses) - require.NoError(t, err) - return rawData -} - -func TestAllowlist_UpdateAndCheck(t *testing.T) { - t.Parallel() - - 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))) -} - -func TestAllowlist_UnsupportedVersion(t *testing.T) { - t.Parallel() - - 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) { - t.Parallel() - - ctx, cancel := context.WithCancel(testutils.Context(t)) - client := mocks.NewClient(t) - client.On("LatestBlockHeight", mock.Anything).Return(big.NewInt(42), nil) - client.On("CallContract", mock.Anything, mock.Anything, mock.Anything).Run(func(args mock.Arguments) { - cancel() - }).Return(sampleEncodedAllowlist(t), nil) - config := functions.OnchainAllowlistConfig{ - ContractAddress: common.Address{}, - ContractVersion: 1, - BlockConfirmations: 1, - UpdateFrequencySec: 1, - UpdateTimeoutSec: 1, - } - allowlist, err := functions.NewOnchainAllowlist(client, config, logger.TestLogger(t)) - require.NoError(t, err) - - err = allowlist.Start(ctx) - require.NoError(t, err) - t.Cleanup(func() { - assert.NoError(t, allowlist.Close()) - }) - - gomega.NewGomegaWithT(t).Eventually(func() bool { - return allowlist.Allow(common.HexToAddress(addr1)) && !allowlist.Allow(common.HexToAddress(addr3)) - }, testutils.WaitTimeout(t), time.Second).Should(gomega.BeTrue()) -} diff --git a/core/services/gateway/handlers/functions/handler.functions.go b/core/services/gateway/handlers/functions/handler.functions.go index 2872c72f76..ff272e4e57 100644 --- a/core/services/gateway/handlers/functions/handler.functions.go +++ b/core/services/gateway/handlers/functions/handler.functions.go @@ -23,6 +23,8 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/services/gateway/config" "github.com/smartcontractkit/chainlink/v2/core/services/gateway/handlers" hc "github.com/smartcontractkit/chainlink/v2/core/services/gateway/handlers/common" + fallow "github.com/smartcontractkit/chainlink/v2/core/services/gateway/handlers/functions/allowlist" + fsub "github.com/smartcontractkit/chainlink/v2/core/services/gateway/handlers/functions/subscriptions" "github.com/smartcontractkit/chainlink/v2/core/services/pg" ) @@ -60,10 +62,10 @@ var ( type FunctionsHandlerConfig struct { ChainID string `json:"chainId"` // Not specifying OnchainAllowlist config disables allowlist checks - OnchainAllowlist *OnchainAllowlistConfig `json:"onchainAllowlist"` + OnchainAllowlist *fallow.OnchainAllowlistConfig `json:"onchainAllowlist"` // Not specifying OnchainSubscriptions config disables minimum balance checks - OnchainSubscriptions *OnchainSubscriptionsConfig `json:"onchainSubscriptions"` - MinimumSubscriptionBalance *assets.Link `json:"minimumSubscriptionBalance"` + OnchainSubscriptions *fsub.OnchainSubscriptionsConfig `json:"onchainSubscriptions"` + MinimumSubscriptionBalance *assets.Link `json:"minimumSubscriptionBalance"` // Not specifying RateLimiter config disables rate limiting UserRateLimiter *hc.RateLimiterConfig `json:"userRateLimiter"` NodeRateLimiter *hc.RateLimiterConfig `json:"nodeRateLimiter"` @@ -79,8 +81,8 @@ type functionsHandler struct { donConfig *config.DONConfig don handlers.DON pendingRequests hc.RequestCache[PendingRequest] - allowlist OnchainAllowlist - subscriptions OnchainSubscriptions + allowlist fallow.OnchainAllowlist + subscriptions fsub.OnchainSubscriptions minimumBalance *assets.Link userRateLimiter *hc.RateLimiter nodeRateLimiter *hc.RateLimiter @@ -105,13 +107,18 @@ func NewFunctionsHandlerFromConfig(handlerConfig json.RawMessage, donConfig *con return nil, err } lggr = lggr.Named("FunctionsHandler:" + donConfig.DonId) - var allowlist OnchainAllowlist + var allowlist fallow.OnchainAllowlist if cfg.OnchainAllowlist != nil { chain, err2 := legacyChains.Get(cfg.ChainID) if err2 != nil { return nil, err2 } - allowlist, err2 = NewOnchainAllowlist(chain.Client(), *cfg.OnchainAllowlist, lggr) + + orm, err2 := fallow.NewORM(db, lggr, qcfg, cfg.OnchainAllowlist.ContractAddress) + if err2 != nil { + return nil, err2 + } + allowlist, err2 = fallow.NewOnchainAllowlist(chain.Client(), *cfg.OnchainAllowlist, orm, lggr) if err2 != nil { return nil, err2 } @@ -129,19 +136,19 @@ func NewFunctionsHandlerFromConfig(handlerConfig json.RawMessage, donConfig *con return nil, err } } - var subscriptions OnchainSubscriptions + var subscriptions fsub.OnchainSubscriptions if cfg.OnchainSubscriptions != nil { chain, err2 := legacyChains.Get(cfg.ChainID) if err2 != nil { return nil, err2 } - orm, err2 := NewORM(db, lggr, qcfg, cfg.OnchainSubscriptions.ContractAddress) + orm, err2 := fsub.NewORM(db, lggr, qcfg, cfg.OnchainSubscriptions.ContractAddress) if err2 != nil { return nil, err2 } - subscriptions, err2 = NewOnchainSubscriptions(chain.Client(), *cfg.OnchainSubscriptions, orm, lggr) + subscriptions, err2 = fsub.NewOnchainSubscriptions(chain.Client(), *cfg.OnchainSubscriptions, orm, lggr) if err2 != nil { return nil, err2 } @@ -159,8 +166,8 @@ func NewFunctionsHandler( donConfig *config.DONConfig, don handlers.DON, pendingRequestsCache hc.RequestCache[PendingRequest], - allowlist OnchainAllowlist, - subscriptions OnchainSubscriptions, + allowlist fallow.OnchainAllowlist, + subscriptions fsub.OnchainSubscriptions, minimumBalance *assets.Link, userRateLimiter *hc.RateLimiter, nodeRateLimiter *hc.RateLimiter, diff --git a/core/services/gateway/handlers/functions/handler.functions_test.go b/core/services/gateway/handlers/functions/handler.functions_test.go index 7e055815c8..2e2c1c77ca 100644 --- a/core/services/gateway/handlers/functions/handler.functions_test.go +++ b/core/services/gateway/handlers/functions/handler.functions_test.go @@ -22,11 +22,12 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/services/gateway/handlers" hc "github.com/smartcontractkit/chainlink/v2/core/services/gateway/handlers/common" "github.com/smartcontractkit/chainlink/v2/core/services/gateway/handlers/functions" - functions_mocks "github.com/smartcontractkit/chainlink/v2/core/services/gateway/handlers/functions/mocks" + allowlist_mocks "github.com/smartcontractkit/chainlink/v2/core/services/gateway/handlers/functions/allowlist/mocks" + subscriptions_mocks "github.com/smartcontractkit/chainlink/v2/core/services/gateway/handlers/functions/subscriptions/mocks" handlers_mocks "github.com/smartcontractkit/chainlink/v2/core/services/gateway/handlers/mocks" ) -func newFunctionsHandlerForATestDON(t *testing.T, nodes []gc.TestNode, requestTimeout time.Duration, heartbeatSender string) (handlers.Handler, *handlers_mocks.DON, *functions_mocks.OnchainAllowlist, *functions_mocks.OnchainSubscriptions) { +func newFunctionsHandlerForATestDON(t *testing.T, nodes []gc.TestNode, requestTimeout time.Duration, heartbeatSender string) (handlers.Handler, *handlers_mocks.DON, *allowlist_mocks.OnchainAllowlist, *subscriptions_mocks.OnchainSubscriptions) { cfg := functions.FunctionsHandlerConfig{} donConfig := &config.DONConfig{ Members: []config.NodeConfig{}, @@ -41,8 +42,8 @@ func newFunctionsHandlerForATestDON(t *testing.T, nodes []gc.TestNode, requestTi } don := handlers_mocks.NewDON(t) - allowlist := functions_mocks.NewOnchainAllowlist(t) - subscriptions := functions_mocks.NewOnchainSubscriptions(t) + allowlist := allowlist_mocks.NewOnchainAllowlist(t) + subscriptions := subscriptions_mocks.NewOnchainSubscriptions(t) minBalance := assets.NewLinkFromJuels(100) userRateLimiter, err := hc.NewRateLimiter(hc.RateLimiterConfig{GlobalRPS: 100.0, GlobalBurst: 100, PerSenderRPS: 100.0, PerSenderBurst: 100}) require.NoError(t, err) diff --git a/core/services/gateway/handlers/functions/mocks/onchain_subscriptions.go b/core/services/gateway/handlers/functions/subscriptions/mocks/onchain_subscriptions.go similarity index 100% rename from core/services/gateway/handlers/functions/mocks/onchain_subscriptions.go rename to core/services/gateway/handlers/functions/subscriptions/mocks/onchain_subscriptions.go diff --git a/core/services/gateway/handlers/functions/mocks/orm.go b/core/services/gateway/handlers/functions/subscriptions/mocks/orm.go similarity index 73% rename from core/services/gateway/handlers/functions/mocks/orm.go rename to core/services/gateway/handlers/functions/subscriptions/mocks/orm.go index 110675c8b5..0f278aa49b 100644 --- a/core/services/gateway/handlers/functions/mocks/orm.go +++ b/core/services/gateway/handlers/functions/subscriptions/mocks/orm.go @@ -3,10 +3,9 @@ package mocks import ( - functions "github.com/smartcontractkit/chainlink/v2/core/services/gateway/handlers/functions" - mock "github.com/stretchr/testify/mock" - + subscriptions "github.com/smartcontractkit/chainlink/v2/core/services/gateway/handlers/functions/subscriptions" pg "github.com/smartcontractkit/chainlink/v2/core/services/pg" + mock "github.com/stretchr/testify/mock" ) // ORM is an autogenerated mock type for the ORM type @@ -15,7 +14,7 @@ type ORM struct { } // GetSubscriptions provides a mock function with given fields: offset, limit, qopts -func (_m *ORM) GetSubscriptions(offset uint, limit uint, qopts ...pg.QOpt) ([]functions.CachedSubscription, error) { +func (_m *ORM) GetSubscriptions(offset uint, limit uint, qopts ...pg.QOpt) ([]subscriptions.StoredSubscription, error) { _va := make([]interface{}, len(qopts)) for _i := range qopts { _va[_i] = qopts[_i] @@ -29,16 +28,16 @@ func (_m *ORM) GetSubscriptions(offset uint, limit uint, qopts ...pg.QOpt) ([]fu panic("no return value specified for GetSubscriptions") } - var r0 []functions.CachedSubscription + var r0 []subscriptions.StoredSubscription var r1 error - if rf, ok := ret.Get(0).(func(uint, uint, ...pg.QOpt) ([]functions.CachedSubscription, error)); ok { + if rf, ok := ret.Get(0).(func(uint, uint, ...pg.QOpt) ([]subscriptions.StoredSubscription, error)); ok { return rf(offset, limit, qopts...) } - if rf, ok := ret.Get(0).(func(uint, uint, ...pg.QOpt) []functions.CachedSubscription); ok { + if rf, ok := ret.Get(0).(func(uint, uint, ...pg.QOpt) []subscriptions.StoredSubscription); ok { r0 = rf(offset, limit, qopts...) } else { if ret.Get(0) != nil { - r0 = ret.Get(0).([]functions.CachedSubscription) + r0 = ret.Get(0).([]subscriptions.StoredSubscription) } } @@ -52,7 +51,7 @@ func (_m *ORM) GetSubscriptions(offset uint, limit uint, qopts ...pg.QOpt) ([]fu } // UpsertSubscription provides a mock function with given fields: subscription, qopts -func (_m *ORM) UpsertSubscription(subscription functions.CachedSubscription, qopts ...pg.QOpt) error { +func (_m *ORM) UpsertSubscription(subscription subscriptions.StoredSubscription, qopts ...pg.QOpt) error { _va := make([]interface{}, len(qopts)) for _i := range qopts { _va[_i] = qopts[_i] @@ -67,7 +66,7 @@ func (_m *ORM) UpsertSubscription(subscription functions.CachedSubscription, qop } var r0 error - if rf, ok := ret.Get(0).(func(functions.CachedSubscription, ...pg.QOpt) error); ok { + if rf, ok := ret.Get(0).(func(subscriptions.StoredSubscription, ...pg.QOpt) error); ok { r0 = rf(subscription, qopts...) } else { r0 = ret.Error(0) diff --git a/core/services/gateway/handlers/functions/orm.go b/core/services/gateway/handlers/functions/subscriptions/orm.go similarity index 73% rename from core/services/gateway/handlers/functions/orm.go rename to core/services/gateway/handlers/functions/subscriptions/orm.go index b7ec8d865d..369291ace5 100644 --- a/core/services/gateway/handlers/functions/orm.go +++ b/core/services/gateway/handlers/functions/subscriptions/orm.go @@ -1,4 +1,4 @@ -package functions +package subscriptions import ( "fmt" @@ -16,27 +16,27 @@ import ( ) //go:generate mockery --quiet --name ORM --output ./mocks/ --case=underscore - type ORM interface { - GetSubscriptions(offset, limit uint, qopts ...pg.QOpt) ([]CachedSubscription, error) - UpsertSubscription(subscription CachedSubscription, qopts ...pg.QOpt) error + GetSubscriptions(offset, limit uint, qopts ...pg.QOpt) ([]StoredSubscription, error) + UpsertSubscription(subscription StoredSubscription, qopts ...pg.QOpt) error } type orm struct { q pg.Q + lggr logger.Logger routerContractAddress common.Address } var _ ORM = (*orm)(nil) var ( - ErrInvalidParameters = errors.New("invalid parameters provided to create a subscription cache ORM") + ErrInvalidParameters = errors.New("invalid parameters provided to create a subscription contract ORM") ) const ( tableName = "functions_subscriptions" ) -type cachedSubscriptionRow struct { +type storedSubscriptionRow struct { SubscriptionID uint64 Owner common.Address Balance int64 @@ -54,13 +54,14 @@ func NewORM(db *sqlx.DB, lggr logger.Logger, cfg pg.QConfig, routerContractAddre return &orm{ q: pg.NewQ(db, lggr, cfg), + lggr: lggr, routerContractAddress: routerContractAddress, }, nil } -func (o *orm) GetSubscriptions(offset, limit uint, qopts ...pg.QOpt) ([]CachedSubscription, error) { - var cacheSubscriptions []CachedSubscription - var cacheSubscriptionRows []cachedSubscriptionRow +func (o *orm) GetSubscriptions(offset, limit uint, qopts ...pg.QOpt) ([]StoredSubscription, error) { + var storedSubscriptions []StoredSubscription + var storedSubscriptionRows []storedSubscriptionRow stmt := fmt.Sprintf(` SELECT subscription_id, owner, balance, blocked_balance, proposed_owner, consumers, flags, router_contract_address FROM %s @@ -69,21 +70,21 @@ func (o *orm) GetSubscriptions(offset, limit uint, qopts ...pg.QOpt) ([]CachedSu OFFSET $2 LIMIT $3; `, tableName) - err := o.q.WithOpts(qopts...).Select(&cacheSubscriptionRows, stmt, o.routerContractAddress, offset, limit) + err := o.q.WithOpts(qopts...).Select(&storedSubscriptionRows, stmt, o.routerContractAddress, offset, limit) if err != nil { - return cacheSubscriptions, err + return storedSubscriptions, err } - for _, cs := range cacheSubscriptionRows { - cacheSubscriptions = append(cacheSubscriptions, cs.encode()) + for _, cs := range storedSubscriptionRows { + storedSubscriptions = append(storedSubscriptions, cs.encode()) } - return cacheSubscriptions, nil + return storedSubscriptions, nil } // UpsertSubscription will update if a subscription exists or create if it does not. // In case a subscription gets deleted we will update it with an owner address equal to 0x0. -func (o *orm) UpsertSubscription(subscription CachedSubscription, qopts ...pg.QOpt) error { +func (o *orm) UpsertSubscription(subscription StoredSubscription, qopts ...pg.QOpt) error { stmt := fmt.Sprintf(` INSERT INTO %s (subscription_id, owner, balance, blocked_balance, proposed_owner, consumers, flags, router_contract_address) VALUES ($1,$2,$3,$4,$5,$6,$7,$8) ON CONFLICT (subscription_id, router_contract_address) DO UPDATE @@ -97,6 +98,11 @@ func (o *orm) UpsertSubscription(subscription CachedSubscription, qopts ...pg.QO subscription.BlockedBalance = big.NewInt(0) } + var consumers [][]byte + for _, c := range subscription.Consumers { + consumers = append(consumers, c.Bytes()) + } + _, err := o.q.WithOpts(qopts...).Exec( stmt, subscription.SubscriptionID, @@ -104,21 +110,26 @@ func (o *orm) UpsertSubscription(subscription CachedSubscription, qopts ...pg.QO subscription.Balance.Int64(), subscription.BlockedBalance.Int64(), subscription.ProposedOwner, - subscription.Consumers, + consumers, subscription.Flags[:], o.routerContractAddress, ) + if err != nil { + return err + } + + o.lggr.Debugf("Successfully updated subscription: %d for routerContractAddress: %s", subscription.SubscriptionID, o.routerContractAddress) - return err + return nil } -func (cs *cachedSubscriptionRow) encode() CachedSubscription { +func (cs *storedSubscriptionRow) encode() StoredSubscription { consumers := make([]common.Address, 0) for _, csc := range cs.Consumers { consumers = append(consumers, common.BytesToAddress(csc)) } - return CachedSubscription{ + return StoredSubscription{ SubscriptionID: cs.SubscriptionID, IFunctionsSubscriptionsSubscription: functions_router.IFunctionsSubscriptionsSubscription{ Balance: big.NewInt(cs.Balance), diff --git a/core/services/gateway/handlers/functions/orm_test.go b/core/services/gateway/handlers/functions/subscriptions/orm_test.go similarity index 81% rename from core/services/gateway/handlers/functions/orm_test.go rename to core/services/gateway/handlers/functions/subscriptions/orm_test.go index 37ec24ea0b..6cb1146f03 100644 --- a/core/services/gateway/handlers/functions/orm_test.go +++ b/core/services/gateway/handlers/functions/subscriptions/orm_test.go @@ -1,4 +1,4 @@ -package functions_test +package subscriptions_test import ( "math/big" @@ -12,14 +12,14 @@ import ( "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/gateway/handlers/functions" + "github.com/smartcontractkit/chainlink/v2/core/services/gateway/handlers/functions/subscriptions" ) var ( defaultFlags = [32]byte{0x1, 0x2, 0x3} ) -func setupORM(t *testing.T) (functions.ORM, error) { +func setupORM(t *testing.T) (subscriptions.ORM, error) { t.Helper() var ( @@ -27,13 +27,13 @@ func setupORM(t *testing.T) (functions.ORM, error) { lggr = logger.TestLogger(t) ) - return functions.NewORM(db, lggr, pgtest.NewQConfig(true), testutils.NewAddress()) + return subscriptions.NewORM(db, lggr, pgtest.NewQConfig(true), testutils.NewAddress()) } -func createSubscriptions(t *testing.T, orm functions.ORM, amount int) []functions.CachedSubscription { - cachedSubscriptions := make([]functions.CachedSubscription, 0) +func seedSubscriptions(t *testing.T, orm subscriptions.ORM, amount int) []subscriptions.StoredSubscription { + storedSubscriptions := make([]subscriptions.StoredSubscription, 0) for i := amount; i > 0; i-- { - cs := functions.CachedSubscription{ + cs := subscriptions.StoredSubscription{ SubscriptionID: uint64(i), IFunctionsSubscriptionsSubscription: functions_router.IFunctionsSubscriptionsSubscription{ Balance: big.NewInt(10), @@ -44,11 +44,11 @@ func createSubscriptions(t *testing.T, orm functions.ORM, amount int) []function Flags: defaultFlags, }, } - cachedSubscriptions = append(cachedSubscriptions, cs) + storedSubscriptions = append(storedSubscriptions, cs) err := orm.UpsertSubscription(cs) require.NoError(t, err) } - return cachedSubscriptions + return storedSubscriptions } func TestORM_GetSubscriptions(t *testing.T) { @@ -56,21 +56,21 @@ func TestORM_GetSubscriptions(t *testing.T) { t.Run("fetch first page", func(t *testing.T) { orm, err := setupORM(t) require.NoError(t, err) - cachedSubscriptions := createSubscriptions(t, orm, 2) + storedSubscriptions := seedSubscriptions(t, orm, 2) results, err := orm.GetSubscriptions(0, 1) require.NoError(t, err) require.Equal(t, 1, len(results), "incorrect results length") - require.Equal(t, cachedSubscriptions[1], results[0]) + require.Equal(t, storedSubscriptions[1], results[0]) }) t.Run("fetch second page", func(t *testing.T) { orm, err := setupORM(t) require.NoError(t, err) - cachedSubscriptions := createSubscriptions(t, orm, 2) + storedSubscriptions := seedSubscriptions(t, orm, 2) results, err := orm.GetSubscriptions(1, 5) require.NoError(t, err) require.Equal(t, 1, len(results), "incorrect results length") - require.Equal(t, cachedSubscriptions[0], results[0]) + require.Equal(t, storedSubscriptions[0], results[0]) }) } @@ -80,14 +80,14 @@ func TestORM_UpsertSubscription(t *testing.T) { t.Run("create a subscription", func(t *testing.T) { orm, err := setupORM(t) require.NoError(t, err) - expected := functions.CachedSubscription{ + expected := subscriptions.StoredSubscription{ SubscriptionID: uint64(1), IFunctionsSubscriptionsSubscription: functions_router.IFunctionsSubscriptionsSubscription{ Balance: big.NewInt(10), Owner: testutils.NewAddress(), BlockedBalance: big.NewInt(20), ProposedOwner: common.Address{}, - Consumers: []common.Address{}, + Consumers: []common.Address{testutils.NewAddress()}, Flags: defaultFlags, }, } @@ -104,7 +104,7 @@ func TestORM_UpsertSubscription(t *testing.T) { orm, err := setupORM(t) require.NoError(t, err) - expectedUpdated := functions.CachedSubscription{ + expectedUpdated := subscriptions.StoredSubscription{ SubscriptionID: uint64(1), IFunctionsSubscriptionsSubscription: functions_router.IFunctionsSubscriptionsSubscription{ Balance: big.NewInt(10), @@ -118,7 +118,7 @@ func TestORM_UpsertSubscription(t *testing.T) { err = orm.UpsertSubscription(expectedUpdated) require.NoError(t, err) - expectedNotUpdated := functions.CachedSubscription{ + expectedNotUpdated := subscriptions.StoredSubscription{ SubscriptionID: uint64(2), IFunctionsSubscriptionsSubscription: functions_router.IFunctionsSubscriptionsSubscription{ Balance: big.NewInt(10), @@ -148,7 +148,7 @@ func TestORM_UpsertSubscription(t *testing.T) { orm, err := setupORM(t) require.NoError(t, err) - subscription := functions.CachedSubscription{ + subscription := subscriptions.StoredSubscription{ SubscriptionID: uint64(1), IFunctionsSubscriptionsSubscription: functions_router.IFunctionsSubscriptionsSubscription{ Balance: big.NewInt(10), @@ -187,12 +187,12 @@ func TestORM_UpsertSubscription(t *testing.T) { lggr = logger.TestLogger(t) ) - orm1, err := functions.NewORM(db, lggr, pgtest.NewQConfig(true), testutils.NewAddress()) + orm1, err := subscriptions.NewORM(db, lggr, pgtest.NewQConfig(true), testutils.NewAddress()) require.NoError(t, err) - orm2, err := functions.NewORM(db, lggr, pgtest.NewQConfig(true), testutils.NewAddress()) + orm2, err := subscriptions.NewORM(db, lggr, pgtest.NewQConfig(true), testutils.NewAddress()) require.NoError(t, err) - subscription := functions.CachedSubscription{ + subscription := subscriptions.StoredSubscription{ SubscriptionID: uint64(1), IFunctionsSubscriptionsSubscription: functions_router.IFunctionsSubscriptionsSubscription{ Balance: assets.Ether(10).ToInt(), @@ -229,18 +229,17 @@ func TestORM_UpsertSubscription(t *testing.T) { require.Equal(t, 1, len(results), "incorrect results length") }) } - func Test_NewORM(t *testing.T) { t.Run("OK-create_ORM", func(t *testing.T) { - _, err := functions.NewORM(pgtest.NewSqlxDB(t), logger.TestLogger(t), pgtest.NewQConfig(true), testutils.NewAddress()) + _, err := subscriptions.NewORM(pgtest.NewSqlxDB(t), logger.TestLogger(t), pgtest.NewQConfig(true), testutils.NewAddress()) require.NoError(t, err) }) t.Run("NOK-create_ORM_with_nil_fields", func(t *testing.T) { - _, err := functions.NewORM(nil, nil, nil, common.Address{}) + _, err := subscriptions.NewORM(nil, nil, nil, common.Address{}) require.Error(t, err) }) t.Run("NOK-create_ORM_with_empty_address", func(t *testing.T) { - _, err := functions.NewORM(pgtest.NewSqlxDB(t), logger.TestLogger(t), pgtest.NewQConfig(true), common.Address{}) + _, err := subscriptions.NewORM(pgtest.NewSqlxDB(t), logger.TestLogger(t), pgtest.NewQConfig(true), common.Address{}) require.Error(t, err) }) } diff --git a/core/services/gateway/handlers/functions/subscriptions.go b/core/services/gateway/handlers/functions/subscriptions/subscriptions.go similarity index 90% rename from core/services/gateway/handlers/functions/subscriptions.go rename to core/services/gateway/handlers/functions/subscriptions/subscriptions.go index 8bc9cf09e7..610aaa1d7f 100644 --- a/core/services/gateway/handlers/functions/subscriptions.go +++ b/core/services/gateway/handlers/functions/subscriptions/subscriptions.go @@ -1,4 +1,4 @@ -package functions +package subscriptions import ( "context" @@ -19,7 +19,7 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/utils" ) -const defaultCacheBatchSize = 100 +const defaultStoreBatchSize = 100 type OnchainSubscriptionsConfig struct { ContractAddress common.Address `json:"contractAddress"` @@ -27,7 +27,7 @@ type OnchainSubscriptionsConfig struct { UpdateFrequencySec uint `json:"updateFrequencySec"` UpdateTimeoutSec uint `json:"updateTimeoutSec"` UpdateRangeSize uint `json:"updateRangeSize"` - CacheBatchSize uint `json:"cacheBatchSize"` + StoreBatchSize uint `json:"storeBatchSize"` } // OnchainSubscriptions maintains a mirror of all subscriptions fetched from the blockchain (EVM-only). @@ -68,10 +68,10 @@ func NewOnchainSubscriptions(client evmclient.Client, config OnchainSubscription return nil, fmt.Errorf("unexpected error during functions_router.NewFunctionsRouter: %s", err) } - // if CacheBatchSize is not specified use the default value - if config.CacheBatchSize == 0 { - lggr.Info("CacheBatchSize not specified, using default size: ", defaultCacheBatchSize) - config.CacheBatchSize = defaultCacheBatchSize + // if StoreBatchSize is not specified use the default value + if config.StoreBatchSize == 0 { + lggr.Info("StoreBatchSize not specified, using default size: ", defaultStoreBatchSize) + config.StoreBatchSize = defaultStoreBatchSize } return &onchainSubscriptions{ @@ -99,7 +99,7 @@ func (s *onchainSubscriptions) Start(ctx context.Context) error { return errors.New("OnchainSubscriptionsConfig.UpdateRangeSize must be greater than 0") } - s.loadCachedSubscriptions() + s.loadStoredSubscriptions() s.closeWait.Add(1) go s.queryLoop() @@ -206,11 +206,11 @@ func (s *onchainSubscriptions) querySubscriptionsRange(ctx context.Context, bloc subscription := subscription updated := s.subscriptions.UpdateSubscription(subscriptionId, &subscription) if updated { - if err = s.orm.UpsertSubscription(CachedSubscription{ + if err = s.orm.UpsertSubscription(StoredSubscription{ SubscriptionID: subscriptionId, IFunctionsSubscriptionsSubscription: subscription, }); err != nil { - s.lggr.Errorf("unexpected error updating subscription in the cache: %w", err) + s.lggr.Errorf("unexpected error updating subscription in the db: %w", err) } } } @@ -226,10 +226,10 @@ func (s *onchainSubscriptions) getSubscriptionsCount(ctx context.Context, blockN }) } -func (s *onchainSubscriptions) loadCachedSubscriptions() { +func (s *onchainSubscriptions) loadStoredSubscriptions() { offset := uint(0) for { - csBatch, err := s.orm.GetSubscriptions(offset, s.config.CacheBatchSize) + csBatch, err := s.orm.GetSubscriptions(offset, s.config.StoreBatchSize) if err != nil { break } @@ -244,11 +244,11 @@ func (s *onchainSubscriptions) loadCachedSubscriptions() { Flags: cs.Flags, }) } - s.lggr.Debugw("Loading cached subscriptions", "offset", offset, "batch_length", len(csBatch)) + s.lggr.Debugw("Loading stored subscriptions", "offset", offset, "batch_length", len(csBatch)) - if len(csBatch) != int(s.config.CacheBatchSize) { + if len(csBatch) != int(s.config.StoreBatchSize) { break } - offset += s.config.CacheBatchSize + offset += s.config.StoreBatchSize } } diff --git a/core/services/gateway/handlers/functions/subscriptions_test.go b/core/services/gateway/handlers/functions/subscriptions/subscriptions_test.go similarity index 89% rename from core/services/gateway/handlers/functions/subscriptions_test.go rename to core/services/gateway/handlers/functions/subscriptions/subscriptions_test.go index 782dcc2332..be1d252043 100644 --- a/core/services/gateway/handlers/functions/subscriptions_test.go +++ b/core/services/gateway/handlers/functions/subscriptions/subscriptions_test.go @@ -1,4 +1,4 @@ -package functions_test +package subscriptions_test import ( "math/big" @@ -18,14 +18,14 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/functions/generated/functions_router" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/logger" - "github.com/smartcontractkit/chainlink/v2/core/services/gateway/handlers/functions" - fmocks "github.com/smartcontractkit/chainlink/v2/core/services/gateway/handlers/functions/mocks" + "github.com/smartcontractkit/chainlink/v2/core/services/gateway/handlers/functions/subscriptions" + smocks "github.com/smartcontractkit/chainlink/v2/core/services/gateway/handlers/functions/subscriptions/mocks" ) const ( validUser = "0x9ED925d8206a4f88a2f643b28B3035B315753Cd6" invalidUser = "0x6E2dc0F9DB014aE19888F539E59285D2Ea04244C" - cachedUser = "0x3E2dc0F9DB014aE19888F539E59285D2Ea04233G" + storedUser = "0x3E2dc0F9DB014aE19888F539E59285D2Ea04233G" ) func TestSubscriptions_OnePass(t *testing.T) { @@ -43,17 +43,17 @@ func TestSubscriptions_OnePass(t *testing.T) { To: &common.Address{}, Data: hexutil.MustDecode("0xec2454e500000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000003"), }, mock.Anything).Return(getSubscriptionsInRange, nil) - config := functions.OnchainSubscriptionsConfig{ + config := subscriptions.OnchainSubscriptionsConfig{ ContractAddress: common.Address{}, BlockConfirmations: 1, UpdateFrequencySec: 1, UpdateTimeoutSec: 1, UpdateRangeSize: 3, } - orm := fmocks.NewORM(t) - orm.On("GetSubscriptions", uint(0), uint(100)).Return([]functions.CachedSubscription{}, nil) + orm := smocks.NewORM(t) + orm.On("GetSubscriptions", uint(0), uint(100)).Return([]subscriptions.StoredSubscription{}, nil) orm.On("UpsertSubscription", mock.Anything).Return(nil) - subscriptions, err := functions.NewOnchainSubscriptions(client, config, orm, logger.TestLogger(t)) + subscriptions, err := subscriptions.NewOnchainSubscriptions(client, config, orm, logger.TestLogger(t)) require.NoError(t, err) err = subscriptions.Start(ctx) @@ -94,17 +94,17 @@ func TestSubscriptions_MultiPass(t *testing.T) { To: &common.Address{}, Data: hexutil.MustDecode("0xec2454e500000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000006"), }, mock.Anything).Return(getSubscriptionsInRange, nil) - config := functions.OnchainSubscriptionsConfig{ + config := subscriptions.OnchainSubscriptionsConfig{ ContractAddress: common.Address{}, BlockConfirmations: 1, UpdateFrequencySec: 1, UpdateTimeoutSec: 1, UpdateRangeSize: 3, } - orm := fmocks.NewORM(t) - orm.On("GetSubscriptions", uint(0), uint(100)).Return([]functions.CachedSubscription{}, nil) + orm := smocks.NewORM(t) + orm.On("GetSubscriptions", uint(0), uint(100)).Return([]subscriptions.StoredSubscription{}, nil) orm.On("UpsertSubscription", mock.Anything).Return(nil) - subscriptions, err := functions.NewOnchainSubscriptions(client, config, orm, logger.TestLogger(t)) + subscriptions, err := subscriptions.NewOnchainSubscriptions(client, config, orm, logger.TestLogger(t)) require.NoError(t, err) err = subscriptions.Start(ctx) @@ -118,7 +118,7 @@ func TestSubscriptions_MultiPass(t *testing.T) { }, testutils.WaitTimeout(t), time.Second).Should(gomega.BeTrue()) } -func TestSubscriptions_Cached(t *testing.T) { +func TestSubscriptions_Stored(t *testing.T) { getSubscriptionCount := hexutil.MustDecode("0x0000000000000000000000000000000000000000000000000000000000000003") getSubscriptionsInRange := hexutil.MustDecode("0x00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000001600000000000000000000000000000000000000000000000000000000000000240000000000000000000000000000000000000000000000000de0b6b3a76400000000000000000000000000000109e6e1b12098cc8f3a1e9719a817ec53ab9b35c000000000000000000000000000000000000000000000000000034e23f515cb0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000f5340f0968ee8b7dfd97e3327a6139273cc2c4fa000000000000000000000000000000000000000000000001158e460913d000000000000000000000000000009ed925d8206a4f88a2f643b28b3035b315753cd60000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001bc14b92364c75e20000000000000000000000009ed925d8206a4f88a2f643b28b3035b315753cd60000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000005439e5881a529f3ccbffc0e82d49f9db3950aefe") @@ -133,31 +133,31 @@ func TestSubscriptions_Cached(t *testing.T) { To: &common.Address{}, Data: hexutil.MustDecode("0xec2454e500000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000003"), }, mock.Anything).Return(getSubscriptionsInRange, nil) - config := functions.OnchainSubscriptionsConfig{ + config := subscriptions.OnchainSubscriptionsConfig{ ContractAddress: common.Address{}, BlockConfirmations: 1, UpdateFrequencySec: 1, UpdateTimeoutSec: 1, UpdateRangeSize: 3, - CacheBatchSize: 1, + StoreBatchSize: 1, } expectedBalance := big.NewInt(5) - orm := fmocks.NewORM(t) - orm.On("GetSubscriptions", uint(0), uint(1)).Return([]functions.CachedSubscription{ + orm := smocks.NewORM(t) + orm.On("GetSubscriptions", uint(0), uint(1)).Return([]subscriptions.StoredSubscription{ { SubscriptionID: 1, IFunctionsSubscriptionsSubscription: functions_router.IFunctionsSubscriptionsSubscription{ Balance: expectedBalance, - Owner: common.HexToAddress(cachedUser), + Owner: common.HexToAddress(storedUser), BlockedBalance: big.NewInt(10), }, }, }, nil) - orm.On("GetSubscriptions", uint(1), uint(1)).Return([]functions.CachedSubscription{}, nil) + orm.On("GetSubscriptions", uint(1), uint(1)).Return([]subscriptions.StoredSubscription{}, nil) orm.On("UpsertSubscription", mock.Anything).Return(nil) - subscriptions, err := functions.NewOnchainSubscriptions(client, config, orm, logger.TestLogger(t)) + subscriptions, err := subscriptions.NewOnchainSubscriptions(client, config, orm, logger.TestLogger(t)) require.NoError(t, err) err = subscriptions.Start(ctx) @@ -167,7 +167,7 @@ func TestSubscriptions_Cached(t *testing.T) { }) gomega.NewGomegaWithT(t).Eventually(func() bool { - actualBalance, err := subscriptions.GetMaxUserBalance(common.HexToAddress(cachedUser)) + actualBalance, err := subscriptions.GetMaxUserBalance(common.HexToAddress(storedUser)) return err == nil && assert.Equal(t, expectedBalance, actualBalance) }, testutils.WaitTimeout(t), time.Second).Should(gomega.BeTrue()) } diff --git a/core/services/gateway/handlers/functions/user_subscriptions.go b/core/services/gateway/handlers/functions/subscriptions/user_subscriptions.go similarity index 95% rename from core/services/gateway/handlers/functions/user_subscriptions.go rename to core/services/gateway/handlers/functions/subscriptions/user_subscriptions.go index 7e63720da7..ec506b6a86 100644 --- a/core/services/gateway/handlers/functions/user_subscriptions.go +++ b/core/services/gateway/handlers/functions/subscriptions/user_subscriptions.go @@ -1,4 +1,4 @@ -package functions +package subscriptions import ( "math/big" @@ -31,8 +31,8 @@ func NewUserSubscriptions() UserSubscriptions { } } -// CachedSubscription is used to populate the user subscription maps from a persistent layer like postgres. -type CachedSubscription struct { +// StoredSubscription is used to populate the user subscription maps from a persistent layer like postgres. +type StoredSubscription struct { SubscriptionID uint64 functions_router.IFunctionsSubscriptionsSubscription } diff --git a/core/services/gateway/handlers/functions/user_subscriptions_test.go b/core/services/gateway/handlers/functions/subscriptions/user_subscriptions_test.go similarity index 92% rename from core/services/gateway/handlers/functions/user_subscriptions_test.go rename to core/services/gateway/handlers/functions/subscriptions/user_subscriptions_test.go index 53827e07e1..4d58155735 100644 --- a/core/services/gateway/handlers/functions/user_subscriptions_test.go +++ b/core/services/gateway/handlers/functions/subscriptions/user_subscriptions_test.go @@ -1,4 +1,4 @@ -package functions_test +package subscriptions_test import ( "math/big" @@ -6,7 +6,7 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/functions/generated/functions_router" - "github.com/smartcontractkit/chainlink/v2/core/services/gateway/handlers/functions" + "github.com/smartcontractkit/chainlink/v2/core/services/gateway/handlers/functions/subscriptions" "github.com/stretchr/testify/assert" ) @@ -14,7 +14,7 @@ import ( func TestUserSubscriptions(t *testing.T) { t.Parallel() - us := functions.NewUserSubscriptions() + us := subscriptions.NewUserSubscriptions() t.Run("GetMaxUserBalance for unknown user", func(t *testing.T) { _, err := us.GetMaxUserBalance(utils.RandomAddress()) @@ -60,7 +60,7 @@ func TestUserSubscriptions_UpdateSubscription(t *testing.T) { t.Parallel() t.Run("update balance", func(t *testing.T) { - us := functions.NewUserSubscriptions() + us := subscriptions.NewUserSubscriptions() owner := utils.RandomAddress() updated := us.UpdateSubscription(1, &functions_router.IFunctionsSubscriptionsSubscription{ @@ -77,7 +77,7 @@ func TestUserSubscriptions_UpdateSubscription(t *testing.T) { }) t.Run("updated proposed owner", func(t *testing.T) { - us := functions.NewUserSubscriptions() + us := subscriptions.NewUserSubscriptions() owner := utils.RandomAddress() updated := us.UpdateSubscription(1, &functions_router.IFunctionsSubscriptionsSubscription{ @@ -94,7 +94,7 @@ func TestUserSubscriptions_UpdateSubscription(t *testing.T) { assert.True(t, updated) }) t.Run("remove subscriptions", func(t *testing.T) { - us := functions.NewUserSubscriptions() + us := subscriptions.NewUserSubscriptions() user2 := utils.RandomAddress() user2Balance1 := big.NewInt(50) user2Balance2 := big.NewInt(70) @@ -126,7 +126,7 @@ func TestUserSubscriptions_UpdateSubscription(t *testing.T) { }) t.Run("remove a non existing subscription", func(t *testing.T) { - us := functions.NewUserSubscriptions() + us := subscriptions.NewUserSubscriptions() updated := us.UpdateSubscription(3, &functions_router.IFunctionsSubscriptionsSubscription{ Owner: utils.ZeroAddress, }) @@ -134,7 +134,7 @@ func TestUserSubscriptions_UpdateSubscription(t *testing.T) { }) t.Run("no actual changes", func(t *testing.T) { - us := functions.NewUserSubscriptions() + us := subscriptions.NewUserSubscriptions() subscription := &functions_router.IFunctionsSubscriptionsSubscription{ Owner: utils.RandomAddress(), Balance: big.NewInt(25), diff --git a/core/services/gateway/integration_tests/gateway_integration_test.go b/core/services/gateway/integration_tests/gateway_integration_test.go index 9e4900efee..a2064b7a59 100644 --- a/core/services/gateway/integration_tests/gateway_integration_test.go +++ b/core/services/gateway/integration_tests/gateway_integration_test.go @@ -5,6 +5,7 @@ import ( "context" "crypto/ecdsa" "fmt" + "io" "net/http" "strings" "sync/atomic" @@ -36,18 +37,18 @@ Path = "/node" Port = 0 HandshakeTimeoutMillis = 2_000 MaxRequestBytes = 20_000 -ReadTimeoutMillis = 100 -RequestTimeoutMillis = 100 -WriteTimeoutMillis = 100 +ReadTimeoutMillis = 1000 +RequestTimeoutMillis = 1000 +WriteTimeoutMillis = 1000 [UserServerConfig] Path = "/user" Port = 0 ContentTypeHeader = "application/jsonrpc" MaxRequestBytes = 20_000 -ReadTimeoutMillis = 100 -RequestTimeoutMillis = 100 -WriteTimeoutMillis = 100 +ReadTimeoutMillis = 1000 +RequestTimeoutMillis = 1000 +WriteTimeoutMillis = 1000 [[Dons]] DonId = "test_don" @@ -72,6 +73,13 @@ Id = "test_gateway" URL = "%s" ` +const ( + messageId1 = "123" + messageId2 = "456" + + nodeResponsePayload = `{"response":"correct response"}` +) + func parseGatewayConfig(t *testing.T, tomlConfig string) *config.GatewayConfig { var cfg config.GatewayConfig err := toml.Unmarshal([]byte(tomlConfig), &cfg) @@ -94,6 +102,21 @@ type client struct { func (c *client) HandleGatewayMessage(ctx context.Context, gatewayId string, msg *api.Message) { c.done.Store(true) + // send back user's message without re-signing - should be ignored by the Gateway + _ = c.connector.SendToGateway(ctx, gatewayId, msg) + // send back a correct response + responseMsg := &api.Message{Body: api.MessageBody{ + MessageId: msg.Body.MessageId, + Method: "test", + DonId: "test_don", + Receiver: msg.Body.Sender, + Payload: []byte(nodeResponsePayload), + }} + err := responseMsg.Sign(c.privateKey) + if err != nil { + panic(err) + } + _ = c.connector.SendToGateway(ctx, gatewayId, responseMsg) } func (c *client) Sign(data ...[]byte) ([]byte, error) { @@ -111,7 +134,9 @@ func (*client) Close() error { func TestIntegration_Gateway_NoFullNodes_BasicConnectionAndMessage(t *testing.T) { t.Parallel() - nodeKeys := common.NewTestNodes(t, 1)[0] + testWallets := common.NewTestNodes(t, 2) + nodeKeys := testWallets[0] + userKeys := testWallets[1] // Verify that addresses in config are case-insensitive nodeKeys.Address = strings.ToUpper(nodeKeys.Address) @@ -132,17 +157,39 @@ func TestIntegration_Gateway_NoFullNodes_BasicConnectionAndMessage(t *testing.T) client.connector = connector servicetest.Run(t, connector) - // Send requests until one of them reaches Connector + // Send requests until one of them reaches Connector (i.e. the node) gomega.NewGomegaWithT(t).Eventually(func() bool { - msg := &api.Message{Body: api.MessageBody{MessageId: "123", Method: "test", DonId: "test_don"}} - require.NoError(t, msg.Sign(nodeKeys.PrivateKey)) - codec := api.JsonRPCCodec{} - rawMsg, err := codec.EncodeRequest(msg) - require.NoError(t, err) - req, err := http.NewRequestWithContext(testutils.Context(t), "POST", userUrl, bytes.NewBuffer(rawMsg)) - require.NoError(t, err) + req := newHttpRequestObject(t, messageId1, userUrl, userKeys.PrivateKey) httpClient := &http.Client{} _, _ = httpClient.Do(req) // could initially return error if Gateway is not fully initialized yet return client.done.Load() }, testutils.WaitTimeout(t), testutils.TestInterval).Should(gomega.Equal(true)) + + // Send another request and validate that response has correct content and sender + req := newHttpRequestObject(t, messageId2, userUrl, userKeys.PrivateKey) + httpClient := &http.Client{} + resp, err := httpClient.Do(req) + require.NoError(t, err) + require.Equal(t, http.StatusOK, resp.StatusCode) + + rawResp, err := io.ReadAll(resp.Body) + require.NoError(t, err) + codec := api.JsonRPCCodec{} + respMsg, err := codec.DecodeResponse(rawResp) + require.NoError(t, err) + require.NoError(t, respMsg.Validate()) + require.Equal(t, strings.ToLower(nodeKeys.Address), respMsg.Body.Sender) + require.Equal(t, messageId2, respMsg.Body.MessageId) + require.Equal(t, nodeResponsePayload, string(respMsg.Body.Payload)) +} + +func newHttpRequestObject(t *testing.T, messageId string, userUrl string, signerKey *ecdsa.PrivateKey) *http.Request { + msg := &api.Message{Body: api.MessageBody{MessageId: messageId, Method: "test", DonId: "test_don"}} + require.NoError(t, msg.Sign(signerKey)) + codec := api.JsonRPCCodec{} + rawMsg, err := codec.EncodeRequest(msg) + require.NoError(t, err) + req, err := http.NewRequestWithContext(testutils.Context(t), "POST", userUrl, bytes.NewBuffer(rawMsg)) + require.NoError(t, err) + return req } diff --git a/core/services/job/models.go b/core/services/job/models.go index 31032d58e0..17bac545be 100644 --- a/core/services/job/models.go +++ b/core/services/job/models.go @@ -277,7 +277,8 @@ func (s *OCROracleSpec) SetID(value string) error { return nil } -// JSONConfig is a Go mapping for JSON based database properties. +// JSONConfig is a map for config properties which are encoded as JSON in the database by implementing +// sql.Scanner and driver.Valuer. type JSONConfig map[string]interface{} // Bytes returns the raw bytes diff --git a/core/services/job/models_test.go b/core/services/job/models_test.go index ddbb815e73..fa15e3b1b2 100644 --- a/core/services/job/models_test.go +++ b/core/services/job/models_test.go @@ -1,10 +1,20 @@ package job import ( + _ "embed" "reflect" "testing" + "time" + "github.com/pelletier/go-toml/v2" + "github.com/stretchr/testify/require" + "gopkg.in/guregu/null.v4" + + "github.com/smartcontractkit/chainlink-common/pkg/codec" + "github.com/smartcontractkit/chainlink-common/pkg/types" "github.com/smartcontractkit/chainlink/v2/core/services/relay" + evmtypes "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/types" + "github.com/smartcontractkit/chainlink/v2/core/store/models" ) func TestOCR2OracleSpec_RelayIdentifier(t *testing.T) { @@ -71,3 +81,183 @@ func TestOCR2OracleSpec_RelayIdentifier(t *testing.T) { }) } } + +var ( + //go:embed testdata/compact.toml + compact string + //go:embed testdata/pretty.toml + pretty string +) + +func TestOCR2OracleSpec(t *testing.T) { + val := OCR2OracleSpec{ + Relay: relay.EVM, + PluginType: types.Median, + ContractID: "foo", + OCRKeyBundleID: null.StringFrom("bar"), + TransmitterID: null.StringFrom("baz"), + ContractConfigConfirmations: 1, + ContractConfigTrackerPollInterval: *models.NewInterval(time.Second), + RelayConfig: map[string]interface{}{ + "chainID": 1337, + "fromBlock": 42, + "chainReader": evmtypes.ChainReaderConfig{ + Contracts: map[string]evmtypes.ChainContractReader{ + "median": { + ContractABI: `[ + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "requester", + "type": "address" + }, + { + "indexed": false, + "internalType": "bytes32", + "name": "configDigest", + "type": "bytes32" + }, + { + "indexed": false, + "internalType": "uint32", + "name": "epoch", + "type": "uint32" + }, + { + "indexed": false, + "internalType": "uint8", + "name": "round", + "type": "uint8" + } + ], + "name": "RoundRequested", + "type": "event" + }, + { + "inputs": [], + "name": "latestTransmissionDetails", + "outputs": [ + { + "internalType": "bytes32", + "name": "configDigest", + "type": "bytes32" + }, + { + "internalType": "uint32", + "name": "epoch", + "type": "uint32" + }, + { + "internalType": "uint8", + "name": "round", + "type": "uint8" + }, + { + "internalType": "int192", + "name": "latestAnswer_", + "type": "int192" + }, + { + "internalType": "uint64", + "name": "latestTimestamp_", + "type": "uint64" + } + ], + "stateMutability": "view", + "type": "function" + } +] +`, + Configs: map[string]*evmtypes.ChainReaderDefinition{ + "LatestTransmissionDetails": { + ChainSpecificName: "latestTransmissionDetails", + OutputModifications: codec.ModifiersConfig{ + &codec.EpochToTimeModifierConfig{ + Fields: []string{"LatestTimestamp_"}, + }, + &codec.RenameModifierConfig{ + Fields: map[string]string{ + "LatestAnswer_": "LatestAnswer", + "LatestTimestamp_": "LatestTimestamp", + }, + }, + }, + }, + "LatestRoundRequested": { + ChainSpecificName: "RoundRequested", + ReadType: evmtypes.Event, + }, + }, + }, + }, + }, + "codec": evmtypes.CodecConfig{ + Configs: map[string]evmtypes.ChainCodecConfig{ + "MedianReport": { + TypeABI: `[ + { + "Name": "Timestamp", + "Type": "uint32" + }, + { + "Name": "Observers", + "Type": "bytes32" + }, + { + "Name": "Observations", + "Type": "int192[]" + }, + { + "Name": "JuelsPerFeeCoin", + "Type": "int192" + } +] +`, + }, + }, + }, + }, + PluginConfig: map[string]interface{}{"juelsPerFeeCoinSource": ` // data source 1 + ds1 [type=bridge name="%s"]; + ds1_parse [type=jsonparse path="data"]; + ds1_multiply [type=multiply times=2]; + + // data source 2 + ds2 [type=http method=GET url="%s"]; + ds2_parse [type=jsonparse path="data"]; + ds2_multiply [type=multiply times=2]; + + ds1 -> ds1_parse -> ds1_multiply -> answer1; + ds2 -> ds2_parse -> ds2_multiply -> answer1; + + answer1 [type=median index=0]; +`, + }, + } + + t.Run("marshal", func(t *testing.T) { + gotB, err := toml.Marshal(val) + require.NoError(t, err) + t.Log("marshaled:", string(gotB)) + require.Equal(t, compact, string(gotB)) + }) + + t.Run("round-trip", func(t *testing.T) { + var gotVal OCR2OracleSpec + require.NoError(t, toml.Unmarshal([]byte(compact), &gotVal)) + gotB, err := toml.Marshal(gotVal) + require.NoError(t, err) + require.Equal(t, compact, string(gotB)) + t.Run("pretty", func(t *testing.T) { + var gotVal OCR2OracleSpec + require.NoError(t, toml.Unmarshal([]byte(pretty), &gotVal)) + gotB, err := toml.Marshal(gotVal) + require.NoError(t, err) + t.Log("marshaled compact:", string(gotB)) + require.Equal(t, compact, string(gotB)) + }) + }) +} diff --git a/core/services/job/testdata/compact.toml b/core/services/job/testdata/compact.toml new file mode 100644 index 0000000000..9f0f54027d --- /dev/null +++ b/core/services/job/testdata/compact.toml @@ -0,0 +1,34 @@ +contractID = 'foo' +relay = 'evm' +chainID = '' +p2pv2Bootstrappers = [] +ocrKeyBundleID = 'bar' +monitoringEndpoint = '' +transmitterID = 'baz' +blockchainTimeout = '0s' +contractConfigTrackerPollInterval = '1s' +contractConfigConfirmations = 1 +pluginType = 'median' +captureEATelemetry = false +captureAutomationCustomTelemetry = false + +[relayConfig] +chainID = 1337 +fromBlock = 42 + +[relayConfig.chainReader] +[relayConfig.chainReader.contracts] +[relayConfig.chainReader.contracts.median] +contractABI = "[\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"requester\",\n \"type\": \"address\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"bytes32\",\n \"name\": \"configDigest\",\n \"type\": \"bytes32\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"uint32\",\n \"name\": \"epoch\",\n \"type\": \"uint32\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"uint8\",\n \"name\": \"round\",\n \"type\": \"uint8\"\n }\n ],\n \"name\": \"RoundRequested\",\n \"type\": \"event\"\n },\n {\n \"inputs\": [],\n \"name\": \"latestTransmissionDetails\",\n \"outputs\": [\n {\n \"internalType\": \"bytes32\",\n \"name\": \"configDigest\",\n \"type\": \"bytes32\"\n },\n {\n \"internalType\": \"uint32\",\n \"name\": \"epoch\",\n \"type\": \"uint32\"\n },\n {\n \"internalType\": \"uint8\",\n \"name\": \"round\",\n \"type\": \"uint8\"\n },\n {\n \"internalType\": \"int192\",\n \"name\": \"latestAnswer_\",\n \"type\": \"int192\"\n },\n {\n \"internalType\": \"uint64\",\n \"name\": \"latestTimestamp_\",\n \"type\": \"uint64\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n }\n]\n" + +[relayConfig.chainReader.contracts.median.configs] +LatestRoundRequested = "{\n \"chainSpecificName\": \"RoundRequested\",\n \"readType\": \"event\"\n}\n" +LatestTransmissionDetails = "{\n \"chainSpecificName\": \"latestTransmissionDetails\",\n \"outputModifications\": [\n {\n \"Fields\": [\n \"LatestTimestamp_\"\n ],\n \"Type\": \"epoch to time\"\n },\n {\n \"Fields\": {\n \"LatestAnswer_\": \"LatestAnswer\",\n \"LatestTimestamp_\": \"LatestTimestamp\"\n },\n \"Type\": \"rename\"\n }\n ]\n}\n" + +[relayConfig.codec] +[relayConfig.codec.configs] +[relayConfig.codec.configs.MedianReport] +typeABI = "[\n {\n \"Name\": \"Timestamp\",\n \"Type\": \"uint32\"\n },\n {\n \"Name\": \"Observers\",\n \"Type\": \"bytes32\"\n },\n {\n \"Name\": \"Observations\",\n \"Type\": \"int192[]\"\n },\n {\n \"Name\": \"JuelsPerFeeCoin\",\n \"Type\": \"int192\"\n }\n]\n" + +[pluginConfig] +juelsPerFeeCoinSource = " // data source 1\n ds1 [type=bridge name=\"%s\"];\n ds1_parse [type=jsonparse path=\"data\"];\n ds1_multiply [type=multiply times=2];\n\n // data source 2\n ds2 [type=http method=GET url=\"%s\"];\n ds2_parse [type=jsonparse path=\"data\"];\n ds2_multiply [type=multiply times=2];\n\n ds1 -> ds1_parse -> ds1_multiply -> answer1;\n ds2 -> ds2_parse -> ds2_multiply -> answer1;\n\n answer1 [type=median index=0];\n" diff --git a/core/services/job/testdata/pretty.toml b/core/services/job/testdata/pretty.toml new file mode 100644 index 0000000000..88bacff7db --- /dev/null +++ b/core/services/job/testdata/pretty.toml @@ -0,0 +1,149 @@ +relay = "evm" +pluginType = "median" +contractID = "foo" +ocrKeyBundleID = "bar" +transmitterID = "baz" +contractConfigConfirmations = 1 +contractConfigTrackerPollInterval = "1s" + +[relayConfig] +chainID = 1337 +fromBlock = 42 + +[relayConfig.chainReader.contracts.median] +contractABI = ''' +[ + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "requester", + "type": "address" + }, + { + "indexed": false, + "internalType": "bytes32", + "name": "configDigest", + "type": "bytes32" + }, + { + "indexed": false, + "internalType": "uint32", + "name": "epoch", + "type": "uint32" + }, + { + "indexed": false, + "internalType": "uint8", + "name": "round", + "type": "uint8" + } + ], + "name": "RoundRequested", + "type": "event" + }, + { + "inputs": [], + "name": "latestTransmissionDetails", + "outputs": [ + { + "internalType": "bytes32", + "name": "configDigest", + "type": "bytes32" + }, + { + "internalType": "uint32", + "name": "epoch", + "type": "uint32" + }, + { + "internalType": "uint8", + "name": "round", + "type": "uint8" + }, + { + "internalType": "int192", + "name": "latestAnswer_", + "type": "int192" + }, + { + "internalType": "uint64", + "name": "latestTimestamp_", + "type": "uint64" + } + ], + "stateMutability": "view", + "type": "function" + } +] +''' + +[relayConfig.chainReader.contracts.median.configs] +LatestRoundRequested = ''' +{ + "chainSpecificName": "RoundRequested", + "readType": "event" +} +''' +LatestTransmissionDetails = ''' +{ + "chainSpecificName": "latestTransmissionDetails", + "outputModifications": [ + { + "Fields": [ + "LatestTimestamp_" + ], + "Type": "epoch to time" + }, + { + "Fields": { + "LatestAnswer_": "LatestAnswer", + "LatestTimestamp_": "LatestTimestamp" + }, + "Type": "rename" + } + ] +} +''' + +[relayConfig.codec.configs.MedianReport] +typeABI = ''' +[ + { + "Name": "Timestamp", + "Type": "uint32" + }, + { + "Name": "Observers", + "Type": "bytes32" + }, + { + "Name": "Observations", + "Type": "int192[]" + }, + { + "Name": "JuelsPerFeeCoin", + "Type": "int192" + } +] +''' + +[pluginConfig] +juelsPerFeeCoinSource = """ + // data source 1 + ds1 [type=bridge name="%s"]; + ds1_parse [type=jsonparse path="data"]; + ds1_multiply [type=multiply times=2]; + + // data source 2 + ds2 [type=http method=GET url="%s"]; + ds2_parse [type=jsonparse path="data"]; + ds2_multiply [type=multiply times=2]; + + ds1 -> ds1_parse -> ds1_multiply -> answer1; + ds2 -> ds2_parse -> ds2_multiply -> answer1; + + answer1 [type=median index=0]; +""" \ No newline at end of file diff --git a/core/services/keystore/keys/ethkey/address.go b/core/services/keystore/keys/ethkey/address.go index 1b26413f63..0d93a4cdb2 100644 --- a/core/services/keystore/keys/ethkey/address.go +++ b/core/services/keystore/keys/ethkey/address.go @@ -53,10 +53,10 @@ func EIP55AddressFromAddress(a common.Address) EIP55Address { func (a EIP55Address) Bytes() []byte { return a.Address().Bytes() } // Big returns a big.Int representation -func (a EIP55Address) Big() *big.Int { return a.Address().Hash().Big() } +func (a EIP55Address) Big() *big.Int { return a.Address().Big() } // Hash returns the Hash -func (a EIP55Address) Hash() common.Hash { return a.Address().Hash() } +func (a EIP55Address) Hash() common.Hash { return common.BytesToHash(a.Bytes()) } // Address returns EIP55Address as a go-ethereum Address type func (a EIP55Address) Address() common.Address { return common.HexToAddress(a.String()) } diff --git a/core/services/ocr/contract_tracker.go b/core/services/ocr/contract_tracker.go index 1287e52e9b..9eabf93a83 100644 --- a/core/services/ocr/contract_tracker.go +++ b/core/services/ocr/contract_tracker.go @@ -402,7 +402,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.ChainCelo, config.ChainOptimismBedrock, config.ChainXDai, config.ChainKroma, config.ChainWeMix, config.ChainZkSync: + case "", config.ChainArbitrum, config.ChainCelo, config.ChainOptimismBedrock, config.ChainXDai, config.ChainKroma, config.ChainWeMix, config.ChainZkSync, config.ChainScroll: // continue } latestBlockHeight := t.getLatestBlockHeight() diff --git a/core/services/ocr2/delegate.go b/core/services/ocr2/delegate.go index 65b5c5e27e..9bf01849bf 100644 --- a/core/services/ocr2/delegate.go +++ b/core/services/ocr2/delegate.go @@ -25,6 +25,7 @@ import ( ocr2keepers20runner "github.com/smartcontractkit/chainlink-automation/pkg/v2/runner" ocr2keepers21config "github.com/smartcontractkit/chainlink-automation/pkg/v3/config" ocr2keepers21 "github.com/smartcontractkit/chainlink-automation/pkg/v3/plugin" + "github.com/smartcontractkit/chainlink/v2/core/config/env" "github.com/smartcontractkit/chainlink-vrf/altbn_128" dkgpkg "github.com/smartcontractkit/chainlink-vrf/dkg" @@ -48,7 +49,6 @@ import ( "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/ocr2key" - "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/models" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/dkg" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/dkg/persistence" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/functions" @@ -194,7 +194,7 @@ type jobPipelineConfig interface { } type mercuryConfig interface { - Credentials(credName string) *models.MercuryCredentials + Credentials(credName string) *types.MercuryCredentials Cache() coreconfig.MercuryCache TLS() coreconfig.MercuryTLS } @@ -529,12 +529,6 @@ type connProvider interface { ClientConn() grpc.ClientConnInterface } -func defaultPathFromPluginName(pluginName string) string { - // By default we install the command on the system path, in the - // form: `chainlink-` - return fmt.Sprintf("chainlink-%s", pluginName) -} - func (d *Delegate) newServicesGenericPlugin( ctx context.Context, lggr logger.SugaredLogger, @@ -555,9 +549,11 @@ func (d *Delegate) newServicesGenericPlugin( return nil, err } + plugEnv := env.NewPlugin(p.PluginName) + command := p.Command if command == "" { - command = defaultPathFromPluginName(p.PluginName) + command = plugEnv.Cmd.Get() } // Add the default pipeline to the pluginConfig @@ -612,8 +608,22 @@ func (d *Delegate) newServicesGenericPlugin( OffchainConfigDigester: provider.OffchainConfigDigester(), } + envVars, err := plugins.ParseEnvFile(plugEnv.Env.Get()) + if err != nil { + return nil, fmt.Errorf("failed to parse median env file: %w", err) + } + if len(p.EnvVars) > 0 { + for k, v := range p.EnvVars { + envVars = append(envVars, k+"="+v) + } + } + pluginLggr := lggr.Named(p.PluginName).Named(spec.ContractID).Named(spec.GetID()) - cmdFn, grpcOpts, err := d.cfg.RegisterLOOP(fmt.Sprintf("%s-%s-%s", p.PluginName, spec.ContractID, spec.GetID()), command) + cmdFn, grpcOpts, err := d.cfg.RegisterLOOP(plugins.CmdConfig{ + ID: fmt.Sprintf("%s-%s-%s", p.PluginName, spec.ContractID, spec.GetID()), + Cmd: command, + Env: envVars, + }) if err != nil { return nil, fmt.Errorf("failed to register loop: %w", err) } @@ -1113,12 +1123,13 @@ func (d *Delegate) newServicesOCR2Keepers21( provider, err := relayer.NewPluginProvider(ctx, types.RelayArgs{ - ExternalJobID: jb.ExternalJobID, - JobID: jb.ID, - ContractID: spec.ContractID, - New: d.isNewlyCreatedJob, - RelayConfig: spec.RelayConfig.Bytes(), - ProviderType: string(spec.PluginType), + ExternalJobID: jb.ExternalJobID, + JobID: jb.ID, + ContractID: spec.ContractID, + New: d.isNewlyCreatedJob, + RelayConfig: spec.RelayConfig.Bytes(), + ProviderType: string(spec.PluginType), + MercuryCredentials: mc, }, types.PluginArgs{ TransmitterID: transmitterID, PluginConfig: spec.PluginConfig.Bytes(), @@ -1132,12 +1143,7 @@ func (d *Delegate) newServicesOCR2Keepers21( return nil, errors.New("could not coerce PluginProvider to AutomationProvider") } - chain, err := d.legacyChains.Get(rid.ChainID) - if err != nil { - return nil, fmt.Errorf("keeper2 services: failed to get chain %s: %w", rid.ChainID, err) - } - - services, err := ocr2keeper.EVMDependencies21(jb, d.db, lggr, chain, mc, kb, d.cfg.Database()) + services, err := ocr2keeper.EVMDependencies21(kb) if err != nil { return nil, errors.Wrap(err, "could not build dependencies for ocr2 keepers") } @@ -1178,15 +1184,15 @@ func (d *Delegate) newServicesOCR2Keepers21( OffchainKeyring: kb, OnchainKeyring: services.Keyring(), LocalConfig: lc, - LogProvider: services.LogEventProvider(), - EventProvider: services.TransmitEventProvider(), - Runnable: services.Registry(), - Encoder: services.Encoder(), - BlockSubscriber: services.BlockSubscriber(), - RecoverableProvider: services.LogRecoverer(), - PayloadBuilder: services.PayloadBuilder(), - UpkeepProvider: services.UpkeepProvider(), - UpkeepStateUpdater: services.UpkeepStateStore(), + LogProvider: keeperProvider.LogEventProvider(), + EventProvider: keeperProvider.TransmitEventProvider(), + Runnable: keeperProvider.Registry(), + Encoder: keeperProvider.Encoder(), + BlockSubscriber: keeperProvider.BlockSubscriber(), + RecoverableProvider: keeperProvider.LogRecoverer(), + PayloadBuilder: keeperProvider.PayloadBuilder(), + UpkeepProvider: keeperProvider.UpkeepProvider(), + UpkeepStateUpdater: keeperProvider.UpkeepStateStore(), UpkeepTypeGetter: ocr2keeper21core.GetUpkeepType, WorkIDGenerator: ocr2keeper21core.UpkeepWorkID, // TODO: Clean up the config @@ -1203,12 +1209,12 @@ func (d *Delegate) newServicesOCR2Keepers21( automationServices := []job.ServiceCtx{ keeperProvider, - services.Registry(), - services.BlockSubscriber(), - services.LogEventProvider(), - services.LogRecoverer(), - services.UpkeepStateStore(), - services.TransmitEventProvider(), + keeperProvider.Registry(), + keeperProvider.BlockSubscriber(), + keeperProvider.LogEventProvider(), + keeperProvider.LogRecoverer(), + keeperProvider.UpkeepStateStore(), + keeperProvider.TransmitEventProvider(), pluginService, } @@ -1218,7 +1224,7 @@ func (d *Delegate) newServicesOCR2Keepers21( customTelemService, custErr := autotelemetry21.NewAutomationCustomTelemetryService( endpoint, lggr, - services.BlockSubscriber(), + keeperProvider.BlockSubscriber(), keeperProvider.ContractConfigTracker(), ) if custErr != nil { @@ -1254,7 +1260,7 @@ func (d *Delegate) newServicesOCR2Keepers20( return nil, fmt.Errorf("keepers2.0 services: failed to get chain (%s): %w", rid.ChainID, err2) } - keeperProvider, rgstry, encoder, logProvider, err2 := ocr2keeper.EVMDependencies20(jb, d.db, lggr, chain, d.ethKs) + keeperProvider, rgstry, encoder, logProvider, err2 := ocr2keeper.EVMDependencies20(jb, d.db, lggr, chain, d.ethKs, d.cfg.Database()) if err2 != nil { return nil, errors.Wrap(err2, "could not build dependencies for ocr2 keepers") } diff --git a/core/services/ocr2/models/models.go b/core/services/ocr2/models/models.go deleted file mode 100644 index 4d3b8bf532..0000000000 --- a/core/services/ocr2/models/models.go +++ /dev/null @@ -1,8 +0,0 @@ -package models - -type MercuryCredentials struct { - LegacyURL string - URL string - Username string - Password string -} diff --git a/core/services/ocr2/plugins/ccip/internal/ccipdata/usdc_reader_internal_test.go b/core/services/ocr2/plugins/ccip/internal/ccipdata/usdc_reader_internal_test.go index a1b63c529c..f7f51b8095 100644 --- a/core/services/ocr2/plugins/ccip/internal/ccipdata/usdc_reader_internal_test.go +++ b/core/services/ocr2/plugins/ccip/internal/ccipdata/usdc_reader_internal_test.go @@ -5,6 +5,7 @@ import ( "fmt" "testing" + "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" @@ -17,7 +18,8 @@ import ( ) func TestLogPollerClient_GetLastUSDCMessagePriorToLogIndexInTx(t *testing.T) { - txHash := utils.RandomAddress().Hash() + addr := utils.RandomAddress() + txHash := common.BytesToHash(addr[:]) ccipLogIndex := int64(100) expectedData := "0x000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000f80000000000000001000000020000000000048d71000000000000000000000000eb08f243e5d3fcff26a9e38ae5520a669f4019d000000000000000000000000023a04d5935ed8bc8e3eb78db3541f0abfb001c6e0000000000000000000000006cb3ed9b441eb674b58495c8b3324b59faff5243000000000000000000000000000000005425890298aed601595a70ab815c96711a31bc65000000000000000000000000ab4f961939bfe6a93567cc57c59eed7084ce2131000000000000000000000000000000000000000000000000000000000000271000000000000000000000000035e08285cfed1ef159236728f843286c55fc08610000000000000000" diff --git a/core/services/ocr2/plugins/ccip/internal/ccipdata/v1_0_0/onramp.go b/core/services/ocr2/plugins/ccip/internal/ccipdata/v1_0_0/onramp.go index 0214666fb7..20850d9f1b 100644 --- a/core/services/ocr2/plugins/ccip/internal/ccipdata/v1_0_0/onramp.go +++ b/core/services/ocr2/plugins/ccip/internal/ccipdata/v1_0_0/onramp.go @@ -37,7 +37,7 @@ type LeafHasher struct { } func GetMetaDataHash[H hashlib.Hash](ctx hashlib.Ctx[H], prefix [32]byte, sourceChainSelector uint64, onRampId common.Address, destChainSelector uint64) H { - paddedOnRamp := onRampId.Hash() + paddedOnRamp := common.BytesToHash(onRampId[:]) return ctx.Hash(utils.ConcatBytes(prefix[:], math.U256Bytes(big.NewInt(0).SetUint64(sourceChainSelector)), math.U256Bytes(big.NewInt(0).SetUint64(destChainSelector)), paddedOnRamp[:])) } diff --git a/core/services/ocr2/plugins/functions/config/config.go b/core/services/ocr2/plugins/functions/config/config.go index 13e0204250..e0e1ba3bfa 100644 --- a/core/services/ocr2/plugins/functions/config/config.go +++ b/core/services/ocr2/plugins/functions/config/config.go @@ -13,40 +13,42 @@ import ( "github.com/smartcontractkit/chainlink-common/pkg/assets" "github.com/smartcontractkit/chainlink/v2/core/services/gateway/connector" "github.com/smartcontractkit/chainlink/v2/core/services/gateway/handlers/common" - "github.com/smartcontractkit/chainlink/v2/core/services/gateway/handlers/functions" + "github.com/smartcontractkit/chainlink/v2/core/services/gateway/handlers/functions/allowlist" + "github.com/smartcontractkit/chainlink/v2/core/services/gateway/handlers/functions/subscriptions" s4PluginConfig "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/s4" "github.com/smartcontractkit/chainlink/v2/core/services/s4" ) // This config is part of the job spec and is loaded only once on node boot/job creation. type PluginConfig struct { - EnableRequestSignatureCheck bool `json:"enableRequestSignatureCheck"` - DONID string `json:"donID"` - ContractVersion uint32 `json:"contractVersion"` - MinRequestConfirmations uint32 `json:"minRequestConfirmations"` - MinResponseConfirmations uint32 `json:"minResponseConfirmations"` - MinIncomingConfirmations uint32 `json:"minIncomingConfirmations"` - PastBlocksToPoll uint32 `json:"pastBlocksToPoll"` - LogPollerCacheDurationSec uint32 `json:"logPollerCacheDurationSec"` // Duration to cache previously detected request or response logs such that they can be filtered when calling logpoller_wrapper.LatestEvents() - RequestTimeoutSec uint32 `json:"requestTimeoutSec"` - RequestTimeoutCheckFrequencySec uint32 `json:"requestTimeoutCheckFrequencySec"` - RequestTimeoutBatchLookupSize uint32 `json:"requestTimeoutBatchLookupSize"` - PruneMaxStoredRequests uint32 `json:"pruneMaxStoredRequests"` - PruneCheckFrequencySec uint32 `json:"pruneCheckFrequencySec"` - PruneBatchSize uint32 `json:"pruneBatchSize"` - ListenerEventHandlerTimeoutSec uint32 `json:"listenerEventHandlerTimeoutSec"` - ListenerEventsCheckFrequencyMillis uint32 `json:"listenerEventsCheckFrequencyMillis"` - ContractUpdateCheckFrequencySec uint32 `json:"contractUpdateCheckFrequencySec"` - MaxRequestSizeBytes uint32 `json:"maxRequestSizeBytes"` - MaxRequestSizesList []uint32 `json:"maxRequestSizesList"` - MaxSecretsSizesList []uint32 `json:"maxSecretsSizesList"` - MinimumSubscriptionBalance assets.Link `json:"minimumSubscriptionBalance"` - GatewayConnectorConfig *connector.ConnectorConfig `json:"gatewayConnectorConfig"` - OnchainAllowlist *functions.OnchainAllowlistConfig `json:"onchainAllowlist"` - OnchainSubscriptions *functions.OnchainSubscriptionsConfig `json:"onchainSubscriptions"` - RateLimiter *common.RateLimiterConfig `json:"rateLimiter"` - S4Constraints *s4.Constraints `json:"s4Constraints"` - DecryptionQueueConfig *DecryptionQueueConfig `json:"decryptionQueueConfig"` + EnableRequestSignatureCheck bool `json:"enableRequestSignatureCheck"` + DONID string `json:"donID"` + ContractVersion uint32 `json:"contractVersion"` + MinRequestConfirmations uint32 `json:"minRequestConfirmations"` + MinResponseConfirmations uint32 `json:"minResponseConfirmations"` + MinIncomingConfirmations uint32 `json:"minIncomingConfirmations"` + PastBlocksToPoll uint32 `json:"pastBlocksToPoll"` + LogPollerCacheDurationSec uint32 `json:"logPollerCacheDurationSec"` // Duration to cache previously detected request or response logs such that they can be filtered when calling logpoller_wrapper.LatestEvents() + RequestTimeoutSec uint32 `json:"requestTimeoutSec"` + RequestTimeoutCheckFrequencySec uint32 `json:"requestTimeoutCheckFrequencySec"` + RequestTimeoutBatchLookupSize uint32 `json:"requestTimeoutBatchLookupSize"` + PruneMaxStoredRequests uint32 `json:"pruneMaxStoredRequests"` + PruneCheckFrequencySec uint32 `json:"pruneCheckFrequencySec"` + PruneBatchSize uint32 `json:"pruneBatchSize"` + ListenerEventHandlerTimeoutSec uint32 `json:"listenerEventHandlerTimeoutSec"` + ListenerEventsCheckFrequencyMillis uint32 `json:"listenerEventsCheckFrequencyMillis"` + ContractUpdateCheckFrequencySec uint32 `json:"contractUpdateCheckFrequencySec"` + MaxRequestSizeBytes uint32 `json:"maxRequestSizeBytes"` + MaxRequestSizesList []uint32 `json:"maxRequestSizesList"` + MaxSecretsSizesList []uint32 `json:"maxSecretsSizesList"` + MinimumSubscriptionBalance assets.Link `json:"minimumSubscriptionBalance"` + AllowedHeartbeatInitiators []string `json:"allowedHeartbeatInitiators"` + GatewayConnectorConfig *connector.ConnectorConfig `json:"gatewayConnectorConfig"` + OnchainAllowlist *allowlist.OnchainAllowlistConfig `json:"onchainAllowlist"` + OnchainSubscriptions *subscriptions.OnchainSubscriptionsConfig `json:"onchainSubscriptions"` + RateLimiter *common.RateLimiterConfig `json:"rateLimiter"` + S4Constraints *s4.Constraints `json:"s4Constraints"` + DecryptionQueueConfig *DecryptionQueueConfig `json:"decryptionQueueConfig"` } type DecryptionQueueConfig struct { diff --git a/core/services/ocr2/plugins/functions/plugin.go b/core/services/ocr2/plugins/functions/plugin.go index c6cfa946ab..15e36f07b0 100644 --- a/core/services/ocr2/plugins/functions/plugin.go +++ b/core/services/ocr2/plugins/functions/plugin.go @@ -13,7 +13,6 @@ import ( "github.com/smartcontractkit/libocr/commontypes" libocr2 "github.com/smartcontractkit/libocr/offchainreporting2plus" - "github.com/smartcontractkit/chainlink-common/pkg/assets" "github.com/smartcontractkit/chainlink-common/pkg/utils/mailbox" "github.com/smartcontractkit/chainlink/v2/core/bridges" @@ -22,7 +21,8 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/services/functions" "github.com/smartcontractkit/chainlink/v2/core/services/gateway/connector" hc "github.com/smartcontractkit/chainlink/v2/core/services/gateway/handlers/common" - gwFunctions "github.com/smartcontractkit/chainlink/v2/core/services/gateway/handlers/functions" + gwAllowlist "github.com/smartcontractkit/chainlink/v2/core/services/gateway/handlers/functions/allowlist" + gwSubscriptions "github.com/smartcontractkit/chainlink/v2/core/services/gateway/handlers/functions/subscriptions" "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" @@ -135,7 +135,11 @@ func NewFunctionsServices(functionsOracleArgs, thresholdOracleArgs, s4OracleArgs allServices = append(allServices, job.NewServiceAdapter(functionsReportingPluginOracle)) if pluginConfig.GatewayConnectorConfig != nil && s4Storage != nil && pluginConfig.OnchainAllowlist != nil && pluginConfig.RateLimiter != nil && pluginConfig.OnchainSubscriptions != nil { - allowlist, err2 := gwFunctions.NewOnchainAllowlist(conf.Chain.Client(), *pluginConfig.OnchainAllowlist, conf.Logger) + allowlistORM, err := gwAllowlist.NewORM(conf.DB, conf.Logger, conf.QConfig, pluginConfig.OnchainAllowlist.ContractAddress) + if err != nil { + return nil, errors.Wrap(err, "failed to create allowlist ORM") + } + allowlist, err2 := gwAllowlist.NewOnchainAllowlist(conf.Chain.Client(), *pluginConfig.OnchainAllowlist, allowlistORM, conf.Logger) if err2 != nil { return nil, errors.Wrap(err, "failed to create OnchainAllowlist") } @@ -143,16 +147,16 @@ func NewFunctionsServices(functionsOracleArgs, thresholdOracleArgs, s4OracleArgs if err2 != nil { return nil, errors.Wrap(err, "failed to create a RateLimiter") } - gwFunctionsORM, err := gwFunctions.NewORM(conf.DB, conf.Logger, conf.QConfig, pluginConfig.OnchainSubscriptions.ContractAddress) + subscriptionsORM, err := gwSubscriptions.NewORM(conf.DB, conf.Logger, conf.QConfig, pluginConfig.OnchainSubscriptions.ContractAddress) if err != nil { - return nil, errors.Wrap(err, "failed to create functions ORM") + return nil, errors.Wrap(err, "failed to create subscriptions ORM") } - subscriptions, err2 := gwFunctions.NewOnchainSubscriptions(conf.Chain.Client(), *pluginConfig.OnchainSubscriptions, gwFunctionsORM, conf.Logger) + subscriptions, err2 := gwSubscriptions.NewOnchainSubscriptions(conf.Chain.Client(), *pluginConfig.OnchainSubscriptions, subscriptionsORM, conf.Logger) if err2 != nil { return nil, errors.Wrap(err, "failed to create a OnchainSubscriptions") } connectorLogger := conf.Logger.Named("GatewayConnector").With("jobName", conf.Job.PipelineSpec.JobName) - connector, err2 := NewConnector(pluginConfig.GatewayConnectorConfig, conf.EthKeystore, conf.Chain.ID(), s4Storage, allowlist, rateLimiter, subscriptions, functionsListener, offchainTransmitter, pluginConfig.MinimumSubscriptionBalance, connectorLogger) + connector, err2 := NewConnector(&pluginConfig, conf.EthKeystore, conf.Chain.ID(), s4Storage, allowlist, rateLimiter, subscriptions, functionsListener, offchainTransmitter, connectorLogger) if err2 != nil { return nil, errors.Wrap(err, "failed to create a GatewayConnector") } @@ -179,24 +183,26 @@ func NewFunctionsServices(functionsOracleArgs, thresholdOracleArgs, s4OracleArgs return allServices, nil } -func NewConnector(gwcCfg *connector.ConnectorConfig, ethKeystore keystore.Eth, chainID *big.Int, s4Storage s4.Storage, allowlist gwFunctions.OnchainAllowlist, rateLimiter *hc.RateLimiter, subscriptions gwFunctions.OnchainSubscriptions, listener functions.FunctionsListener, offchainTransmitter functions.OffchainTransmitter, minimumBalance assets.Link, lggr logger.Logger) (connector.GatewayConnector, error) { +func NewConnector(pluginConfig *config.PluginConfig, ethKeystore keystore.Eth, chainID *big.Int, s4Storage s4.Storage, allowlist gwAllowlist.OnchainAllowlist, rateLimiter *hc.RateLimiter, subscriptions gwSubscriptions.OnchainSubscriptions, listener functions.FunctionsListener, offchainTransmitter functions.OffchainTransmitter, lggr logger.Logger) (connector.GatewayConnector, error) { enabledKeys, err := ethKeystore.EnabledKeysForChain(chainID) if err != nil { return nil, err } - configuredNodeAddress := common.HexToAddress(gwcCfg.NodeAddress) + configuredNodeAddress := common.HexToAddress(pluginConfig.GatewayConnectorConfig.NodeAddress) idx := slices.IndexFunc(enabledKeys, func(key ethkey.KeyV2) bool { return key.Address == configuredNodeAddress }) if idx == -1 { return nil, errors.New("key for configured node address not found") } signerKey := enabledKeys[idx].ToEcdsaPrivKey() - nodeAddress := enabledKeys[idx].ID() + if enabledKeys[idx].ID() != pluginConfig.GatewayConnectorConfig.NodeAddress { + return nil, errors.New("node address mismatch") + } - handler, err := functions.NewFunctionsConnectorHandler(nodeAddress, signerKey, s4Storage, allowlist, rateLimiter, subscriptions, listener, offchainTransmitter, minimumBalance, lggr) + handler, err := functions.NewFunctionsConnectorHandler(pluginConfig, signerKey, s4Storage, allowlist, rateLimiter, subscriptions, listener, offchainTransmitter, lggr) if err != nil { return nil, err } - connector, err := connector.NewGatewayConnector(gwcCfg, handler, handler, utils.NewRealClock(), lggr) + connector, err := connector.NewGatewayConnector(pluginConfig.GatewayConnectorConfig, handler, handler, utils.NewRealClock(), lggr) if err != nil { return nil, err } diff --git a/core/services/ocr2/plugins/functions/plugin_test.go b/core/services/ocr2/plugins/functions/plugin_test.go index d77fabcc43..cd7956240d 100644 --- a/core/services/ocr2/plugins/functions/plugin_test.go +++ b/core/services/ocr2/plugins/functions/plugin_test.go @@ -8,15 +8,16 @@ import ( "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" - "github.com/smartcontractkit/chainlink-common/pkg/assets" "github.com/smartcontractkit/chainlink/v2/core/logger" sfmocks "github.com/smartcontractkit/chainlink/v2/core/services/functions/mocks" "github.com/smartcontractkit/chainlink/v2/core/services/gateway/connector" hc "github.com/smartcontractkit/chainlink/v2/core/services/gateway/handlers/common" - gfmocks "github.com/smartcontractkit/chainlink/v2/core/services/gateway/handlers/functions/mocks" + gfaMocks "github.com/smartcontractkit/chainlink/v2/core/services/gateway/handlers/functions/allowlist/mocks" + gfsMocks "github.com/smartcontractkit/chainlink/v2/core/services/gateway/handlers/functions/subscriptions/mocks" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/ethkey" ksmocks "github.com/smartcontractkit/chainlink/v2/core/services/keystore/mocks" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/functions" + "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/functions/config" s4mocks "github.com/smartcontractkit/chainlink/v2/core/services/s4/mocks" ) @@ -32,14 +33,17 @@ func TestNewConnector_Success(t *testing.T) { chainID := big.NewInt(80001) ethKeystore := ksmocks.NewEth(t) s4Storage := s4mocks.NewStorage(t) - allowlist := gfmocks.NewOnchainAllowlist(t) - subscriptions := gfmocks.NewOnchainSubscriptions(t) + allowlist := gfaMocks.NewOnchainAllowlist(t) + subscriptions := gfsMocks.NewOnchainSubscriptions(t) rateLimiter, err := hc.NewRateLimiter(hc.RateLimiterConfig{GlobalRPS: 100.0, GlobalBurst: 100, PerSenderRPS: 100.0, PerSenderBurst: 100}) require.NoError(t, err) listener := sfmocks.NewFunctionsListener(t) offchainTransmitter := sfmocks.NewOffchainTransmitter(t) ethKeystore.On("EnabledKeysForChain", mock.Anything).Return([]ethkey.KeyV2{keyV2}, nil) - _, err = functions.NewConnector(gwcCfg, ethKeystore, chainID, s4Storage, allowlist, rateLimiter, subscriptions, listener, offchainTransmitter, *assets.NewLinkFromJuels(0), logger.TestLogger(t)) + config := &config.PluginConfig{ + GatewayConnectorConfig: gwcCfg, + } + _, err = functions.NewConnector(config, ethKeystore, chainID, s4Storage, allowlist, rateLimiter, subscriptions, listener, offchainTransmitter, logger.TestLogger(t)) require.NoError(t, err) } @@ -57,13 +61,16 @@ func TestNewConnector_NoKeyForConfiguredAddress(t *testing.T) { chainID := big.NewInt(80001) ethKeystore := ksmocks.NewEth(t) s4Storage := s4mocks.NewStorage(t) - allowlist := gfmocks.NewOnchainAllowlist(t) - subscriptions := gfmocks.NewOnchainSubscriptions(t) + allowlist := gfaMocks.NewOnchainAllowlist(t) + subscriptions := gfsMocks.NewOnchainSubscriptions(t) rateLimiter, err := hc.NewRateLimiter(hc.RateLimiterConfig{GlobalRPS: 100.0, GlobalBurst: 100, PerSenderRPS: 100.0, PerSenderBurst: 100}) require.NoError(t, err) listener := sfmocks.NewFunctionsListener(t) offchainTransmitter := sfmocks.NewOffchainTransmitter(t) ethKeystore.On("EnabledKeysForChain", mock.Anything).Return([]ethkey.KeyV2{{Address: common.HexToAddress(addresses[1])}}, nil) - _, err = functions.NewConnector(gwcCfg, ethKeystore, chainID, s4Storage, allowlist, rateLimiter, subscriptions, listener, offchainTransmitter, *assets.NewLinkFromJuels(0), logger.TestLogger(t)) + config := &config.PluginConfig{ + GatewayConnectorConfig: gwcCfg, + } + _, err = functions.NewConnector(config, ethKeystore, chainID, s4Storage, allowlist, rateLimiter, subscriptions, listener, offchainTransmitter, logger.TestLogger(t)) require.Error(t, err) } diff --git a/core/services/ocr2/plugins/median/plugin.go b/core/services/ocr2/plugins/median/plugin.go deleted file mode 100644 index cad2099832..0000000000 --- a/core/services/ocr2/plugins/median/plugin.go +++ /dev/null @@ -1,68 +0,0 @@ -package median - -import ( - "context" - - "github.com/smartcontractkit/libocr/offchainreporting2/reportingplugin/median" - ocrtypes "github.com/smartcontractkit/libocr/offchainreporting2plus/types" - - "github.com/smartcontractkit/chainlink-common/pkg/logger" - "github.com/smartcontractkit/chainlink-common/pkg/loop" - "github.com/smartcontractkit/chainlink-common/pkg/services" - "github.com/smartcontractkit/chainlink-common/pkg/types" -) - -type Plugin struct { - loop.Plugin - stop services.StopChan -} - -func NewPlugin(lggr logger.Logger) *Plugin { - return &Plugin{Plugin: loop.Plugin{Logger: lggr}, stop: make(services.StopChan)} -} - -func (p *Plugin) NewMedianFactory(ctx context.Context, provider types.MedianProvider, dataSource, juelsPerFeeCoin median.DataSource, errorLog loop.ErrorLog) (loop.ReportingPluginFactory, error) { - var ctxVals loop.ContextValues - ctxVals.SetValues(ctx) - lggr := logger.With(p.Logger, ctxVals.Args()...) - - factory := median.NumericalMedianFactory{ - ContractTransmitter: provider.MedianContract(), - DataSource: dataSource, - JuelsPerFeeCoinDataSource: juelsPerFeeCoin, - Logger: logger.NewOCRWrapper(lggr, true, func(msg string) { - ctx, cancelFn := p.stop.NewCtx() - defer cancelFn() - if err := errorLog.SaveError(ctx, msg); err != nil { - lggr.Errorw("Unable to save error", "err", msg) - } - }), - OnchainConfigCodec: provider.OnchainConfigCodec(), - ReportCodec: provider.ReportCodec(), - } - s := &reportingPluginFactoryService{lggr: logger.Named(lggr, "ReportingPluginFactory"), ReportingPluginFactory: factory} - - p.SubService(s) - - return s, nil -} - -type reportingPluginFactoryService struct { - services.StateMachine - lggr logger.Logger - ocrtypes.ReportingPluginFactory -} - -func (r *reportingPluginFactoryService) Name() string { return r.lggr.Name() } - -func (r *reportingPluginFactoryService) Start(ctx context.Context) error { - return r.StartOnce("ReportingPluginFactory", func() error { return nil }) -} - -func (r *reportingPluginFactoryService) Close() error { - return r.StopOnce("ReportingPluginFactory", func() error { return nil }) -} - -func (r *reportingPluginFactoryService) HealthReport() map[string]error { - return map[string]error{r.Name(): r.Healthy()} -} diff --git a/core/services/ocr2/plugins/median/services.go b/core/services/ocr2/plugins/median/services.go index 4adfc306d6..2a874ff175 100644 --- a/core/services/ocr2/plugins/median/services.go +++ b/core/services/ocr2/plugins/median/services.go @@ -5,14 +5,9 @@ import ( "encoding/json" "errors" "fmt" - "math/big" "time" - "github.com/ethereum/go-ethereum/common" libocr "github.com/smartcontractkit/libocr/offchainreporting2plus" - ocr2types "github.com/smartcontractkit/libocr/offchainreporting2plus/types" - - mediantypes "github.com/smartcontractkit/libocr/offchainreporting2/reportingplugin/median" "github.com/smartcontractkit/chainlink-common/pkg/loop" "github.com/smartcontractkit/chainlink-common/pkg/types" @@ -57,21 +52,6 @@ func (m *medianConfig) JobPipelineResultWriteQueueDepth() uint64 { return m.jobPipelineResultWriteQueueDepth } -// This wrapper avoids the need to modify the signature of NewMedianFactory in all of the non-evm -// relay repos as well as its primary definition in chainlink-common. Once ChainReader is implemented -// and working on all 4 blockchain families, we can remove the original MedianContract() method from -// MedianProvider and pass medianContract as a separate param to NewMedianFactory -type medianProviderWrapper struct { - types.MedianProvider - contract mediantypes.MedianContract -} - -// Override relay's implementation of MedianContract with product plugin's implementation of -// MedianContract, making use of product-agnostic ChainReader to read the contract instead of relay MedianContract -func (m medianProviderWrapper) MedianContract() mediantypes.MedianContract { - return m.contract -} - func NewMedianServices(ctx context.Context, jb job.Job, isNewlyCreatedJob bool, @@ -145,24 +125,20 @@ func NewMedianServices(ctx context.Context, CreatedAt: time.Now(), }, lggr) - medianPluginCmd := env.MedianPluginCmd.Get() - medianLoopEnabled := medianPluginCmd != "" - - // TODO BCF-2821 handle this properly as this blocks Solana chain reader dev - if !medianLoopEnabled && medianProvider.ChainReader() != nil { - lggr.Info("Chain Reader enabled") - medianProvider = medianProviderWrapper{ - medianProvider, // attach newer MedianContract which uses ChainReader - newMedianContract(provider.ChainReader(), common.HexToAddress(spec.ContractID)), - } - } else { - lggr.Info("Chain Reader disabled") - } - - if medianLoopEnabled { + if cmdName := env.MedianPlugin.Cmd.Get(); cmdName != "" { // use unique logger names so we can use it to register a loop medianLggr := lggr.Named("Median").Named(spec.ContractID).Named(spec.GetID()) - cmdFn, telem, err2 := cfg.RegisterLOOP(medianLggr.Name(), medianPluginCmd) + envVars, err2 := plugins.ParseEnvFile(env.MedianPlugin.Env.Get()) + if err2 != nil { + err = fmt.Errorf("failed to parse median env file: %w", err2) + abort() + return + } + cmdFn, telem, err2 := cfg.RegisterLOOP(plugins.CmdConfig{ + ID: medianLggr.Name(), + Cmd: cmdName, + Env: envVars, + }) if err2 != nil { err = fmt.Errorf("failed to register loop: %w", err2) abort() @@ -192,49 +168,3 @@ func NewMedianServices(ctx context.Context, } return } - -type medianContract struct { - chainReader types.ChainReader - contract types.BoundContract -} - -type latestTransmissionDetailsResponse struct { - configDigest ocr2types.ConfigDigest - epoch uint32 - round uint8 - latestAnswer *big.Int - latestTimestamp time.Time -} - -type latestRoundRequested struct { - configDigest ocr2types.ConfigDigest - epoch uint32 - round uint8 -} - -func (m *medianContract) LatestTransmissionDetails(ctx context.Context) (configDigest ocr2types.ConfigDigest, epoch uint32, round uint8, latestAnswer *big.Int, latestTimestamp time.Time, err error) { - var resp latestTransmissionDetailsResponse - - err = m.chainReader.GetLatestValue(ctx, m.contract, "LatestTransmissionDetails", nil, &resp) - if err != nil { - return - } - - return resp.configDigest, resp.epoch, resp.round, resp.latestAnswer, resp.latestTimestamp, err -} - -func (m *medianContract) LatestRoundRequested(ctx context.Context, lookback time.Duration) (configDigest ocr2types.ConfigDigest, epoch uint32, round uint8, err error) { - var resp latestRoundRequested - - err = m.chainReader.GetLatestValue(ctx, m.contract, "LatestRoundReported", map[string]string{}, &resp) - if err != nil { - return - } - - return resp.configDigest, resp.epoch, resp.round, err -} - -func newMedianContract(chainReader types.ChainReader, address common.Address) *medianContract { - contract := types.BoundContract{Address: address.String(), Name: "median", Pending: true} - return &medianContract{chainReader, contract} -} diff --git a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/active_list.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/active_list.go index 7ea476ee77..55c01939cb 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/active_list.go +++ b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/active_list.go @@ -4,7 +4,9 @@ import ( "math/big" "sync" - ocr2keepers "github.com/smartcontractkit/chainlink-automation/pkg/v3/types" + "github.com/smartcontractkit/chainlink-automation/pkg/v3/types" + + ocr2keepers "github.com/smartcontractkit/chainlink-common/pkg/types/automation" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/core" ) @@ -18,7 +20,7 @@ type ActiveUpkeepList interface { // Remove removes entries from the list Remove(id ...*big.Int) int // View returns the list of IDs of the given type - View(...ocr2keepers.UpkeepType) []*big.Int + View(...types.UpkeepType) []*big.Int // IsActive returns true if the given ID is of an active upkeep IsActive(id *big.Int) bool Size() int @@ -81,7 +83,7 @@ func (al *activeList) Remove(ids ...*big.Int) int { } // View returns the list of IDs of the given type -func (al *activeList) View(upkeepTypes ...ocr2keepers.UpkeepType) []*big.Int { +func (al *activeList) View(upkeepTypes ...types.UpkeepType) []*big.Int { al.lock.RLock() defer al.lock.RUnlock() diff --git a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/active_list_test.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/active_list_test.go index 378589d177..d9f9c45d74 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/active_list_test.go +++ b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/active_list_test.go @@ -5,27 +5,29 @@ import ( "sort" "testing" + "github.com/smartcontractkit/chainlink-automation/pkg/v3/types" + "github.com/stretchr/testify/require" - ocr2keepers "github.com/smartcontractkit/chainlink-automation/pkg/v3/types" + ocr2keepers "github.com/smartcontractkit/chainlink-common/pkg/types/automation" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/core" ) func TestActiveUpkeepList(t *testing.T) { logIDs := []ocr2keepers.UpkeepIdentifier{ - core.GenUpkeepID(ocr2keepers.LogTrigger, "0"), - core.GenUpkeepID(ocr2keepers.LogTrigger, "1"), - core.GenUpkeepID(ocr2keepers.LogTrigger, "2"), - core.GenUpkeepID(ocr2keepers.LogTrigger, "3"), - core.GenUpkeepID(ocr2keepers.LogTrigger, "4"), + core.GenUpkeepID(types.LogTrigger, "0"), + core.GenUpkeepID(types.LogTrigger, "1"), + core.GenUpkeepID(types.LogTrigger, "2"), + core.GenUpkeepID(types.LogTrigger, "3"), + core.GenUpkeepID(types.LogTrigger, "4"), } conditionalIDs := []ocr2keepers.UpkeepIdentifier{ - core.GenUpkeepID(ocr2keepers.ConditionTrigger, "0"), - core.GenUpkeepID(ocr2keepers.ConditionTrigger, "1"), - core.GenUpkeepID(ocr2keepers.ConditionTrigger, "2"), - core.GenUpkeepID(ocr2keepers.ConditionTrigger, "3"), - core.GenUpkeepID(ocr2keepers.ConditionTrigger, "4"), + core.GenUpkeepID(types.ConditionTrigger, "0"), + core.GenUpkeepID(types.ConditionTrigger, "1"), + core.GenUpkeepID(types.ConditionTrigger, "2"), + core.GenUpkeepID(types.ConditionTrigger, "3"), + core.GenUpkeepID(types.ConditionTrigger, "4"), } tests := []struct { @@ -70,7 +72,7 @@ func TestActiveUpkeepList(t *testing.T) { for _, id := range tc.remove { require.False(t, al.IsActive(id)) } - logIds := al.View(ocr2keepers.LogTrigger) + logIds := al.View(types.LogTrigger) require.Equal(t, len(tc.expectedLogIds), len(logIds)) sort.Slice(logIds, func(i, j int) bool { return logIds[i].Cmp(logIds[j]) < 0 @@ -78,7 +80,7 @@ func TestActiveUpkeepList(t *testing.T) { for i := range logIds { require.Equal(t, tc.expectedLogIds[i], logIds[i]) } - conditionalIds := al.View(ocr2keepers.ConditionTrigger) + conditionalIds := al.View(types.ConditionTrigger) require.Equal(t, len(tc.expectedConditionalIds), len(conditionalIds)) sort.Slice(conditionalIds, func(i, j int) bool { return conditionalIds[i].Cmp(conditionalIds[j]) < 0 @@ -98,7 +100,7 @@ func TestActiveUpkeepList_error(t *testing.T) { al.items["-1"] = true al.items["100"] = true - keys := al.View(ocr2keepers.ConditionTrigger) + keys := al.View(types.ConditionTrigger) require.Equal(t, []*big.Int{big.NewInt(100)}, keys) }) } diff --git a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/autotelemetry21/custom_telemetry.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/autotelemetry21/custom_telemetry.go index e7e9728c3a..53303553db 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/autotelemetry21/custom_telemetry.go +++ b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/autotelemetry21/custom_telemetry.go @@ -10,12 +10,11 @@ import ( "github.com/smartcontractkit/libocr/commontypes" "github.com/smartcontractkit/libocr/offchainreporting2plus/types" - ocr2keepers "github.com/smartcontractkit/chainlink-automation/pkg/v3/types" + ocr2keepers "github.com/smartcontractkit/chainlink-common/pkg/types/automation" "github.com/smartcontractkit/chainlink-common/pkg/services" "github.com/smartcontractkit/chainlink/v2/core/logger" - evm21 "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21" "github.com/smartcontractkit/chainlink/v2/core/services/synchronization/telem" "github.com/smartcontractkit/chainlink/v2/core/static" "github.com/smartcontractkit/chainlink/v2/core/utils" @@ -24,7 +23,7 @@ import ( type AutomationCustomTelemetryService struct { services.StateMachine monitoringEndpoint commontypes.MonitoringEndpoint - blockSubscriber *evm21.BlockSubscriber + blockSubscriber ocr2keepers.BlockSubscriber blockSubChanID int threadCtrl utils.ThreadControl lggr logger.Logger @@ -34,7 +33,7 @@ type AutomationCustomTelemetryService struct { // NewAutomationCustomTelemetryService creates a telemetry service for new blocks and node version func NewAutomationCustomTelemetryService(me commontypes.MonitoringEndpoint, - lggr logger.Logger, blocksub *evm21.BlockSubscriber, configTracker types.ContractConfigTracker) (*AutomationCustomTelemetryService, error) { + lggr logger.Logger, blocksub ocr2keepers.BlockSubscriber, configTracker types.ContractConfigTracker) (*AutomationCustomTelemetryService, error) { return &AutomationCustomTelemetryService{ monitoringEndpoint: me, threadCtrl: utils.NewThreadControl(), diff --git a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/block_subscriber.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/block_subscriber.go index 134a75fc2c..9ae17c08ee 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/block_subscriber.go +++ b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/block_subscriber.go @@ -9,7 +9,7 @@ import ( "github.com/ethereum/go-ethereum/common" - ocr2keepers "github.com/smartcontractkit/chainlink-automation/pkg/v3/types" + ocr2keepers "github.com/smartcontractkit/chainlink-common/pkg/types/automation" "github.com/smartcontractkit/chainlink-common/pkg/services" diff --git a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/block_subscriber_test.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/block_subscriber_test.go index 41a43b951e..2be6a6a874 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/block_subscriber_test.go +++ b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/block_subscriber_test.go @@ -9,7 +9,7 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" - ocr2keepers "github.com/smartcontractkit/chainlink-automation/pkg/v3/types" + ocr2keepers "github.com/smartcontractkit/chainlink-common/pkg/types/automation" commonmocks "github.com/smartcontractkit/chainlink/v2/common/mocks" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/headtracker/types" diff --git a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/core/interfaces.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/core/interfaces.go index 49975855b5..4dd4d387a8 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/core/interfaces.go +++ b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/core/interfaces.go @@ -3,7 +3,7 @@ package core import ( "context" - ocr2keepers "github.com/smartcontractkit/chainlink-automation/pkg/v3/types" + ocr2keepers "github.com/smartcontractkit/chainlink-common/pkg/types/automation" ) // UpkeepStateReader is the interface for reading the current state of upkeeps. diff --git a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/core/mocks/upkeep_state_reader.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/core/mocks/upkeep_state_reader.go index 3167cf97aa..5a815987a8 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/core/mocks/upkeep_state_reader.go +++ b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/core/mocks/upkeep_state_reader.go @@ -5,9 +5,9 @@ package mocks import ( context "context" - mock "github.com/stretchr/testify/mock" + automation "github.com/smartcontractkit/chainlink-common/pkg/types/automation" - types "github.com/smartcontractkit/chainlink-automation/pkg/v3/types" + mock "github.com/stretchr/testify/mock" ) // UpkeepStateReader is an autogenerated mock type for the UpkeepStateReader type @@ -16,7 +16,7 @@ type UpkeepStateReader struct { } // SelectByWorkIDs provides a mock function with given fields: ctx, workIDs -func (_m *UpkeepStateReader) SelectByWorkIDs(ctx context.Context, workIDs ...string) ([]types.UpkeepState, error) { +func (_m *UpkeepStateReader) SelectByWorkIDs(ctx context.Context, workIDs ...string) ([]automation.UpkeepState, error) { _va := make([]interface{}, len(workIDs)) for _i := range workIDs { _va[_i] = workIDs[_i] @@ -30,16 +30,16 @@ func (_m *UpkeepStateReader) SelectByWorkIDs(ctx context.Context, workIDs ...str panic("no return value specified for SelectByWorkIDs") } - var r0 []types.UpkeepState + var r0 []automation.UpkeepState var r1 error - if rf, ok := ret.Get(0).(func(context.Context, ...string) ([]types.UpkeepState, error)); ok { + if rf, ok := ret.Get(0).(func(context.Context, ...string) ([]automation.UpkeepState, error)); ok { return rf(ctx, workIDs...) } - if rf, ok := ret.Get(0).(func(context.Context, ...string) []types.UpkeepState); ok { + if rf, ok := ret.Get(0).(func(context.Context, ...string) []automation.UpkeepState); ok { r0 = rf(ctx, workIDs...) } else { if ret.Get(0) != nil { - r0 = ret.Get(0).([]types.UpkeepState) + r0 = ret.Get(0).([]automation.UpkeepState) } } diff --git a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/core/payload.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/core/payload.go index ed5530ae7b..5077e7b74d 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/core/payload.go +++ b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/core/payload.go @@ -7,7 +7,7 @@ import ( "github.com/ethereum/go-ethereum/crypto" - ocr2keepers "github.com/smartcontractkit/chainlink-automation/pkg/v3/types" + ocr2keepers "github.com/smartcontractkit/chainlink-common/pkg/types/automation" ) var ( diff --git a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/core/payload_test.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/core/payload_test.go index cb3a67dde0..63de1f25ec 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/core/payload_test.go +++ b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/core/payload_test.go @@ -4,10 +4,12 @@ import ( "math/big" "testing" + "github.com/smartcontractkit/chainlink-automation/pkg/v3/types" + "github.com/ethereum/go-ethereum/common" "github.com/stretchr/testify/assert" - ocr2keepers "github.com/smartcontractkit/chainlink-automation/pkg/v3/types" + ocr2keepers "github.com/smartcontractkit/chainlink-common/pkg/types/automation" ) func TestWorkID(t *testing.T) { @@ -35,7 +37,7 @@ func TestWorkID(t *testing.T) { }, { name: "happy flow with extension", - upkeepID: GenUpkeepID(ocr2keepers.LogTrigger, "12345").String(), + upkeepID: GenUpkeepID(types.LogTrigger, "12345").String(), trigger: ocr2keepers.Trigger{ BlockNumber: 123, BlockHash: common.HexToHash("0xabcdef"), @@ -96,7 +98,7 @@ func TestNewUpkeepPayload(t *testing.T) { tests := []struct { name string upkeepID *big.Int - upkeepType ocr2keepers.UpkeepType + upkeepType types.UpkeepType trigger ocr2keepers.Trigger check []byte errored bool @@ -105,7 +107,7 @@ func TestNewUpkeepPayload(t *testing.T) { { name: "happy flow no extension", upkeepID: big.NewInt(111), - upkeepType: ocr2keepers.ConditionTrigger, + upkeepType: types.ConditionTrigger, trigger: ocr2keepers.Trigger{ BlockNumber: 11, BlockHash: common.HexToHash("0x11111"), @@ -116,7 +118,7 @@ func TestNewUpkeepPayload(t *testing.T) { { name: "happy flow with extension", upkeepID: big.NewInt(111), - upkeepType: ocr2keepers.LogTrigger, + upkeepType: types.LogTrigger, trigger: ocr2keepers.Trigger{ BlockNumber: 11, BlockHash: common.HexToHash("0x11111"), diff --git a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/core/testutil.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/core/testutil.go index 3c0eeb1c44..18f4a73de0 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/core/testutil.go +++ b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/core/testutil.go @@ -3,13 +3,15 @@ package core import ( "math/big" + "github.com/smartcontractkit/chainlink-automation/pkg/v3/types" + "github.com/ethereum/go-ethereum/common" - ocr2keepers "github.com/smartcontractkit/chainlink-automation/pkg/v3/types" + ocr2keepers "github.com/smartcontractkit/chainlink-common/pkg/types/automation" ) // GenUpkeepID generates an ocr2keepers.UpkeepIdentifier with a specific UpkeepType and some random string -func GenUpkeepID(uType ocr2keepers.UpkeepType, rand string) ocr2keepers.UpkeepIdentifier { +func GenUpkeepID(uType types.UpkeepType, rand string) ocr2keepers.UpkeepIdentifier { b := append([]byte{1}, common.LeftPadBytes([]byte{uint8(uType)}, 15)...) b = append(b, []byte(rand)...) b = common.RightPadBytes(b, 32-len(b)) diff --git a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/core/trigger.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/core/trigger.go index 02e6946c8f..b6ea739973 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/core/trigger.go +++ b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/core/trigger.go @@ -5,9 +5,9 @@ import ( "math/big" "strings" - "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/smartcontractkit/chainlink-automation/pkg/v3/types" - ocr2keepers "github.com/smartcontractkit/chainlink-automation/pkg/v3/types" + "github.com/ethereum/go-ethereum/accounts/abi" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/automation_utils_2_1" ) @@ -33,13 +33,13 @@ func PackTrigger(id *big.Int, trig triggerWrapper) ([]byte, error) { return nil, ErrInvalidUpkeepID } switch upkeepType { - case ocr2keepers.ConditionTrigger: + case types.ConditionTrigger: trig := automation_utils_2_1.KeeperRegistryBase21ConditionalTrigger{ BlockNum: trig.BlockNum, BlockHash: trig.BlockHash, } trigger, err = utilsABI.Pack("_conditionalTrigger", &trig) - case ocr2keepers.LogTrigger: + case types.LogTrigger: logTrig := automation_utils_2_1.KeeperRegistryBase21LogTrigger{ BlockNum: trig.BlockNum, BlockHash: trig.BlockHash, @@ -70,7 +70,7 @@ func UnpackTrigger(id *big.Int, raw []byte) (triggerWrapper, error) { return triggerWrapper{}, ErrInvalidUpkeepID } switch upkeepType { - case ocr2keepers.ConditionTrigger: + case types.ConditionTrigger: unpacked, err := utilsABI.Methods["_conditionalTrigger"].Inputs.Unpack(raw) if err != nil { return triggerWrapper{}, fmt.Errorf("%w: failed to unpack conditional trigger", err) @@ -84,7 +84,7 @@ func UnpackTrigger(id *big.Int, raw []byte) (triggerWrapper, error) { } copy(triggerW.BlockHash[:], converted.BlockHash[:]) return triggerW, nil - case ocr2keepers.LogTrigger: + case types.LogTrigger: unpacked, err := utilsABI.Methods["_logTrigger"].Inputs.Unpack(raw) if err != nil { return triggerWrapper{}, fmt.Errorf("%w: failed to unpack log trigger", err) diff --git a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/core/trigger_test.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/core/trigger_test.go index 366d59b639..0a5d3fba4a 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/core/trigger_test.go +++ b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/core/trigger_test.go @@ -9,7 +9,7 @@ import ( "github.com/ethereum/go-ethereum/common/hexutil" "github.com/stretchr/testify/assert" - ocr2keepers "github.com/smartcontractkit/chainlink-automation/pkg/v3/types" + ocr2keepers "github.com/smartcontractkit/chainlink-common/pkg/types/automation" ) func TestPackUnpackTrigger(t *testing.T) { diff --git a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/core/type.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/core/type.go index 7820b47e6e..b285db4d8a 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/core/type.go +++ b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/core/type.go @@ -3,7 +3,9 @@ package core import ( "math/big" - ocr2keepers "github.com/smartcontractkit/chainlink-automation/pkg/v3/types" + "github.com/smartcontractkit/chainlink-automation/pkg/v3/types" + + ocr2keepers "github.com/smartcontractkit/chainlink-common/pkg/types/automation" ) const ( @@ -17,17 +19,17 @@ const ( // GetUpkeepType returns the upkeep type from the given ID. // it follows the same logic as the contract, but performs it locally. -func GetUpkeepType(id ocr2keepers.UpkeepIdentifier) ocr2keepers.UpkeepType { +func GetUpkeepType(id ocr2keepers.UpkeepIdentifier) types.UpkeepType { for i := upkeepTypeStartIndex; i < upkeepTypeByteIndex; i++ { if id[i] != 0 { // old id - return ocr2keepers.ConditionTrigger + return types.ConditionTrigger } } typeByte := id[upkeepTypeByteIndex] - return ocr2keepers.UpkeepType(typeByte) + return types.UpkeepType(typeByte) } -func getUpkeepTypeFromBigInt(id *big.Int) (ocr2keepers.UpkeepType, bool) { +func getUpkeepTypeFromBigInt(id *big.Int) (types.UpkeepType, bool) { uid := &ocr2keepers.UpkeepIdentifier{} ok := uid.FromBigInt(id) return GetUpkeepType(*uid), ok diff --git a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/core/type_test.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/core/type_test.go index 6f81ca7690..1e4ec201b4 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/core/type_test.go +++ b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/core/type_test.go @@ -4,36 +4,38 @@ import ( "math/big" "testing" + "github.com/smartcontractkit/chainlink-automation/pkg/v3/types" + "github.com/stretchr/testify/assert" - ocr2keepers "github.com/smartcontractkit/chainlink-automation/pkg/v3/types" + ocr2keepers "github.com/smartcontractkit/chainlink-common/pkg/types/automation" ) func TestGetUpkeepType(t *testing.T) { tests := []struct { name string upkeepID []byte - upkeepType ocr2keepers.UpkeepType + upkeepType types.UpkeepType }{ { "zeroed id", big.NewInt(0).Bytes(), - ocr2keepers.ConditionTrigger, + types.ConditionTrigger, }, { "old id", []byte("5820911532554020907796191562093071158274499580927271776163559390280294438608"), - ocr2keepers.ConditionTrigger, + types.ConditionTrigger, }, { "condition trigger", - GenUpkeepID(ocr2keepers.ConditionTrigger, "").BigInt().Bytes(), - ocr2keepers.ConditionTrigger, + GenUpkeepID(types.ConditionTrigger, "").BigInt().Bytes(), + types.ConditionTrigger, }, { "log trigger", - GenUpkeepID(ocr2keepers.LogTrigger, "111").BigInt().Bytes(), - ocr2keepers.LogTrigger, + GenUpkeepID(types.LogTrigger, "111").BigInt().Bytes(), + types.LogTrigger, }, { "log trigger id", @@ -41,7 +43,7 @@ func TestGetUpkeepType(t *testing.T) { id, _ := big.NewInt(0).SetString("32329108151019397958065800113404894502874153543356521479058624064899121404671", 10) return id.Bytes() }(), - ocr2keepers.LogTrigger, + types.LogTrigger, }, } diff --git a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/encoding/encoder.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/encoding/encoder.go index 89fcbb4a0e..cdf2b0ea52 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/encoding/encoder.go +++ b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/encoding/encoder.go @@ -4,7 +4,9 @@ import ( "fmt" "math/big" - ocr2keepers "github.com/smartcontractkit/chainlink-automation/pkg/v3/types" + "github.com/smartcontractkit/chainlink-automation/pkg/v3/types" + + ocr2keepers "github.com/smartcontractkit/chainlink-common/pkg/types/automation" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/automation_utils_2_1" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/core" @@ -65,7 +67,7 @@ func (e reportEncoder) Encode(results ...ocr2keepers.CheckResult) ([]byte, error BlockHash: result.Trigger.BlockHash, } switch core.GetUpkeepType(result.UpkeepID) { - case ocr2keepers.LogTrigger: + case types.LogTrigger: triggerW.TxHash = result.Trigger.LogTriggerExtension.TxHash triggerW.LogIndex = result.Trigger.LogTriggerExtension.Index triggerW.LogBlockHash = result.Trigger.LogTriggerExtension.BlockHash @@ -107,7 +109,7 @@ func (e reportEncoder) Extract(raw []byte) ([]ocr2keepers.ReportedUpkeep, error) triggerW.BlockHash, ) switch core.GetUpkeepType(*id) { - case ocr2keepers.LogTrigger: + case types.LogTrigger: trigger.LogTriggerExtension = &ocr2keepers.LogTriggerExtension{} trigger.LogTriggerExtension.TxHash = triggerW.TxHash trigger.LogTriggerExtension.Index = triggerW.LogIndex diff --git a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/encoding/encoder_test.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/encoding/encoder_test.go index aa549ab3ec..600dc85172 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/encoding/encoder_test.go +++ b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/encoding/encoder_test.go @@ -7,10 +7,12 @@ import ( "os" "testing" + "github.com/smartcontractkit/chainlink-automation/pkg/v3/types" + "github.com/ethereum/go-ethereum/common" "github.com/stretchr/testify/assert" - ocr2keepers "github.com/smartcontractkit/chainlink-automation/pkg/v3/types" + ocr2keepers "github.com/smartcontractkit/chainlink-common/pkg/types/automation" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/core" ) @@ -44,7 +46,7 @@ func TestReportEncoder_EncodeExtract(t *testing.T) { { "happy flow single", []ocr2keepers.CheckResult{ - newResult(1, 1, core.GenUpkeepID(ocr2keepers.LogTrigger, "123"), 1, 1), + newResult(1, 1, core.GenUpkeepID(types.LogTrigger, "123"), 1, 1), }, 736, 1, @@ -54,9 +56,9 @@ func TestReportEncoder_EncodeExtract(t *testing.T) { { "happy flow multiple", []ocr2keepers.CheckResult{ - newResult(1, 1, core.GenUpkeepID(ocr2keepers.LogTrigger, "10"), 1, 1), - newResult(1, 1, core.GenUpkeepID(ocr2keepers.ConditionTrigger, "20"), 1, 1), - newResult(1, 1, core.GenUpkeepID(ocr2keepers.ConditionTrigger, "30"), 1, 1), + newResult(1, 1, core.GenUpkeepID(types.LogTrigger, "10"), 1, 1), + newResult(1, 1, core.GenUpkeepID(types.ConditionTrigger, "20"), 1, 1), + newResult(1, 1, core.GenUpkeepID(types.ConditionTrigger, "30"), 1, 1), }, 1312, 3, @@ -66,9 +68,9 @@ func TestReportEncoder_EncodeExtract(t *testing.T) { { "happy flow highest block number first", []ocr2keepers.CheckResult{ - newResult(1, 1, core.GenUpkeepID(ocr2keepers.ConditionTrigger, "30"), 1, 1), - newResult(1, 1, core.GenUpkeepID(ocr2keepers.ConditionTrigger, "20"), 1, 1), - newResult(1, 1, core.GenUpkeepID(ocr2keepers.LogTrigger, "10"), 1, 1), + newResult(1, 1, core.GenUpkeepID(types.ConditionTrigger, "30"), 1, 1), + newResult(1, 1, core.GenUpkeepID(types.ConditionTrigger, "20"), 1, 1), + newResult(1, 1, core.GenUpkeepID(types.LogTrigger, "10"), 1, 1), }, 1312, 1000, @@ -114,8 +116,8 @@ func TestReportEncoder_BackwardsCompatibility(t *testing.T) { packer: NewAbiPacker(), } results := []ocr2keepers.CheckResult{ - newResult(1, 2, core.GenUpkeepID(ocr2keepers.LogTrigger, "10"), 5, 6), - newResult(3, 4, core.GenUpkeepID(ocr2keepers.ConditionTrigger, "20"), 7, 8), + newResult(1, 2, core.GenUpkeepID(types.LogTrigger, "10"), 5, 6), + newResult(3, 4, core.GenUpkeepID(types.ConditionTrigger, "20"), 7, 8), } encoded, err := encoder.Encode(results...) assert.NoError(t, err) @@ -136,7 +138,7 @@ func newResult(block int64, checkBlock ocr2keepers.BlockNumber, id ocr2keepers.U BlockHash: [32]byte{1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8}, } - if tp == ocr2keepers.LogTrigger { + if tp == types.LogTrigger { trig.LogTriggerExtension = &ocr2keepers.LogTriggerExtension{ Index: 1, TxHash: common.HexToHash("0x1234567890123456789012345678901234567890123456789012345678901234"), diff --git a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/encoding/interface.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/encoding/interface.go index 4555a5b0b9..1f93fd3ee2 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/encoding/interface.go +++ b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/encoding/interface.go @@ -1,7 +1,7 @@ package encoding import ( - ocr2keepers "github.com/smartcontractkit/chainlink-automation/pkg/v3/types" + ocr2keepers "github.com/smartcontractkit/chainlink-common/pkg/types/automation" "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" diff --git a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/encoding/packer.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/encoding/packer.go index 7db8b220a4..81f4716a51 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/encoding/packer.go +++ b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/encoding/packer.go @@ -7,7 +7,7 @@ import ( "github.com/ethereum/go-ethereum/accounts/abi" "github.com/ethereum/go-ethereum/common/hexutil" - ocr2keepers "github.com/smartcontractkit/chainlink-automation/pkg/v3/types" + ocr2keepers "github.com/smartcontractkit/chainlink-common/pkg/types/automation" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/automation_utils_2_1" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/core" diff --git a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/encoding/packer_test.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/encoding/packer_test.go index 3f08fcf0a2..79221a620e 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/encoding/packer_test.go +++ b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/encoding/packer_test.go @@ -10,7 +10,7 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - ocr2keepers "github.com/smartcontractkit/chainlink-automation/pkg/v3/types" + ocr2keepers "github.com/smartcontractkit/chainlink-common/pkg/types/automation" "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" diff --git a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/logprovider/buffer.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/logprovider/buffer.go index f2c58fd30c..9f11a1fca0 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/logprovider/buffer.go +++ b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/logprovider/buffer.go @@ -8,17 +8,19 @@ import ( "sync/atomic" "github.com/smartcontractkit/chainlink-automation/pkg/v3/random" - ocr2keepers "github.com/smartcontractkit/chainlink-automation/pkg/v3/types" + ocr2keepers "github.com/smartcontractkit/chainlink-common/pkg/types/automation" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller" "github.com/smartcontractkit/chainlink/v2/core/logger" ) var ( - // maxLogsPerUpkeepInBlock is the maximum number of logs allowed per upkeep in a block. - maxLogsPerUpkeepInBlock = 32 - // maxLogsPerBlock is the maximum number of blocks in the buffer. - maxLogsPerBlock = 1024 + // defaultFastExecLogsHigh is the default upper bound / maximum number of logs that Automation is committed to process for each upkeep, + // based on available capacity, i.e. if there are no logs from other upkeeps. + // Used by Log buffer to limit the number of logs we are saving in memory for each upkeep in a block + defaultFastExecLogsHigh = 32 + // defaultNumOfLogUpkeeps is the default number of log upkeeps supported by the registry. + defaultNumOfLogUpkeeps = 50 ) // fetchedLog holds the log and the ID of the upkeep @@ -143,20 +145,20 @@ type logEventBuffer struct { // size is the number of blocks supported by the buffer size int32 - maxBlockLogs, maxUpkeepLogsPerBlock int + numOfLogUpkeeps, fastExecLogsHigh uint32 // blocks is the circular buffer of fetched blocks blocks []fetchedBlock // latestBlock is the latest block number seen latestBlock int64 } -func newLogEventBuffer(lggr logger.Logger, size, maxBlockLogs, maxUpkeepLogsPerBlock int) *logEventBuffer { +func newLogEventBuffer(lggr logger.Logger, size, numOfLogUpkeeps, fastExecLogsHigh int) *logEventBuffer { return &logEventBuffer{ - lggr: lggr.Named("KeepersRegistry.LogEventBuffer"), - size: int32(size), - blocks: make([]fetchedBlock, size), - maxBlockLogs: maxBlockLogs, - maxUpkeepLogsPerBlock: maxUpkeepLogsPerBlock, + lggr: lggr.Named("KeepersRegistry.LogEventBuffer"), + size: int32(size), + blocks: make([]fetchedBlock, size), + numOfLogUpkeeps: uint32(numOfLogUpkeeps), + fastExecLogsHigh: uint32(fastExecLogsHigh), } } @@ -168,6 +170,11 @@ func (b *logEventBuffer) bufferSize() int { return int(atomic.LoadInt32(&b.size)) } +func (b *logEventBuffer) SetLimits(numOfLogUpkeeps, fastExecLogsHigh int) { + atomic.StoreUint32(&b.numOfLogUpkeeps, uint32(numOfLogUpkeeps)) + atomic.StoreUint32(&b.fastExecLogsHigh, uint32(fastExecLogsHigh)) +} + // enqueue adds logs (if not exist) to the buffer, returning the number of logs added // minus the number of logs dropped. func (b *logEventBuffer) enqueue(id *big.Int, logs ...logpoller.Log) int { @@ -176,8 +183,8 @@ func (b *logEventBuffer) enqueue(id *big.Int, logs ...logpoller.Log) int { lggr := b.lggr.With("id", id.String()) - maxBlockLogs := b.maxBlockLogs - maxUpkeepLogs := b.maxUpkeepLogsPerBlock + maxBlockLogs := int(atomic.LoadUint32(&b.fastExecLogsHigh) * atomic.LoadUint32(&b.numOfLogUpkeeps)) + maxUpkeepLogs := int(atomic.LoadUint32(&b.fastExecLogsHigh)) latestBlock := b.latestBlockSeen() added, dropped := 0, 0 diff --git a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/logprovider/buffer_test.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/logprovider/buffer_test.go index 046c93a428..dca43ca14a 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/logprovider/buffer_test.go +++ b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/logprovider/buffer_test.go @@ -6,10 +6,12 @@ import ( "math/big" "testing" + "github.com/smartcontractkit/chainlink-automation/pkg/v3/types" + "github.com/ethereum/go-ethereum/common" "github.com/stretchr/testify/require" - ocr2keepers "github.com/smartcontractkit/chainlink-automation/pkg/v3/types" + ocr2keepers "github.com/smartcontractkit/chainlink-common/pkg/types/automation" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller" "github.com/smartcontractkit/chainlink/v2/core/logger" @@ -185,7 +187,7 @@ func TestLogEventBuffer_EnqueueDequeue(t *testing.T) { }) t.Run("enqueue logs overflow", func(t *testing.T) { - buf := newLogEventBuffer(logger.TestLogger(t), 2, 2, 10) + buf := newLogEventBuffer(logger.TestLogger(t), 2, 2, 2) require.Equal(t, 2, buf.enqueue(big.NewInt(1), logpoller.Log{BlockNumber: 1, TxHash: common.HexToHash("0x1"), LogIndex: 0}, @@ -197,6 +199,50 @@ func TestLogEventBuffer_EnqueueDequeue(t *testing.T) { buf.lock.Unlock() }) + t.Run("enqueue logs overflow with dynamic limits", func(t *testing.T) { + buf := newLogEventBuffer(logger.TestLogger(t), 2, 10, 2) + + require.Equal(t, 2, buf.enqueue(big.NewInt(1), + logpoller.Log{BlockNumber: 1, TxHash: common.HexToHash("0x1"), LogIndex: 0}, + logpoller.Log{BlockNumber: 1, TxHash: common.HexToHash("0x1"), LogIndex: 1}, + logpoller.Log{BlockNumber: 1, TxHash: common.HexToHash("0x1"), LogIndex: 2}, + )) + buf.SetLimits(10, 3) + require.Equal(t, 3, buf.enqueue(big.NewInt(1), + logpoller.Log{BlockNumber: 2, TxHash: common.HexToHash("0x21"), LogIndex: 0}, + logpoller.Log{BlockNumber: 2, TxHash: common.HexToHash("0x21"), LogIndex: 1}, + logpoller.Log{BlockNumber: 2, TxHash: common.HexToHash("0x21"), LogIndex: 2}, + logpoller.Log{BlockNumber: 2, TxHash: common.HexToHash("0x21"), LogIndex: 3}, + )) + + buf.lock.Lock() + defer buf.lock.Unlock() + require.Equal(t, 2, len(buf.blocks[0].logs)) + require.Equal(t, 3, len(buf.blocks[1].logs)) + }) + + t.Run("enqueue logs overflow with dynamic limits", func(t *testing.T) { + buf := newLogEventBuffer(logger.TestLogger(t), 2, 10, 2) + + require.Equal(t, 2, buf.enqueue(big.NewInt(1), + logpoller.Log{BlockNumber: 1, TxHash: common.HexToHash("0x1"), LogIndex: 0}, + logpoller.Log{BlockNumber: 1, TxHash: common.HexToHash("0x1"), LogIndex: 1}, + logpoller.Log{BlockNumber: 1, TxHash: common.HexToHash("0x1"), LogIndex: 2}, + logpoller.Log{BlockNumber: 1, TxHash: common.HexToHash("0x1"), LogIndex: 3}, + )) + buf.SetLimits(10, 3) + require.Equal(t, 3, buf.enqueue(big.NewInt(1), + logpoller.Log{BlockNumber: 2, TxHash: common.HexToHash("0x21"), LogIndex: 0}, + logpoller.Log{BlockNumber: 2, TxHash: common.HexToHash("0x21"), LogIndex: 1}, + logpoller.Log{BlockNumber: 2, TxHash: common.HexToHash("0x21"), LogIndex: 2}, + logpoller.Log{BlockNumber: 2, TxHash: common.HexToHash("0x21"), LogIndex: 3}, + )) + + buf.lock.Lock() + defer buf.lock.Unlock() + require.Equal(t, 2, len(buf.blocks[0].logs)) + }) + t.Run("enqueue block overflow", func(t *testing.T) { buf := newLogEventBuffer(logger.TestLogger(t), 3, 2, 10) @@ -378,7 +424,7 @@ func TestLogEventBuffer_FetchedBlock_Append(t *testing.T) { TxHash: common.HexToHash("0x1"), LogIndex: 0, }, - upkeepID: core.GenUpkeepID(ocr2keepers.LogTrigger, "111").BigInt(), + upkeepID: core.GenUpkeepID(types.LogTrigger, "111").BigInt(), }, maxBlockLogs: 10, maxUpkeepLogs: 2, @@ -392,7 +438,7 @@ func TestLogEventBuffer_FetchedBlock_Append(t *testing.T) { TxHash: common.HexToHash("0x1"), LogIndex: 0, }, - upkeepID: core.GenUpkeepID(ocr2keepers.LogTrigger, "111").BigInt(), + upkeepID: core.GenUpkeepID(types.LogTrigger, "111").BigInt(), }, }, }, @@ -406,7 +452,7 @@ func TestLogEventBuffer_FetchedBlock_Append(t *testing.T) { TxHash: common.HexToHash("0x1"), LogIndex: 0, }, - upkeepID: core.GenUpkeepID(ocr2keepers.LogTrigger, "111").BigInt(), + upkeepID: core.GenUpkeepID(types.LogTrigger, "111").BigInt(), }, }, visited: []fetchedLog{}, @@ -418,7 +464,7 @@ func TestLogEventBuffer_FetchedBlock_Append(t *testing.T) { TxHash: common.HexToHash("0x1"), LogIndex: 0, }, - upkeepID: core.GenUpkeepID(ocr2keepers.LogTrigger, "111").BigInt(), + upkeepID: core.GenUpkeepID(types.LogTrigger, "111").BigInt(), }, maxBlockLogs: 10, maxUpkeepLogs: 2, @@ -432,7 +478,7 @@ func TestLogEventBuffer_FetchedBlock_Append(t *testing.T) { TxHash: common.HexToHash("0x1"), LogIndex: 0, }, - upkeepID: core.GenUpkeepID(ocr2keepers.LogTrigger, "111").BigInt(), + upkeepID: core.GenUpkeepID(types.LogTrigger, "111").BigInt(), }, }, }, @@ -447,7 +493,7 @@ func TestLogEventBuffer_FetchedBlock_Append(t *testing.T) { TxHash: common.HexToHash("0x1"), LogIndex: 0, }, - upkeepID: core.GenUpkeepID(ocr2keepers.LogTrigger, "111").BigInt(), + upkeepID: core.GenUpkeepID(types.LogTrigger, "111").BigInt(), }, }, toAdd: []appendArgs{ @@ -458,7 +504,7 @@ func TestLogEventBuffer_FetchedBlock_Append(t *testing.T) { TxHash: common.HexToHash("0x1"), LogIndex: 0, }, - upkeepID: core.GenUpkeepID(ocr2keepers.LogTrigger, "111").BigInt(), + upkeepID: core.GenUpkeepID(types.LogTrigger, "111").BigInt(), }, maxBlockLogs: 10, maxUpkeepLogs: 2, @@ -480,7 +526,7 @@ func TestLogEventBuffer_FetchedBlock_Append(t *testing.T) { TxHash: common.HexToHash("0x1"), LogIndex: 0, }, - upkeepID: core.GenUpkeepID(ocr2keepers.LogTrigger, "111").BigInt(), + upkeepID: core.GenUpkeepID(types.LogTrigger, "111").BigInt(), }, maxBlockLogs: 10, maxUpkeepLogs: 2, @@ -493,7 +539,7 @@ func TestLogEventBuffer_FetchedBlock_Append(t *testing.T) { TxHash: common.HexToHash("0x1"), LogIndex: 1, }, - upkeepID: core.GenUpkeepID(ocr2keepers.LogTrigger, "111").BigInt(), + upkeepID: core.GenUpkeepID(types.LogTrigger, "111").BigInt(), }, maxBlockLogs: 10, maxUpkeepLogs: 2, @@ -506,7 +552,7 @@ func TestLogEventBuffer_FetchedBlock_Append(t *testing.T) { TxHash: common.HexToHash("0x1"), LogIndex: 2, }, - upkeepID: core.GenUpkeepID(ocr2keepers.LogTrigger, "111").BigInt(), + upkeepID: core.GenUpkeepID(types.LogTrigger, "111").BigInt(), }, maxBlockLogs: 10, maxUpkeepLogs: 2, @@ -521,7 +567,7 @@ func TestLogEventBuffer_FetchedBlock_Append(t *testing.T) { TxHash: common.HexToHash("0x1"), LogIndex: 1, }, - upkeepID: core.GenUpkeepID(ocr2keepers.LogTrigger, "111").BigInt(), + upkeepID: core.GenUpkeepID(types.LogTrigger, "111").BigInt(), }, { log: logpoller.Log{ @@ -529,7 +575,7 @@ func TestLogEventBuffer_FetchedBlock_Append(t *testing.T) { TxHash: common.HexToHash("0x1"), LogIndex: 2, }, - upkeepID: core.GenUpkeepID(ocr2keepers.LogTrigger, "111").BigInt(), + upkeepID: core.GenUpkeepID(types.LogTrigger, "111").BigInt(), }, }, }, @@ -546,7 +592,7 @@ func TestLogEventBuffer_FetchedBlock_Append(t *testing.T) { TxHash: common.HexToHash("0x1"), LogIndex: 0, }, - upkeepID: core.GenUpkeepID(ocr2keepers.LogTrigger, "111").BigInt(), + upkeepID: core.GenUpkeepID(types.LogTrigger, "111").BigInt(), }, maxBlockLogs: 2, maxUpkeepLogs: 4, @@ -559,7 +605,7 @@ func TestLogEventBuffer_FetchedBlock_Append(t *testing.T) { TxHash: common.HexToHash("0x1"), LogIndex: 1, }, - upkeepID: core.GenUpkeepID(ocr2keepers.LogTrigger, "111").BigInt(), + upkeepID: core.GenUpkeepID(types.LogTrigger, "111").BigInt(), }, maxBlockLogs: 2, maxUpkeepLogs: 4, @@ -572,7 +618,7 @@ func TestLogEventBuffer_FetchedBlock_Append(t *testing.T) { TxHash: common.HexToHash("0x1"), LogIndex: 2, }, - upkeepID: core.GenUpkeepID(ocr2keepers.LogTrigger, "111").BigInt(), + upkeepID: core.GenUpkeepID(types.LogTrigger, "111").BigInt(), }, maxBlockLogs: 2, maxUpkeepLogs: 4, @@ -587,7 +633,7 @@ func TestLogEventBuffer_FetchedBlock_Append(t *testing.T) { TxHash: common.HexToHash("0x1"), LogIndex: 1, }, - upkeepID: core.GenUpkeepID(ocr2keepers.LogTrigger, "111").BigInt(), + upkeepID: core.GenUpkeepID(types.LogTrigger, "111").BigInt(), }, { log: logpoller.Log{ @@ -595,7 +641,7 @@ func TestLogEventBuffer_FetchedBlock_Append(t *testing.T) { TxHash: common.HexToHash("0x1"), LogIndex: 2, }, - upkeepID: core.GenUpkeepID(ocr2keepers.LogTrigger, "111").BigInt(), + upkeepID: core.GenUpkeepID(types.LogTrigger, "111").BigInt(), }, }, }, @@ -676,7 +722,7 @@ func TestLogEventBuffer_FetchedBlock_Sort(t *testing.T) { TxHash: common.HexToHash("0xb711bd1103927611ee41152aa8ae27f3330"), LogIndex: 0, }, - upkeepID: core.GenUpkeepID(ocr2keepers.LogTrigger, "111").BigInt(), + upkeepID: core.GenUpkeepID(types.LogTrigger, "111").BigInt(), }, { log: logpoller.Log{ @@ -685,7 +731,7 @@ func TestLogEventBuffer_FetchedBlock_Sort(t *testing.T) { TxHash: common.HexToHash("0xa651bd1109922111ee411525ebae27f3fb6"), LogIndex: 0, }, - upkeepID: core.GenUpkeepID(ocr2keepers.LogTrigger, "222").BigInt(), + upkeepID: core.GenUpkeepID(types.LogTrigger, "222").BigInt(), }, { log: logpoller.Log{ @@ -694,7 +740,7 @@ func TestLogEventBuffer_FetchedBlock_Sort(t *testing.T) { TxHash: common.HexToHash("0xa651bd1109922111ee411525ebae27f3fb6"), LogIndex: 4, }, - upkeepID: core.GenUpkeepID(ocr2keepers.LogTrigger, "111").BigInt(), + upkeepID: core.GenUpkeepID(types.LogTrigger, "111").BigInt(), }, { log: logpoller.Log{ @@ -703,7 +749,7 @@ func TestLogEventBuffer_FetchedBlock_Sort(t *testing.T) { TxHash: common.HexToHash("0xa651bd1109922111ee411525ebae27f3fb6"), LogIndex: 3, }, - upkeepID: core.GenUpkeepID(ocr2keepers.LogTrigger, "222").BigInt(), + upkeepID: core.GenUpkeepID(types.LogTrigger, "222").BigInt(), }, { log: logpoller.Log{ @@ -712,7 +758,7 @@ func TestLogEventBuffer_FetchedBlock_Sort(t *testing.T) { TxHash: common.HexToHash("0xa651bd1109922111ee411525ebae27f3fb6"), LogIndex: 2, }, - upkeepID: core.GenUpkeepID(ocr2keepers.LogTrigger, "111").BigInt(), + upkeepID: core.GenUpkeepID(types.LogTrigger, "111").BigInt(), }, { log: logpoller.Log{ @@ -721,7 +767,7 @@ func TestLogEventBuffer_FetchedBlock_Sort(t *testing.T) { TxHash: common.HexToHash("0xa651bd1109922111ee411525ebae27f3fb6"), LogIndex: 5, }, - upkeepID: core.GenUpkeepID(ocr2keepers.LogTrigger, "111").BigInt(), + upkeepID: core.GenUpkeepID(types.LogTrigger, "111").BigInt(), }, { log: logpoller.Log{ @@ -730,7 +776,7 @@ func TestLogEventBuffer_FetchedBlock_Sort(t *testing.T) { TxHash: common.HexToHash("0xa651bd1109922111ee411525ebae27f3fb6"), LogIndex: 3, }, - upkeepID: core.GenUpkeepID(ocr2keepers.LogTrigger, "111").BigInt(), + upkeepID: core.GenUpkeepID(types.LogTrigger, "111").BigInt(), }, { log: logpoller.Log{ @@ -739,7 +785,7 @@ func TestLogEventBuffer_FetchedBlock_Sort(t *testing.T) { TxHash: common.HexToHash("0xa651bd1109922111ee411525ebae27f3fb6"), LogIndex: 1, }, - upkeepID: core.GenUpkeepID(ocr2keepers.LogTrigger, "111").BigInt(), + upkeepID: core.GenUpkeepID(types.LogTrigger, "111").BigInt(), }, }, beforeSort: []string{ @@ -801,7 +847,7 @@ func TestLogEventBuffer_FetchedBlock_Clone(t *testing.T) { TxHash: common.HexToHash("0x1"), LogIndex: 0, }, - upkeepID: core.GenUpkeepID(ocr2keepers.LogTrigger, "111").BigInt(), + upkeepID: core.GenUpkeepID(types.LogTrigger, "111").BigInt(), }, { log: logpoller.Log{ @@ -809,7 +855,7 @@ func TestLogEventBuffer_FetchedBlock_Clone(t *testing.T) { TxHash: common.HexToHash("0x1"), LogIndex: 2, }, - upkeepID: core.GenUpkeepID(ocr2keepers.LogTrigger, "111").BigInt(), + upkeepID: core.GenUpkeepID(types.LogTrigger, "111").BigInt(), }, }, } diff --git a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/logprovider/filter_test.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/logprovider/filter_test.go index 8b3b836f87..75684d17bd 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/logprovider/filter_test.go +++ b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/logprovider/filter_test.go @@ -74,7 +74,7 @@ func TestUpkeepFilter_Select(t *testing.T) { "no selector configured - all logs are returned", upkeepFilter{ selector: 0, - topics: []common.Hash{contractAddress.Hash(), emptyTopic, emptyTopic, emptyTopic}, + topics: []common.Hash{common.BytesToHash(contractAddress.Bytes()), emptyTopic, emptyTopic, emptyTopic}, upkeepID: uid, }, []logpoller.Log{ @@ -90,7 +90,7 @@ func TestUpkeepFilter_Select(t *testing.T) { "selector is 1 - topics 1 is used to filter logs", upkeepFilter{ selector: 1, - topics: []common.Hash{contractAddress.Hash(), common.HexToHash(topic10), emptyTopic, emptyTopic}, + topics: []common.Hash{common.BytesToHash(contractAddress.Bytes()), common.HexToHash(topic10), emptyTopic, emptyTopic}, upkeepID: uid, }, []logpoller.Log{ @@ -105,7 +105,7 @@ func TestUpkeepFilter_Select(t *testing.T) { "selector is 2 - topic 2 is used to filter logs", upkeepFilter{ selector: 2, - topics: []common.Hash{contractAddress.Hash(), emptyTopic, common.HexToHash(topic21), emptyTopic}, + topics: []common.Hash{common.BytesToHash(contractAddress.Bytes()), emptyTopic, common.HexToHash(topic21), emptyTopic}, upkeepID: uid, }, []logpoller.Log{ @@ -120,7 +120,7 @@ func TestUpkeepFilter_Select(t *testing.T) { "selector is 3 - topics 1 2 are used to filter logs", upkeepFilter{ selector: 3, - topics: []common.Hash{contractAddress.Hash(), common.HexToHash(topic10), common.HexToHash(topic21), emptyTopic}, + topics: []common.Hash{common.BytesToHash(contractAddress.Bytes()), common.HexToHash(topic10), common.HexToHash(topic21), emptyTopic}, upkeepID: uid, }, []logpoller.Log{ @@ -137,7 +137,7 @@ func TestUpkeepFilter_Select(t *testing.T) { "selector is 4 - topic 3 is used to filter logs", upkeepFilter{ selector: 4, - topics: []common.Hash{contractAddress.Hash(), emptyTopic, emptyTopic, common.HexToHash(topic31)}, + topics: []common.Hash{common.BytesToHash(contractAddress.Bytes()), emptyTopic, emptyTopic, common.HexToHash(topic31)}, upkeepID: uid, }, []logpoller.Log{ @@ -152,7 +152,7 @@ func TestUpkeepFilter_Select(t *testing.T) { "selector is 5 - topics 1 3 are used to filter logs", upkeepFilter{ selector: 5, - topics: []common.Hash{contractAddress.Hash(), common.HexToHash(topic11), emptyTopic, common.HexToHash(topic31)}, + topics: []common.Hash{common.BytesToHash(contractAddress.Bytes()), common.HexToHash(topic11), emptyTopic, common.HexToHash(topic31)}, upkeepID: uid, }, []logpoller.Log{ @@ -170,7 +170,7 @@ func TestUpkeepFilter_Select(t *testing.T) { "selector is 7 - topics 1 2 3 are used to filter logs", upkeepFilter{ selector: 7, - topics: []common.Hash{contractAddress.Hash(), common.HexToHash(topic10), common.HexToHash(topic20), common.HexToHash(topic30)}, + topics: []common.Hash{common.BytesToHash(contractAddress.Bytes()), common.HexToHash(topic10), common.HexToHash(topic20), common.HexToHash(topic30)}, upkeepID: uid, }, []logpoller.Log{ diff --git a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/logprovider/integration_test.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/logprovider/integration_test.go index caad1adc9a..5ef06f1bd0 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/logprovider/integration_test.go +++ b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/logprovider/integration_test.go @@ -7,6 +7,8 @@ import ( "testing" "time" + "github.com/smartcontractkit/chainlink-automation/pkg/v3/types" + "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/accounts/abi/bind/backends" "github.com/ethereum/go-ethereum/common" @@ -18,7 +20,7 @@ import ( "go.uber.org/zap/zapcore" "golang.org/x/time/rate" - ocr2keepers "github.com/smartcontractkit/chainlink-automation/pkg/v3/types" + ocr2keepers "github.com/smartcontractkit/chainlink-common/pkg/types/automation" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" @@ -150,7 +152,7 @@ func TestIntegration_LogEventProvider_UpdateConfig(t *testing.T) { require.Equal(t, 1, len(addrs)) t.Run("update filter config", func(t *testing.T) { - upkeepID := evmregistry21.GenUpkeepID(ocr2keepers.LogTrigger, "111") + upkeepID := evmregistry21.GenUpkeepID(types.LogTrigger, "111") id := upkeepID.BigInt() cfg := newPlainLogTriggerConfig(addrs[0]) b, err := ethClient.BlockByHash(ctx, backend.Commit()) @@ -182,7 +184,7 @@ func TestIntegration_LogEventProvider_UpdateConfig(t *testing.T) { }) t.Run("register same log filter", func(t *testing.T) { - upkeepID := evmregistry21.GenUpkeepID(ocr2keepers.LogTrigger, "222") + upkeepID := evmregistry21.GenUpkeepID(types.LogTrigger, "222") id := upkeepID.BigInt() cfg := newPlainLogTriggerConfig(addrs[0]) b, err := ethClient.BlockByHash(ctx, backend.Commit()) diff --git a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/logprovider/provider.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/logprovider/provider.go index 2dabcc8267..d1360faaf6 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/logprovider/provider.go +++ b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/logprovider/provider.go @@ -16,7 +16,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" - ocr2keepers "github.com/smartcontractkit/chainlink-automation/pkg/v3/types" + ocr2keepers "github.com/smartcontractkit/chainlink-common/pkg/types/automation" "github.com/smartcontractkit/chainlink-common/pkg/services" @@ -109,7 +109,7 @@ func NewLogProvider(lggr logger.Logger, poller logpoller.LogPoller, packer LogDa threadCtrl: utils.NewThreadControl(), lggr: lggr.Named("KeepersRegistry.LogEventProvider"), packer: packer, - buffer: newLogEventBuffer(lggr, int(opts.LookbackBlocks), maxLogsPerBlock, maxLogsPerUpkeepInBlock), + buffer: newLogEventBuffer(lggr, int(opts.LookbackBlocks), defaultNumOfLogUpkeeps, defaultFastExecLogsHigh), poller: poller, opts: opts, filterStore: filterStore, diff --git a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/logprovider/provider_life_cycle_test.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/logprovider/provider_life_cycle_test.go index 278c727a06..d978940d29 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/logprovider/provider_life_cycle_test.go +++ b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/logprovider/provider_life_cycle_test.go @@ -5,13 +5,13 @@ import ( "math/big" "testing" + "github.com/smartcontractkit/chainlink-automation/pkg/v3/types" + "github.com/ethereum/go-ethereum/common" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" - ocr2keepers "github.com/smartcontractkit/chainlink-automation/pkg/v3/types" - "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller/mocks" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" @@ -155,7 +155,7 @@ func TestEventLogProvider_RefreshActiveUpkeeps(t *testing.T) { p := NewLogProvider(logger.TestLogger(t), mp, &mockedPacker{}, NewUpkeepFilterStore(), NewOptions(200)) require.NoError(t, p.RegisterFilter(ctx, FilterOptions{ - UpkeepID: core.GenUpkeepID(ocr2keepers.LogTrigger, "1111").BigInt(), + UpkeepID: core.GenUpkeepID(types.LogTrigger, "1111").BigInt(), TriggerConfig: LogTriggerConfig{ ContractAddress: common.BytesToAddress(common.LeftPadBytes([]byte{1, 2, 3, 4}, 20)), Topic0: common.BytesToHash(common.LeftPadBytes([]byte{1, 2, 3, 4}, 32)), @@ -163,7 +163,7 @@ func TestEventLogProvider_RefreshActiveUpkeeps(t *testing.T) { UpdateBlock: uint64(0), })) require.NoError(t, p.RegisterFilter(ctx, FilterOptions{ - UpkeepID: core.GenUpkeepID(ocr2keepers.LogTrigger, "2222").BigInt(), + UpkeepID: core.GenUpkeepID(types.LogTrigger, "2222").BigInt(), TriggerConfig: LogTriggerConfig{ ContractAddress: common.BytesToAddress(common.LeftPadBytes([]byte{1, 2, 3, 4}, 20)), Topic0: common.BytesToHash(common.LeftPadBytes([]byte{1, 2, 3, 4}, 32)), @@ -175,11 +175,11 @@ func TestEventLogProvider_RefreshActiveUpkeeps(t *testing.T) { newIds, err := p.RefreshActiveUpkeeps() require.NoError(t, err) require.Len(t, newIds, 0) - mp.On("HasFilter", p.filterName(core.GenUpkeepID(ocr2keepers.LogTrigger, "2222").BigInt())).Return(true) + mp.On("HasFilter", p.filterName(core.GenUpkeepID(types.LogTrigger, "2222").BigInt())).Return(true) newIds, err = p.RefreshActiveUpkeeps( - core.GenUpkeepID(ocr2keepers.LogTrigger, "2222").BigInt(), - core.GenUpkeepID(ocr2keepers.LogTrigger, "1234").BigInt(), - core.GenUpkeepID(ocr2keepers.LogTrigger, "123").BigInt()) + core.GenUpkeepID(types.LogTrigger, "2222").BigInt(), + core.GenUpkeepID(types.LogTrigger, "1234").BigInt(), + core.GenUpkeepID(types.LogTrigger, "123").BigInt()) require.NoError(t, err) require.Len(t, newIds, 2) require.Equal(t, 1, p.filterStore.Size()) diff --git a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/logprovider/provider_test.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/logprovider/provider_test.go index 81774e2638..464b9aa3ba 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/logprovider/provider_test.go +++ b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/logprovider/provider_test.go @@ -13,7 +13,7 @@ import ( "github.com/stretchr/testify/require" "golang.org/x/time/rate" - ocr2keepers "github.com/smartcontractkit/chainlink-automation/pkg/v3/types" + ocr2keepers "github.com/smartcontractkit/chainlink-common/pkg/types/automation" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller/mocks" diff --git a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/logprovider/recoverer.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/logprovider/recoverer.go index c7f6884426..b28ece9843 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/logprovider/recoverer.go +++ b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/logprovider/recoverer.go @@ -14,10 +14,12 @@ import ( "sync/atomic" "time" + "github.com/smartcontractkit/chainlink-automation/pkg/v3/types" + "github.com/ethereum/go-ethereum/common" "github.com/smartcontractkit/chainlink-automation/pkg/v3/random" - ocr2keepers "github.com/smartcontractkit/chainlink-automation/pkg/v3/types" + ocr2keepers "github.com/smartcontractkit/chainlink-common/pkg/types/automation" "github.com/smartcontractkit/chainlink-common/pkg/services" @@ -193,7 +195,7 @@ func (r *logRecoverer) HealthReport() map[string]error { func (r *logRecoverer) GetProposalData(ctx context.Context, proposal ocr2keepers.CoordinatedBlockProposal) ([]byte, error) { switch core.GetUpkeepType(proposal.UpkeepID) { - case ocr2keepers.LogTrigger: + case types.LogTrigger: return r.getLogTriggerCheckData(ctx, proposal) default: return []byte{}, errors.New("not a log trigger upkeep ID") diff --git a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/logprovider/recoverer_test.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/logprovider/recoverer_test.go index 65fe3c85fb..eadd0446da 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/logprovider/recoverer_test.go +++ b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/logprovider/recoverer_test.go @@ -9,13 +9,15 @@ import ( "testing" "time" + types2 "github.com/smartcontractkit/chainlink-automation/pkg/v3/types" + "github.com/ethereum/go-ethereum/common" "github.com/pkg/errors" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" - ocr2keepers "github.com/smartcontractkit/chainlink-automation/pkg/v3/types" + ocr2keepers "github.com/smartcontractkit/chainlink-common/pkg/types/automation" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller" @@ -50,33 +52,33 @@ func TestLogRecoverer_GetRecoverables(t *testing.T) { { "happy flow", []ocr2keepers.UpkeepPayload{ - {WorkID: "1", UpkeepID: core.GenUpkeepID(ocr2keepers.LogTrigger, "1")}, - {WorkID: "2", UpkeepID: core.GenUpkeepID(ocr2keepers.LogTrigger, "2")}, + {WorkID: "1", UpkeepID: core.GenUpkeepID(types2.LogTrigger, "1")}, + {WorkID: "2", UpkeepID: core.GenUpkeepID(types2.LogTrigger, "2")}, }, []ocr2keepers.UpkeepPayload{ - {WorkID: "1", UpkeepID: core.GenUpkeepID(ocr2keepers.LogTrigger, "1")}, - {WorkID: "2", UpkeepID: core.GenUpkeepID(ocr2keepers.LogTrigger, "2")}, + {WorkID: "1", UpkeepID: core.GenUpkeepID(types2.LogTrigger, "1")}, + {WorkID: "2", UpkeepID: core.GenUpkeepID(types2.LogTrigger, "2")}, }, false, }, { "rate limiting", []ocr2keepers.UpkeepPayload{ - {WorkID: "1", UpkeepID: core.GenUpkeepID(ocr2keepers.LogTrigger, "1")}, - {WorkID: "2", UpkeepID: core.GenUpkeepID(ocr2keepers.LogTrigger, "1")}, - {WorkID: "3", UpkeepID: core.GenUpkeepID(ocr2keepers.LogTrigger, "1")}, - {WorkID: "4", UpkeepID: core.GenUpkeepID(ocr2keepers.LogTrigger, "1")}, - {WorkID: "5", UpkeepID: core.GenUpkeepID(ocr2keepers.LogTrigger, "1")}, - {WorkID: "6", UpkeepID: core.GenUpkeepID(ocr2keepers.LogTrigger, "1")}, - {WorkID: "2", UpkeepID: core.GenUpkeepID(ocr2keepers.LogTrigger, "2")}, + {WorkID: "1", UpkeepID: core.GenUpkeepID(types2.LogTrigger, "1")}, + {WorkID: "2", UpkeepID: core.GenUpkeepID(types2.LogTrigger, "1")}, + {WorkID: "3", UpkeepID: core.GenUpkeepID(types2.LogTrigger, "1")}, + {WorkID: "4", UpkeepID: core.GenUpkeepID(types2.LogTrigger, "1")}, + {WorkID: "5", UpkeepID: core.GenUpkeepID(types2.LogTrigger, "1")}, + {WorkID: "6", UpkeepID: core.GenUpkeepID(types2.LogTrigger, "1")}, + {WorkID: "2", UpkeepID: core.GenUpkeepID(types2.LogTrigger, "2")}, }, []ocr2keepers.UpkeepPayload{ - {WorkID: "1", UpkeepID: core.GenUpkeepID(ocr2keepers.LogTrigger, "1")}, - {WorkID: "2", UpkeepID: core.GenUpkeepID(ocr2keepers.LogTrigger, "1")}, - {WorkID: "3", UpkeepID: core.GenUpkeepID(ocr2keepers.LogTrigger, "1")}, - {WorkID: "4", UpkeepID: core.GenUpkeepID(ocr2keepers.LogTrigger, "1")}, - {WorkID: "5", UpkeepID: core.GenUpkeepID(ocr2keepers.LogTrigger, "1")}, - {WorkID: "2", UpkeepID: core.GenUpkeepID(ocr2keepers.LogTrigger, "2")}, + {WorkID: "1", UpkeepID: core.GenUpkeepID(types2.LogTrigger, "1")}, + {WorkID: "2", UpkeepID: core.GenUpkeepID(types2.LogTrigger, "1")}, + {WorkID: "3", UpkeepID: core.GenUpkeepID(types2.LogTrigger, "1")}, + {WorkID: "4", UpkeepID: core.GenUpkeepID(types2.LogTrigger, "1")}, + {WorkID: "5", UpkeepID: core.GenUpkeepID(types2.LogTrigger, "1")}, + {WorkID: "2", UpkeepID: core.GenUpkeepID(types2.LogTrigger, "2")}, }, false, }, @@ -121,9 +123,9 @@ func TestLogRecoverer_Clean(t *testing.T) { { "clean expired", []ocr2keepers.UpkeepPayload{ - {WorkID: "1", UpkeepID: core.GenUpkeepID(ocr2keepers.LogTrigger, "1")}, - {WorkID: "2", UpkeepID: core.GenUpkeepID(ocr2keepers.LogTrigger, "2")}, - {WorkID: "3", UpkeepID: core.GenUpkeepID(ocr2keepers.LogTrigger, "3")}, + {WorkID: "1", UpkeepID: core.GenUpkeepID(types2.LogTrigger, "1")}, + {WorkID: "2", UpkeepID: core.GenUpkeepID(types2.LogTrigger, "2")}, + {WorkID: "3", UpkeepID: core.GenUpkeepID(types2.LogTrigger, "3")}, }, map[string]visitedRecord{ "1": visitedRecord{time.Now(), ocr2keepers.UpkeepPayload{ @@ -164,9 +166,9 @@ func TestLogRecoverer_Clean(t *testing.T) { ocr2keepers.UnknownState, }, []ocr2keepers.UpkeepPayload{ - {WorkID: "1", UpkeepID: core.GenUpkeepID(ocr2keepers.LogTrigger, "1")}, - {WorkID: "2", UpkeepID: core.GenUpkeepID(ocr2keepers.LogTrigger, "2")}, - {WorkID: "4", UpkeepID: core.GenUpkeepID(ocr2keepers.LogTrigger, "4")}, + {WorkID: "1", UpkeepID: core.GenUpkeepID(types2.LogTrigger, "1")}, + {WorkID: "2", UpkeepID: core.GenUpkeepID(types2.LogTrigger, "2")}, + {WorkID: "4", UpkeepID: core.GenUpkeepID(types2.LogTrigger, "4")}, }, []string{"1", "2", "4"}, }, @@ -583,7 +585,7 @@ func TestLogRecoverer_GetProposalData(t *testing.T) { { name: "if a filter is not found for the upkeep ID, an error is returned", proposal: ocr2keepers.CoordinatedBlockProposal{ - UpkeepID: core.GenUpkeepID(ocr2keepers.LogTrigger, "123"), + UpkeepID: core.GenUpkeepID(types2.LogTrigger, "123"), }, skipFilter: true, expectErr: true, @@ -592,7 +594,7 @@ func TestLogRecoverer_GetProposalData(t *testing.T) { { name: "if an error is encountered fetching the latest block, an error is returned", proposal: ocr2keepers.CoordinatedBlockProposal{ - UpkeepID: core.GenUpkeepID(ocr2keepers.LogTrigger, "123"), + UpkeepID: core.GenUpkeepID(types2.LogTrigger, "123"), Trigger: ocr2keepers.Trigger{ LogTriggerExtension: &ocr2keepers.LogTriggerExtension{ BlockNumber: 0, @@ -615,7 +617,7 @@ func TestLogRecoverer_GetProposalData(t *testing.T) { { name: "if an error is encountered fetching the tx receipt, an error is returned", proposal: ocr2keepers.CoordinatedBlockProposal{ - UpkeepID: core.GenUpkeepID(ocr2keepers.LogTrigger, "123"), + UpkeepID: core.GenUpkeepID(types2.LogTrigger, "123"), Trigger: ocr2keepers.Trigger{ LogTriggerExtension: &ocr2keepers.LogTriggerExtension{ BlockNumber: 0, @@ -643,7 +645,7 @@ func TestLogRecoverer_GetProposalData(t *testing.T) { { name: "if the tx block is nil, an error is returned", proposal: ocr2keepers.CoordinatedBlockProposal{ - UpkeepID: core.GenUpkeepID(ocr2keepers.LogTrigger, "123"), + UpkeepID: core.GenUpkeepID(types2.LogTrigger, "123"), Trigger: ocr2keepers.Trigger{ LogTriggerExtension: &ocr2keepers.LogTriggerExtension{ BlockNumber: 0, @@ -671,7 +673,7 @@ func TestLogRecoverer_GetProposalData(t *testing.T) { { name: "if a log trigger extension block number is 0, and the block number on the tx receipt is not recoverable, an error is returned", proposal: ocr2keepers.CoordinatedBlockProposal{ - UpkeepID: core.GenUpkeepID(ocr2keepers.LogTrigger, "123"), + UpkeepID: core.GenUpkeepID(types2.LogTrigger, "123"), Trigger: ocr2keepers.Trigger{ LogTriggerExtension: &ocr2keepers.LogTriggerExtension{ BlockNumber: 0, @@ -701,7 +703,7 @@ func TestLogRecoverer_GetProposalData(t *testing.T) { { name: "if a log block is not recoverable, an error is returned", proposal: ocr2keepers.CoordinatedBlockProposal{ - UpkeepID: core.GenUpkeepID(ocr2keepers.LogTrigger, "123"), + UpkeepID: core.GenUpkeepID(types2.LogTrigger, "123"), Trigger: ocr2keepers.Trigger{ LogTriggerExtension: &ocr2keepers.LogTriggerExtension{ BlockNumber: 200, @@ -731,7 +733,7 @@ func TestLogRecoverer_GetProposalData(t *testing.T) { { name: "if a log block has does not match, an error is returned", proposal: ocr2keepers.CoordinatedBlockProposal{ - UpkeepID: core.GenUpkeepID(ocr2keepers.LogTrigger, "123"), + UpkeepID: core.GenUpkeepID(types2.LogTrigger, "123"), Trigger: ocr2keepers.Trigger{ LogTriggerExtension: &ocr2keepers.LogTriggerExtension{ BlockNumber: 200, @@ -763,7 +765,7 @@ func TestLogRecoverer_GetProposalData(t *testing.T) { { name: "if a log block is recoverable, when the upkeep state reader errors, an error is returned", proposal: ocr2keepers.CoordinatedBlockProposal{ - UpkeepID: core.GenUpkeepID(ocr2keepers.LogTrigger, "123"), + UpkeepID: core.GenUpkeepID(types2.LogTrigger, "123"), Trigger: ocr2keepers.Trigger{ LogTriggerExtension: &ocr2keepers.LogTriggerExtension{ BlockNumber: 80, @@ -798,7 +800,7 @@ func TestLogRecoverer_GetProposalData(t *testing.T) { { name: "if a log block is recoverable, when the upkeep state reader returns a non recoverable state, an error is returned", proposal: ocr2keepers.CoordinatedBlockProposal{ - UpkeepID: core.GenUpkeepID(ocr2keepers.LogTrigger, "123"), + UpkeepID: core.GenUpkeepID(types2.LogTrigger, "123"), Trigger: ocr2keepers.Trigger{ LogTriggerExtension: &ocr2keepers.LogTriggerExtension{ BlockNumber: 80, @@ -835,7 +837,7 @@ func TestLogRecoverer_GetProposalData(t *testing.T) { { name: "if a log block is recoverable, when the filter address is empty, an error is returned", proposal: ocr2keepers.CoordinatedBlockProposal{ - UpkeepID: core.GenUpkeepID(ocr2keepers.LogTrigger, "123"), + UpkeepID: core.GenUpkeepID(types2.LogTrigger, "123"), Trigger: ocr2keepers.Trigger{ LogTriggerExtension: &ocr2keepers.LogTriggerExtension{ BlockNumber: 80, @@ -875,7 +877,7 @@ func TestLogRecoverer_GetProposalData(t *testing.T) { { name: "if a log block is recoverable, when the log poller returns an error fetching logs, an error is returned", proposal: ocr2keepers.CoordinatedBlockProposal{ - UpkeepID: core.GenUpkeepID(ocr2keepers.LogTrigger, "123"), + UpkeepID: core.GenUpkeepID(types2.LogTrigger, "123"), Trigger: ocr2keepers.Trigger{ LogTriggerExtension: &ocr2keepers.LogTriggerExtension{ BlockNumber: 80, @@ -910,7 +912,7 @@ func TestLogRecoverer_GetProposalData(t *testing.T) { { name: "if a log block is recoverable, when logs cannot be found for an upkeep ID, an error is returned", proposal: ocr2keepers.CoordinatedBlockProposal{ - UpkeepID: core.GenUpkeepID(ocr2keepers.LogTrigger, "123"), + UpkeepID: core.GenUpkeepID(types2.LogTrigger, "123"), Trigger: ocr2keepers.Trigger{ LogTriggerExtension: &ocr2keepers.LogTriggerExtension{ BlockNumber: 80, @@ -949,7 +951,7 @@ func TestLogRecoverer_GetProposalData(t *testing.T) { { name: "happy path with empty check data", proposal: ocr2keepers.CoordinatedBlockProposal{ - UpkeepID: core.GenUpkeepID(ocr2keepers.LogTrigger, "123"), + UpkeepID: core.GenUpkeepID(types2.LogTrigger, "123"), Trigger: func() ocr2keepers.Trigger { t := ocr2keepers.NewTrigger( ocr2keepers.BlockNumber(80), @@ -1000,7 +1002,7 @@ func TestLogRecoverer_GetProposalData(t *testing.T) { { name: "happy path with check data", proposal: ocr2keepers.CoordinatedBlockProposal{ - UpkeepID: core.GenUpkeepID(ocr2keepers.LogTrigger, "123"), + UpkeepID: core.GenUpkeepID(types2.LogTrigger, "123"), Trigger: func() ocr2keepers.Trigger { t := ocr2keepers.NewTrigger( ocr2keepers.BlockNumber(80), @@ -1061,7 +1063,7 @@ func TestLogRecoverer_GetProposalData(t *testing.T) { filterStore.AddActiveUpkeeps(upkeepFilter{ addr: []byte("test"), topics: []common.Hash{common.HexToHash("0x1"), common.HexToHash("0x2"), common.HexToHash("0x3"), common.HexToHash("0x4")}, - upkeepID: core.GenUpkeepID(ocr2keepers.LogTrigger, "123").BigInt(), + upkeepID: core.GenUpkeepID(types2.LogTrigger, "123").BigInt(), }) } @@ -1111,34 +1113,34 @@ func TestLogRecoverer_pending(t *testing.T) { name: "add new and existing", maxPerUpkeep: 10, exist: []ocr2keepers.UpkeepPayload{ - {WorkID: "1", UpkeepID: core.GenUpkeepID(ocr2keepers.LogTrigger, "1")}, + {WorkID: "1", UpkeepID: core.GenUpkeepID(types2.LogTrigger, "1")}, }, new: []ocr2keepers.UpkeepPayload{ - {WorkID: "1", UpkeepID: core.GenUpkeepID(ocr2keepers.LogTrigger, "1")}, - {WorkID: "2", UpkeepID: core.GenUpkeepID(ocr2keepers.LogTrigger, "2")}, + {WorkID: "1", UpkeepID: core.GenUpkeepID(types2.LogTrigger, "1")}, + {WorkID: "2", UpkeepID: core.GenUpkeepID(types2.LogTrigger, "2")}, }, errored: []bool{false, false}, want: []ocr2keepers.UpkeepPayload{ - {WorkID: "1", UpkeepID: core.GenUpkeepID(ocr2keepers.LogTrigger, "1")}, - {WorkID: "2", UpkeepID: core.GenUpkeepID(ocr2keepers.LogTrigger, "2")}, + {WorkID: "1", UpkeepID: core.GenUpkeepID(types2.LogTrigger, "1")}, + {WorkID: "2", UpkeepID: core.GenUpkeepID(types2.LogTrigger, "2")}, }, }, { name: "exceed limits for upkeep", maxPerUpkeep: 3, exist: []ocr2keepers.UpkeepPayload{ - {WorkID: "1", UpkeepID: core.GenUpkeepID(ocr2keepers.LogTrigger, "1")}, - {WorkID: "2", UpkeepID: core.GenUpkeepID(ocr2keepers.LogTrigger, "1")}, - {WorkID: "3", UpkeepID: core.GenUpkeepID(ocr2keepers.LogTrigger, "1")}, + {WorkID: "1", UpkeepID: core.GenUpkeepID(types2.LogTrigger, "1")}, + {WorkID: "2", UpkeepID: core.GenUpkeepID(types2.LogTrigger, "1")}, + {WorkID: "3", UpkeepID: core.GenUpkeepID(types2.LogTrigger, "1")}, }, new: []ocr2keepers.UpkeepPayload{ - {WorkID: "4", UpkeepID: core.GenUpkeepID(ocr2keepers.LogTrigger, "1")}, + {WorkID: "4", UpkeepID: core.GenUpkeepID(types2.LogTrigger, "1")}, }, errored: []bool{true}, want: []ocr2keepers.UpkeepPayload{ - {WorkID: "1", UpkeepID: core.GenUpkeepID(ocr2keepers.LogTrigger, "1")}, - {WorkID: "2", UpkeepID: core.GenUpkeepID(ocr2keepers.LogTrigger, "1")}, - {WorkID: "3", UpkeepID: core.GenUpkeepID(ocr2keepers.LogTrigger, "1")}, + {WorkID: "1", UpkeepID: core.GenUpkeepID(types2.LogTrigger, "1")}, + {WorkID: "2", UpkeepID: core.GenUpkeepID(types2.LogTrigger, "1")}, + {WorkID: "3", UpkeepID: core.GenUpkeepID(types2.LogTrigger, "1")}, }, }, } diff --git a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mercury/mercury.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mercury/mercury.go index d3a5167ef7..d24442b6ee 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mercury/mercury.go +++ b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mercury/mercury.go @@ -10,11 +10,12 @@ import ( "net/http" "time" + "github.com/smartcontractkit/chainlink-common/pkg/types" + "github.com/ethereum/go-ethereum/accounts/abi" "github.com/ethereum/go-ethereum/common/hexutil" "github.com/patrickmn/go-cache" - "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/models" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/core" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/encoding" ) @@ -73,7 +74,7 @@ type MercuryData struct { } type MercuryConfigProvider interface { - Credentials() *models.MercuryCredentials + Credentials() *types.MercuryCredentials IsUpkeepAllowed(string) (interface{}, bool) SetUpkeepAllowed(string, interface{}, time.Duration) GetPluginRetry(string) (interface{}, bool) diff --git a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mercury/mercury_test.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mercury/mercury_test.go index c7e22d4587..ce82ec7ae8 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mercury/mercury_test.go +++ b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mercury/mercury_test.go @@ -80,7 +80,7 @@ func TestPacker_DecodeStreamsLookupRequest(t *testing.T) { { name: "failure - unpack error", data: []byte{1, 2, 3, 4}, - err: errors.New("unpack error: invalid data for unpacking"), + err: errors.New("unpack error: invalid identifier, have 0x01020304 want 0xf055e4a2"), }, } diff --git a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mercury/streams/streams.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mercury/streams/streams.go index 27aafeca55..a0dba9c8ac 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mercury/streams/streams.go +++ b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mercury/streams/streams.go @@ -15,8 +15,8 @@ import ( "github.com/ethereum/go-ethereum/common/hexutil" "github.com/patrickmn/go-cache" - ocr2keepers "github.com/smartcontractkit/chainlink-automation/pkg/v3/types" "github.com/smartcontractkit/chainlink-common/pkg/services" + ocr2keepers "github.com/smartcontractkit/chainlink-common/pkg/types/automation" iregistry21 "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/i_keeper_registry_master_wrapper_2_1" "github.com/smartcontractkit/chainlink/v2/core/logger" diff --git a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mercury/streams/streams_test.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mercury/streams/streams_test.go index 31b6597bb2..c7bff2eac7 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mercury/streams/streams_test.go +++ b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mercury/streams/streams_test.go @@ -11,6 +11,8 @@ import ( "testing" "time" + "github.com/smartcontractkit/chainlink-common/pkg/types" + "github.com/pkg/errors" "github.com/ethereum/go-ethereum/accounts/abi/bind" @@ -20,13 +22,12 @@ import ( "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" - ocr2keepers "github.com/smartcontractkit/chainlink-automation/pkg/v3/types" + ocr2keepers "github.com/smartcontractkit/chainlink-common/pkg/types/automation" evmClientMocks "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client/mocks" iregistry21 "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/i_keeper_registry_master_wrapper_2_1" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "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/evmregistry/v21/encoding" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mercury" v02 "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mercury/v02" @@ -37,8 +38,8 @@ type MockMercuryConfigProvider struct { mock.Mock } -func (m *MockMercuryConfigProvider) Credentials() *models.MercuryCredentials { - mc := &models.MercuryCredentials{ +func (m *MockMercuryConfigProvider) Credentials() *types.MercuryCredentials { + mc := &types.MercuryCredentials{ LegacyURL: "https://google.old.com", URL: "https://google.com", Username: "FakeClientID", diff --git a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mercury/v02/v02_request_test.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mercury/v02/v02_request_test.go index 686b2199eb..6c07c38350 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mercury/v02/v02_request_test.go +++ b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mercury/v02/v02_request_test.go @@ -11,13 +11,14 @@ import ( "testing" "time" + "github.com/smartcontractkit/chainlink-common/pkg/types" + "github.com/ethereum/go-ethereum/common/hexutil" "github.com/patrickmn/go-cache" "github.com/stretchr/testify/mock" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "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/evmregistry/v21/encoding" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mercury" "github.com/smartcontractkit/chainlink/v2/core/utils" @@ -41,8 +42,8 @@ func NewMockMercuryConfigProvider() *MockMercuryConfigProvider { } } -func (m *MockMercuryConfigProvider) Credentials() *models.MercuryCredentials { - mc := &models.MercuryCredentials{ +func (m *MockMercuryConfigProvider) Credentials() *types.MercuryCredentials { + mc := &types.MercuryCredentials{ LegacyURL: "https://google.old.com", URL: "https://google.com", Username: "FakeClientID", diff --git a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mercury/v03/v03_request_test.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mercury/v03/v03_request_test.go index 4a22ae477e..a7742c0487 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mercury/v03/v03_request_test.go +++ b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mercury/v03/v03_request_test.go @@ -9,13 +9,14 @@ import ( "testing" "time" + "github.com/smartcontractkit/chainlink-common/pkg/types" + "github.com/ethereum/go-ethereum/common/hexutil" "github.com/patrickmn/go-cache" "github.com/stretchr/testify/mock" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "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/evmregistry/v21/encoding" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mercury" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mocks" @@ -40,8 +41,8 @@ func NewMockMercuryConfigProvider() *MockMercuryConfigProvider { } } -func (m *MockMercuryConfigProvider) Credentials() *models.MercuryCredentials { - mc := &models.MercuryCredentials{ +func (m *MockMercuryConfigProvider) Credentials() *types.MercuryCredentials { + mc := &types.MercuryCredentials{ LegacyURL: "https://google.old.com", URL: "https://google.com", Username: "FakeClientID", diff --git a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/payload_builder.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/payload_builder.go index 37c458ae6e..4854f517c4 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/payload_builder.go +++ b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/payload_builder.go @@ -3,7 +3,9 @@ package evm import ( "context" - ocr2keepers "github.com/smartcontractkit/chainlink-automation/pkg/v3/types" + "github.com/smartcontractkit/chainlink-automation/pkg/v3/types" + + ocr2keepers "github.com/smartcontractkit/chainlink-common/pkg/types/automation" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/core" @@ -36,13 +38,13 @@ func (b *payloadBuilder) BuildPayloads(ctx context.Context, proposals ...ocr2kee var checkData []byte var err error switch core.GetUpkeepType(proposal.UpkeepID) { - case ocr2keepers.LogTrigger: + case types.LogTrigger: checkData, err = b.recoverer.GetProposalData(ctx, proposal) if err != nil { b.lggr.Warnw("failed to get log proposal data", "err", err, "upkeepID", proposal.UpkeepID, "trigger", proposal.Trigger) continue } - case ocr2keepers.ConditionTrigger: + case types.ConditionTrigger: // Empty checkData for conditionals } payload, err = core.NewUpkeepPayload(proposal.UpkeepID.BigInt(), proposal.Trigger, checkData) diff --git a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/payload_builder_test.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/payload_builder_test.go index 7e55267f6d..7cd63dd308 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/payload_builder_test.go +++ b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/payload_builder_test.go @@ -5,10 +5,12 @@ import ( "math/big" "testing" + types2 "github.com/smartcontractkit/chainlink-automation/pkg/v3/types" + "github.com/pkg/errors" "github.com/stretchr/testify/assert" - "github.com/smartcontractkit/chainlink-automation/pkg/v3/types" + types "github.com/smartcontractkit/chainlink-common/pkg/types/automation" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/logger" @@ -33,7 +35,7 @@ func TestNewPayloadBuilder(t *testing.T) { }, proposals: []types.CoordinatedBlockProposal{ { - UpkeepID: core.GenUpkeepID(types.LogTrigger, "abc"), + UpkeepID: core.GenUpkeepID(types2.LogTrigger, "abc"), WorkID: "workID1", Trigger: types.Trigger{ BlockNumber: 1, @@ -41,7 +43,7 @@ func TestNewPayloadBuilder(t *testing.T) { }, }, { - UpkeepID: core.GenUpkeepID(types.LogTrigger, "def"), + UpkeepID: core.GenUpkeepID(types2.LogTrigger, "def"), WorkID: "workID2", Trigger: types.Trigger{ BlockNumber: 2, @@ -56,7 +58,7 @@ func TestNewPayloadBuilder(t *testing.T) { }, wantPayloads: []types.UpkeepPayload{ { - UpkeepID: core.GenUpkeepID(types.LogTrigger, "abc"), + UpkeepID: core.GenUpkeepID(types2.LogTrigger, "abc"), WorkID: "714f83255c5b562823725748c4a75777c9b78ea8c5ba72ea819926a1fecd389e", Trigger: types.Trigger{ BlockNumber: 1, @@ -65,7 +67,7 @@ func TestNewPayloadBuilder(t *testing.T) { CheckData: []byte{1, 2, 3}, }, { - UpkeepID: core.GenUpkeepID(types.LogTrigger, "def"), + UpkeepID: core.GenUpkeepID(types2.LogTrigger, "def"), WorkID: "3956daa0378d6a761fe972ee00fe98338f17fb6b7865c1d49a8a416cd85977b8", Trigger: types.Trigger{ BlockNumber: 2, @@ -79,12 +81,12 @@ func TestNewPayloadBuilder(t *testing.T) { name: "for an inactive log trigger upkeep, an empty payload is added to the list of payloads", activeList: &mockActiveUpkeepList{ IsActiveFn: func(id *big.Int) bool { - return core.GenUpkeepID(types.LogTrigger, "ghi").BigInt().Cmp(id) != 0 + return core.GenUpkeepID(types2.LogTrigger, "ghi").BigInt().Cmp(id) != 0 }, }, proposals: []types.CoordinatedBlockProposal{ { - UpkeepID: core.GenUpkeepID(types.LogTrigger, "abc"), + UpkeepID: core.GenUpkeepID(types2.LogTrigger, "abc"), WorkID: "workID1", Trigger: types.Trigger{ BlockNumber: 1, @@ -92,7 +94,7 @@ func TestNewPayloadBuilder(t *testing.T) { }, }, { - UpkeepID: core.GenUpkeepID(types.LogTrigger, "def"), + UpkeepID: core.GenUpkeepID(types2.LogTrigger, "def"), WorkID: "workID2", Trigger: types.Trigger{ BlockNumber: 2, @@ -100,7 +102,7 @@ func TestNewPayloadBuilder(t *testing.T) { }, }, { - UpkeepID: core.GenUpkeepID(types.LogTrigger, "ghi"), + UpkeepID: core.GenUpkeepID(types2.LogTrigger, "ghi"), WorkID: "workID3", Trigger: types.Trigger{ BlockNumber: 3, @@ -115,7 +117,7 @@ func TestNewPayloadBuilder(t *testing.T) { }, wantPayloads: []types.UpkeepPayload{ { - UpkeepID: core.GenUpkeepID(types.LogTrigger, "abc"), + UpkeepID: core.GenUpkeepID(types2.LogTrigger, "abc"), WorkID: "714f83255c5b562823725748c4a75777c9b78ea8c5ba72ea819926a1fecd389e", Trigger: types.Trigger{ BlockNumber: 1, @@ -124,7 +126,7 @@ func TestNewPayloadBuilder(t *testing.T) { CheckData: []byte{1, 2, 3}, }, { - UpkeepID: core.GenUpkeepID(types.LogTrigger, "def"), + UpkeepID: core.GenUpkeepID(types2.LogTrigger, "def"), WorkID: "3956daa0378d6a761fe972ee00fe98338f17fb6b7865c1d49a8a416cd85977b8", Trigger: types.Trigger{ BlockNumber: 2, @@ -144,7 +146,7 @@ func TestNewPayloadBuilder(t *testing.T) { }, proposals: []types.CoordinatedBlockProposal{ { - UpkeepID: core.GenUpkeepID(types.LogTrigger, "abc"), + UpkeepID: core.GenUpkeepID(types2.LogTrigger, "abc"), WorkID: "workID1", Trigger: types.Trigger{ BlockNumber: 1, @@ -170,7 +172,7 @@ func TestNewPayloadBuilder(t *testing.T) { }, proposals: []types.CoordinatedBlockProposal{ { - UpkeepID: core.GenUpkeepID(types.ConditionTrigger, "def"), + UpkeepID: core.GenUpkeepID(types2.ConditionTrigger, "def"), WorkID: "workID1", Trigger: types.Trigger{ BlockNumber: 1, @@ -180,7 +182,7 @@ func TestNewPayloadBuilder(t *testing.T) { }, wantPayloads: []types.UpkeepPayload{ { - UpkeepID: core.GenUpkeepID(types.ConditionTrigger, "def"), + UpkeepID: core.GenUpkeepID(types2.ConditionTrigger, "def"), WorkID: "58f2f231792448679a75bac6efc2af4ba731901f0cb93a44a366525751cbabfb", Trigger: types.Trigger{ BlockNumber: 1, diff --git a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/registry.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/registry.go index 39862bb753..fd7bfa91d7 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/registry.go +++ b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/registry.go @@ -9,6 +9,10 @@ import ( "sync" "time" + types2 "github.com/smartcontractkit/chainlink-automation/pkg/v3/types" + + "github.com/smartcontractkit/chainlink-common/pkg/types" + "github.com/ethereum/go-ethereum/accounts/abi" "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" @@ -19,7 +23,7 @@ import ( "github.com/smartcontractkit/chainlink-common/pkg/services" - ocr2keepers "github.com/smartcontractkit/chainlink-automation/pkg/v3/types" + ocr2keepers "github.com/smartcontractkit/chainlink-common/pkg/types/automation" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller" @@ -27,7 +31,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated" iregistry21 "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/i_keeper_registry_master_wrapper_2_1" "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/evmregistry/v21/core" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/encoding" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/logprovider" @@ -81,7 +84,7 @@ func NewEvmRegistry( addr common.Address, client legacyevm.Chain, registry *iregistry21.IKeeperRegistryMaster, - mc *models.MercuryCredentials, + mc *types.MercuryCredentials, al ActiveUpkeepList, logEventProvider logprovider.LogEventProvider, packer encoding.Packer, @@ -129,14 +132,14 @@ var upkeepStateEvents = []common.Hash{ } type MercuryConfig struct { - cred *models.MercuryCredentials + cred *types.MercuryCredentials Abi abi.ABI // AllowListCache stores the upkeeps privileges. In 2.1, this only includes a JSON bytes for allowed to use mercury AllowListCache *cache.Cache pluginRetryCache *cache.Cache } -func NewMercuryConfig(credentials *models.MercuryCredentials, abi abi.ABI) *MercuryConfig { +func NewMercuryConfig(credentials *types.MercuryCredentials, abi abi.ABI) *MercuryConfig { return &MercuryConfig{ cred: credentials, Abi: abi, @@ -145,7 +148,7 @@ func NewMercuryConfig(credentials *models.MercuryCredentials, abi abi.ABI) *Merc } } -func (c *MercuryConfig) Credentials() *models.MercuryCredentials { +func (c *MercuryConfig) Credentials() *types.MercuryCredentials { return c.cred } @@ -295,7 +298,7 @@ func (r *EvmRegistry) refreshActiveUpkeeps() error { continue } switch core.GetUpkeepType(*uid) { - case ocr2keepers.LogTrigger: + case types2.LogTrigger: logTriggerIDs = append(logTriggerIDs, id) default: } @@ -517,7 +520,7 @@ func (r *EvmRegistry) removeFromActive(id *big.Int) { uid.FromBigInt(id) trigger := core.GetUpkeepType(*uid) switch trigger { - case ocr2keepers.LogTrigger: + case types2.LogTrigger: if err := r.logEventProvider.UnregisterFilter(id); err != nil { r.lggr.Warnw("failed to unregister log filter", "upkeepID", id.String()) } @@ -585,7 +588,7 @@ func (r *EvmRegistry) updateTriggerConfig(id *big.Int, cfg []byte, logBlock uint uid := &ocr2keepers.UpkeepIdentifier{} uid.FromBigInt(id) switch core.GetUpkeepType(*uid) { - case ocr2keepers.LogTrigger: + case types2.LogTrigger: if len(cfg) == 0 { fetched, err := r.fetchTriggerConfig(id) if err != nil { diff --git a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/registry_check_pipeline.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/registry_check_pipeline.go index 33d4a7157b..6475b3ef7d 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/registry_check_pipeline.go +++ b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/registry_check_pipeline.go @@ -6,11 +6,13 @@ import ( "math/big" "strings" + "github.com/smartcontractkit/chainlink-automation/pkg/v3/types" + "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/rpc" - ocr2keepers "github.com/smartcontractkit/chainlink-automation/pkg/v3/types" + ocr2keepers "github.com/smartcontractkit/chainlink-common/pkg/types/automation" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/core" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/encoding" @@ -197,7 +199,7 @@ func (r *EvmRegistry) checkUpkeeps(ctx context.Context, payloads []ocr2keepers.U uid := &ocr2keepers.UpkeepIdentifier{} uid.FromBigInt(upkeepId) switch core.GetUpkeepType(*uid) { - case ocr2keepers.LogTrigger: + case types.LogTrigger: reason, state, retryable := r.verifyLogExists(upkeepId, p) if reason != encoding.UpkeepFailureReasonNone || state != encoding.NoPipelineError { results[i] = encoding.GetIneligibleCheckResultWithoutPerformData(p, reason, state, retryable) diff --git a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/registry_check_pipeline_test.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/registry_check_pipeline_test.go index 9867a58201..e6b61be8d0 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/registry_check_pipeline_test.go +++ b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/registry_check_pipeline_test.go @@ -8,6 +8,10 @@ import ( "sync/atomic" "testing" + types3 "github.com/smartcontractkit/chainlink-automation/pkg/v3/types" + + types2 "github.com/smartcontractkit/chainlink-common/pkg/types" + "github.com/ethereum/go-ethereum/accounts/abi" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/rpc" @@ -16,7 +20,7 @@ import ( "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" - ocr2keepers "github.com/smartcontractkit/chainlink-automation/pkg/v3/types" + ocr2keepers "github.com/smartcontractkit/chainlink-common/pkg/types/automation" evmClientMocks "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client/mocks" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller" @@ -25,7 +29,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/streams_lookup_compatible_interface" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "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/evmregistry/v21/core" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/encoding" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mocks" @@ -376,9 +379,9 @@ func TestRegistry_VerifyLogExists(t *testing.T) { func TestRegistry_CheckUpkeeps(t *testing.T) { lggr := logger.TestLogger(t) - uid0 := core.GenUpkeepID(ocr2keepers.UpkeepType(0), "p0") - uid1 := core.GenUpkeepID(ocr2keepers.UpkeepType(1), "p1") - uid2 := core.GenUpkeepID(ocr2keepers.UpkeepType(1), "p2") + uid0 := core.GenUpkeepID(types3.UpkeepType(0), "p0") + uid1 := core.GenUpkeepID(types3.UpkeepType(1), "p1") + uid2 := core.GenUpkeepID(types3.UpkeepType(1), "p2") extension1 := &ocr2keepers.LogTriggerExtension{ TxHash: common.HexToHash("0xc8def8abdcf3a4eaaf6cc13bff3e4e2a7168d86ea41dbbf97451235aa76c3651"), @@ -536,9 +539,9 @@ func TestRegistry_CheckUpkeeps(t *testing.T) { } func TestRegistry_SimulatePerformUpkeeps(t *testing.T) { - uid0 := core.GenUpkeepID(ocr2keepers.UpkeepType(0), "p0") - uid1 := core.GenUpkeepID(ocr2keepers.UpkeepType(1), "p1") - uid2 := core.GenUpkeepID(ocr2keepers.UpkeepType(1), "p2") + uid0 := core.GenUpkeepID(types3.UpkeepType(0), "p0") + uid1 := core.GenUpkeepID(types3.UpkeepType(1), "p1") + uid2 := core.GenUpkeepID(types3.UpkeepType(1), "p2") extension1 := &ocr2keepers.LogTriggerExtension{ TxHash: common.HexToHash("0xc8def8abdcf3a4eaaf6cc13bff3e4e2a7168d86ea41dbbf97451235aa76c3651"), @@ -682,7 +685,7 @@ func setupEVMRegistry(t *testing.T) *EvmRegistry { headFunc: func(ocr2keepers.BlockKey) {}, chLog: make(chan logpoller.Log, 1000), mercury: &MercuryConfig{ - cred: &models.MercuryCredentials{ + cred: &types2.MercuryCredentials{ LegacyURL: "https://google.old.com", URL: "https://google.com", Username: "FakeClientID", diff --git a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/registry_test.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/registry_test.go index 0d097ceadb..dc48c3d75f 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/registry_test.go +++ b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/registry_test.go @@ -8,14 +8,14 @@ import ( "testing" "time" + types2 "github.com/smartcontractkit/chainlink-automation/pkg/v3/types" + "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" coreTypes "github.com/ethereum/go-ethereum/core/types" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" - "github.com/smartcontractkit/chainlink-automation/pkg/v3/types" - types3 "github.com/smartcontractkit/chainlink/v2/core/chains/evm/headtracker/types" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller/mocks" @@ -211,7 +211,7 @@ func TestRegistry_refreshLogTriggerUpkeeps(t *testing.T) { { name: "an error is returned when fetching indexed logs for IKeeperRegistryMasterUpkeepUnpaused errors", ids: []*big.Int{ - core.GenUpkeepID(types.LogTrigger, "abc").BigInt(), + core.GenUpkeepID(types2.LogTrigger, "abc").BigInt(), }, logEventProvider: &mockLogEventProvider{ RefreshActiveUpkeepsFn: func(ids ...*big.Int) ([]*big.Int, error) { @@ -234,8 +234,8 @@ func TestRegistry_refreshLogTriggerUpkeeps(t *testing.T) { { name: "an error is returned when fetching indexed logs for IKeeperRegistryMasterUpkeepTriggerConfigSet errors", ids: []*big.Int{ - core.GenUpkeepID(types.LogTrigger, "abc").BigInt(), - core.GenUpkeepID(types.ConditionTrigger, "abc").BigInt(), + core.GenUpkeepID(types2.LogTrigger, "abc").BigInt(), + core.GenUpkeepID(types2.ConditionTrigger, "abc").BigInt(), big.NewInt(-1), }, logEventProvider: &mockLogEventProvider{ @@ -259,8 +259,8 @@ func TestRegistry_refreshLogTriggerUpkeeps(t *testing.T) { { name: "an error is returned when parsing the logs using the registry errors", ids: []*big.Int{ - core.GenUpkeepID(types.LogTrigger, "abc").BigInt(), - core.GenUpkeepID(types.ConditionTrigger, "abc").BigInt(), + core.GenUpkeepID(types2.LogTrigger, "abc").BigInt(), + core.GenUpkeepID(types2.ConditionTrigger, "abc").BigInt(), big.NewInt(-1), }, logEventProvider: &mockLogEventProvider{ @@ -288,8 +288,8 @@ func TestRegistry_refreshLogTriggerUpkeeps(t *testing.T) { { name: "an error is returned when registering the filter errors", ids: []*big.Int{ - core.GenUpkeepID(types.LogTrigger, "abc").BigInt(), - core.GenUpkeepID(types.ConditionTrigger, "abc").BigInt(), + core.GenUpkeepID(types2.LogTrigger, "abc").BigInt(), + core.GenUpkeepID(types2.ConditionTrigger, "abc").BigInt(), big.NewInt(-1), }, logEventProvider: &mockLogEventProvider{ @@ -319,11 +319,11 @@ func TestRegistry_refreshLogTriggerUpkeeps(t *testing.T) { if log.BlockNumber == 1 { return &iregistry21.IKeeperRegistryMasterUpkeepTriggerConfigSet{ TriggerConfig: []byte{1, 2, 3}, - Id: core.GenUpkeepID(types.LogTrigger, "abc").BigInt(), + Id: core.GenUpkeepID(types2.LogTrigger, "abc").BigInt(), }, nil } return &iregistry21.IKeeperRegistryMasterUpkeepUnpaused{ - Id: core.GenUpkeepID(types.LogTrigger, "abc").BigInt(), + Id: core.GenUpkeepID(types2.LogTrigger, "abc").BigInt(), }, nil }, GetUpkeepTriggerConfigFn: func(opts *bind.CallOpts, upkeepId *big.Int) ([]byte, error) { @@ -341,9 +341,9 @@ func TestRegistry_refreshLogTriggerUpkeeps(t *testing.T) { { name: "log trigger upkeeps are refreshed without error", ids: []*big.Int{ - core.GenUpkeepID(types.LogTrigger, "abc").BigInt(), - core.GenUpkeepID(types.LogTrigger, "def").BigInt(), - core.GenUpkeepID(types.ConditionTrigger, "abc").BigInt(), + core.GenUpkeepID(types2.LogTrigger, "abc").BigInt(), + core.GenUpkeepID(types2.LogTrigger, "def").BigInt(), + core.GenUpkeepID(types2.ConditionTrigger, "abc").BigInt(), big.NewInt(-1), }, logEventProvider: &mockLogEventProvider{ @@ -372,12 +372,12 @@ func TestRegistry_refreshLogTriggerUpkeeps(t *testing.T) { ParseLogFn: func(log coreTypes.Log) (generated.AbigenLog, error) { if log.BlockNumber == 1 { return &iregistry21.IKeeperRegistryMasterUpkeepTriggerConfigSet{ - Id: core.GenUpkeepID(types.LogTrigger, "abc").BigInt(), + Id: core.GenUpkeepID(types2.LogTrigger, "abc").BigInt(), TriggerConfig: []byte{1, 2, 3}, }, nil } return &iregistry21.IKeeperRegistryMasterUpkeepUnpaused{ - Id: core.GenUpkeepID(types.LogTrigger, "def").BigInt(), + Id: core.GenUpkeepID(types2.LogTrigger, "def").BigInt(), }, nil }, GetUpkeepTriggerConfigFn: func(opts *bind.CallOpts, upkeepId *big.Int) ([]byte, error) { @@ -395,7 +395,7 @@ func TestRegistry_refreshLogTriggerUpkeeps(t *testing.T) { ids: func() []*big.Int { res := []*big.Int{} for i := 0; i < logTriggerRefreshBatchSize*3; i++ { - res = append(res, core.GenUpkeepID(types.LogTrigger, fmt.Sprintf("%d", i)).BigInt()) + res = append(res, core.GenUpkeepID(types2.LogTrigger, fmt.Sprintf("%d", i)).BigInt()) } return res }(), @@ -424,12 +424,12 @@ func TestRegistry_refreshLogTriggerUpkeeps(t *testing.T) { ParseLogFn: func(log coreTypes.Log) (generated.AbigenLog, error) { if log.BlockNumber == 1 { return &iregistry21.IKeeperRegistryMasterUpkeepTriggerConfigSet{ - Id: core.GenUpkeepID(types.LogTrigger, "abc").BigInt(), + Id: core.GenUpkeepID(types2.LogTrigger, "abc").BigInt(), TriggerConfig: []byte{1, 2, 3}, }, nil } return &iregistry21.IKeeperRegistryMasterUpkeepUnpaused{ - Id: core.GenUpkeepID(types.LogTrigger, "def").BigInt(), + Id: core.GenUpkeepID(types2.LogTrigger, "def").BigInt(), }, nil }, GetUpkeepTriggerConfigFn: func(opts *bind.CallOpts, upkeepId *big.Int) ([]byte, error) { @@ -447,7 +447,7 @@ func TestRegistry_refreshLogTriggerUpkeeps(t *testing.T) { ids: func() []*big.Int { res := []*big.Int{} for i := 0; i < logTriggerRefreshBatchSize+3; i++ { - res = append(res, core.GenUpkeepID(types.LogTrigger, fmt.Sprintf("%d", i)).BigInt()) + res = append(res, core.GenUpkeepID(types2.LogTrigger, fmt.Sprintf("%d", i)).BigInt()) } return res }(), @@ -478,12 +478,12 @@ func TestRegistry_refreshLogTriggerUpkeeps(t *testing.T) { ParseLogFn: func(log coreTypes.Log) (generated.AbigenLog, error) { if log.BlockNumber == 1 { return &iregistry21.IKeeperRegistryMasterUpkeepTriggerConfigSet{ - Id: core.GenUpkeepID(types.LogTrigger, "abc").BigInt(), + Id: core.GenUpkeepID(types2.LogTrigger, "abc").BigInt(), TriggerConfig: []byte{1, 2, 3}, }, nil } return &iregistry21.IKeeperRegistryMasterUpkeepUnpaused{ - Id: core.GenUpkeepID(types.LogTrigger, "def").BigInt(), + Id: core.GenUpkeepID(types2.LogTrigger, "def").BigInt(), }, nil }, GetUpkeepTriggerConfigFn: func(opts *bind.CallOpts, upkeepId *big.Int) ([]byte, error) { diff --git a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/services.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/services.go index 71ccee872f..5fe21b0872 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/services.go +++ b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/services.go @@ -1,136 +1,31 @@ package evm import ( - "fmt" - - "github.com/ethereum/go-ethereum/common" - "github.com/jmoiron/sqlx" - "github.com/smartcontractkit/libocr/offchainreporting2plus/ocr3types" ocrtypes "github.com/smartcontractkit/libocr/offchainreporting2plus/types" "github.com/smartcontractkit/chainlink-automation/pkg/v3/plugin" - ocr2keepers "github.com/smartcontractkit/chainlink-automation/pkg/v3/types" - - "github.com/smartcontractkit/chainlink/v2/core/chains/legacyevm" - iregistry21 "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/i_keeper_registry_master_wrapper_2_1" - "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/evmregistry/v21/encoding" - "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/logprovider" - "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/transmit" - "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/upkeepstate" - "github.com/smartcontractkit/chainlink/v2/core/services/pg" ) type AutomationServices interface { - Registry() *EvmRegistry - Encoder() ocr2keepers.Encoder - TransmitEventProvider() *transmit.EventProvider - BlockSubscriber() *BlockSubscriber - PayloadBuilder() ocr2keepers.PayloadBuilder - UpkeepStateStore() upkeepstate.UpkeepStateStore - LogEventProvider() logprovider.LogEventProvider - LogRecoverer() logprovider.LogRecoverer - UpkeepProvider() ocr2keepers.ConditionalUpkeepProvider Keyring() ocr3types.OnchainKeyring[plugin.AutomationReportInfo] } -func New(addr common.Address, client legacyevm.Chain, mc *models.MercuryCredentials, keyring ocrtypes.OnchainKeyring, lggr logger.Logger, db *sqlx.DB, dbCfg pg.QConfig) (AutomationServices, error) { - registryContract, err := iregistry21.NewIKeeperRegistryMaster(addr, client.Client()) - if err != nil { - return nil, fmt.Errorf("%w: failed to create caller for address and backend", ErrInitializationFailure) - } - // lookback blocks for transmit event is hard coded and should provide ample time for logs - // to be detected in most cases - var transmitLookbackBlocks int64 = 250 - transmitEventProvider, err := transmit.NewTransmitEventProvider(lggr, client.LogPoller(), addr, client.Client(), transmitLookbackBlocks) - if err != nil { - return nil, err - } +func New(keyring ocrtypes.OnchainKeyring) (AutomationServices, error) { services := new(automationServices) - services.transmitEventProvider = transmitEventProvider - - packer := encoding.NewAbiPacker() - services.encoder = encoding.NewReportEncoder(packer) - - finalityDepth := client.Config().EVM().FinalityDepth() - - orm := upkeepstate.NewORM(client.ID(), db, lggr, dbCfg) - scanner := upkeepstate.NewPerformedEventsScanner(lggr, client.LogPoller(), addr, finalityDepth) - services.upkeepState = upkeepstate.NewUpkeepStateStore(orm, lggr, scanner) - - 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) services.keyring = NewOnchainKeyringV3Wrapper(keyring) - al := NewActiveUpkeepList() - services.payloadBuilder = NewPayloadBuilder(al, logRecoverer, lggr) - - services.reg = NewEvmRegistry(lggr, addr, client, - registryContract, mc, al, services.logProvider, - packer, services.blockSub, finalityDepth) - - services.upkeepProvider = NewUpkeepProvider(al, services.blockSub, client.LogPoller()) - return services, nil } type automationServices struct { - reg *EvmRegistry - encoder ocr2keepers.Encoder - transmitEventProvider *transmit.EventProvider - blockSub *BlockSubscriber - payloadBuilder ocr2keepers.PayloadBuilder - upkeepState upkeepstate.UpkeepStateStore - logProvider logprovider.LogEventProvider - logRecoverer logprovider.LogRecoverer - upkeepProvider *upkeepProvider - keyring *onchainKeyringV3Wrapper + keyring *onchainKeyringV3Wrapper } var _ AutomationServices = &automationServices{} -func (f *automationServices) Registry() *EvmRegistry { - return f.reg -} - -func (f *automationServices) Encoder() ocr2keepers.Encoder { - return f.encoder -} - -func (f *automationServices) TransmitEventProvider() *transmit.EventProvider { - return f.transmitEventProvider -} - -func (f *automationServices) BlockSubscriber() *BlockSubscriber { - return f.blockSub -} - -func (f *automationServices) PayloadBuilder() ocr2keepers.PayloadBuilder { - return f.payloadBuilder -} - -func (f *automationServices) UpkeepStateStore() upkeepstate.UpkeepStateStore { - return f.upkeepState -} - -func (f *automationServices) LogEventProvider() logprovider.LogEventProvider { - return f.logProvider -} - -func (f *automationServices) LogRecoverer() logprovider.LogRecoverer { - return f.logRecoverer -} - -func (f *automationServices) UpkeepProvider() ocr2keepers.ConditionalUpkeepProvider { - return f.upkeepProvider -} - func (f *automationServices) Keyring() ocr3types.OnchainKeyring[plugin.AutomationReportInfo] { return f.keyring } diff --git a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/transmit/cache.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/transmit/cache.go index 2c0055482e..814e86040b 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/transmit/cache.go +++ b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/transmit/cache.go @@ -3,7 +3,7 @@ package transmit import ( "sync" - ocr2keepers "github.com/smartcontractkit/chainlink-automation/pkg/v3/types" + ocr2keepers "github.com/smartcontractkit/chainlink-common/pkg/types/automation" ) // transmitEventCache holds a ring buffer of the last visited blocks (transmit block), diff --git a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/transmit/cache_test.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/transmit/cache_test.go index 7f4a129656..e7b7ca800a 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/transmit/cache_test.go +++ b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/transmit/cache_test.go @@ -5,7 +5,7 @@ import ( "github.com/stretchr/testify/require" - ocr2keepers "github.com/smartcontractkit/chainlink-automation/pkg/v3/types" + ocr2keepers "github.com/smartcontractkit/chainlink-common/pkg/types/automation" ) func TestTransmitEventCache_Sanity(t *testing.T) { diff --git a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/transmit/encoding.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/transmit/encoding.go index 17d3cd439f..89dbb52c0e 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/transmit/encoding.go +++ b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/transmit/encoding.go @@ -4,7 +4,7 @@ import ( "fmt" "math/big" - ocr2keepers "github.com/smartcontractkit/chainlink-automation/pkg/v3/types" + ocr2keepers "github.com/smartcontractkit/chainlink-common/pkg/types/automation" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller" iregistry21 "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/i_keeper_registry_master_wrapper_2_1" diff --git a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/transmit/encoding_test.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/transmit/encoding_test.go index da32376aab..97aed4706e 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/transmit/encoding_test.go +++ b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/transmit/encoding_test.go @@ -3,10 +3,12 @@ package transmit import ( "testing" + "github.com/smartcontractkit/chainlink-automation/pkg/v3/types" + "github.com/ethereum/go-ethereum/common" "github.com/stretchr/testify/require" - ocr2keepers "github.com/smartcontractkit/chainlink-automation/pkg/v3/types" + ocr2keepers "github.com/smartcontractkit/chainlink-common/pkg/types/automation" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller" iregistry21 "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/i_keeper_registry_master_wrapper_2_1" @@ -14,7 +16,7 @@ import ( ) func TestTransmitEventLog(t *testing.T) { - uid := core.GenUpkeepID(ocr2keepers.ConditionTrigger, "111") + uid := core.GenUpkeepID(types.ConditionTrigger, "111") tests := []struct { name string diff --git a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/transmit/event_provider.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/transmit/event_provider.go index f66711c2b7..eb8dc1793c 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/transmit/event_provider.go +++ b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/transmit/event_provider.go @@ -6,9 +6,11 @@ import ( "fmt" "sync" + "github.com/smartcontractkit/chainlink-automation/pkg/v3/types" + "github.com/ethereum/go-ethereum/common" - ocr2keepers "github.com/smartcontractkit/chainlink-automation/pkg/v3/types" + ocr2keepers "github.com/smartcontractkit/chainlink-common/pkg/types/automation" "github.com/smartcontractkit/chainlink-common/pkg/services" @@ -20,7 +22,7 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/services/pg" ) -var _ ocr2keepers.TransmitEventProvider = &EventProvider{} +var _ types.TransmitEventProvider = &EventProvider{} type logParser func(registry *iregistry21.IKeeperRegistryMaster, log logpoller.Log) (transmitEventLog, error) @@ -189,7 +191,7 @@ func (c *EventProvider) processLogs(latestBlock int64, logs ...logpoller.Log) ([ triggerW.BlockHash, ) switch core.GetUpkeepType(*upkeepId) { - case ocr2keepers.LogTrigger: + case types.LogTrigger: trigger.LogTriggerExtension = &ocr2keepers.LogTriggerExtension{} trigger.LogTriggerExtension.TxHash = triggerW.TxHash trigger.LogTriggerExtension.Index = triggerW.LogIndex diff --git a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/transmit/event_provider_test.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/transmit/event_provider_test.go index 950ec81040..89a49f0780 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/transmit/event_provider_test.go +++ b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/transmit/event_provider_test.go @@ -5,12 +5,14 @@ import ( "runtime" "testing" + "github.com/smartcontractkit/chainlink-automation/pkg/v3/types" + "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" - ocr2keepers "github.com/smartcontractkit/chainlink-automation/pkg/v3/types" + ocr2keepers "github.com/smartcontractkit/chainlink-common/pkg/types/automation" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" evmClientMocks "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client/mocks" @@ -107,7 +109,7 @@ func TestTransmitEventProvider_ProcessLogs(t *testing.T) { provider, err := NewTransmitEventProvider(logger.TestLogger(t), lp, common.HexToAddress("0x"), client, 250) require.NoError(t, err) - id := core.GenUpkeepID(ocr2keepers.LogTrigger, "1111111111111111") + id := core.GenUpkeepID(types.LogTrigger, "1111111111111111") tests := []struct { name string diff --git a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/upkeep_provider.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/upkeep_provider.go index b30215e4fb..01f136aaa6 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/upkeep_provider.go +++ b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/upkeep_provider.go @@ -4,7 +4,8 @@ import ( "context" "fmt" - ocr2keepers "github.com/smartcontractkit/chainlink-automation/pkg/v3/types" + "github.com/smartcontractkit/chainlink-automation/pkg/v3/types" + ocr2keepers "github.com/smartcontractkit/chainlink-common/pkg/types/automation" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/core" @@ -32,7 +33,7 @@ func (p *upkeepProvider) GetActiveUpkeeps(_ context.Context) ([]ocr2keepers.Upke return nil, fmt.Errorf("no latest block found when fetching active upkeeps") } var payloads []ocr2keepers.UpkeepPayload - for _, uid := range p.activeUpkeeps.View(ocr2keepers.ConditionTrigger) { + for _, uid := range p.activeUpkeeps.View(types.ConditionTrigger) { payload, err := core.NewUpkeepPayload( uid, ocr2keepers.NewTrigger(latestBlock.Number, latestBlock.Hash), diff --git a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/upkeep_provider_test.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/upkeep_provider_test.go index 81ea391318..cad2d77411 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/upkeep_provider_test.go +++ b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/upkeep_provider_test.go @@ -5,9 +5,11 @@ import ( "sync/atomic" "testing" + "github.com/smartcontractkit/chainlink-automation/pkg/v3/types" + "github.com/stretchr/testify/require" - ocr2keepers "github.com/smartcontractkit/chainlink-automation/pkg/v3/types" + ocr2keepers "github.com/smartcontractkit/chainlink-common/pkg/types/automation" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" @@ -29,7 +31,7 @@ func TestUpkeepProvider_GetActiveUpkeeps(t *testing.T) { { "empty", &mockActiveUpkeepList{ - ViewFn: func(upkeepType ...ocr2keepers.UpkeepType) []*big.Int { + ViewFn: func(upkeepType ...types.UpkeepType) []*big.Int { return []*big.Int{} }, }, @@ -40,7 +42,7 @@ func TestUpkeepProvider_GetActiveUpkeeps(t *testing.T) { { "happy flow", &mockActiveUpkeepList{ - ViewFn: func(upkeepType ...ocr2keepers.UpkeepType) []*big.Int { + ViewFn: func(upkeepType ...types.UpkeepType) []*big.Int { return []*big.Int{ big.NewInt(1), big.NewInt(2), @@ -65,7 +67,7 @@ func TestUpkeepProvider_GetActiveUpkeeps(t *testing.T) { { "latest block not found", &mockActiveUpkeepList{ - ViewFn: func(upkeepType ...ocr2keepers.UpkeepType) []*big.Int { + ViewFn: func(upkeepType ...types.UpkeepType) []*big.Int { return []*big.Int{ big.NewInt(1), big.NewInt(2), @@ -100,11 +102,11 @@ func TestUpkeepProvider_GetActiveUpkeeps(t *testing.T) { type mockActiveUpkeepList struct { ActiveUpkeepList - ViewFn func(...ocr2keepers.UpkeepType) []*big.Int + ViewFn func(...types.UpkeepType) []*big.Int IsActiveFn func(id *big.Int) bool } -func (l *mockActiveUpkeepList) View(u ...ocr2keepers.UpkeepType) []*big.Int { +func (l *mockActiveUpkeepList) View(u ...types.UpkeepType) []*big.Int { return l.ViewFn(u...) } diff --git a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/upkeepstate/store.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/upkeepstate/store.go index 19b3c46f50..9410374d7c 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/upkeepstate/store.go +++ b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/upkeepstate/store.go @@ -8,7 +8,7 @@ import ( "sync" "time" - ocr2keepers "github.com/smartcontractkit/chainlink-automation/pkg/v3/types" + ocr2keepers "github.com/smartcontractkit/chainlink-common/pkg/types/automation" "github.com/smartcontractkit/chainlink-common/pkg/services" diff --git a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/upkeepstate/store_test.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/upkeepstate/store_test.go index 7108e1b64c..3912e2a99c 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/upkeepstate/store_test.go +++ b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/upkeepstate/store_test.go @@ -12,7 +12,7 @@ import ( "github.com/stretchr/testify/require" "go.uber.org/zap/zapcore" - ocr2keepers "github.com/smartcontractkit/chainlink-automation/pkg/v3/types" + ocr2keepers "github.com/smartcontractkit/chainlink-common/pkg/types/automation" "github.com/smartcontractkit/chainlink-common/pkg/services/servicetest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" diff --git a/core/services/ocr2/plugins/ocr2keeper/util.go b/core/services/ocr2/plugins/ocr2keeper/util.go index 199bbac053..53fff8751c 100644 --- a/core/services/ocr2/plugins/ocr2keeper/util.go +++ b/core/services/ocr2/plugins/ocr2keeper/util.go @@ -15,13 +15,12 @@ import ( ocr2keepers20coordinator "github.com/smartcontractkit/chainlink-automation/pkg/v2/coordinator" ocr2keepers20polling "github.com/smartcontractkit/chainlink-automation/pkg/v2/observer/polling" ocr2keepers20runner "github.com/smartcontractkit/chainlink-automation/pkg/v2/runner" - ocr2keepers21 "github.com/smartcontractkit/chainlink-automation/pkg/v3/types" + ocr2keepers21 "github.com/smartcontractkit/chainlink-common/pkg/types/automation" "github.com/smartcontractkit/chainlink/v2/core/chains/legacyevm" "github.com/smartcontractkit/chainlink/v2/core/logger" "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/ocr2/models" evmregistry20 "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v20" evmregistry21 "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21" evmregistry21transmit "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/transmit" @@ -44,9 +43,9 @@ var ( ErrNoChainFromSpec = fmt.Errorf("could not create chain from spec") ) -func EVMProvider(db *sqlx.DB, chain legacyevm.Chain, lggr logger.Logger, spec job.Job, ethKeystore keystore.Eth) (evmrelay.OCR2KeeperProvider, error) { +func EVMProvider(db *sqlx.DB, chain legacyevm.Chain, lggr logger.Logger, spec job.Job, ethKeystore keystore.Eth, dbCfg pg.QConfig) (evmrelay.OCR2KeeperProvider, error) { oSpec := spec.OCR2OracleSpec - ocr2keeperRelayer := evmrelay.NewOCR2KeeperRelayer(db, chain, lggr.Named("OCR2KeeperRelayer"), ethKeystore) + ocr2keeperRelayer := evmrelay.NewOCR2KeeperRelayer(db, chain, lggr.Named("OCR2KeeperRelayer"), ethKeystore, dbCfg) keeperProvider, err := ocr2keeperRelayer.NewOCR2KeeperProvider( types.RelayArgs{ @@ -73,6 +72,7 @@ func EVMDependencies20( lggr logger.Logger, chain legacyevm.Chain, ethKeystore keystore.Eth, + dbCfg pg.QConfig, ) (evmrelay.OCR2KeeperProvider, *evmregistry20.EvmRegistry, Encoder20, *evmregistry20.LogProvider, error) { var err error @@ -80,7 +80,7 @@ func EVMDependencies20( var registry *evmregistry20.EvmRegistry // the provider will be returned as a dependency - if keeperProvider, err = EVMProvider(db, chain, lggr, spec, ethKeystore); err != nil { + if keeperProvider, err = EVMProvider(db, chain, lggr, spec, ethKeystore, dbCfg); err != nil { return nil, nil, nil, nil, err } @@ -109,25 +109,9 @@ func FilterNamesFromSpec20(spec *job.OCR2OracleSpec) (names []string, err error) } func EVMDependencies21( - spec job.Job, - db *sqlx.DB, - lggr logger.Logger, - chain legacyevm.Chain, - mc *models.MercuryCredentials, keyring ocrtypes.OnchainKeyring, - dbCfg pg.QConfig, ) (evmregistry21.AutomationServices, error) { - var err error - - oSpec := spec.OCR2OracleSpec - - rAddr := ethkey.MustEIP55Address(oSpec.ContractID).Address() - services, err := evmregistry21.New(rAddr, chain, mc, keyring, lggr, db, dbCfg) - if err != nil { - return nil, err - } - - return services, err + return evmregistry21.New(keyring) } func FilterNamesFromSpec21(spec *job.OCR2OracleSpec) (names []string, err error) { diff --git a/core/services/ocr2/validate/config.go b/core/services/ocr2/validate/config.go index 549b929b23..0084a18308 100644 --- a/core/services/ocr2/validate/config.go +++ b/core/services/ocr2/validate/config.go @@ -49,7 +49,7 @@ func ToLocalConfig(ocr2Config OCR2Config, insConf InsecureConfig, spec job.OCR2O ContractTransmitterTransmitTimeout: ocr2Config.ContractTransmitterTransmitTimeout(), DatabaseTimeout: ocr2Config.DatabaseTimeout(), } - if spec.Relay == relay.Solana && env.MedianPluginCmd.Get() != "" { + if spec.Relay == relay.Solana && env.MedianPlugin.Cmd.Get() != "" { // Work around for Solana Feeds configured with zero values to support LOOP Plugins. minOCR2MaxDurationQuery, err := getMinOCR2MaxDurationQuery() if err != nil { diff --git a/core/services/ocr2/validate/validate.go b/core/services/ocr2/validate/validate.go index 5a7062867a..21d33f469c 100644 --- a/core/services/ocr2/validate/validate.go +++ b/core/services/ocr2/validate/validate.go @@ -146,10 +146,11 @@ type Config struct { } type innerConfig struct { - Command string `json:"command"` - ProviderType string `json:"providerType"` - PluginName string `json:"pluginName"` - TelemetryType string `json:"telemetryType"` + Command string `json:"command"` + EnvVars map[string]string `json:"envVars"` + ProviderType string `json:"providerType"` + PluginName string `json:"pluginName"` + TelemetryType string `json:"telemetryType"` Config } diff --git a/core/services/pipeline/internal/eautils/eautils.go b/core/services/pipeline/internal/eautils/eautils.go new file mode 100644 index 0000000000..30faa826b2 --- /dev/null +++ b/core/services/pipeline/internal/eautils/eautils.go @@ -0,0 +1,39 @@ +package eautils + +import ( + "encoding/json" + "net/http" +) + +type AdapterStatus struct { + ErrorMessage *string `json:"errorMessage"` + Error any `json:"error"` + StatusCode *int `json:"statusCode"` + ProviderStatusCode *int `json:"providerStatusCode"` +} + +func BestEffortExtractEAStatus(responseBytes []byte) (code int, ok bool) { + var status AdapterStatus + err := json.Unmarshal(responseBytes, &status) + if err != nil { + return 0, false + } + + if status.StatusCode == nil { + return 0, false + } + + if *status.StatusCode != http.StatusOK { + return *status.StatusCode, true + } + + if status.ProviderStatusCode != nil && *status.ProviderStatusCode != http.StatusOK { + return *status.ProviderStatusCode, true + } + + if status.Error != nil { + return http.StatusInternalServerError, true + } + + return *status.StatusCode, true +} diff --git a/core/services/pipeline/internal/eautils/eautils_test.go b/core/services/pipeline/internal/eautils/eautils_test.go new file mode 100644 index 0000000000..80183b80d2 --- /dev/null +++ b/core/services/pipeline/internal/eautils/eautils_test.go @@ -0,0 +1,61 @@ +package eautils + +import ( + "net/http" + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestBestEffortExtractEAStatus(t *testing.T) { + tests := []struct { + name string + arg []byte + expectCode int + expectOk bool + }{ + { + name: "invalid object", + arg: []byte(`{"error": "invalid json object" `), + expectCode: 0, + expectOk: false, + }, + { + name: "no status code in object", + arg: []byte(`{}`), + expectCode: 0, + expectOk: false, + }, + { + name: "invalid status code", + arg: []byte(`{"statusCode":400}`), + expectCode: http.StatusBadRequest, + expectOk: true, + }, + { + name: "invalid provider status code", + arg: []byte(`{"statusCode":200, "providerStatusCode":500}`), + expectCode: http.StatusInternalServerError, + expectOk: true, + }, + { + name: "valid statuses with error message", + arg: []byte(`{"statusCode":200, "providerStatusCode":200, "error": "unexpected error"}`), + expectCode: http.StatusInternalServerError, + expectOk: true, + }, + { + name: "valid status code", + arg: []byte(`{"statusCode":200}`), + expectCode: http.StatusOK, + expectOk: true, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + code, ok := BestEffortExtractEAStatus(tt.arg) + assert.Equal(t, tt.expectCode, code) + assert.Equal(t, tt.expectOk, ok) + }) + } +} diff --git a/core/services/pipeline/task.bridge.go b/core/services/pipeline/task.bridge.go index f9490ea791..1da34d1913 100644 --- a/core/services/pipeline/task.bridge.go +++ b/core/services/pipeline/task.bridge.go @@ -16,6 +16,7 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/bridges" "github.com/smartcontractkit/chainlink/v2/core/logger" + "github.com/smartcontractkit/chainlink/v2/core/services/pipeline/internal/eautils" ) // NOTE: These metrics generate a new label per bridge, this should be safe @@ -167,7 +168,13 @@ func (t *BridgeTask) Run(ctx context.Context, lggr logger.Logger, vars Vars, inp var cachedResponse bool responseBytes, statusCode, headers, elapsed, err := makeHTTPRequest(requestCtx, lggr, "POST", url, reqHeaders, requestData, t.httpClient, t.config.DefaultHTTPLimit()) - if err != nil { + + // check for external adapter response object status + if code, ok := eautils.BestEffortExtractEAStatus(responseBytes); ok { + statusCode = code + } + + if err != nil || statusCode != http.StatusOK { promBridgeErrors.WithLabelValues(t.Name).Inc() if cacheTTL == 0 { return Result{Error: err}, RunInfo{IsRetryable: isRetryableHTTPError(statusCode, err)} diff --git a/core/services/pipeline/task.bridge_test.go b/core/services/pipeline/task.bridge_test.go index bf1e63d631..7673add1e3 100644 --- a/core/services/pipeline/task.bridge_test.go +++ b/core/services/pipeline/task.bridge_test.go @@ -19,7 +19,6 @@ import ( "github.com/shopspring/decimal" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - "gopkg.in/guregu/null.v4" commonconfig "github.com/smartcontractkit/chainlink-common/pkg/config" "github.com/smartcontractkit/chainlink/v2/core/bridges" @@ -32,6 +31,7 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" "github.com/smartcontractkit/chainlink/v2/core/services/pg" "github.com/smartcontractkit/chainlink/v2/core/services/pipeline" + "github.com/smartcontractkit/chainlink/v2/core/services/pipeline/internal/eautils" "github.com/smartcontractkit/chainlink/v2/core/store/models" "github.com/smartcontractkit/chainlink/v2/core/utils" ) @@ -59,11 +59,43 @@ type adapterResponseData struct { // adapterResponse is the HTTP response as defined by the external adapter: // https://github.com/smartcontractkit/bnc-adapter type adapterResponse struct { - Data adapterResponseData `json:"data"` - ErrorMessage null.String `json:"errorMessage"` + eautils.AdapterStatus + Data adapterResponseData `json:"data"` } -func (pr adapterResponse) Result() *decimal.Decimal { +func (pr *adapterResponse) SetStatusCode(code int) { + pr.StatusCode = &code +} + +func (pr *adapterResponse) UnsetStatusCode() { + pr.StatusCode = nil +} + +func (pr *adapterResponse) SetProviderStatusCode(code int) { + pr.ProviderStatusCode = &code +} + +func (pr *adapterResponse) UnsetProviderStatusCode() { + pr.ProviderStatusCode = nil +} + +func (pr *adapterResponse) SetError(msg string) { + pr.Error = msg +} + +func (pr *adapterResponse) UnsetError() { + pr.Error = nil +} + +func (pr *adapterResponse) SetErrorMessage(msg string) { + pr.ErrorMessage = &msg +} + +func (pr *adapterResponse) UnsetErrorMessage() { + pr.ErrorMessage = nil +} + +func (pr *adapterResponse) Result() *decimal.Decimal { return pr.Data.Result } @@ -295,7 +327,7 @@ func TestBridgeTask_DoesNotReturnStaleResults(t *testing.T) { task.HelperSetDependencies(cfg.JobPipeline(), cfg.WebServer(), orm, specID, uuid.UUID{}, c) // Insert entry 1m in the past, stale value, should not be used in case of EA failure. - err = queryer.ExecQ(`INSERT INTO bridge_last_value(dot_id, spec_id, value, finished_at) + err = queryer.ExecQ(`INSERT INTO bridge_last_value(dot_id, spec_id, value, finished_at) VALUES($1, $2, $3, $4) ON CONFLICT ON CONSTRAINT bridge_last_value_pkey DO UPDATE SET value = $3, finished_at = $4;`, task.DotID(), specID, big.NewInt(9700).Bytes(), time.Now().Add(-1*time.Minute)) require.NoError(t, err) @@ -786,9 +818,10 @@ func TestBridgeTask_ErrorMessage(t *testing.T) { handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusTooManyRequests) - err := json.NewEncoder(w).Encode(adapterResponse{ - ErrorMessage: null.StringFrom("could not hit data fetcher"), - }) + + resp := &adapterResponse{} + resp.SetErrorMessage("could not hit data fetcher") + err := json.NewEncoder(w).Encode(resp) require.NoError(t, err) }) @@ -1016,3 +1049,93 @@ func TestBridgeTask_Headers(t *testing.T) { assert.Equal(t, []string{"Content-Length", "38", "Content-Type", "footype", "User-Agent", "Go-http-client/1.1", "X-Header-1", "foo", "X-Header-2", "bar"}, allHeaders(headers)) }) } + +func TestBridgeTask_AdapterResponseStatusFailure(t *testing.T) { + t.Parallel() + + db := pgtest.NewSqlxDB(t) + cfg := configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { + c.WebServer.BridgeCacheTTL = commonconfig.MustNewDuration(1 * time.Minute) + }) + + testAdapterResponse := &adapterResponse{ + Data: adapterResponseData{Result: &decimal.Zero}, + } + + queryer := pg.NewQ(db, logger.TestLogger(t), cfg.Database()) + s1 := httptest.NewServer( + http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + err := json.NewEncoder(w).Encode(testAdapterResponse) + require.NoError(t, err) + })) + defer s1.Close() + + feedURL, err := url.ParseRequestURI(s1.URL) + require.NoError(t, err) + + orm := bridges.NewORM(db, logger.TestLogger(t), cfg.Database()) + _, bridge := cltest.MustCreateBridge(t, db, cltest.BridgeOpts{URL: feedURL.String()}, cfg.Database()) + + task := pipeline.BridgeTask{ + BaseTask: pipeline.NewBaseTask(0, "bridge", nil, nil, 0), + Name: bridge.Name.String(), + RequestData: btcUSDPairing, + } + c := clhttptest.NewTestLocalOnlyHTTPClient() + trORM := pipeline.NewORM(db, logger.TestLogger(t), cfg.Database(), cfg.JobPipeline().MaxSuccessfulRuns()) + specID, err := trORM.CreateSpec(pipeline.Pipeline{}, *models.NewInterval(5 * time.Minute), pg.WithParentCtx(testutils.Context(t))) + require.NoError(t, err) + task.HelperSetDependencies(cfg.JobPipeline(), cfg.WebServer(), orm, specID, uuid.UUID{}, c) + + // Insert entry 1m in the past, stale value, should not be used in case of EA failure. + err = queryer.ExecQ(`INSERT INTO bridge_last_value(dot_id, spec_id, value, finished_at) + VALUES($1, $2, $3, $4) ON CONFLICT ON CONSTRAINT bridge_last_value_pkey + DO UPDATE SET value = $3, finished_at = $4;`, task.DotID(), specID, big.NewInt(9700).Bytes(), time.Now()) + require.NoError(t, err) + + vars := pipeline.NewVarsFrom( + map[string]interface{}{ + "jobRun": map[string]interface{}{ + "meta": map[string]interface{}{ + "shouldFail": true, + }, + }, + }, + ) + + // expect all external adapter response status failures to be served from the cache + testAdapterResponse.SetStatusCode(http.StatusBadRequest) + result, runInfo := task.Run(testutils.Context(t), logger.TestLogger(t), vars, nil) + + require.NoError(t, result.Error) + require.NotNil(t, result.Value) + require.False(t, runInfo.IsRetryable) + require.False(t, runInfo.IsPending) + + testAdapterResponse.SetStatusCode(http.StatusOK) + testAdapterResponse.SetProviderStatusCode(http.StatusBadRequest) + result, runInfo = task.Run(testutils.Context(t), logger.TestLogger(t), vars, nil) + + require.NoError(t, result.Error) + require.NotNil(t, result.Value) + require.False(t, runInfo.IsRetryable) + require.False(t, runInfo.IsPending) + + testAdapterResponse.SetStatusCode(http.StatusOK) + testAdapterResponse.SetProviderStatusCode(http.StatusOK) + testAdapterResponse.SetError("some error") + result, runInfo = task.Run(testutils.Context(t), logger.TestLogger(t), vars, nil) + + require.NoError(t, result.Error) + require.NotNil(t, result.Value) + require.False(t, runInfo.IsRetryable) + require.False(t, runInfo.IsPending) + + testAdapterResponse.SetStatusCode(http.StatusInternalServerError) + result, runInfo = task.Run(testutils.Context(t), logger.TestLogger(t), vars, nil) + + require.NoError(t, result.Error) + require.NotNil(t, result.Value) + require.False(t, runInfo.IsRetryable) + require.False(t, runInfo.IsPending) +} diff --git a/core/services/pipeline/task.http_test.go b/core/services/pipeline/task.http_test.go index c0dd93df43..36ccc147a7 100644 --- a/core/services/pipeline/task.http_test.go +++ b/core/services/pipeline/task.http_test.go @@ -14,7 +14,6 @@ import ( "github.com/shopspring/decimal" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - "gopkg.in/guregu/null.v4" "github.com/smartcontractkit/chainlink/v2/core/bridges" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" @@ -264,9 +263,9 @@ func TestHTTPTask_ErrorMessage(t *testing.T) { handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusTooManyRequests) - err := json.NewEncoder(w).Encode(adapterResponse{ - ErrorMessage: null.StringFrom("could not hit data fetcher"), - }) + resp := &adapterResponse{} + resp.SetErrorMessage("could not hit data fetcher") + err := json.NewEncoder(w).Encode(resp) require.NoError(t, err) }) diff --git a/core/services/relay/evm/binding.go b/core/services/relay/evm/binding.go new file mode 100644 index 0000000000..e78d9f0a77 --- /dev/null +++ b/core/services/relay/evm/binding.go @@ -0,0 +1,15 @@ +package evm + +import ( + "context" + + commontypes "github.com/smartcontractkit/chainlink-common/pkg/types" +) + +type readBinding interface { + GetLatestValue(ctx context.Context, params, returnVal any) error + Bind(binding commontypes.BoundContract) error + SetCodec(codec commontypes.RemoteCodec) + Register() error + Unregister() error +} diff --git a/core/services/relay/evm/bindings.go b/core/services/relay/evm/bindings.go new file mode 100644 index 0000000000..1a23128d19 --- /dev/null +++ b/core/services/relay/evm/bindings.go @@ -0,0 +1,61 @@ +package evm + +import ( + "fmt" + + commontypes "github.com/smartcontractkit/chainlink-common/pkg/types" +) + +// key is contract name +type contractBindings map[string]readBindings + +// key is read name +type readBindings map[string]readBinding + +func (b contractBindings) GetReadBinding(contractName, readName string) (readBinding, error) { + rb, rbExists := b[contractName] + if !rbExists { + return nil, fmt.Errorf("%w: no contract named %s", commontypes.ErrInvalidType, contractName) + } + + reader, readerExists := rb[readName] + if !readerExists { + return nil, fmt.Errorf("%w: no readName named %s in contract %s", commontypes.ErrInvalidType, readName, contractName) + } + return reader, nil +} + +func (b contractBindings) AddReadBinding(contractName, readName string, reader readBinding) { + rbs, rbsExists := b[contractName] + if !rbsExists { + rbs = readBindings{} + b[contractName] = rbs + } + rbs[readName] = reader +} + +func (b contractBindings) Bind(boundContracts []commontypes.BoundContract) error { + for _, bc := range boundContracts { + rbs, rbsExist := b[bc.Name] + if !rbsExist { + return fmt.Errorf("%w: no contract named %s", commontypes.ErrInvalidConfig, bc.Name) + } + for _, r := range rbs { + if err := r.Bind(bc); err != nil { + return err + } + } + } + return nil +} + +func (b contractBindings) ForEach(fn func(readBinding) error) error { + for _, rbs := range b { + for _, rb := range rbs { + if err := fn(rb); err != nil { + return err + } + } + } + return nil +} diff --git a/core/services/relay/evm/ccip.go b/core/services/relay/evm/ccip.go index 4a2f06751e..c89c17b700 100644 --- a/core/services/relay/evm/ccip.go +++ b/core/services/relay/evm/ccip.go @@ -64,6 +64,10 @@ func (c *ccipCommitProvider) ChainReader() commontypes.ChainReader { return nil } +func (c *ccipCommitProvider) Codec() commontypes.Codec { + return nil +} + type ccipExecutionProvider struct { *configWatcher contractTransmitter *contractTransmitter @@ -104,3 +108,7 @@ func (c *ccipExecutionProvider) ContractTransmitter() ocrtypes.ContractTransmitt func (c *ccipExecutionProvider) ChainReader() commontypes.ChainReader { return nil } + +func (c *ccipExecutionProvider) Codec() commontypes.Codec { + return nil +} diff --git a/core/services/relay/evm/chain_reader.go b/core/services/relay/evm/chain_reader.go index e4da4cc1a4..dba05af7e3 100644 --- a/core/services/relay/evm/chain_reader.go +++ b/core/services/relay/evm/chain_reader.go @@ -3,14 +3,20 @@ package evm import ( "context" "fmt" - "slices" + "reflect" "strings" "github.com/ethereum/go-ethereum/accounts/abi" - "github.com/ethereum/go-ethereum/common" + "github.com/google/uuid" + "github.com/smartcontractkit/chainlink-common/pkg/codec" + + commonservices "github.com/smartcontractkit/chainlink-common/pkg/services" commontypes "github.com/smartcontractkit/chainlink-common/pkg/types" + evmclient "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" + "github.com/smartcontractkit/chainlink/v2/core/chains/legacyevm" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services" @@ -23,132 +29,264 @@ type ChainReaderService interface { } type chainReader struct { - lggr logger.Logger - contractID common.Address - lp logpoller.LogPoller + lggr logger.Logger + lp logpoller.LogPoller + client evmclient.Client + contractBindings contractBindings + parsed *parsedTypes + codec commontypes.RemoteCodec + commonservices.StateMachine } -// NewChainReaderService constructor for ChainReader -func NewChainReaderService(lggr logger.Logger, lp logpoller.LogPoller, contractID common.Address, config types.ChainReaderConfig) (*chainReader, error) { - if err := validateChainReaderConfig(config); err != nil { - return nil, fmt.Errorf("%w: %w", commontypes.ErrInvalidConfig, err) +// NewChainReaderService is a constructor for ChainReader, returns nil if there is any error +func NewChainReaderService(lggr logger.Logger, lp logpoller.LogPoller, chain legacyevm.Chain, config types.ChainReaderConfig) (ChainReaderService, error) { + cr := &chainReader{ + lggr: lggr.Named("ChainReader"), + lp: lp, + client: chain.Client(), + contractBindings: contractBindings{}, + parsed: &parsedTypes{encoderDefs: map[string]types.CodecEntry{}, decoderDefs: map[string]types.CodecEntry{}}, } - // TODO BCF-2814 implement initialisation of chain reading definitions and pass them into chainReader - return &chainReader{lggr.Named("ChainReader"), contractID, lp}, nil -} + var err error + if err = cr.init(config.Contracts); err != nil { + return nil, err + } -func (cr *chainReader) Name() string { return cr.lggr.Name() } + if cr.codec, err = cr.parsed.toCodec(); err != nil { + return nil, err + } -func (cr *chainReader) initialize() error { - // Initialize chain reader, start cache polling loop, etc. - return nil -} + err = cr.contractBindings.ForEach(func(b readBinding) error { + b.SetCodec(cr.codec) + return nil + }) -func (cr *chainReader) Start(ctx context.Context) error { - if err := cr.initialize(); err != nil { - return fmt.Errorf("Failed to initialize ChainReader: %w", err) - } - return nil + return cr, err } -func (cr *chainReader) Close() error { return nil } +func (cr *chainReader) Name() string { return cr.lggr.Name() } -func (cr *chainReader) Ready() error { return nil } +var _ commontypes.ContractTypeProvider = &chainReader{} -func (cr *chainReader) HealthReport() map[string]error { - return map[string]error{cr.Name(): nil} -} +func (cr *chainReader) GetLatestValue(ctx context.Context, contractName, method string, params any, returnVal any) error { + b, err := cr.contractBindings.GetReadBinding(contractName, method) + if err != nil { + return err + } -func (cr *chainReader) GetLatestValue(ctx context.Context, bc commontypes.BoundContract, method string, params any, returnVal any) error { - return commontypes.UnimplementedError("Unimplemented method GetLatestValue called") + return b.GetLatestValue(ctx, params, returnVal) } -func validateChainReaderConfig(cfg types.ChainReaderConfig) error { - if len(cfg.ChainContractReaders) == 0 { - return fmt.Errorf("%w: no contract readers defined", commontypes.ErrInvalidConfig) - } +func (cr *chainReader) Bind(_ context.Context, bindings []commontypes.BoundContract) error { + return cr.contractBindings.Bind(bindings) +} - for contractName, chainContractReader := range cfg.ChainContractReaders { - abi, err := abi.JSON(strings.NewReader(chainContractReader.ContractABI)) +func (cr *chainReader) init(chainContractReaders map[string]types.ChainContractReader) error { + for contractName, chainContractReader := range chainContractReaders { + contractAbi, err := abi.JSON(strings.NewReader(chainContractReader.ContractABI)) if err != nil { - return fmt.Errorf("invalid abi: %w", err) + return err } - for chainReadingDefinitionName, chainReaderDefinition := range chainContractReader.ChainReaderDefinitions { + for typeName, chainReaderDefinition := range chainContractReader.Configs { switch chainReaderDefinition.ReadType { case types.Method: - err = validateMethods(abi, chainReaderDefinition) + err = cr.addMethod(contractName, typeName, contractAbi, *chainReaderDefinition) case types.Event: - err = validateEvents(abi, chainReaderDefinition) + err = cr.addEvent(contractName, typeName, contractAbi, *chainReaderDefinition) default: - return fmt.Errorf("%w: invalid chainreading definition read type: %d for contract: %q", commontypes.ErrInvalidConfig, chainReaderDefinition.ReadType, contractName) + return fmt.Errorf( + "%w: invalid chain reader definition read type: %s", + commontypes.ErrInvalidConfig, + chainReaderDefinition.ReadType) } + if err != nil { - return fmt.Errorf("%w: invalid chainreading definition: %q for contract: %q, err: %w", commontypes.ErrInvalidConfig, chainReadingDefinitionName, contractName, err) + return err } } } - return nil } -func validateEvents(contractABI abi.ABI, chainReaderDefinition types.ChainReaderDefinition) error { - event, methodExists := contractABI.Events[chainReaderDefinition.ChainSpecificName] +func (cr *chainReader) Start(_ context.Context) error { + return cr.StartOnce("ChainReader", func() error { + return cr.contractBindings.ForEach(readBinding.Register) + }) +} + +func (cr *chainReader) Close() error { + return cr.StopOnce("ChainReader", func() error { + return cr.contractBindings.ForEach(readBinding.Unregister) + }) +} + +func (cr *chainReader) Ready() error { return nil } +func (cr *chainReader) HealthReport() map[string]error { + return map[string]error{cr.Name(): nil} +} + +func (cr *chainReader) CreateContractType(contractName, methodName string, forEncoding bool) (any, error) { + return cr.codec.CreateType(wrapItemType(contractName, methodName, forEncoding), forEncoding) +} + +func wrapItemType(contractName, methodName string, isParams bool) string { + if isParams { + return fmt.Sprintf("params.%s.%s", contractName, methodName) + } + return fmt.Sprintf("return.%s.%s", contractName, methodName) +} + +func (cr *chainReader) addMethod( + contractName, + methodName string, + abi abi.ABI, + chainReaderDefinition types.ChainReaderDefinition) error { + method, methodExists := abi.Methods[chainReaderDefinition.ChainSpecificName] if !methodExists { - return fmt.Errorf("event: %s doesn't exist", chainReaderDefinition.ChainSpecificName) + return fmt.Errorf("%w: method %s doesn't exist", commontypes.ErrInvalidConfig, chainReaderDefinition.ChainSpecificName) } - var abiEventIndexedInputs []abi.Argument - for _, eventInput := range event.Inputs { - if eventInput.Indexed { - abiEventIndexedInputs = append(abiEventIndexedInputs, eventInput) - } + if len(chainReaderDefinition.EventInputFields) != 0 { + return fmt.Errorf( + "%w: method %s has event topic fields defined, but is not an event", + commontypes.ErrInvalidConfig, + chainReaderDefinition.ChainSpecificName) } - var chainReaderEventParams []string - for chainReaderEventParam := range chainReaderDefinition.Params { - chainReaderEventParams = append(chainReaderEventParams, chainReaderEventParam) + cr.contractBindings.AddReadBinding(contractName, methodName, &methodBinding{ + contractName: contractName, + method: methodName, + client: cr.client, + }) + + if err := cr.addEncoderDef(contractName, methodName, method.Inputs, method.ID, chainReaderDefinition); err != nil { + return err } - if !areChainReaderArgumentsValid(abiEventIndexedInputs, chainReaderEventParams) { - var abiEventIndexedInputsNames []string - for _, abiEventIndexedInput := range abiEventIndexedInputs { - abiEventIndexedInputsNames = append(abiEventIndexedInputsNames, abiEventIndexedInput.Name) - } - return fmt.Errorf("params: [%s] don't match abi event indexed inputs: [%s]", strings.Join(chainReaderEventParams, ","), strings.Join(abiEventIndexedInputsNames, ",")) + return cr.addDecoderDef(contractName, methodName, method.Outputs, chainReaderDefinition) +} + +func (cr *chainReader) addEvent(contractName, eventName string, a abi.ABI, chainReaderDefinition types.ChainReaderDefinition) error { + event, eventExists := a.Events[chainReaderDefinition.ChainSpecificName] + if !eventExists { + return fmt.Errorf("%w: event %s doesn't exist", commontypes.ErrInvalidConfig, chainReaderDefinition.ChainSpecificName) } - return nil + + filterArgs, topicInfo, indexArgNames := setupEventInput(event, chainReaderDefinition) + if err := verifyEventInputsUsed(chainReaderDefinition, indexArgNames); err != nil { + return err + } + + if err := topicInfo.Init(); err != nil { + return err + } + + // Encoder def's codec won't be used to encode, only for its type as input for GetLatestValue + if err := cr.addEncoderDef(contractName, eventName, filterArgs, nil, chainReaderDefinition); err != nil { + return err + } + + inputInfo, inputModifier, err := cr.getEventInput(chainReaderDefinition, contractName, eventName) + if err != nil { + return err + } + + cr.contractBindings.AddReadBinding(contractName, eventName, &eventBinding{ + contractName: contractName, + eventName: eventName, + lp: cr.lp, + hash: event.ID, + inputInfo: inputInfo, + inputModifier: inputModifier, + topicInfo: topicInfo, + id: wrapItemType(contractName, eventName, false) + uuid.NewString(), + }) + + return cr.addDecoderDef(contractName, eventName, event.Inputs, chainReaderDefinition) } -func validateMethods(abi abi.ABI, chainReaderDefinition types.ChainReaderDefinition) error { - method, methodExists := abi.Methods[chainReaderDefinition.ChainSpecificName] - if !methodExists { - return fmt.Errorf("method: %q doesn't exist", chainReaderDefinition.ChainSpecificName) +func (cr *chainReader) getEventInput(def types.ChainReaderDefinition, contractName, eventName string) ( + types.CodecEntry, codec.Modifier, error) { + inputInfo := cr.parsed.encoderDefs[wrapItemType(contractName, eventName, true)] + inMod, err := def.InputModifications.ToModifier(evmDecoderHooks...) + if err != nil { + return nil, nil, err } - var methodNames []string - for methodName := range chainReaderDefinition.Params { - methodNames = append(methodNames, methodName) + // initialize the modification + if _, err = inMod.RetypeToOffChain(reflect.PointerTo(inputInfo.CheckedType()), ""); err != nil { + return nil, nil, err } - if !areChainReaderArgumentsValid(method.Inputs, methodNames) { - var abiMethodInputs []string - for _, input := range method.Inputs { - abiMethodInputs = append(abiMethodInputs, input.Name) + return inputInfo, inMod, nil +} + +func verifyEventInputsUsed(chainReaderDefinition types.ChainReaderDefinition, indexArgNames map[string]bool) error { + for _, value := range chainReaderDefinition.EventInputFields { + if !indexArgNames[abi.ToCamelCase(value)] { + return fmt.Errorf("%w: %s is not an indexed argument of event %s", commontypes.ErrInvalidConfig, value, chainReaderDefinition.ChainSpecificName) } - return fmt.Errorf("params: [%s] don't match abi method inputs: [%s]", strings.Join(methodNames, ","), strings.Join(abiMethodInputs, ",")) } + return nil +} +func (cr *chainReader) addEncoderDef(contractName, methodName string, args abi.Arguments, prefix []byte, chainReaderDefinition types.ChainReaderDefinition) error { + // ABI.Pack prepends the method.ID to the encodings, we'll need the encoder to do the same. + inputMod, err := chainReaderDefinition.InputModifications.ToModifier(evmDecoderHooks...) + if err != nil { + return err + } + input := types.NewCodecEntry(args, prefix, inputMod) + + if err := input.Init(); err != nil { + return err + } + + cr.parsed.encoderDefs[wrapItemType(contractName, methodName, true)] = input return nil } -func areChainReaderArgumentsValid(contractArgs []abi.Argument, chainReaderArgs []string) bool { - for _, contractArg := range contractArgs { - if !slices.Contains(chainReaderArgs, contractArg.Name) { - return false +func (cr *chainReader) addDecoderDef(contractName, methodName string, outputs abi.Arguments, def types.ChainReaderDefinition) error { + mod, err := def.OutputModifications.ToModifier(evmDecoderHooks...) + if err != nil { + return err + } + output := types.NewCodecEntry(outputs, nil, mod) + cr.parsed.decoderDefs[wrapItemType(contractName, methodName, false)] = output + return output.Init() +} + +func setupEventInput(event abi.Event, def types.ChainReaderDefinition) ([]abi.Argument, types.CodecEntry, map[string]bool) { + topicFieldDefs := map[string]bool{} + for _, value := range def.EventInputFields { + capFirstValue := abi.ToCamelCase(value) + topicFieldDefs[capFirstValue] = true + } + + filterArgs := make([]abi.Argument, 0, types.MaxTopicFields) + inputArgs := make([]abi.Argument, 0, len(event.Inputs)) + indexArgNames := map[string]bool{} + + for _, input := range event.Inputs { + if !input.Indexed { + continue + } + + filterWith := topicFieldDefs[abi.ToCamelCase(input.Name)] + if filterWith { + // When presenting the filter off-chain, + // the user will provide the unhashed version of the input + // The reader will hash topics if needed. + inputUnindexed := input + inputUnindexed.Indexed = false + filterArgs = append(filterArgs, inputUnindexed) } + + inputArgs = append(inputArgs, input) + indexArgNames[abi.ToCamelCase(input.Name)] = true } - return true + return filterArgs, types.NewCodecEntry(inputArgs, nil, nil), indexArgNames } diff --git a/core/services/relay/evm/chain_reader_test.go b/core/services/relay/evm/chain_reader_test.go index ece2234ab5..02e9d4e3f6 100644 --- a/core/services/relay/evm/chain_reader_test.go +++ b/core/services/relay/evm/chain_reader_test.go @@ -1,272 +1,426 @@ -package evm +package evm_test import ( - "encoding/json" + "crypto/ecdsa" "fmt" - "strings" + "math" + "math/big" + "os" + "reflect" + "strconv" "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" + "github.com/ethereum/go-ethereum/common/hexutil" + "github.com/ethereum/go-ethereum/core" + evmtypes "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/crypto" + "github.com/smartcontractkit/libocr/commontypes" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" - commontypes "github.com/smartcontractkit/chainlink-common/pkg/types" + "github.com/smartcontractkit/chainlink-common/pkg/codec" - mocklogpoller "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller/mocks" + clcommontypes "github.com/smartcontractkit/chainlink-common/pkg/types" + . "github.com/smartcontractkit/chainlink-common/pkg/types/interfacetests" //nolint common practice to import test mods with . + + commontestutils "github.com/smartcontractkit/chainlink-common/pkg/loop/testutils" + + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller" "github.com/smartcontractkit/chainlink/v2/core/chains/legacyevm/mocks" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/chain_reader_example" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" + "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest" "github.com/smartcontractkit/chainlink/v2/core/logger" - evmtypes "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/types" + "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm" + "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/types" +) + +const ( + commonGasLimitOnEvms = uint64(4712388) + triggerWithDynamicTopic = "TriggeredEventWithDynamicTopic" + triggerWithAllTopics = "TriggeredWithFourTopics" ) -type chainReaderTestHelper struct { +func TestChainReader(t *testing.T) { + t.Parallel() + it := &chainReaderInterfaceTester{} + RunChainReaderInterfaceTests(t, it) + RunChainReaderInterfaceTests(t, commontestutils.WrapChainReaderTesterForLoop(it)) + t.Run("Dynamically typed topics can be used to filter and have type correct in return", func(t *testing.T) { + it.Setup(t) + + anyString := "foo" + tx, err := it.evmTest.LatestValueHolderTransactor.TriggerEventWithDynamicTopic(it.auth, anyString) + require.NoError(t, err) + it.sim.Commit() + it.incNonce() + it.awaitTx(t, tx) + ctx := testutils.Context(t) + + cr := it.GetChainReader(t) + require.NoError(t, cr.Bind(ctx, it.GetBindings(t))) + + input := struct{ Field string }{Field: anyString} + tp := cr.(clcommontypes.ContractTypeProvider) + output, err := tp.CreateContractType(AnyContractName, triggerWithDynamicTopic, false) + require.NoError(t, err) + rOutput := reflect.Indirect(reflect.ValueOf(output)) + + require.Eventually(t, func() bool { + return cr.GetLatestValue(ctx, AnyContractName, triggerWithDynamicTopic, input, output) == nil + }, it.MaxWaitTimeForEvents(), time.Millisecond*10) + + assert.Equal(t, &anyString, rOutput.FieldByName("Field").Interface()) + topic, err := abi.MakeTopics([]any{anyString}) + require.NoError(t, err) + assert.Equal(t, &topic[0][0], rOutput.FieldByName("FieldHash").Interface()) + }) + + t.Run("Multiple topics can filter together", func(t *testing.T) { + it.Setup(t) + triggerFourTopics(t, it, int32(1), int32(2), int32(3)) + triggerFourTopics(t, it, int32(2), int32(2), int32(3)) + triggerFourTopics(t, it, int32(1), int32(3), int32(3)) + triggerFourTopics(t, it, int32(1), int32(2), int32(4)) + + ctx := testutils.Context(t) + cr := it.GetChainReader(t) + require.NoError(t, cr.Bind(ctx, it.GetBindings(t))) + var latest struct{ Field1, Field2, Field3 int32 } + params := struct{ Field1, Field2, Field3 int32 }{Field1: 1, Field2: 2, Field3: 3} + + time.Sleep(it.MaxWaitTimeForEvents()) + + require.NoError(t, cr.GetLatestValue(ctx, AnyContractName, triggerWithAllTopics, params, &latest)) + assert.Equal(t, int32(1), latest.Field1) + assert.Equal(t, int32(2), latest.Field2) + assert.Equal(t, int32(3), latest.Field3) + }) +} + +func triggerFourTopics(t *testing.T, it *chainReaderInterfaceTester, i1, i2, i3 int32) { + tx, err := it.evmTest.LatestValueHolderTransactor.TriggerWithFourTopics(it.auth, i1, i2, i3) + require.NoError(t, err) + require.NoError(t, err) + it.sim.Commit() + it.incNonce() + it.awaitTx(t, tx) +} + +type chainReaderInterfaceTester struct { + chain *mocks.Chain + address string + address2 string + chainConfig types.ChainReaderConfig + auth *bind.TransactOpts + sim *backends.SimulatedBackend + pk *ecdsa.PrivateKey + evmTest *chain_reader_example.LatestValueHolder + cr evm.ChainReaderService +} + +func (it *chainReaderInterfaceTester) MaxWaitTimeForEvents() time.Duration { + // From trial and error, when running on CI, sometimes the boxes get slow + maxWaitTime := time.Second * 20 + maxWaitTimeStr, ok := os.LookupEnv("MAX_WAIT_TIME_FOR_EVENTS_S") + if ok { + wiatS, err := strconv.ParseInt(maxWaitTimeStr, 10, 64) + if err != nil { + fmt.Printf("Error parsing MAX_WAIT_TIME_FOR_EVENTS_S: %v, defaulting to %v\n", err, maxWaitTime) + } + maxWaitTime = time.Second * time.Duration(wiatS) + } + + return maxWaitTime } -func (crTestHelper chainReaderTestHelper) makeChainReaderConfig(abi string, params map[string]any) evmtypes.ChainReaderConfig { - return evmtypes.ChainReaderConfig{ - ChainContractReaders: map[string]evmtypes.ChainContractReader{ - "MyContract": { - ContractABI: abi, - ChainReaderDefinitions: map[string]evmtypes.ChainReaderDefinition{ - "MyGenericMethod": { - ChainSpecificName: "name", - Params: params, - CacheEnabled: false, - ReadType: evmtypes.Method, +func (it *chainReaderInterfaceTester) Setup(t *testing.T) { + t.Cleanup(func() { + // DB may be closed by the test already, ignore errors + if it.cr != nil { + _ = it.cr.Close() + } + it.cr = nil + it.evmTest = nil + }) + + // can re-use the same chain for tests, just make new contract for each test + if it.chain != nil { + it.deployNewContracts(t) + return + } + + it.chain = &mocks.Chain{} + it.setupChainNoClient(t) + + testStruct := CreateTestStruct(0, it) + + it.chainConfig = types.ChainReaderConfig{ + Contracts: map[string]types.ChainContractReader{ + AnyContractName: { + ContractABI: chain_reader_example.LatestValueHolderMetaData.ABI, + Configs: map[string]*types.ChainReaderDefinition{ + MethodTakingLatestParamsReturningTestStruct: { + ChainSpecificName: "getElementAtIndex", + OutputModifications: codec.ModifiersConfig{ + &codec.RenameModifierConfig{Fields: map[string]string{"NestedStruct.Inner.IntVal": "I"}}, + }, + }, + MethodReturningUint64: { + ChainSpecificName: "getPrimitiveValue", + }, + DifferentMethodReturningUint64: { + ChainSpecificName: "getDifferentPrimitiveValue", + }, + MethodReturningUint64Slice: { + ChainSpecificName: "getSliceValue", + }, + EventName: { + ChainSpecificName: "Triggered", + ReadType: types.Event, + OutputModifications: codec.ModifiersConfig{ + &codec.RenameModifierConfig{Fields: map[string]string{"NestedStruct.Inner.IntVal": "I"}}, + }, + }, + EventWithFilterName: { + ChainSpecificName: "Triggered", + ReadType: types.Event, + EventInputFields: []string{"Field"}, + }, + triggerWithDynamicTopic: { + ChainSpecificName: triggerWithDynamicTopic, + ReadType: types.Event, + EventInputFields: []string{"fieldHash"}, + InputModifications: codec.ModifiersConfig{ + &codec.RenameModifierConfig{Fields: map[string]string{"FieldHash": "Field"}}, + }, + }, + triggerWithAllTopics: { + ChainSpecificName: triggerWithAllTopics, + ReadType: types.Event, + EventInputFields: []string{"Field1", "Field2", "Field3"}, + }, + MethodReturningSeenStruct: { + ChainSpecificName: "returnSeen", + InputModifications: codec.ModifiersConfig{ + &codec.HardCodeModifierConfig{ + OnChainValues: map[string]any{ + "BigField": testStruct.BigField.String(), + "Account": hexutil.Encode(testStruct.Account), + }, + }, + &codec.RenameModifierConfig{Fields: map[string]string{"NestedStruct.Inner.IntVal": "I"}}, + }, + OutputModifications: codec.ModifiersConfig{ + &codec.HardCodeModifierConfig{OffChainValues: map[string]any{"ExtraField": anyExtraValue}}, + &codec.RenameModifierConfig{Fields: map[string]string{"NestedStruct.Inner.IntVal": "I"}}, + }, + }, + }, + }, + AnySecondContractName: { + ContractABI: chain_reader_example.LatestValueHolderMetaData.ABI, + Configs: map[string]*types.ChainReaderDefinition{ + MethodReturningUint64: { + ChainSpecificName: "getDifferentPrimitiveValue", }, }, }, }, } + it.chain.On("Client").Return(client.NewSimulatedBackendClient(t, it.sim, big.NewInt(1337))) + it.deployNewContracts(t) } -func (crTestHelper chainReaderTestHelper) makeChainReaderConfigFromStrings(abi string, chainReadingDefinitions string) (evmtypes.ChainReaderConfig, error) { - chainReaderConfigTemplate := `{ - "chainContractReaders": { - "testContract": { - "contractName": "testContract", - "contractABI": "[%s]", - "chainReaderDefinitions": { - %s - } - } - } - }` - - abi = strings.Replace(abi, `"`, `\"`, -1) - formattedCfgJsonString := fmt.Sprintf(chainReaderConfigTemplate, abi, chainReadingDefinitions) - var chainReaderConfig evmtypes.ChainReaderConfig - err := json.Unmarshal([]byte(formattedCfgJsonString), &chainReaderConfig) - return chainReaderConfig, err +func (it *chainReaderInterfaceTester) Name() string { + return "EVM" } -func TestNewChainReader(t *testing.T) { - lggr := logger.TestLogger(t) - lp := mocklogpoller.NewLogPoller(t) - chain := mocks.NewChain(t) - contractID := testutils.NewAddress() - contractABI := `[{"inputs":[{"internalType":"string","name":"param","type":"string"}],"name":"name","stateMutability":"view","type":"function"}]` - - t.Run("happy path", func(t *testing.T) { - params := make(map[string]any) - params["param"] = "" - chainReaderConfig := chainReaderTestHelper{}.makeChainReaderConfig(contractABI, params) - chain.On("LogPoller").Return(lp) - _, err := NewChainReaderService(lggr, chain.LogPoller(), contractID, chainReaderConfig) - assert.NoError(t, err) - }) +func (it *chainReaderInterfaceTester) GetAccountBytes(i int) []byte { + account := [20]byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10} + account[i%20] += byte(i) + account[(i+3)%20] += byte(i + 3) + return account[:] +} - t.Run("invalid config", func(t *testing.T) { - invalidChainReaderConfig := chainReaderTestHelper{}.makeChainReaderConfig(contractABI, map[string]any{}) // missing param - _, err := NewChainReaderService(lggr, chain.LogPoller(), contractID, invalidChainReaderConfig) - assert.ErrorIs(t, err, commontypes.ErrInvalidConfig) - }) +func (it *chainReaderInterfaceTester) GetChainReader(t *testing.T) clcommontypes.ChainReader { + ctx := testutils.Context(t) + if it.cr != nil { + return it.cr + } - t.Run("ChainReader config is empty", func(t *testing.T) { - emptyChainReaderConfig := evmtypes.ChainReaderConfig{} - _, err := NewChainReaderService(lggr, chain.LogPoller(), contractID, emptyChainReaderConfig) - assert.ErrorIs(t, err, commontypes.ErrInvalidConfig) - assert.ErrorContains(t, err, "no contract readers defined") - }) + lggr := logger.NullLogger + db := pgtest.NewSqlxDB(t) + lp := logpoller.NewLogPoller(logpoller.NewORM(testutils.SimulatedChainID, db, lggr, pgtest.NewQConfig(true)), it.chain.Client(), lggr, time.Millisecond, false, 0, 1, 1, 10000) + require.NoError(t, lp.Start(ctx)) + it.chain.On("LogPoller").Return(lp) + cr, err := evm.NewChainReaderService(lggr, lp, it.chain, it.chainConfig) + require.NoError(t, err) + require.NoError(t, cr.Start(ctx)) + it.cr = cr + return cr } -func TestChainReaderStartClose(t *testing.T) { - lggr := logger.TestLogger(t) - lp := mocklogpoller.NewLogPoller(t) - cr := chainReader{ - lggr: lggr, - lp: lp, +func (it *chainReaderInterfaceTester) SetLatestValue(t *testing.T, testStruct *TestStruct) { + it.sendTxWithTestStruct(t, testStruct, (*chain_reader_example.LatestValueHolderTransactor).AddTestStruct) +} + +func (it *chainReaderInterfaceTester) TriggerEvent(t *testing.T, testStruct *TestStruct) { + it.sendTxWithTestStruct(t, testStruct, (*chain_reader_example.LatestValueHolderTransactor).TriggerEvent) +} + +func (it *chainReaderInterfaceTester) GetBindings(t *testing.T) []clcommontypes.BoundContract { + return []clcommontypes.BoundContract{ + {Name: AnyContractName, Address: it.address, Pending: true}, + {Name: AnySecondContractName, Address: it.address2, Pending: true}, } - err := cr.Start(testutils.Context(t)) - assert.NoError(t, err) - err = cr.Close() - assert.NoError(t, err) } -// TODO Chain Reading Definitions return values are WIP, waiting on codec work and BCF-2789 -func TestValidateChainReaderConfig_HappyPath(t *testing.T) { - type testCase struct { - name string - abiInput string - chainReadingDefinitions string +type testStructFn = func(*chain_reader_example.LatestValueHolderTransactor, *bind.TransactOpts, int32, string, uint8, [32]uint8, common.Address, []common.Address, *big.Int, chain_reader_example.MidLevelTestStruct) (*evmtypes.Transaction, error) + +func (it *chainReaderInterfaceTester) sendTxWithTestStruct(t *testing.T, testStruct *TestStruct, fn testStructFn) { + tx, err := fn( + &it.evmTest.LatestValueHolderTransactor, + it.auth, + *testStruct.Field, + testStruct.DifferentField, + uint8(testStruct.OracleID), + convertOracleIDs(testStruct.OracleIDs), + common.Address(testStruct.Account), + convertAccounts(testStruct.Accounts), + testStruct.BigField, + midToInternalType(testStruct.NestedStruct), + ) + require.NoError(t, err) + it.sim.Commit() + it.incNonce() + it.awaitTx(t, tx) +} + +func convertOracleIDs(oracleIDs [32]commontypes.OracleID) [32]byte { + convertedIds := [32]byte{} + for i, id := range oracleIDs { + convertedIds[i] = byte(id) } + return convertedIds +} - var testCases []testCase - testCases = append(testCases, - testCase{ - name: "eventWithMultipleIndexedTopics", - abiInput: `{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"}],"name":"Swap","type":"event"}`, - chainReadingDefinitions: `"Swap":{ - "chainSpecificName": "Swap", - "params":{ - "sender": "0x0", - "to": "0x0" - }, - "readType": 1 - }`, - }) - - testCases = append(testCases, - testCase{ - name: "methodWithOneParamAndMultipleResponses", - abiInput: `{"constant":true,"inputs":[{"internalType":"address","name":"_user","type":"address"}],"name":"getUserAccountData","payable":false,"stateMutability":"view","type":"function"}`, - chainReadingDefinitions: `"getUserAccountData":{ - "chainSpecificName": "getUserAccountData", - "params":{ - "_user": "0x0" - }, - "readType": 0 - }`, - }) - - testCases = append(testCases, - testCase{ - name: "methodWithMultipleParamsAndOneResult", - abiInput: `{"inputs":[{"internalType":"address","name":"_input","type":"address"},{"internalType":"address","name":"_output","type":"address"},{"internalType":"uint256","name":"_inputQuantity","type":"uint256"}],"name":"getSwapOutput","stateMutability":"view","type":"function"}`, - chainReadingDefinitions: `"getSwapOutput":{ - "chainSpecificName": "getSwapOutput", - "params":{ - "_input":"0x0", - "_output":"0x0", - "_inputQuantity":"0x0" - }, - "readType": 0 - }`, - }) - - for _, tc := range testCases { - t.Run(tc.name, func(t *testing.T) { - cfg, err := chainReaderTestHelper{}.makeChainReaderConfigFromStrings(tc.abiInput, tc.chainReadingDefinitions) - assert.NoError(t, err) - assert.NoError(t, validateChainReaderConfig(cfg)) - }) +func convertAccounts(accounts [][]byte) []common.Address { + convertedAccounts := make([]common.Address, len(accounts)) + for i, a := range accounts { + convertedAccounts[i] = common.Address(a) } + return convertedAccounts +} - t.Run("large config with all test cases", func(t *testing.T) { - var largeABI string - var manyChainReadingDefinitions string - for _, tc := range testCases { - largeABI += tc.abiInput + "," - manyChainReadingDefinitions += tc.chainReadingDefinitions + "," - } +func (it *chainReaderInterfaceTester) setupChainNoClient(t require.TestingT) { + privateKey, err := crypto.GenerateKey() + require.NoError(t, err) + it.pk = privateKey - largeABI = largeABI[:len(largeABI)-1] - manyChainReadingDefinitions = manyChainReadingDefinitions[:len(manyChainReadingDefinitions)-1] - cfg, err := chainReaderTestHelper{}.makeChainReaderConfigFromStrings(largeABI, manyChainReadingDefinitions) - assert.NoError(t, err) - assert.NoError(t, validateChainReaderConfig(cfg)) - }) + it.auth, err = bind.NewKeyedTransactorWithChainID(privateKey, big.NewInt(1337)) + require.NoError(t, err) + + it.sim = backends.NewSimulatedBackend(core.GenesisAlloc{it.auth.From: {Balance: big.NewInt(math.MaxInt64)}}, commonGasLimitOnEvms*5000) + it.sim.Commit() } -// TODO Chain Reading Definitions return values are WIP, waiting on codec work and BCF-2789 -func TestValidateChainReaderConfig_BadPath(t *testing.T) { - type testCase struct { - name string - abiInput string - chainReadingDefinitions string - expected error +func (it *chainReaderInterfaceTester) deployNewContracts(t *testing.T) { + it.address = it.deployNewContract(t) + it.address2 = it.deployNewContract(t) +} + +func (it *chainReaderInterfaceTester) deployNewContract(t *testing.T) string { + ctx := testutils.Context(t) + gasPrice, err := it.sim.SuggestGasPrice(ctx) + require.NoError(t, err) + it.auth.GasPrice = gasPrice + + // 105528 was in the error: gas too low: have 0, want 105528 + // Not sure if there's a better way to get it. + it.auth.GasLimit = 10552800 + + address, tx, ts, err := chain_reader_example.DeployLatestValueHolder(it.auth, it.sim) + + require.NoError(t, err) + it.sim.Commit() + if it.evmTest == nil { + it.evmTest = ts } + it.incNonce() + it.awaitTx(t, tx) + return address.String() +} - var testCases []testCase - mismatchedEventArgumentsTestABI := `{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"Swap","type":"event"}` - testCases = append(testCases, - testCase{ - name: "mismatched abi and event chain reading param values", - abiInput: mismatchedEventArgumentsTestABI, - chainReadingDefinitions: `"Swap":{ - "chainSpecificName": "Swap", - "params":{ - "malformedParam": "0x0" - }, - "readType": 1 - }`, - expected: fmt.Errorf("invalid chainreading definition: \"Swap\" for contract: \"testContract\", err: params: [malformedParam] don't match abi event indexed inputs: [sender]"), - }) - - mismatchedFunctionArgumentsTestABI := `{"constant":true,"inputs":[{"internalType":"address","name":"from","type":"address"}],"name":"Swap","payable":false,"stateMutability":"view","type":"function"}` - testCases = append(testCases, - testCase{ - name: "mismatched abi and method chain reading param values", - abiInput: mismatchedFunctionArgumentsTestABI, - chainReadingDefinitions: `"Swap":{ - "chainSpecificName": "Swap", - "params":{ - "malformedParam": "0x0" - }, - "readType": 0 - }`, - expected: fmt.Errorf("invalid chainreading definition: \"Swap\" for contract: \"testContract\", err: params: [malformedParam] don't match abi method inputs: [from]"), - }, - ) +func (it *chainReaderInterfaceTester) awaitTx(t *testing.T, tx *evmtypes.Transaction) { + ctx := testutils.Context(t) + receipt, err := it.sim.TransactionReceipt(ctx, tx.Hash()) + require.NoError(t, err) + require.Equal(t, evmtypes.ReceiptStatusSuccessful, receipt.Status) +} - testCases = append(testCases, - testCase{ - name: "event doesn't exist", - abiInput: `{"constant":true,"inputs":[],"name":"someName","payable":false,"stateMutability":"view","type":"function"}`, - chainReadingDefinitions: `"TestMethod":{ - "chainSpecificName": "Swap", - "readType": 1 - }`, - expected: fmt.Errorf("invalid chainreading definition: \"TestMethod\" for contract: \"testContract\", err: event: Swap doesn't exist"), - }, - ) +func (it *chainReaderInterfaceTester) incNonce() { + if it.auth.Nonce == nil { + it.auth.Nonce = big.NewInt(1) + } else { + it.auth.Nonce = it.auth.Nonce.Add(it.auth.Nonce, big.NewInt(1)) + } +} - testCases = append(testCases, - testCase{ - name: "method doesn't exist", - abiInput: `{"constant":true,"inputs":[],"name":"someName","payable":false,"stateMutability":"view","type":"function"}`, - chainReadingDefinitions: `"TestMethod":{ - "chainSpecificName": "Swap", - "readType": 0 - }`, - expected: fmt.Errorf("invalid chainreading definition: \"TestMethod\" for contract: \"testContract\", err: method: \"Swap\" doesn't exist"), - }, - ) +func getAccounts(first TestStruct) []common.Address { + accountBytes := make([]common.Address, len(first.Accounts)) + for i, account := range first.Accounts { + accountBytes[i] = common.Address(account) + } + return accountBytes +} - testCases = append(testCases, testCase{ - name: "invalid abi", - abiInput: `broken abi`, - chainReadingDefinitions: `"TestMethod":{ - "chainSpecificName": "Swap", - "readType": 0 - }`, - expected: fmt.Errorf("invalid abi"), - }) +func argsFromTestStruct(ts TestStruct) []any { + return []any{ + ts.Field, + ts.DifferentField, + uint8(ts.OracleID), + getOracleIDs(ts), + common.Address(ts.Account), + getAccounts(ts), + ts.BigField, + midToInternalType(ts.NestedStruct), + } +} - testCases = append(testCases, testCase{ - name: "invalid read type", - abiInput: `{"constant":true,"inputs":[],"name":"someName","payable":false,"stateMutability":"view","type":"function"}`, - chainReadingDefinitions: `"TestMethod":{"readType": 59}`, - expected: fmt.Errorf("invalid chainreading definition read type: 59"), - }) +func getOracleIDs(first TestStruct) [32]byte { + oracleIDs := [32]byte{} + for i, oracleID := range first.OracleIDs { + oracleIDs[i] = byte(oracleID) + } + return oracleIDs +} - for _, tc := range testCases { - t.Run(tc.name, func(t *testing.T) { - cfg, err := chainReaderTestHelper{}.makeChainReaderConfigFromStrings(tc.abiInput, tc.chainReadingDefinitions) - assert.NoError(t, err) - if tc.expected == nil { - assert.NoError(t, validateChainReaderConfig(cfg)) - } else { - assert.ErrorContains(t, validateChainReaderConfig(cfg), tc.expected.Error()) - } - }) +func toInternalType(testStruct TestStruct) chain_reader_example.TestStruct { + return chain_reader_example.TestStruct{ + Field: *testStruct.Field, + DifferentField: testStruct.DifferentField, + OracleId: byte(testStruct.OracleID), + OracleIds: convertOracleIDs(testStruct.OracleIDs), + Account: common.Address(testStruct.Account), + Accounts: convertAccounts(testStruct.Accounts), + BigField: testStruct.BigField, + NestedStruct: midToInternalType(testStruct.NestedStruct), + } +} + +func midToInternalType(m MidLevelTestStruct) chain_reader_example.MidLevelTestStruct { + return chain_reader_example.MidLevelTestStruct{ + FixedBytes: m.FixedBytes, + Inner: chain_reader_example.InnerTestStruct{ + IntVal: int64(m.Inner.I), + S: m.Inner.S, + }, } } diff --git a/core/services/relay/evm/codec.go b/core/services/relay/evm/codec.go new file mode 100644 index 0000000000..a87976da54 --- /dev/null +++ b/core/services/relay/evm/codec.go @@ -0,0 +1,146 @@ +package evm + +import ( + "encoding/json" + "fmt" + "math/big" + "reflect" + + "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/hexutil" + "github.com/mitchellh/mapstructure" + + "github.com/smartcontractkit/chainlink-common/pkg/codec" + + commontypes "github.com/smartcontractkit/chainlink-common/pkg/types" + + "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/types" +) + +// decodeAccountAndAllowArraySliceHook allows: +// +// strings to be converted to [32]byte allowing config to represent them as 0x... +// slices or arrays to be converted to a pointer to that type +// +// BigIntHook allows *big.Int to be represented as any integer type or a string and to go back to them. +// Useful for config, or if when a model may use a go type that isn't a *big.Int when Pack expects one. +// Eg: int32 in a go struct from a plugin could require a *big.Int in Pack for int24, if it fits, we shouldn't care. +// SliceToArrayVerifySizeHook verifies that slices have the correct size when converting to an array +// sizeVerifyBigIntHook allows our custom types that verify the number fits in the on-chain type to be converted as-if +// it was a *big.Int +var evmDecoderHooks = []mapstructure.DecodeHookFunc{decodeAccountAndAllowArraySliceHook, codec.BigIntHook, codec.SliceToArrayVerifySizeHook, sizeVerifyBigIntHook} + +// NewCodec creates a new [commontypes.RemoteCodec] for EVM. +// Note that names in the ABI are converted to Go names using [abi.ToCamelCase], +// this is per convention in [abi.MakeTopics], [abi.Arguments.Pack] etc. +// This allows names on-chain to be in go convention when generated. +// It means that if you need to use a [codec.Modifier] to reference a field +// you need to use the Go name instead of the name on-chain. +// eg: rename FooBar -> Bar, not foo_bar_ to Bar if the name on-chain is foo_bar_ +func NewCodec(conf types.CodecConfig) (commontypes.RemoteCodec, error) { + parsed := &parsedTypes{ + encoderDefs: map[string]types.CodecEntry{}, + decoderDefs: map[string]types.CodecEntry{}, + } + + for k, v := range conf.Configs { + args := abi.Arguments{} + if err := json.Unmarshal(([]byte)(v.TypeABI), &args); err != nil { + return nil, err + } + + mod, err := v.ModifierConfigs.ToModifier(evmDecoderHooks...) + if err != nil { + return nil, err + } + + item := types.NewCodecEntry(args, nil, mod) + if err = item.Init(); err != nil { + return nil, err + } + + parsed.encoderDefs[k] = item + parsed.decoderDefs[k] = item + } + + return parsed.toCodec() +} + +type evmCodec struct { + *encoder + *decoder + *parsedTypes +} + +func (c *evmCodec) CreateType(itemType string, forEncoding bool) (any, error) { + var itemTypes map[string]types.CodecEntry + if forEncoding { + itemTypes = c.encoderDefs + } else { + itemTypes = c.decoderDefs + } + + def, ok := itemTypes[itemType] + if !ok { + return nil, fmt.Errorf("%w: cannot find type name %s", commontypes.ErrInvalidType, itemType) + } + + return reflect.New(def.CheckedType()).Interface(), nil +} + +var bigIntType = reflect.TypeOf((*big.Int)(nil)) + +func sizeVerifyBigIntHook(from, to reflect.Type, data any) (any, error) { + if from.Implements(types.SizedBigIntType()) && + !to.Implements(types.SizedBigIntType()) && + !reflect.PointerTo(to).Implements(types.SizedBigIntType()) { + return codec.BigIntHook(from, bigIntType, reflect.ValueOf(data).Convert(bigIntType).Interface()) + } + + if !to.Implements(types.SizedBigIntType()) { + return data, nil + } + + var err error + data, err = codec.BigIntHook(from, bigIntType, data) + if err != nil { + return nil, err + } + + bi, ok := data.(*big.Int) + if !ok { + return data, nil + } + + converted := reflect.ValueOf(bi).Convert(to).Interface().(types.SizedBigInt) + return converted, converted.Verify() +} + +func decodeAccountAndAllowArraySliceHook(from, to reflect.Type, data any) (any, error) { + if from.Kind() == reflect.String && + (to == reflect.TypeOf(common.Address{}) || to == reflect.TypeOf(&common.Address{})) { + return decodeAddress(data) + } + + if from.Kind() == reflect.Pointer && to.Kind() != reflect.Pointer && from != nil && + (from.Elem().Kind() == reflect.Slice || from.Elem().Kind() == reflect.Array) { + return reflect.ValueOf(data).Elem().Interface(), nil + } + + return data, nil +} + +func decodeAddress(data any) (any, error) { + decoded, err := hexutil.Decode(data.(string)) + if err != nil { + return nil, fmt.Errorf("%w: %w", commontypes.ErrInvalidType, err) + } else if len(decoded) != common.AddressLength { + return nil, fmt.Errorf( + "%w: wrong number size for address expected %v got %v", + commontypes.ErrSliceWrongLen, + common.AddressLength, len(decoded)) + } + + return common.Address(decoded), nil +} diff --git a/core/services/relay/evm/codec_fuzz_test.go b/core/services/relay/evm/codec_fuzz_test.go new file mode 100644 index 0000000000..5870e9d77a --- /dev/null +++ b/core/services/relay/evm/codec_fuzz_test.go @@ -0,0 +1,12 @@ +package evm_test + +import ( + "testing" + + "github.com/smartcontractkit/chainlink-common/pkg/types/interfacetests" +) + +func FuzzCodec(f *testing.F) { + tester := &codecInterfaceTester{} + interfacetests.RunCodecInterfaceFuzzTests(f, tester) +} diff --git a/core/services/relay/evm/codec_test.go b/core/services/relay/evm/codec_test.go new file mode 100644 index 0000000000..b13051cb01 --- /dev/null +++ b/core/services/relay/evm/codec_test.go @@ -0,0 +1,210 @@ +package evm_test + +import ( + "encoding/json" + "testing" + + "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/ethereum/go-ethereum/common/hexutil" + ocr2types "github.com/smartcontractkit/libocr/offchainreporting2plus/types" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + "github.com/smartcontractkit/chainlink-common/pkg/codec" + + looptestutils "github.com/smartcontractkit/chainlink-common/pkg/loop/testutils" //nolint common practice to import test mods with . + commontypes "github.com/smartcontractkit/chainlink-common/pkg/types" + . "github.com/smartcontractkit/chainlink-common/pkg/types/interfacetests" //nolint common practice to import test mods with . + + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/chain_reader_example" + "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" + "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm" + "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/types" +) + +const anyExtraValue = 3 + +func TestCodec(t *testing.T) { + tester := &codecInterfaceTester{} + RunCodecInterfaceTests(t, tester) + RunCodecInterfaceTests(t, looptestutils.WrapCodecTesterForLoop(tester)) + + anyN := 10 + c := tester.GetCodec(t) + t.Run("GetMaxEncodingSize delegates to GetMaxSize", func(t *testing.T) { + actual, err := c.GetMaxEncodingSize(testutils.Context(t), anyN, sizeItemType) + assert.NoError(t, err) + + expected, err := types.GetMaxSize(anyN, parseDefs(t)[sizeItemType]) + require.NoError(t, err) + assert.Equal(t, expected, actual) + }) + + t.Run("GetMaxDecodingSize delegates to GetMaxSize", func(t *testing.T) { + actual, err := c.GetMaxDecodingSize(testutils.Context(t), anyN, sizeItemType) + assert.NoError(t, err) + + expected, err := types.GetMaxSize(anyN, parseDefs(t)[sizeItemType]) + require.NoError(t, err) + assert.Equal(t, expected, actual) + }) +} + +type codecInterfaceTester struct{} + +func (it *codecInterfaceTester) Setup(_ *testing.T) {} + +func (it *codecInterfaceTester) GetAccountBytes(i int) []byte { + account := [20]byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10} + // fuzz tests can make -ve numbers + if i < 0 { + i = -i + } + account[i%20] += byte(i) + account[(i+3)%20] += byte(i + 3) + return account[:] +} + +func (it *codecInterfaceTester) EncodeFields(t *testing.T, request *EncodeRequest) []byte { + if request.TestOn == TestItemType { + return encodeFieldsOnItem(t, request) + } + + return encodeFieldsOnSliceOrArray(t, request) +} + +func (it *codecInterfaceTester) GetCodec(t *testing.T) commontypes.Codec { + codecConfig := types.CodecConfig{Configs: map[string]types.ChainCodecConfig{}} + testStruct := CreateTestStruct(0, it) + for k, v := range codecDefs { + defBytes, err := json.Marshal(v) + require.NoError(t, err) + entry := codecConfig.Configs[k] + entry.TypeABI = string(defBytes) + + if k != sizeItemType && k != NilType { + entry.ModifierConfigs = codec.ModifiersConfig{ + &codec.RenameModifierConfig{Fields: map[string]string{"NestedStruct.Inner.IntVal": "I"}}, + } + } + + if k == TestItemWithConfigExtra { + hardCode := &codec.HardCodeModifierConfig{ + OnChainValues: map[string]any{ + "BigField": testStruct.BigField.String(), + "Account": hexutil.Encode(testStruct.Account), + }, + OffChainValues: map[string]any{"ExtraField": anyExtraValue}, + } + entry.ModifierConfigs = append(entry.ModifierConfigs, hardCode) + } + codecConfig.Configs[k] = entry + } + + c, err := evm.NewCodec(codecConfig) + require.NoError(t, err) + return c +} + +func (it *codecInterfaceTester) IncludeArrayEncodingSizeEnforcement() bool { + return true +} +func (it *codecInterfaceTester) Name() string { + return "EVM" +} + +func encodeFieldsOnItem(t *testing.T, request *EncodeRequest) ocr2types.Report { + return packArgs(t, argsFromTestStruct(request.TestStructs[0]), parseDefs(t)[TestItemType], request) +} + +func encodeFieldsOnSliceOrArray(t *testing.T, request *EncodeRequest) []byte { + oargs := parseDefs(t)[request.TestOn] + args := make([]any, 1) + + switch request.TestOn { + case TestItemArray1Type: + args[0] = [1]chain_reader_example.TestStruct{toInternalType(request.TestStructs[0])} + case TestItemArray2Type: + args[0] = [2]chain_reader_example.TestStruct{toInternalType(request.TestStructs[0]), toInternalType(request.TestStructs[1])} + default: + tmp := make([]chain_reader_example.TestStruct, len(request.TestStructs)) + for i, ts := range request.TestStructs { + tmp[i] = toInternalType(ts) + } + args[0] = tmp + } + + return packArgs(t, args, oargs, request) +} + +func packArgs(t *testing.T, allArgs []any, oargs abi.Arguments, request *EncodeRequest) []byte { + // extra capacity in case we add an argument + args := make(abi.Arguments, len(oargs), len(oargs)+1) + copy(args, oargs) + // decoding has extra field to decode + if request.ExtraField { + fakeType, err := abi.NewType("int32", "", []abi.ArgumentMarshaling{}) + require.NoError(t, err) + args = append(args, abi.Argument{Name: "FakeField", Type: fakeType}) + allArgs = append(allArgs, 11) + } + + if request.MissingField { + args = args[1:] //nolint we know it's non-zero len + allArgs = allArgs[1:] //nolint we know it's non-zero len + } + + bytes, err := args.Pack(allArgs...) + require.NoError(t, err) + return bytes +} + +var inner = []abi.ArgumentMarshaling{ + {Name: "IntVal", Type: "int64"}, + {Name: "S", Type: "string"}, +} + +var nested = []abi.ArgumentMarshaling{ + {Name: "FixedBytes", Type: "bytes2"}, + {Name: "Inner", Type: "tuple", Components: inner}, +} + +var ts = []abi.ArgumentMarshaling{ + {Name: "Field", Type: "int32"}, + {Name: "DifferentField", Type: "string"}, + {Name: "OracleId", Type: "uint8"}, + {Name: "OracleIds", Type: "uint8[32]"}, + {Name: "Account", Type: "address"}, + {Name: "Accounts", Type: "address[]"}, + {Name: "BigField", Type: "int192"}, + {Name: "NestedStruct", Type: "tuple", Components: nested}, +} + +const sizeItemType = "item for size" + +var codecDefs = map[string][]abi.ArgumentMarshaling{ + TestItemType: ts, + TestItemSliceType: { + {Name: "", Type: "tuple[]", Components: ts}, + }, + TestItemArray1Type: { + {Name: "", Type: "tuple[1]", Components: ts}, + }, + TestItemArray2Type: { + {Name: "", Type: "tuple[2]", Components: ts}, + }, + sizeItemType: { + {Name: "Stuff", Type: "int256[]"}, + {Name: "OtherStuff", Type: "int256"}, + }, + TestItemWithConfigExtra: ts, + NilType: {}, +} + +func parseDefs(t *testing.T) map[string]abi.Arguments { + bytes, err := json.Marshal(codecDefs) + require.NoError(t, err) + var results map[string]abi.Arguments + require.NoError(t, json.Unmarshal(bytes, &results)) + return results +} diff --git a/core/services/relay/evm/decoder.go b/core/services/relay/evm/decoder.go new file mode 100644 index 0000000000..f16875d80f --- /dev/null +++ b/core/services/relay/evm/decoder.go @@ -0,0 +1,102 @@ +package evm + +import ( + "context" + "fmt" + "reflect" + + "github.com/mitchellh/mapstructure" + + commontypes "github.com/smartcontractkit/chainlink-common/pkg/types" + + "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/types" +) + +type decoder struct { + Definitions map[string]types.CodecEntry +} + +var _ commontypes.Decoder = &decoder{} + +func (m *decoder) Decode(_ context.Context, raw []byte, into any, itemType string) error { + info, ok := m.Definitions[itemType] + if !ok { + return fmt.Errorf("%w: cannot find definition for %s", commontypes.ErrInvalidType, itemType) + } + + decode, err := extractDecoding(info, raw) + if err != nil { + return err + } + + rDecode := reflect.ValueOf(decode) + switch rDecode.Kind() { + case reflect.Array: + return m.decodeArray(into, rDecode) + case reflect.Slice: + iInto := reflect.Indirect(reflect.ValueOf(into)) + length := rDecode.Len() + iInto.Set(reflect.MakeSlice(iInto.Type(), length, length)) + return setElements(length, rDecode, iInto) + default: + return mapstructureDecode(decode, into) + } +} + +func (m *decoder) decodeArray(into any, rDecode reflect.Value) error { + iInto := reflect.Indirect(reflect.ValueOf(into)) + length := rDecode.Len() + if length != iInto.Len() { + return commontypes.ErrSliceWrongLen + } + iInto.Set(reflect.New(iInto.Type()).Elem()) + return setElements(length, rDecode, iInto) +} + +func (m *decoder) GetMaxDecodingSize(_ context.Context, n int, itemType string) (int, error) { + entry, ok := m.Definitions[itemType] + if !ok { + return 0, fmt.Errorf("%w: nil entry", commontypes.ErrInvalidType) + } + return entry.GetMaxSize(n) +} + +func extractDecoding(info types.CodecEntry, raw []byte) (any, error) { + unpacked := map[string]any{} + args := info.Args() + if err := args.UnpackIntoMap(unpacked, raw); err != nil { + return nil, fmt.Errorf("%w: %w: for args %#v", commontypes.ErrInvalidEncoding, err, args) + } + var decode any = unpacked + + if noName, ok := unpacked[""]; ok { + decode = noName + } + return decode, nil +} + +func setElements(length int, rDecode reflect.Value, iInto reflect.Value) error { + for i := 0; i < length; i++ { + if err := mapstructureDecode(rDecode.Index(i).Interface(), iInto.Index(i).Addr().Interface()); err != nil { + return err + } + } + + return nil +} + +func mapstructureDecode(src, dest any) error { + mDecoder, err := mapstructure.NewDecoder(&mapstructure.DecoderConfig{ + DecodeHook: mapstructure.ComposeDecodeHookFunc(evmDecoderHooks...), + Result: dest, + Squash: true, + }) + if err != nil { + return fmt.Errorf("%w: %w", commontypes.ErrInvalidType, err) + } + + if err = mDecoder.Decode(src); err != nil { + return fmt.Errorf("%w: %w", commontypes.ErrInvalidType, err) + } + return nil +} diff --git a/core/services/relay/evm/encoder.go b/core/services/relay/evm/encoder.go new file mode 100644 index 0000000000..ae60e4ab35 --- /dev/null +++ b/core/services/relay/evm/encoder.go @@ -0,0 +1,145 @@ +package evm + +import ( + "context" + "fmt" + "reflect" + + commontypes "github.com/smartcontractkit/chainlink-common/pkg/types" + + "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/types" +) + +type encoder struct { + Definitions map[string]types.CodecEntry +} + +var _ commontypes.Encoder = &encoder{} + +func (e *encoder) Encode(_ context.Context, item any, itemType string) (res []byte, err error) { + // nil values can cause abi.Arguments.Pack to panic. + defer func() { + if r := recover(); r != nil { + res = nil + err = fmt.Errorf("%w: cannot encode type", commontypes.ErrInvalidType) + } + }() + info, ok := e.Definitions[itemType] + if !ok { + return nil, fmt.Errorf("%w: cannot find definition for %s", commontypes.ErrInvalidType, itemType) + } + + if len(info.Args()) == 0 { + return info.EncodingPrefix(), nil + } else if item == nil { + return nil, fmt.Errorf("%w: cannot encode nil value for %s", commontypes.ErrInvalidType, itemType) + } + + return encode(reflect.ValueOf(item), info) +} + +func (e *encoder) GetMaxEncodingSize(_ context.Context, n int, itemType string) (int, error) { + entry, ok := e.Definitions[itemType] + if !ok { + return 0, fmt.Errorf("%w: nil entry", commontypes.ErrInvalidType) + } + return entry.GetMaxSize(n) +} + +func encode(item reflect.Value, info types.CodecEntry) ([]byte, error) { + for item.Kind() == reflect.Pointer { + item = reflect.Indirect(item) + } + switch item.Kind() { + case reflect.Array, reflect.Slice: + native, err := representArray(item, info) + if err != nil { + return nil, err + } + return pack(info, native) + case reflect.Struct, reflect.Map: + values, err := unrollItem(item, info) + if err != nil { + return nil, err + } + return pack(info, values...) + default: + return nil, fmt.Errorf("%w: cannot encode kind %v", commontypes.ErrInvalidType, item.Kind()) + } +} + +func representArray(item reflect.Value, info types.CodecEntry) (any, error) { + length := item.Len() + checkedType := info.CheckedType() + checked := reflect.New(checkedType) + iChecked := reflect.Indirect(checked) + switch checkedType.Kind() { + case reflect.Array: + if checkedType.Len() != length { + return nil, commontypes.ErrSliceWrongLen + } + case reflect.Slice: + iChecked.Set(reflect.MakeSlice(checkedType, length, length)) + default: + return nil, fmt.Errorf("%w: cannot encode %v as array", commontypes.ErrInvalidType, checkedType.Kind()) + } + + checkedElm := checkedType.Elem() + for i := 0; i < length; i++ { + tmp := reflect.New(checkedElm) + if err := mapstructureDecode(item.Index(i).Interface(), tmp.Interface()); err != nil { + return nil, err + } + iChecked.Index(i).Set(tmp.Elem()) + } + native, err := info.ToNative(checked) + if err != nil { + return nil, err + } + + return native.Elem().Interface(), nil +} + +func unrollItem(item reflect.Value, info types.CodecEntry) ([]any, error) { + checkedType := info.CheckedType() + if item.CanAddr() { + item = item.Addr() + } + + if item.Type() == reflect.PointerTo(checkedType) { + var err error + if item, err = info.ToNative(item); err != nil { + return nil, err + } + } else if !info.IsNativePointer(item.Type()) { + var err error + checked := reflect.New(checkedType) + if err = mapstructureDecode(item.Interface(), checked.Interface()); err != nil { + return nil, err + } + if item, err = info.ToNative(checked); err != nil { + return nil, err + } + } + + item = reflect.Indirect(item) + length := item.NumField() + values := make([]any, length) + iType := item.Type() + for i := 0; i < length; i++ { + if iType.Field(i).IsExported() { + values[i] = item.Field(i).Interface() + } + } + return values, nil +} + +func pack(info types.CodecEntry, values ...any) ([]byte, error) { + bytes, err := info.Args().Pack(values...) + if err != nil { + return nil, fmt.Errorf("%w: %w", commontypes.ErrInvalidType, err) + } + + withPrefix := info.EncodingPrefix() + return append(withPrefix, bytes...), nil +} diff --git a/core/services/relay/evm/event_binding.go b/core/services/relay/evm/event_binding.go new file mode 100644 index 0000000000..b7148348e4 --- /dev/null +++ b/core/services/relay/evm/event_binding.go @@ -0,0 +1,291 @@ +package evm + +import ( + "context" + "fmt" + "reflect" + "strings" + "sync" + + "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/ethereum/go-ethereum/common" + + "github.com/smartcontractkit/chainlink-common/pkg/codec" + commontypes "github.com/smartcontractkit/chainlink-common/pkg/types" + + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller" + evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" + "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/types" +) + +type eventBinding struct { + address common.Address + contractName string + eventName string + lp logpoller.LogPoller + hash common.Hash + codec commontypes.RemoteCodec + pending bool + bound bool + registerCalled bool + lock sync.Mutex + inputInfo types.CodecEntry + inputModifier codec.Modifier + topicInfo types.CodecEntry + // used to allow Register and Unregister to be unique in case two bindings have the same event. + // otherwise, if one unregisters, it'll unregister both with the LogPoller. + id string +} + +var _ readBinding = &eventBinding{} + +func (e *eventBinding) SetCodec(codec commontypes.RemoteCodec) { + e.codec = codec +} + +func (e *eventBinding) Register() error { + e.lock.Lock() + defer e.lock.Unlock() + + e.registerCalled = true + if !e.bound || e.lp.HasFilter(e.id) { + return nil + } + + if err := e.lp.RegisterFilter(logpoller.Filter{ + Name: e.id, + EventSigs: evmtypes.HashArray{e.hash}, + Addresses: evmtypes.AddressArray{e.address}, + }); err != nil { + return fmt.Errorf("%w: %w", commontypes.ErrInternal, err) + } + return nil +} + +func (e *eventBinding) Unregister() error { + e.lock.Lock() + defer e.lock.Unlock() + + if !e.lp.HasFilter(e.id) { + return nil + } + + if err := e.lp.UnregisterFilter(e.id); err != nil { + return fmt.Errorf("%w: %w", commontypes.ErrInternal, err) + } + return nil +} + +func (e *eventBinding) GetLatestValue(ctx context.Context, params, into any) error { + if !e.bound { + return fmt.Errorf("%w: event not bound", commontypes.ErrInvalidType) + } + + confs := logpoller.Finalized + if e.pending { + confs = logpoller.Unconfirmed + } + + if len(e.inputInfo.Args()) == 0 { + return e.getLatestValueWithoutFilters(ctx, confs, into) + } + + return e.getLatestValueWithFilters(ctx, confs, params, into) +} + +func (e *eventBinding) Bind(binding commontypes.BoundContract) error { + if err := e.Unregister(); err != nil { + return err + } + + e.address = common.HexToAddress(binding.Address) + e.pending = binding.Pending + e.bound = true + + if e.registerCalled { + return e.Register() + } + return nil +} + +func (e *eventBinding) getLatestValueWithoutFilters(ctx context.Context, confs logpoller.Confirmations, into any) error { + log, err := e.lp.LatestLogByEventSigWithConfs(e.hash, e.address, confs) + if err = wrapInternalErr(err); err != nil { + return err + } + + return e.decodeLog(ctx, log, into) +} + +func (e *eventBinding) getLatestValueWithFilters( + ctx context.Context, confs logpoller.Confirmations, params, into any) error { + offChain, err := e.convertToOffChainType(params) + if err != nil { + return err + } + + checkedParams, err := e.inputModifier.TransformToOnChain(offChain, "" /* unused */) + if err != nil { + return err + } + + nativeParams, err := e.inputInfo.ToNative(reflect.ValueOf(checkedParams)) + if err != nil { + return err + } + + filtersAndIndices, err := e.encodeParams(nativeParams) + if err != nil { + return err + } + + fai := filtersAndIndices[0] + remainingFilters := filtersAndIndices[1:] + + logs, err := e.lp.IndexedLogs(e.hash, e.address, 1, []common.Hash{fai}, confs) + if err != nil { + return wrapInternalErr(err) + } + + // TODO: there should be a better way to ask log poller to filter these + // First, you should be able to ask for as many topics to match + // Second, you should be able to get the latest only + var logToUse *logpoller.Log + for _, log := range logs { + tmp := log + if compareLogs(&tmp, logToUse) > 0 && matchesRemainingFilters(&tmp, remainingFilters) { + // copy so that it's not pointing to the changing variable + logToUse = &tmp + } + } + + if logToUse == nil { + return fmt.Errorf("%w: no events found", commontypes.ErrNotFound) + } + + return e.decodeLog(ctx, logToUse, into) +} + +func (e *eventBinding) convertToOffChainType(params any) (any, error) { + itemType := wrapItemType(e.contractName, e.eventName, true) + offChain, err := e.codec.CreateType(itemType, true) + if err != nil { + return nil, err + } + + if err = mapstructureDecode(params, offChain); err != nil { + return nil, err + } + + return offChain, nil +} + +func compareLogs(log, use *logpoller.Log) int64 { + if use == nil { + return 1 + } + + if log.BlockNumber != use.BlockNumber { + return log.BlockNumber - use.BlockNumber + } + + return log.LogIndex - use.LogIndex +} + +func matchesRemainingFilters(log *logpoller.Log, filters []common.Hash) bool { + for i, rfai := range filters { + if !reflect.DeepEqual(rfai[:], log.Topics[i+2]) { + return false + } + } + + return true +} + +func (e *eventBinding) encodeParams(item reflect.Value) ([]common.Hash, error) { + for item.Kind() == reflect.Pointer { + item = reflect.Indirect(item) + } + + var topics []any + switch item.Kind() { + case reflect.Array, reflect.Slice: + native, err := representArray(item, e.inputInfo) + if err != nil { + return nil, err + } + topics = []any{native} + case reflect.Struct, reflect.Map: + var err error + if topics, err = unrollItem(item, e.inputInfo); err != nil { + return nil, err + } + default: + return nil, fmt.Errorf("%w: cannot encode kind %v", commontypes.ErrInvalidType, item.Kind()) + } + + // abi params allow you to Pack a pointers, but MakeTopics doesn't work with pointers. + if err := e.derefTopics(topics); err != nil { + return nil, err + } + + hashes, err := abi.MakeTopics(topics) + if err != nil { + return nil, wrapInternalErr(err) + } + + if len(hashes) != 1 { + return nil, fmt.Errorf("%w: expected 1 filter set, got %d", commontypes.ErrInternal, len(hashes)) + } + + return hashes[0], nil +} + +func (e *eventBinding) derefTopics(topics []any) error { + for i, topic := range topics { + rTopic := reflect.ValueOf(topic) + if rTopic.Kind() == reflect.Pointer { + if rTopic.IsNil() { + return fmt.Errorf( + "%w: input topic %s cannot be nil", commontypes.ErrInvalidType, e.inputInfo.Args()[i].Name) + } + topics[i] = rTopic.Elem().Interface() + } + } + return nil +} + +func (e *eventBinding) decodeLog(ctx context.Context, log *logpoller.Log, into any) error { + dataType := wrapItemType(e.contractName, e.eventName, false) + if err := e.codec.Decode(ctx, log.Data, into, dataType); err != nil { + return err + } + + topics := make([]common.Hash, len(e.topicInfo.Args())) + if len(log.Topics) < len(topics)+1 { + return fmt.Errorf("%w: not enough topics to decode", commontypes.ErrInvalidType) + } + + for i := 0; i < len(topics); i++ { + topics[i] = common.Hash(log.Topics[i+1]) + } + + topicsInto := map[string]any{} + if err := abi.ParseTopicsIntoMap(topicsInto, e.topicInfo.Args(), topics); err != nil { + return fmt.Errorf("%w: %w", commontypes.ErrInvalidType, err) + } + + return mapstructureDecode(topicsInto, into) +} + +func wrapInternalErr(err error) error { + if err == nil { + return nil + } + + errStr := err.Error() + if strings.Contains(errStr, "not found") || strings.Contains(errStr, "no rows") { + return fmt.Errorf("%w: %w", commontypes.ErrNotFound, err) + } + return fmt.Errorf("%w: %w", commontypes.ErrInternal, err) +} diff --git a/core/services/relay/evm/evm.go b/core/services/relay/evm/evm.go index 36e4a2eb3b..55f705d098 100644 --- a/core/services/relay/evm/evm.go +++ b/core/services/relay/evm/evm.go @@ -52,6 +52,7 @@ type Relayer struct { mercuryPool wsrpc.Pool pgCfg pg.QConfig chainReader commontypes.ChainReader + codec commontypes.Codec } type CSAETHKeystore interface { @@ -183,7 +184,7 @@ func (r *Relayer) NewMercuryProvider(rargs commontypes.RelayArgs, pargs commonty } transmitter := mercury.NewTransmitter(lggr, cw.ContractConfigTracker(), client, privKey.PublicKey, rargs.JobID, *relayConfig.FeedID, r.db, r.pgCfg, transmitterCodec) - return NewMercuryProvider(cw, r.chainReader, NewMercuryChainReader(r.chain.HeadTracker()), transmitter, reportCodecV1, reportCodecV2, reportCodecV3, lggr), nil + return NewMercuryProvider(cw, r.chainReader, r.codec, NewMercuryChainReader(r.chain.HeadTracker()), transmitter, reportCodecV1, reportCodecV2, reportCodecV3, lggr), nil } func (r *Relayer) NewFunctionsProvider(rargs commontypes.RelayArgs, pargs commontypes.PluginArgs) (commontypes.FunctionsProvider, error) { @@ -483,9 +484,14 @@ func (r *Relayer) NewMedianProvider(rargs commontypes.RelayArgs, pargs commontyp } // allow fallback until chain reader is default and median contract is removed, but still log just in case - var chainReaderService commontypes.ChainReader + var chainReaderService ChainReaderService if relayConfig.ChainReader != nil { - if chainReaderService, err = NewChainReaderService(lggr, r.chain.LogPoller(), contractID, *relayConfig.ChainReader); err != nil { + if chainReaderService, err = NewChainReaderService(lggr, r.chain.LogPoller(), r.chain, *relayConfig.ChainReader); err != nil { + return nil, err + } + + boundContracts := []commontypes.BoundContract{{Name: "median", Pending: true, Address: contractID.String()}} + if err = chainReaderService.Bind(context.Background(), boundContracts); err != nil { return nil, err } } else { @@ -493,12 +499,21 @@ func (r *Relayer) NewMedianProvider(rargs commontypes.RelayArgs, pargs commontyp } medianProvider.chainReader = chainReaderService + if relayConfig.Codec != nil { + medianProvider.codec, err = NewCodec(*relayConfig.Codec) + if err != nil { + return nil, err + } + } else { + lggr.Info("Codec missing from RelayConfig; falling back to internal MedianContract") + } + return &medianProvider, nil } func (r *Relayer) NewAutomationProvider(rargs commontypes.RelayArgs, pargs commontypes.PluginArgs) (commontypes.AutomationProvider, error) { lggr := r.lggr.Named("AutomationProvider").Named(rargs.ExternalJobID.String()) - ocr2keeperRelayer := NewOCR2KeeperRelayer(r.db, r.chain, lggr.Named("OCR2KeeperRelayer"), r.ks.Eth()) + ocr2keeperRelayer := NewOCR2KeeperRelayer(r.db, r.chain, lggr.Named("OCR2KeeperRelayer"), r.ks.Eth(), r.pgCfg) return ocr2keeperRelayer.NewOCR2KeeperProvider(rargs, pargs) } @@ -511,14 +526,20 @@ type medianProvider struct { contractTransmitter ContractTransmitter reportCodec median.ReportCodec medianContract *medianContract - chainReader commontypes.ChainReader + chainReader ChainReaderService + codec commontypes.Codec ms services.MultiStart } func (p *medianProvider) Name() string { return p.lggr.Name() } func (p *medianProvider) Start(ctx context.Context) error { - return p.ms.Start(ctx, p.configWatcher, p.contractTransmitter, p.medianContract) + srvcs := []services.StartClose{p.configWatcher, p.contractTransmitter, p.medianContract} + if p.chainReader != nil { + srvcs = append(srvcs, p.chainReader) + } + + return p.ms.Start(ctx, srvcs...) } func (p *medianProvider) Close() error { return p.ms.Close() } @@ -560,3 +581,7 @@ func (p *medianProvider) ContractConfigTracker() ocrtypes.ContractConfigTracker func (p *medianProvider) ChainReader() commontypes.ChainReader { return p.chainReader } + +func (p *medianProvider) Codec() commontypes.Codec { + return p.codec +} diff --git a/core/services/relay/evm/functions.go b/core/services/relay/evm/functions.go index f1d652fd6f..b957ab56f3 100644 --- a/core/services/relay/evm/functions.go +++ b/core/services/relay/evm/functions.go @@ -90,6 +90,10 @@ func (p *functionsProvider) ChainReader() commontypes.ChainReader { return nil } +func (p *functionsProvider) Codec() commontypes.Codec { + return nil +} + func NewFunctionsProvider(chain legacyevm.Chain, rargs commontypes.RelayArgs, pargs commontypes.PluginArgs, lggr logger.Logger, ethKeystore keystore.Eth, pluginType functionsRelay.FunctionsPluginType) (evmRelayTypes.FunctionsProvider, error) { relayOpts := evmRelayTypes.NewRelayOpts(rargs) relayConfig, err := relayOpts.RelayConfig() diff --git a/core/services/relay/evm/mercury/v1/data_source_test.go b/core/services/relay/evm/mercury/v1/data_source_test.go index e02efd8d9a..e0769fe5b6 100644 --- a/core/services/relay/evm/mercury/v1/data_source_test.go +++ b/core/services/relay/evm/mercury/v1/data_source_test.go @@ -432,7 +432,6 @@ func TestMercury_SetLatestBlocks(t *testing.T) { headTracker := commonmocks.NewHeadTracker[*evmtypes.Head, common.Hash](t) // This can happen in some cases e.g. RPC node is offline headTracker.On("LatestChain").Return((*evmtypes.Head)(nil)) - ds.mercuryChainReader = evm.NewChainReader(headTracker) obs := v1.Observation{} err := ds.setLatestBlocks(testutils.Context(t), &obs) diff --git a/core/services/relay/evm/mercury/wsrpc/cache/cache.go b/core/services/relay/evm/mercury/wsrpc/cache/cache.go index 181900bc15..712e62e5c0 100644 --- a/core/services/relay/evm/mercury/wsrpc/cache/cache.go +++ b/core/services/relay/evm/mercury/wsrpc/cache/cache.go @@ -237,7 +237,7 @@ func (m *memCache) LatestReport(ctx context.Context, req *pb.LatestReportRequest // CACHE HIT promCacheHitCount.WithLabelValues(m.client.ServerURL(), feedIDHex).Inc() m.lggr.Tracew("LatestReport CACHE HIT (cold path)", "feedID", feedIDHex) - defer v.RUnlock() + defer v.Unlock() return v.val, nil } else if v.fetching { // CACHE WAIT diff --git a/core/services/relay/evm/mercury/wsrpc/metrics.go b/core/services/relay/evm/mercury/wsrpc/metrics.go index f2000674f7..8c12184cd8 100644 --- a/core/services/relay/evm/mercury/wsrpc/metrics.go +++ b/core/services/relay/evm/mercury/wsrpc/metrics.go @@ -28,7 +28,7 @@ var ( Namespace: "mercury", Name: "wsrpc_request_latency", Help: "Latency of requests made to the Mercury WSRPC server", - Buckets: []float64{10, 30, 100, 300, 1000, 3000, 10000}, + Buckets: []float64{10, 30, 100, 200, 250, 300, 350, 400, 500, 750, 1000, 3000, 10000}, }) ) diff --git a/core/services/relay/evm/mercury_provider.go b/core/services/relay/evm/mercury_provider.go index 2ff882efa6..d9858ac64c 100644 --- a/core/services/relay/evm/mercury_provider.go +++ b/core/services/relay/evm/mercury_provider.go @@ -8,6 +8,7 @@ import ( "github.com/smartcontractkit/chainlink-common/pkg/services" commontypes "github.com/smartcontractkit/chainlink-common/pkg/types" + mercurytypes "github.com/smartcontractkit/chainlink-common/pkg/types/mercury" v1 "github.com/smartcontractkit/chainlink-common/pkg/types/mercury/v1" v2 "github.com/smartcontractkit/chainlink-common/pkg/types/mercury/v2" @@ -24,6 +25,7 @@ var _ commontypes.MercuryProvider = (*mercuryProvider)(nil) type mercuryProvider struct { configWatcher *configWatcher chainReader commontypes.ChainReader + codec commontypes.Codec transmitter evmmercury.Transmitter reportCodecV1 v1.ReportCodec reportCodecV2 v2.ReportCodec @@ -36,6 +38,7 @@ type mercuryProvider struct { func NewMercuryProvider( configWatcher *configWatcher, chainReader commontypes.ChainReader, + codec commontypes.Codec, mercuryChainReader mercurytypes.ChainReader, transmitter evmmercury.Transmitter, reportCodecV1 v1.ReportCodec, @@ -46,6 +49,7 @@ func NewMercuryProvider( return &mercuryProvider{ configWatcher, chainReader, + codec, transmitter, reportCodecV1, reportCodecV2, @@ -83,6 +87,10 @@ func (p *mercuryProvider) MercuryChainReader() mercurytypes.ChainReader { return p.mercuryChainReader } +func (p *mercuryProvider) Codec() commontypes.Codec { + return p.codec +} + func (p *mercuryProvider) ContractConfigTracker() ocrtypes.ContractConfigTracker { return p.configWatcher.ContractConfigTracker() } diff --git a/core/services/relay/evm/method_binding.go b/core/services/relay/evm/method_binding.go new file mode 100644 index 0000000000..c5e10cce1c --- /dev/null +++ b/core/services/relay/evm/method_binding.go @@ -0,0 +1,66 @@ +package evm + +import ( + "context" + "fmt" + + "github.com/ethereum/go-ethereum" + "github.com/ethereum/go-ethereum/common" + + commontypes "github.com/smartcontractkit/chainlink-common/pkg/types" + + evmclient "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" +) + +type methodBinding struct { + address common.Address + contractName string + method string + client evmclient.Client + codec commontypes.Codec + bound bool +} + +var _ readBinding = &methodBinding{} + +func (m *methodBinding) SetCodec(codec commontypes.RemoteCodec) { + m.codec = codec +} + +func (m *methodBinding) Register() error { + return nil +} + +func (m *methodBinding) Unregister() error { + return nil +} + +func (m *methodBinding) GetLatestValue(ctx context.Context, params, returnValue any) error { + if !m.bound { + return fmt.Errorf("%w: method not bound", commontypes.ErrInvalidType) + } + + data, err := m.codec.Encode(ctx, params, wrapItemType(m.contractName, m.method, true)) + if err != nil { + return err + } + + callMsg := ethereum.CallMsg{ + To: &m.address, + From: m.address, + Data: data, + } + + bytes, err := m.client.CallContract(ctx, callMsg, nil) + if err != nil { + return fmt.Errorf("%w: %w", commontypes.ErrInternal, err) + } + + return m.codec.Decode(ctx, bytes, returnValue, wrapItemType(m.contractName, m.method, false)) +} + +func (m *methodBinding) Bind(binding commontypes.BoundContract) error { + m.address = common.HexToAddress(binding.Address) + m.bound = true + return nil +} diff --git a/core/services/relay/evm/ocr2keeper.go b/core/services/relay/evm/ocr2keeper.go index 4d925221c2..e95fcff5d1 100644 --- a/core/services/relay/evm/ocr2keeper.go +++ b/core/services/relay/evm/ocr2keeper.go @@ -6,6 +6,17 @@ import ( "fmt" "strings" + iregistry21 "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/i_keeper_registry_master_wrapper_2_1" + "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/ethkey" + evm "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21" + "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/encoding" + "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/logprovider" + "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/transmit" + "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/upkeepstate" + "github.com/smartcontractkit/chainlink/v2/core/services/pg" + + "github.com/smartcontractkit/chainlink-common/pkg/types/automation" + "github.com/ethereum/go-ethereum/accounts/abi" "github.com/ethereum/go-ethereum/common" "github.com/jmoiron/sqlx" @@ -27,8 +38,9 @@ import ( ) var ( - _ OCR2KeeperRelayer = (*ocr2keeperRelayer)(nil) - _ OCR2KeeperProvider = (*ocr2keeperProvider)(nil) + _ OCR2KeeperRelayer = (*ocr2keeperRelayer)(nil) + _ OCR2KeeperProvider = (*ocr2keeperProvider)(nil) + ErrInitializationFailure = fmt.Errorf("failed to initialize registry") ) // OCR2KeeperProviderOpts is the custom options to create a keeper provider @@ -41,6 +53,15 @@ type OCR2KeeperProviderOpts struct { // OCR2KeeperProvider provides all components needed for a OCR2Keeper plugin. type OCR2KeeperProvider interface { commontypes.Plugin + Registry() automation.Registry + Encoder() automation.Encoder + TransmitEventProvider() automation.EventProvider + BlockSubscriber() automation.BlockSubscriber + PayloadBuilder() automation.PayloadBuilder + UpkeepStateStore() automation.UpkeepStateStore + LogEventProvider() automation.LogEventProvider + LogRecoverer() automation.LogRecoverer + UpkeepProvider() automation.ConditionalUpkeepProvider } // OCR2KeeperRelayer contains the relayer and instantiating functions for OCR2Keeper providers. @@ -54,15 +75,17 @@ type ocr2keeperRelayer struct { chain legacyevm.Chain lggr logger.Logger ethKeystore keystore.Eth + dbCfg pg.QConfig } // NewOCR2KeeperRelayer is the constructor of ocr2keeperRelayer -func NewOCR2KeeperRelayer(db *sqlx.DB, chain legacyevm.Chain, lggr logger.Logger, ethKeystore keystore.Eth) OCR2KeeperRelayer { +func NewOCR2KeeperRelayer(db *sqlx.DB, chain legacyevm.Chain, lggr logger.Logger, ethKeystore keystore.Eth, dbCfg pg.QConfig) OCR2KeeperRelayer { return &ocr2keeperRelayer{ db: db, chain: chain, lggr: lggr, ethKeystore: ethKeystore, + dbCfg: dbCfg, } } @@ -78,10 +101,53 @@ func (r *ocr2keeperRelayer) NewOCR2KeeperProvider(rargs commontypes.RelayArgs, p return nil, err } - return &ocr2keeperProvider{ - configWatcher: cfgWatcher, - contractTransmitter: contractTransmitter, - }, nil + client := r.chain + + services := new(ocr2keeperProvider) + services.configWatcher = cfgWatcher + services.contractTransmitter = contractTransmitter + + addr := ethkey.MustEIP55Address(rargs.ContractID).Address() + + registryContract, err := iregistry21.NewIKeeperRegistryMaster(addr, client.Client()) + if err != nil { + return nil, fmt.Errorf("%w: failed to create caller for address and backend", ErrInitializationFailure) + } + // lookback blocks for transmit event is hard coded and should provide ample time for logs + // to be detected in most cases + var transmitLookbackBlocks int64 = 250 + transmitEventProvider, err := transmit.NewTransmitEventProvider(r.lggr, client.LogPoller(), addr, client.Client(), transmitLookbackBlocks) + if err != nil { + return nil, err + } + + services.transmitEventProvider = transmitEventProvider + + packer := encoding.NewAbiPacker() + services.encoder = encoding.NewReportEncoder(packer) + + finalityDepth := client.Config().EVM().FinalityDepth() + + orm := upkeepstate.NewORM(client.ID(), r.db, r.lggr, r.dbCfg) + scanner := upkeepstate.NewPerformedEventsScanner(r.lggr, client.LogPoller(), addr, finalityDepth) + services.upkeepStateStore = upkeepstate.NewUpkeepStateStore(orm, r.lggr, scanner) + + logProvider, logRecoverer := logprovider.New(r.lggr, client.LogPoller(), client.Client(), services.upkeepStateStore, finalityDepth) + services.logEventProvider = logProvider + services.logRecoverer = logRecoverer + blockSubscriber := evm.NewBlockSubscriber(client.HeadBroadcaster(), client.LogPoller(), finalityDepth, r.lggr) + services.blockSubscriber = blockSubscriber + + al := evm.NewActiveUpkeepList() + services.payloadBuilder = evm.NewPayloadBuilder(al, logRecoverer, r.lggr) + + services.registry = evm.NewEvmRegistry(r.lggr, addr, client, + registryContract, rargs.MercuryCredentials, al, logProvider, + packer, blockSubscriber, finalityDepth) + + services.conditionalUpkeepProvider = evm.NewUpkeepProvider(al, blockSubscriber, client.LogPoller()) + + return services, nil } type ocr3keeperProviderContractTransmitter struct { @@ -120,7 +186,16 @@ func (t *ocr3keeperProviderContractTransmitter) FromAccount() (ocrtypes.Account, type ocr2keeperProvider struct { *configWatcher - contractTransmitter ContractTransmitter + contractTransmitter ContractTransmitter + registry automation.Registry + encoder automation.Encoder + transmitEventProvider automation.EventProvider + blockSubscriber automation.BlockSubscriber + payloadBuilder automation.PayloadBuilder + upkeepStateStore automation.UpkeepStateStore + logEventProvider automation.LogEventProvider + logRecoverer automation.LogRecoverer + conditionalUpkeepProvider automation.ConditionalUpkeepProvider } func (c *ocr2keeperProvider) ContractTransmitter() ocrtypes.ContractTransmitter { @@ -131,6 +206,10 @@ func (c *ocr2keeperProvider) ChainReader() commontypes.ChainReader { return nil } +func (c *ocr2keeperProvider) Codec() commontypes.Codec { + return nil +} + func newOCR2KeeperConfigProvider(lggr logger.Logger, chain legacyevm.Chain, rargs commontypes.RelayArgs) (*configWatcher, error) { var relayConfig types.RelayConfig err := json.Unmarshal(rargs.RelayConfig, &relayConfig) @@ -175,3 +254,39 @@ func newOCR2KeeperConfigProvider(lggr logger.Logger, chain legacyevm.Chain, rarg rargs.New, ), nil } + +func (c *ocr2keeperProvider) Registry() automation.Registry { + return c.registry +} + +func (c *ocr2keeperProvider) Encoder() automation.Encoder { + return c.encoder +} + +func (c *ocr2keeperProvider) TransmitEventProvider() automation.EventProvider { + return c.transmitEventProvider +} + +func (c *ocr2keeperProvider) BlockSubscriber() automation.BlockSubscriber { + return c.blockSubscriber +} + +func (c *ocr2keeperProvider) PayloadBuilder() automation.PayloadBuilder { + return c.payloadBuilder +} + +func (c *ocr2keeperProvider) UpkeepStateStore() automation.UpkeepStateStore { + return c.upkeepStateStore +} + +func (c *ocr2keeperProvider) LogEventProvider() automation.LogEventProvider { + return c.logEventProvider +} + +func (c *ocr2keeperProvider) LogRecoverer() automation.LogRecoverer { + return c.logRecoverer +} + +func (c *ocr2keeperProvider) UpkeepProvider() automation.ConditionalUpkeepProvider { + return c.conditionalUpkeepProvider +} diff --git a/core/services/relay/evm/ocr2vrf.go b/core/services/relay/evm/ocr2vrf.go index 829d2747ab..810f3d2ed7 100644 --- a/core/services/relay/evm/ocr2vrf.go +++ b/core/services/relay/evm/ocr2vrf.go @@ -114,6 +114,10 @@ func (c *dkgProvider) ChainReader() commontypes.ChainReader { return nil } +func (c *dkgProvider) Codec() commontypes.Codec { + return nil +} + type ocr2vrfProvider struct { *configWatcher contractTransmitter ContractTransmitter @@ -127,6 +131,10 @@ func (c *ocr2vrfProvider) ChainReader() commontypes.ChainReader { return nil } +func (c *ocr2vrfProvider) Codec() commontypes.Codec { + return nil +} + func newOCR2VRFConfigProvider(lggr logger.Logger, chain legacyevm.Chain, rargs commontypes.RelayArgs) (*configWatcher, error) { var relayConfig types.RelayConfig err := json.Unmarshal(rargs.RelayConfig, &relayConfig) diff --git a/core/services/relay/evm/parsed_types.go b/core/services/relay/evm/parsed_types.go new file mode 100644 index 0000000000..168057e998 --- /dev/null +++ b/core/services/relay/evm/parsed_types.go @@ -0,0 +1,50 @@ +package evm + +import ( + "fmt" + "reflect" + + "github.com/smartcontractkit/chainlink-common/pkg/codec" + commontypes "github.com/smartcontractkit/chainlink-common/pkg/types" + + "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/types" +) + +type parsedTypes struct { + encoderDefs map[string]types.CodecEntry + decoderDefs map[string]types.CodecEntry +} + +func (parsed *parsedTypes) toCodec() (commontypes.RemoteCodec, error) { + modByTypeName := map[string]codec.Modifier{} + if err := addEntries(parsed.encoderDefs, modByTypeName); err != nil { + return nil, err + } + if err := addEntries(parsed.decoderDefs, modByTypeName); err != nil { + return nil, err + } + + mod, err := codec.NewByItemTypeModifier(modByTypeName) + if err != nil { + return nil, err + } + underlying := &evmCodec{ + encoder: &encoder{Definitions: parsed.encoderDefs}, + decoder: &decoder{Definitions: parsed.decoderDefs}, + parsedTypes: parsed, + } + return codec.NewModifierCodec(underlying, mod, evmDecoderHooks...) +} + +// addEntries extracts the mods from codecEntry and adds them to modByTypeName use with codec.NewByItemTypeModifier +// Since each input/output can have its own modifications, we need to keep track of them by type name +func addEntries(defs map[string]types.CodecEntry, modByTypeName map[string]codec.Modifier) error { + for k, def := range defs { + modByTypeName[k] = def.Modifier() + _, err := def.Modifier().RetypeToOffChain(reflect.PointerTo(def.CheckedType()), k) + if err != nil { + return fmt.Errorf("%w: cannot retype %v: %w", commontypes.ErrInvalidConfig, k, err) + } + } + return nil +} diff --git a/core/services/relay/evm/rebalancer.go b/core/services/relay/evm/rebalancer.go index f0c2d642d3..1345c22688 100644 --- a/core/services/relay/evm/rebalancer.go +++ b/core/services/relay/evm/rebalancer.go @@ -127,6 +127,10 @@ type rebalancerProvider struct { lmFactory liquiditymanager.Factory } +func (r *rebalancerProvider) Codec() commontypes.Codec { + return nil +} + // ChainReader implements RebalancerProvider. func (*rebalancerProvider) ChainReader() commontypes.ChainReader { return nil diff --git a/core/services/relay/evm/types/abi_types.go b/core/services/relay/evm/types/abi_types.go new file mode 100644 index 0000000000..34b12d885b --- /dev/null +++ b/core/services/relay/evm/types/abi_types.go @@ -0,0 +1,66 @@ +package types + +import ( + "reflect" + + "github.com/ethereum/go-ethereum/common" +) + +//go:generate go run ./gen/main.go + +var typeMap = map[string]*ABIEncodingType{ + "bool": { + native: reflect.TypeOf(true), + checked: reflect.TypeOf(true), + }, + "int8": { + native: reflect.TypeOf(int8(0)), + checked: reflect.TypeOf(int8(0)), + }, + "int16": { + native: reflect.TypeOf(int16(0)), + checked: reflect.TypeOf(int16(0)), + }, + "int32": { + native: reflect.TypeOf(int32(0)), + checked: reflect.TypeOf(int32(0)), + }, + "int64": { + native: reflect.TypeOf(int64(0)), + checked: reflect.TypeOf(int64(0)), + }, + "uint8": { + native: reflect.TypeOf(uint8(0)), + checked: reflect.TypeOf(uint8(0)), + }, + "uint16": { + native: reflect.TypeOf(uint16(0)), + checked: reflect.TypeOf(uint16(0)), + }, + "uint32": { + native: reflect.TypeOf(uint32(0)), + checked: reflect.TypeOf(uint32(0)), + }, + "uint64": { + native: reflect.TypeOf(uint64(0)), + checked: reflect.TypeOf(uint64(0)), + }, + "string": { + native: reflect.TypeOf(""), + checked: reflect.TypeOf(""), + }, + "address": { + native: reflect.TypeOf(common.Address{}), + checked: reflect.TypeOf(common.Address{}), + }, +} + +type ABIEncodingType struct { + native reflect.Type + checked reflect.Type +} + +func GetAbiEncodingType(name string) (*ABIEncodingType, bool) { + abiType, ok := typeMap[name] + return abiType, ok +} diff --git a/core/services/relay/evm/types/byte_types_gen.go b/core/services/relay/evm/types/byte_types_gen.go new file mode 100644 index 0000000000..cf8d15ccab --- /dev/null +++ b/core/services/relay/evm/types/byte_types_gen.go @@ -0,0 +1,300 @@ +package types + +import "reflect" + +type bytes1 [1]byte + +func init() { + typeMap["bytes1"] = &ABIEncodingType{ + native: reflect.TypeOf([1]byte{}), + checked: reflect.TypeOf(bytes1{}), + } +} + +type bytes2 [2]byte + +func init() { + typeMap["bytes2"] = &ABIEncodingType{ + native: reflect.TypeOf([2]byte{}), + checked: reflect.TypeOf(bytes2{}), + } +} + +type bytes3 [3]byte + +func init() { + typeMap["bytes3"] = &ABIEncodingType{ + native: reflect.TypeOf([3]byte{}), + checked: reflect.TypeOf(bytes3{}), + } +} + +type bytes4 [4]byte + +func init() { + typeMap["bytes4"] = &ABIEncodingType{ + native: reflect.TypeOf([4]byte{}), + checked: reflect.TypeOf(bytes4{}), + } +} + +type bytes5 [5]byte + +func init() { + typeMap["bytes5"] = &ABIEncodingType{ + native: reflect.TypeOf([5]byte{}), + checked: reflect.TypeOf(bytes5{}), + } +} + +type bytes6 [6]byte + +func init() { + typeMap["bytes6"] = &ABIEncodingType{ + native: reflect.TypeOf([6]byte{}), + checked: reflect.TypeOf(bytes6{}), + } +} + +type bytes7 [7]byte + +func init() { + typeMap["bytes7"] = &ABIEncodingType{ + native: reflect.TypeOf([7]byte{}), + checked: reflect.TypeOf(bytes7{}), + } +} + +type bytes8 [8]byte + +func init() { + typeMap["bytes8"] = &ABIEncodingType{ + native: reflect.TypeOf([8]byte{}), + checked: reflect.TypeOf(bytes8{}), + } +} + +type bytes9 [9]byte + +func init() { + typeMap["bytes9"] = &ABIEncodingType{ + native: reflect.TypeOf([9]byte{}), + checked: reflect.TypeOf(bytes9{}), + } +} + +type bytes10 [10]byte + +func init() { + typeMap["bytes10"] = &ABIEncodingType{ + native: reflect.TypeOf([10]byte{}), + checked: reflect.TypeOf(bytes10{}), + } +} + +type bytes11 [11]byte + +func init() { + typeMap["bytes11"] = &ABIEncodingType{ + native: reflect.TypeOf([11]byte{}), + checked: reflect.TypeOf(bytes11{}), + } +} + +type bytes12 [12]byte + +func init() { + typeMap["bytes12"] = &ABIEncodingType{ + native: reflect.TypeOf([12]byte{}), + checked: reflect.TypeOf(bytes12{}), + } +} + +type bytes13 [13]byte + +func init() { + typeMap["bytes13"] = &ABIEncodingType{ + native: reflect.TypeOf([13]byte{}), + checked: reflect.TypeOf(bytes13{}), + } +} + +type bytes14 [14]byte + +func init() { + typeMap["bytes14"] = &ABIEncodingType{ + native: reflect.TypeOf([14]byte{}), + checked: reflect.TypeOf(bytes14{}), + } +} + +type bytes15 [15]byte + +func init() { + typeMap["bytes15"] = &ABIEncodingType{ + native: reflect.TypeOf([15]byte{}), + checked: reflect.TypeOf(bytes15{}), + } +} + +type bytes16 [16]byte + +func init() { + typeMap["bytes16"] = &ABIEncodingType{ + native: reflect.TypeOf([16]byte{}), + checked: reflect.TypeOf(bytes16{}), + } +} + +type bytes17 [17]byte + +func init() { + typeMap["bytes17"] = &ABIEncodingType{ + native: reflect.TypeOf([17]byte{}), + checked: reflect.TypeOf(bytes17{}), + } +} + +type bytes18 [18]byte + +func init() { + typeMap["bytes18"] = &ABIEncodingType{ + native: reflect.TypeOf([18]byte{}), + checked: reflect.TypeOf(bytes18{}), + } +} + +type bytes19 [19]byte + +func init() { + typeMap["bytes19"] = &ABIEncodingType{ + native: reflect.TypeOf([19]byte{}), + checked: reflect.TypeOf(bytes19{}), + } +} + +type bytes20 [20]byte + +func init() { + typeMap["bytes20"] = &ABIEncodingType{ + native: reflect.TypeOf([20]byte{}), + checked: reflect.TypeOf(bytes20{}), + } +} + +type bytes21 [21]byte + +func init() { + typeMap["bytes21"] = &ABIEncodingType{ + native: reflect.TypeOf([21]byte{}), + checked: reflect.TypeOf(bytes21{}), + } +} + +type bytes22 [22]byte + +func init() { + typeMap["bytes22"] = &ABIEncodingType{ + native: reflect.TypeOf([22]byte{}), + checked: reflect.TypeOf(bytes22{}), + } +} + +type bytes23 [23]byte + +func init() { + typeMap["bytes23"] = &ABIEncodingType{ + native: reflect.TypeOf([23]byte{}), + checked: reflect.TypeOf(bytes23{}), + } +} + +type bytes24 [24]byte + +func init() { + typeMap["bytes24"] = &ABIEncodingType{ + native: reflect.TypeOf([24]byte{}), + checked: reflect.TypeOf(bytes24{}), + } +} + +type bytes25 [25]byte + +func init() { + typeMap["bytes25"] = &ABIEncodingType{ + native: reflect.TypeOf([25]byte{}), + checked: reflect.TypeOf(bytes25{}), + } +} + +type bytes26 [26]byte + +func init() { + typeMap["bytes26"] = &ABIEncodingType{ + native: reflect.TypeOf([26]byte{}), + checked: reflect.TypeOf(bytes26{}), + } +} + +type bytes27 [27]byte + +func init() { + typeMap["bytes27"] = &ABIEncodingType{ + native: reflect.TypeOf([27]byte{}), + checked: reflect.TypeOf(bytes27{}), + } +} + +type bytes28 [28]byte + +func init() { + typeMap["bytes28"] = &ABIEncodingType{ + native: reflect.TypeOf([28]byte{}), + checked: reflect.TypeOf(bytes28{}), + } +} + +type bytes29 [29]byte + +func init() { + typeMap["bytes29"] = &ABIEncodingType{ + native: reflect.TypeOf([29]byte{}), + checked: reflect.TypeOf(bytes29{}), + } +} + +type bytes30 [30]byte + +func init() { + typeMap["bytes30"] = &ABIEncodingType{ + native: reflect.TypeOf([30]byte{}), + checked: reflect.TypeOf(bytes30{}), + } +} + +type bytes31 [31]byte + +func init() { + typeMap["bytes31"] = &ABIEncodingType{ + native: reflect.TypeOf([31]byte{}), + checked: reflect.TypeOf(bytes31{}), + } +} + +type bytes32 [32]byte + +func init() { + typeMap["bytes32"] = &ABIEncodingType{ + native: reflect.TypeOf([32]byte{}), + checked: reflect.TypeOf(bytes32{}), + } +} + +type bytes0 [0]byte + +func init() { + typeMap["bytes0"] = &ABIEncodingType{ + native: reflect.TypeOf([0]byte{}), + checked: reflect.TypeOf(bytes0{}), + } +} diff --git a/core/services/relay/evm/types/codec_entry.go b/core/services/relay/evm/types/codec_entry.go new file mode 100644 index 0000000000..b87f7ced72 --- /dev/null +++ b/core/services/relay/evm/types/codec_entry.go @@ -0,0 +1,256 @@ +package types + +import ( + "fmt" + "reflect" + "strings" + + "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/ethereum/go-ethereum/common" + + "github.com/smartcontractkit/chainlink-common/pkg/codec" + + commontypes "github.com/smartcontractkit/chainlink-common/pkg/types" +) + +// MaxTopicFields is three because the EVM has a max of four topics, but the first topic is always the event signature. +const MaxTopicFields = 3 + +type CodecEntry interface { + Init() error + Args() abi.Arguments + EncodingPrefix() []byte + GetMaxSize(n int) (int, error) + Modifier() codec.Modifier + + // CheckedType provides a type that can be used to decode into with type-safety around sizes of integers etc. + CheckedType() reflect.Type + + // ToNative converts a pointer to checked value into a pointer of a type to use with the go-ethereum ABI encoder + // Note that modification of the returned value will modify the original checked value and vice versa. + ToNative(checked reflect.Value) (reflect.Value, error) + + // IsNativePointer returns if the type is a pointer to the native type + IsNativePointer(item reflect.Type) bool +} + +func NewCodecEntry(args abi.Arguments, encodingPrefix []byte, mod codec.Modifier) CodecEntry { + if mod == nil { + mod = codec.MultiModifier{} + } + return &codecEntry{args: args, encodingPrefix: encodingPrefix, mod: mod} +} + +type codecEntry struct { + args abi.Arguments + encodingPrefix []byte + checkedType reflect.Type + nativeType reflect.Type + mod codec.Modifier +} + +func (entry *codecEntry) CheckedType() reflect.Type { + return entry.checkedType +} + +func (entry *codecEntry) NativeType() reflect.Type { + return entry.nativeType +} + +func (entry *codecEntry) ToNative(checked reflect.Value) (reflect.Value, error) { + if checked.Type() != reflect.PointerTo(entry.checkedType) { + return reflect.Value{}, fmt.Errorf("%w: checked type %v does not match expected type %v", commontypes.ErrInvalidType, reflect.TypeOf(checked), entry.checkedType) + } + + return reflect.NewAt(entry.nativeType, checked.UnsafePointer()), nil +} + +func (entry *codecEntry) IsNativePointer(item reflect.Type) bool { + return item == reflect.PointerTo(entry.nativeType) +} + +func (entry *codecEntry) Modifier() codec.Modifier { + return entry.mod +} + +func (entry *codecEntry) Args() abi.Arguments { + tmp := make(abi.Arguments, len(entry.args)) + copy(tmp, entry.args) + return tmp +} + +func (entry *codecEntry) EncodingPrefix() []byte { + tmp := make([]byte, len(entry.encodingPrefix)) + copy(tmp, entry.encodingPrefix) + return tmp +} + +func (entry *codecEntry) Init() error { + if entry.checkedType != nil { + return nil + } + + args := unwrapArgs(entry.args) + argLen := len(args) + native := make([]reflect.StructField, argLen) + checked := make([]reflect.StructField, argLen) + + // Single returns that aren't named will return that type + // whereas named parameters will return a struct with the fields + // Eg: function foo() returns (int256) ... will return a *big.Int for the native type + // function foo() returns (int256 i) ... will return a struct { I *big.Int } for the native type + // function foo() returns (int256 i1, int256 i2) ... will return a struct { I1 *big.Int, I2 *big.Int } for the native type + if len(args) == 1 && args[0].Name == "" { + nativeArg, checkedArg, err := getNativeAndCheckedTypesForArg(&args[0]) + if err != nil { + return err + } + entry.nativeType = nativeArg + entry.checkedType = checkedArg + return nil + } + + numIndices := 0 + seenNames := map[string]bool{} + for i, arg := range args { + if arg.Indexed { + if numIndices == MaxTopicFields { + return fmt.Errorf("%w: too many indexed arguments", commontypes.ErrInvalidConfig) + } + numIndices++ + } + + tmp := arg + nativeArg, checkedArg, err := getNativeAndCheckedTypesForArg(&tmp) + if err != nil { + return err + } + if len(arg.Name) == 0 { + return fmt.Errorf("%w: empty field names are not supported for multiple returns", commontypes.ErrInvalidType) + } + + name := strings.ToUpper(arg.Name[:1]) + arg.Name[1:] + if seenNames[name] { + return fmt.Errorf("%w: duplicate field name %s, after ToCamelCase", commontypes.ErrInvalidConfig, name) + } + seenNames[name] = true + native[i] = reflect.StructField{Name: name, Type: nativeArg} + checked[i] = reflect.StructField{Name: name, Type: checkedArg} + } + + entry.nativeType = structOfPointers(native) + entry.checkedType = structOfPointers(checked) + return nil +} + +func (entry *codecEntry) GetMaxSize(n int) (int, error) { + return GetMaxSize(n, entry.args) +} + +func unwrapArgs(args abi.Arguments) abi.Arguments { + // Unwrap an unnamed tuple so that callers don't need to wrap it + // Eg: If you have struct Foo { ... } and return an unnamed Foo, you should be able ot decode to a go Foo{} directly + if len(args) != 1 || args[0].Name != "" { + return args + } + + elms := args[0].Type.TupleElems + if len(elms) != 0 { + names := args[0].Type.TupleRawNames + args = make(abi.Arguments, len(elms)) + for i, elm := range elms { + args[i] = abi.Argument{ + Name: names[i], + Type: *elm, + } + } + } + return args +} + +func getNativeAndCheckedTypesForArg(arg *abi.Argument) (reflect.Type, reflect.Type, error) { + tmp := arg.Type + if arg.Indexed { + switch arg.Type.T { + case abi.StringTy: + return reflect.TypeOf(common.Hash{}), reflect.TypeOf(common.Hash{}), nil + case abi.ArrayTy: + u8, _ := GetAbiEncodingType("uint8") + if arg.Type.Elem.GetType() == u8.native { + return reflect.TypeOf(common.Hash{}), reflect.TypeOf(common.Hash{}), nil + } + fallthrough + case abi.SliceTy, abi.TupleTy, abi.FixedBytesTy, abi.FixedPointTy, abi.FunctionTy: + // https://github.com/ethereum/go-ethereum/blob/release/1.12/accounts/abi/topics.go#L78 + return nil, nil, fmt.Errorf("%w: unsupported indexed type: %v", commontypes.ErrInvalidConfig, arg.Type) + default: + } + } + + return getNativeAndCheckedTypes(&tmp) +} + +func getNativeAndCheckedTypes(curType *abi.Type) (reflect.Type, reflect.Type, error) { + converter := func(t reflect.Type) reflect.Type { return t } + for curType.Elem != nil { + prior := converter + switch curType.GetType().Kind() { + case reflect.Slice: + converter = func(t reflect.Type) reflect.Type { + return prior(reflect.SliceOf(t)) + } + curType = curType.Elem + case reflect.Array: + tmp := curType + converter = func(t reflect.Type) reflect.Type { + return prior(reflect.ArrayOf(tmp.Size, t)) + } + curType = curType.Elem + default: + return nil, nil, fmt.Errorf( + "%w: cannot create type for kind %v", commontypes.ErrInvalidType, curType.GetType().Kind()) + } + } + base, ok := GetAbiEncodingType(curType.String()) + if ok { + return converter(base.native), converter(base.checked), nil + } + + return createTupleType(curType, converter) +} + +func createTupleType(curType *abi.Type, converter func(reflect.Type) reflect.Type) (reflect.Type, reflect.Type, error) { + if len(curType.TupleElems) == 0 { + if curType.TupleType == nil { + return nil, nil, fmt.Errorf("%w: unsupported solitidy type: %v", commontypes.ErrInvalidType, curType.String()) + } + return curType.TupleType, curType.TupleType, nil + } + + // Our naive types always have the same layout as the checked ones. + // This differs intentionally from the type.GetType() in abi as fields on structs are pointers in ours to + // verify that fields are intentionally set. + nativeFields := make([]reflect.StructField, len(curType.TupleElems)) + checkedFields := make([]reflect.StructField, len(curType.TupleElems)) + for i, elm := range curType.TupleElems { + name := curType.TupleRawNames[i] + nativeFields[i].Name = name + checkedFields[i].Name = name + nativeArgType, checkedArgType, err := getNativeAndCheckedTypes(elm) + if err != nil { + return nil, nil, err + } + nativeFields[i].Type = nativeArgType + checkedFields[i].Type = checkedArgType + } + return converter(structOfPointers(nativeFields)), converter(structOfPointers(checkedFields)), nil +} + +func structOfPointers(fields []reflect.StructField) reflect.Type { + for i := range fields { + if fields[i].Type.Kind() != reflect.Pointer { + fields[i].Type = reflect.PointerTo(fields[i].Type) + } + } + return reflect.StructOf(fields) +} diff --git a/core/services/relay/evm/types/codec_entry_test.go b/core/services/relay/evm/types/codec_entry_test.go new file mode 100644 index 0000000000..1ea3a9ae57 --- /dev/null +++ b/core/services/relay/evm/types/codec_entry_test.go @@ -0,0 +1,289 @@ +package types + +import ( + "errors" + "math/big" + "reflect" + "testing" + + "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/ethereum/go-ethereum/common" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + "github.com/smartcontractkit/chainlink-common/pkg/codec" + + commontypes "github.com/smartcontractkit/chainlink-common/pkg/types" +) + +func TestCodecEntry(t *testing.T) { + t.Run("basic types", func(t *testing.T) { + type1, err := abi.NewType("uint16", "", []abi.ArgumentMarshaling{}) + require.NoError(t, err) + type2, err := abi.NewType("string", "", []abi.ArgumentMarshaling{}) + require.NoError(t, err) + type3, err := abi.NewType("uint24", "", []abi.ArgumentMarshaling{}) + require.NoError(t, err) + type4, err := abi.NewType("int24", "", []abi.ArgumentMarshaling{}) + require.NoError(t, err) + args := abi.Arguments{ + {Name: "Field1", Type: type1}, + {Name: "Field2", Type: type2}, + {Name: "Field3", Type: type3}, + {Name: "Field4", Type: type4}, + } + entry := NewCodecEntry(args, nil, nil) + require.NoError(t, entry.Init()) + checked := reflect.New(entry.CheckedType()) + iChecked := reflect.Indirect(checked) + f1 := uint16(2) + iChecked.FieldByName("Field1").Set(reflect.ValueOf(&f1)) + f2 := "any string" + iChecked.FieldByName("Field2").Set(reflect.ValueOf(&f2)) + + f3 := big.NewInt( /*2^24 - 1*/ 16777215) + setAndVerifyLimit(t, (*uint24)(f3), f3, iChecked.FieldByName("Field3")) + + f4 := big.NewInt( /*2^23 - 1*/ 8388607) + setAndVerifyLimit(t, (*int24)(f4), f4, iChecked.FieldByName("Field4")) + + rNative, err := entry.ToNative(checked) + require.NoError(t, err) + iNative := reflect.Indirect(rNative) + assert.Equal(t, iNative.Field(0).Interface(), iChecked.Field(0).Interface()) + assert.Equal(t, iNative.Field(1).Interface(), iChecked.Field(1).Interface()) + assert.Equal(t, iNative.Field(2).Interface(), f3) + assert.Equal(t, iNative.Field(3).Interface(), f4) + assertHaveSameStructureAndNames(t, iNative.Type(), entry.CheckedType()) + }) + + t.Run("tuples", func(t *testing.T) { + type1, err := abi.NewType("uint16", "", []abi.ArgumentMarshaling{}) + require.NoError(t, err) + tupleType, err := abi.NewType("tuple", "", []abi.ArgumentMarshaling{ + {Name: "Field3", Type: "uint24"}, + {Name: "Field4", Type: "int24"}, + }) + require.NoError(t, err) + args := abi.Arguments{ + {Name: "Field1", Type: type1}, + {Name: "Field2", Type: tupleType}, + } + entry := NewCodecEntry(args, nil, nil) + require.NoError(t, entry.Init()) + + checked := reflect.New(entry.CheckedType()) + iChecked := reflect.Indirect(checked) + f1 := uint16(2) + iChecked.FieldByName("Field1").Set(reflect.ValueOf(&f1)) + f2 := iChecked.FieldByName("Field2") + f2.Set(reflect.New(f2.Type().Elem())) + f2 = reflect.Indirect(f2) + f3 := big.NewInt( /*2^24 - 1*/ 16777215) + setAndVerifyLimit(t, (*uint24)(f3), f3, f2.FieldByName("Field3")) + f4 := big.NewInt( /*2^23 - 1*/ 8388607) + setAndVerifyLimit(t, (*int24)(f4), f4, f2.FieldByName("Field4")) + + native, err := entry.ToNative(checked) + require.NoError(t, err) + iNative := reflect.Indirect(native) + require.Equal(t, iNative.Field(0).Interface(), iChecked.Field(0).Interface()) + nF2 := reflect.Indirect(iNative.Field(1)) + assert.Equal(t, nF2.Field(0).Interface(), f3) + assert.Equal(t, nF2.Field(1).Interface(), f4) + assertHaveSameStructureAndNames(t, iNative.Type(), entry.CheckedType()) + }) + + t.Run("unwrapped types", func(t *testing.T) { + // This exists to allow you to decode single returned values without naming the parameter + wrappedTuple, err := abi.NewType("tuple", "", []abi.ArgumentMarshaling{ + {Name: "Field1", Type: "int16"}, + }) + require.NoError(t, err) + entry := NewCodecEntry(abi.Arguments{{Name: "", Type: wrappedTuple}}, nil, nil) + require.NoError(t, entry.Init()) + checked := reflect.New(entry.CheckedType()) + iChecked := reflect.Indirect(checked) + anyValue := int16(2) + iChecked.FieldByName("Field1").Set(reflect.ValueOf(&anyValue)) + native, err := entry.ToNative(checked) + require.NoError(t, err) + iNative := reflect.Indirect(native) + assert.Equal(t, &anyValue, iNative.FieldByName("Field1").Interface()) + assertHaveSameStructureAndNames(t, iNative.Type(), entry.CheckedType()) + }) + + t.Run("slice types", func(t *testing.T) { + type1, err := abi.NewType("int16[]", "", []abi.ArgumentMarshaling{}) + require.NoError(t, err) + entry := NewCodecEntry(abi.Arguments{{Name: "Field1", Type: type1}}, nil, nil) + + require.NoError(t, entry.Init()) + checked := reflect.New(entry.CheckedType()) + iChecked := reflect.Indirect(checked) + anySliceValue := &[]int16{2, 3} + iChecked.FieldByName("Field1").Set(reflect.ValueOf(anySliceValue)) + native, err := entry.ToNative(checked) + require.NoError(t, err) + iNative := reflect.Indirect(native) + assert.Equal(t, anySliceValue, iNative.FieldByName("Field1").Interface()) + assertHaveSameStructureAndNames(t, iNative.Type(), entry.CheckedType()) + }) + + t.Run("array types", func(t *testing.T) { + type1, err := abi.NewType("int16[3]", "", []abi.ArgumentMarshaling{}) + require.NoError(t, err) + entry := NewCodecEntry(abi.Arguments{{Name: "Field1", Type: type1}}, nil, nil) + require.NoError(t, entry.Init()) + checked := reflect.New(entry.CheckedType()) + iChecked := reflect.Indirect(checked) + anySliceValue := &[3]int16{2, 3, 30} + iChecked.FieldByName("Field1").Set(reflect.ValueOf(anySliceValue)) + native, err := entry.ToNative(checked) + require.NoError(t, err) + iNative := reflect.Indirect(native) + assert.Equal(t, anySliceValue, iNative.FieldByName("Field1").Interface()) + }) + + t.Run("Not return values makes struct{}", func(t *testing.T) { + entry := NewCodecEntry(abi.Arguments{}, nil, nil) + require.NoError(t, entry.Init()) + assert.Equal(t, reflect.TypeOf(struct{}{}), entry.CheckedType()) + native, err := entry.ToNative(reflect.ValueOf(&struct{}{})) + require.NoError(t, err) + assert.Equal(t, &struct{}{}, native.Interface()) + }) + + t.Run("Address works", func(t *testing.T) { + address, err := abi.NewType("address", "", []abi.ArgumentMarshaling{}) + require.NoError(t, err) + entry := NewCodecEntry(abi.Arguments{{Name: "foo", Type: address}}, nil, nil) + require.NoError(t, entry.Init()) + + checked := reflect.New(entry.CheckedType()) + iChecked := reflect.Indirect(checked) + anyAddr := &common.Address{1, 2, 3} + iChecked.FieldByName("Foo").Set(reflect.ValueOf(anyAddr)) + + native, err := entry.ToNative(checked) + require.NoError(t, err) + iNative := reflect.Indirect(native) + assert.Equal(t, anyAddr, iNative.FieldByName("Foo").Interface()) + assertHaveSameStructureAndNames(t, iNative.Type(), entry.CheckedType()) + }) + + t.Run("Multiple unnamed parameters are not supported", func(t *testing.T) { + anyType, err := abi.NewType("int16[3]", "", []abi.ArgumentMarshaling{}) + require.NoError(t, err) + entry := NewCodecEntry(abi.Arguments{{Name: "", Type: anyType}, {Name: "", Type: anyType}}, nil, nil) + assert.True(t, errors.Is(entry.Init(), commontypes.ErrInvalidType)) + }) + + t.Run("Multiple abi arguments with the same name returns an error", func(t *testing.T) { + anyType, err := abi.NewType("int16[3]", "", []abi.ArgumentMarshaling{}) + require.NoError(t, err) + entry := NewCodecEntry(abi.Arguments{{Name: "Name", Type: anyType}, {Name: "Name", Type: anyType}}, nil, nil) + assert.True(t, errors.Is(entry.Init(), commontypes.ErrInvalidConfig)) + }) + + t.Run("Indexed basic types leave their native and checked types as-is", func(t *testing.T) { + anyType, err := abi.NewType("int16", "", []abi.ArgumentMarshaling{}) + require.NoError(t, err) + entry := NewCodecEntry(abi.Arguments{{Name: "Name", Type: anyType, Indexed: true}}, nil, nil) + require.NoError(t, entry.Init()) + checkedField, ok := entry.CheckedType().FieldByName("Name") + require.True(t, ok) + assert.Equal(t, reflect.TypeOf((*int16)(nil)), checkedField.Type) + native, err := entry.ToNative(reflect.New(entry.CheckedType())) + require.NoError(t, err) + iNative := reflect.Indirect(native) + assertHaveSameStructureAndNames(t, iNative.Type(), entry.CheckedType()) + }) + + t.Run("Indexed non basic types change to hash", func(t *testing.T) { + anyType, err := abi.NewType("string", "", []abi.ArgumentMarshaling{}) + require.NoError(t, err) + entry := NewCodecEntry(abi.Arguments{{Name: "Name", Type: anyType, Indexed: true}}, nil, nil) + require.NoError(t, entry.Init()) + nativeField, ok := entry.CheckedType().FieldByName("Name") + require.True(t, ok) + assert.Equal(t, reflect.TypeOf(&common.Hash{}), nativeField.Type) + native, err := entry.ToNative(reflect.New(entry.CheckedType())) + require.NoError(t, err) + assertHaveSameStructureAndNames(t, native.Type().Elem(), entry.CheckedType()) + }) + + t.Run("Too many indexed items returns an error", func(t *testing.T) { + anyType, err := abi.NewType("int16", "", []abi.ArgumentMarshaling{}) + require.NoError(t, err) + entry := NewCodecEntry( + abi.Arguments{ + {Name: "Name1", Type: anyType, Indexed: true}, + {Name: "Name2", Type: anyType, Indexed: true}, + {Name: "Name3", Type: anyType, Indexed: true}, + {Name: "Name4", Type: anyType, Indexed: true}, + }, nil, nil) + require.True(t, errors.Is(entry.Init(), commontypes.ErrInvalidConfig)) + }) + + // TODO: when the TODO on + // https://github.com/ethereum/go-ethereum/blob/release/1.12/accounts/abi/topics.go#L78 + // is removed, remove this test. + t.Run("Using unsupported types by go-ethereum returns an error", func(t *testing.T) { + anyType, err := abi.NewType("int256[2]", "", []abi.ArgumentMarshaling{}) + require.NoError(t, err) + entry := NewCodecEntry(abi.Arguments{{Name: "Name", Type: anyType, Indexed: true}}, nil, nil) + assert.True(t, errors.Is(entry.Init(), commontypes.ErrInvalidConfig)) + }) + + t.Run("Modifier returns provided modifier", func(t *testing.T) { + anyType, err := abi.NewType("int16", "", []abi.ArgumentMarshaling{}) + require.NoError(t, err) + mod := codec.NewRenamer(map[string]string{"Name": "RenamedName"}) + entry := NewCodecEntry(abi.Arguments{{Name: "Name", Type: anyType, Indexed: true}}, nil, mod) + assert.Equal(t, mod, entry.Modifier()) + }) + + t.Run("EncodingPrefix returns provided prefix", func(t *testing.T) { + anyType, err := abi.NewType("int16", "", []abi.ArgumentMarshaling{}) + require.NoError(t, err) + prefix := []byte{1, 2, 3} + entry := NewCodecEntry(abi.Arguments{{Name: "Name", Type: anyType, Indexed: true}}, prefix, nil) + assert.Equal(t, prefix, entry.EncodingPrefix()) + }) +} + +// sized and bi must be the same pointer. +func setAndVerifyLimit(t *testing.T, sbi SizedBigInt, bi *big.Int, field reflect.Value) { + require.Same(t, reflect.NewAt(reflect.TypeOf(big.Int{}), reflect.ValueOf(sbi).UnsafePointer()).Interface(), bi) + field.Set(reflect.ValueOf(sbi)) + assert.NoError(t, sbi.Verify()) + bi.Add(bi, big.NewInt(1)) + assert.IsType(t, commontypes.ErrInvalidType, sbi.Verify()) +} + +// verifying the same structure allows us to use unsafe pointers to cast between them. +// This is done for perf and simplicity in mapping the two structures. +// [reflect.NewAt]'s use is the same as (*native)(unsafe.Pointer(checked)) +// See the safe usecase 1 from [unsafe.Pointer], as this is a subset of that. +// This also verifies field names are the same. +func assertHaveSameStructureAndNames(t *testing.T, t1, t2 reflect.Type) { + require.Equal(t, t1.Kind(), t2.Kind()) + + switch t1.Kind() { + case reflect.Array: + require.Equal(t, t1.Len(), t2.Len()) + assertHaveSameStructureAndNames(t, t1.Elem(), t2.Elem()) + case reflect.Slice, reflect.Pointer: + assertHaveSameStructureAndNames(t, t1.Elem(), t2.Elem()) + case reflect.Struct: + numFields := t1.NumField() + require.Equal(t, numFields, t2.NumField()) + for i := 0; i < numFields; i++ { + require.Equal(t, t1.Field(i).Name, t2.Field(i).Name) + assertHaveSameStructureAndNames(t, t1.Field(i).Type, t2.Field(i).Type) + } + default: + require.Equal(t, t1, t2) + } +} diff --git a/core/services/relay/evm/types/gen/bytes.go.tmpl b/core/services/relay/evm/types/gen/bytes.go.tmpl new file mode 100644 index 0000000000..3c06529b0f --- /dev/null +++ b/core/services/relay/evm/types/gen/bytes.go.tmpl @@ -0,0 +1,14 @@ +package types + +import "reflect" + +{{ range . }} +type bytes{{.Size}} [{{.Size}}]byte +func init() { + typeMap["bytes{{.Size}}"] = &ABIEncodingType { + native: reflect.TypeOf([{{.Size}}]byte{}), + checked: reflect.TypeOf(bytes{{.Size}}{}), + } +} + +{{ end }} \ No newline at end of file diff --git a/core/services/relay/evm/types/gen/ints.go.tmpl b/core/services/relay/evm/types/gen/ints.go.tmpl new file mode 100644 index 0000000000..b5f0fa363c --- /dev/null +++ b/core/services/relay/evm/types/gen/ints.go.tmpl @@ -0,0 +1,74 @@ +package types + +import ( + "math/big" + "reflect" + + "github.com/fxamacker/cbor/v2" + + "github.com/smartcontractkit/chainlink-common/pkg/codec" + "github.com/smartcontractkit/chainlink-common/pkg/types" +) + +type SizedBigInt interface { + Verify() error + private() +} + +var sizedBigIntType = reflect.TypeOf((*SizedBigInt)(nil)).Elem() +func SizedBigIntType() reflect.Type { + return sizedBigIntType +} + +{{ range . }} +type {{.Prefix}}int{{.Size}} big.Int +func (i *{{.Prefix}}int{{.Size}}) UnmarshalCBOR(input []byte) error { + bi := (*big.Int)(i) + if err := cbor.Unmarshal(input, bi); err != nil { + return err + } + + return i.Verify() +} + +func (i *{{.Prefix}}int{{.Size}}) MarshalCBOR() ([]byte, error) { + return cbor.Marshal((*big.Int)(i)) +} + +func (i *{{.Prefix}}int{{.Size}}) UnmarshalText(input []byte) error { + bi := (*big.Int)(i) + if _, ok := bi.SetString(string(input), 10); !ok { + return types.ErrInvalidType + } + + return i.Verify() +} + +func (i *{{.Prefix}}int{{.Size}}) MarshalText() ([]byte, error) { + bi := (*big.Int)(i) + return []byte(bi.String()), nil +} + +func (i *{{.Prefix}}int{{.Size}}) Verify() error { + bi := (*big.Int)(i) + {{ if .Signed }} + if !codec.FitsInNBitsSigned({{.Size}}, bi) { + return types.ErrInvalidType + } + {{ else }} + if bi.BitLen() > {{.Size}} || bi.Sign() < 0 { + return types.ErrInvalidType + } + {{ end }} + return nil +} + +func (i *{{.Prefix}}int{{.Size}}) private() {} + +func init() { + typeMap["{{.Prefix}}int{{.Size}}"] = &ABIEncodingType { + native: reflect.TypeOf((*big.Int)(nil)), + checked: reflect.TypeOf((*{{.Prefix}}int{{.Size}})(nil)), + } +} +{{ end }} \ No newline at end of file diff --git a/core/services/relay/evm/types/gen/main.go b/core/services/relay/evm/types/gen/main.go new file mode 100644 index 0000000000..84e7c008ee --- /dev/null +++ b/core/services/relay/evm/types/gen/main.go @@ -0,0 +1,73 @@ +package main + +import ( + "bytes" + _ "embed" + "go/format" + "os" + "text/template" +) + +func main() { + genInts() + genBytes() +} + +func genBytes() { + byteTypes := [33]ByteType{} + for i := 1; i < 33; i++ { + byteTypes[i-1].Size = i + } + mustRunTemplate("bytes", bytesTemplate, "byte_types_gen.go", byteTypes) +} + +func genInts() { + var intTypes []*IntType + + // 8, 16, 32, and 64 bits have their own type in go that is used by abi. + // The test use *big.Int + for i := 24; i <= 256; i += 8 { + if i == 32 || i == 64 { + continue + } + + signed := &IntType{Size: i, Signed: true} + unsigned := &IntType{Prefix: "u", Size: i} + intTypes = append(intTypes, signed, unsigned) + } + mustRunTemplate("ints", intsTemplate, "int_types_gen.go", intTypes) +} + +func mustRunTemplate(name, rawTemplate, outputFile string, input any) { + t := template.Must(template.New(name).Parse(rawTemplate)) + + br := bytes.Buffer{} + if err := t.Execute(&br, input); err != nil { + panic(err) + } + + res, err := format.Source(br.Bytes()) + if err != nil { + panic(err) + } + + if err = os.WriteFile(outputFile, res, 0600); err != nil { + panic(err) + } +} + +type IntType struct { + Prefix string + Size int + Signed bool +} + +type ByteType struct { + Size int +} + +//go:embed bytes.go.tmpl +var bytesTemplate string + +//go:embed ints.go.tmpl +var intsTemplate string diff --git a/core/services/relay/evm/types/int_types_gen.go b/core/services/relay/evm/types/int_types_gen.go new file mode 100644 index 0000000000..1ff82d5691 --- /dev/null +++ b/core/services/relay/evm/types/int_types_gen.go @@ -0,0 +1,2710 @@ +package types + +import ( + "math/big" + "reflect" + + "github.com/fxamacker/cbor/v2" + + "github.com/smartcontractkit/chainlink-common/pkg/codec" + "github.com/smartcontractkit/chainlink-common/pkg/types" +) + +type SizedBigInt interface { + Verify() error + private() +} + +var sizedBigIntType = reflect.TypeOf((*SizedBigInt)(nil)).Elem() + +func SizedBigIntType() reflect.Type { + return sizedBigIntType +} + +type int24 big.Int + +func (i *int24) UnmarshalCBOR(input []byte) error { + bi := (*big.Int)(i) + if err := cbor.Unmarshal(input, bi); err != nil { + return err + } + + return i.Verify() +} + +func (i *int24) MarshalCBOR() ([]byte, error) { + return cbor.Marshal((*big.Int)(i)) +} + +func (i *int24) UnmarshalText(input []byte) error { + bi := (*big.Int)(i) + if _, ok := bi.SetString(string(input), 10); !ok { + return types.ErrInvalidType + } + + return i.Verify() +} + +func (i *int24) MarshalText() ([]byte, error) { + bi := (*big.Int)(i) + return []byte(bi.String()), nil +} + +func (i *int24) Verify() error { + bi := (*big.Int)(i) + + if !codec.FitsInNBitsSigned(24, bi) { + return types.ErrInvalidType + } + + return nil +} + +func (i *int24) private() {} + +func init() { + typeMap["int24"] = &ABIEncodingType{ + native: reflect.TypeOf((*big.Int)(nil)), + checked: reflect.TypeOf((*int24)(nil)), + } +} + +type uint24 big.Int + +func (i *uint24) UnmarshalCBOR(input []byte) error { + bi := (*big.Int)(i) + if err := cbor.Unmarshal(input, bi); err != nil { + return err + } + + return i.Verify() +} + +func (i *uint24) MarshalCBOR() ([]byte, error) { + return cbor.Marshal((*big.Int)(i)) +} + +func (i *uint24) UnmarshalText(input []byte) error { + bi := (*big.Int)(i) + if _, ok := bi.SetString(string(input), 10); !ok { + return types.ErrInvalidType + } + + return i.Verify() +} + +func (i *uint24) MarshalText() ([]byte, error) { + bi := (*big.Int)(i) + return []byte(bi.String()), nil +} + +func (i *uint24) Verify() error { + bi := (*big.Int)(i) + + if bi.BitLen() > 24 || bi.Sign() < 0 { + return types.ErrInvalidType + } + + return nil +} + +func (i *uint24) private() {} + +func init() { + typeMap["uint24"] = &ABIEncodingType{ + native: reflect.TypeOf((*big.Int)(nil)), + checked: reflect.TypeOf((*uint24)(nil)), + } +} + +type int40 big.Int + +func (i *int40) UnmarshalCBOR(input []byte) error { + bi := (*big.Int)(i) + if err := cbor.Unmarshal(input, bi); err != nil { + return err + } + + return i.Verify() +} + +func (i *int40) MarshalCBOR() ([]byte, error) { + return cbor.Marshal((*big.Int)(i)) +} + +func (i *int40) UnmarshalText(input []byte) error { + bi := (*big.Int)(i) + if _, ok := bi.SetString(string(input), 10); !ok { + return types.ErrInvalidType + } + + return i.Verify() +} + +func (i *int40) MarshalText() ([]byte, error) { + bi := (*big.Int)(i) + return []byte(bi.String()), nil +} + +func (i *int40) Verify() error { + bi := (*big.Int)(i) + + if !codec.FitsInNBitsSigned(40, bi) { + return types.ErrInvalidType + } + + return nil +} + +func (i *int40) private() {} + +func init() { + typeMap["int40"] = &ABIEncodingType{ + native: reflect.TypeOf((*big.Int)(nil)), + checked: reflect.TypeOf((*int40)(nil)), + } +} + +type uint40 big.Int + +func (i *uint40) UnmarshalCBOR(input []byte) error { + bi := (*big.Int)(i) + if err := cbor.Unmarshal(input, bi); err != nil { + return err + } + + return i.Verify() +} + +func (i *uint40) MarshalCBOR() ([]byte, error) { + return cbor.Marshal((*big.Int)(i)) +} + +func (i *uint40) UnmarshalText(input []byte) error { + bi := (*big.Int)(i) + if _, ok := bi.SetString(string(input), 10); !ok { + return types.ErrInvalidType + } + + return i.Verify() +} + +func (i *uint40) MarshalText() ([]byte, error) { + bi := (*big.Int)(i) + return []byte(bi.String()), nil +} + +func (i *uint40) Verify() error { + bi := (*big.Int)(i) + + if bi.BitLen() > 40 || bi.Sign() < 0 { + return types.ErrInvalidType + } + + return nil +} + +func (i *uint40) private() {} + +func init() { + typeMap["uint40"] = &ABIEncodingType{ + native: reflect.TypeOf((*big.Int)(nil)), + checked: reflect.TypeOf((*uint40)(nil)), + } +} + +type int48 big.Int + +func (i *int48) UnmarshalCBOR(input []byte) error { + bi := (*big.Int)(i) + if err := cbor.Unmarshal(input, bi); err != nil { + return err + } + + return i.Verify() +} + +func (i *int48) MarshalCBOR() ([]byte, error) { + return cbor.Marshal((*big.Int)(i)) +} + +func (i *int48) UnmarshalText(input []byte) error { + bi := (*big.Int)(i) + if _, ok := bi.SetString(string(input), 10); !ok { + return types.ErrInvalidType + } + + return i.Verify() +} + +func (i *int48) MarshalText() ([]byte, error) { + bi := (*big.Int)(i) + return []byte(bi.String()), nil +} + +func (i *int48) Verify() error { + bi := (*big.Int)(i) + + if !codec.FitsInNBitsSigned(48, bi) { + return types.ErrInvalidType + } + + return nil +} + +func (i *int48) private() {} + +func init() { + typeMap["int48"] = &ABIEncodingType{ + native: reflect.TypeOf((*big.Int)(nil)), + checked: reflect.TypeOf((*int48)(nil)), + } +} + +type uint48 big.Int + +func (i *uint48) UnmarshalCBOR(input []byte) error { + bi := (*big.Int)(i) + if err := cbor.Unmarshal(input, bi); err != nil { + return err + } + + return i.Verify() +} + +func (i *uint48) MarshalCBOR() ([]byte, error) { + return cbor.Marshal((*big.Int)(i)) +} + +func (i *uint48) UnmarshalText(input []byte) error { + bi := (*big.Int)(i) + if _, ok := bi.SetString(string(input), 10); !ok { + return types.ErrInvalidType + } + + return i.Verify() +} + +func (i *uint48) MarshalText() ([]byte, error) { + bi := (*big.Int)(i) + return []byte(bi.String()), nil +} + +func (i *uint48) Verify() error { + bi := (*big.Int)(i) + + if bi.BitLen() > 48 || bi.Sign() < 0 { + return types.ErrInvalidType + } + + return nil +} + +func (i *uint48) private() {} + +func init() { + typeMap["uint48"] = &ABIEncodingType{ + native: reflect.TypeOf((*big.Int)(nil)), + checked: reflect.TypeOf((*uint48)(nil)), + } +} + +type int56 big.Int + +func (i *int56) UnmarshalCBOR(input []byte) error { + bi := (*big.Int)(i) + if err := cbor.Unmarshal(input, bi); err != nil { + return err + } + + return i.Verify() +} + +func (i *int56) MarshalCBOR() ([]byte, error) { + return cbor.Marshal((*big.Int)(i)) +} + +func (i *int56) UnmarshalText(input []byte) error { + bi := (*big.Int)(i) + if _, ok := bi.SetString(string(input), 10); !ok { + return types.ErrInvalidType + } + + return i.Verify() +} + +func (i *int56) MarshalText() ([]byte, error) { + bi := (*big.Int)(i) + return []byte(bi.String()), nil +} + +func (i *int56) Verify() error { + bi := (*big.Int)(i) + + if !codec.FitsInNBitsSigned(56, bi) { + return types.ErrInvalidType + } + + return nil +} + +func (i *int56) private() {} + +func init() { + typeMap["int56"] = &ABIEncodingType{ + native: reflect.TypeOf((*big.Int)(nil)), + checked: reflect.TypeOf((*int56)(nil)), + } +} + +type uint56 big.Int + +func (i *uint56) UnmarshalCBOR(input []byte) error { + bi := (*big.Int)(i) + if err := cbor.Unmarshal(input, bi); err != nil { + return err + } + + return i.Verify() +} + +func (i *uint56) MarshalCBOR() ([]byte, error) { + return cbor.Marshal((*big.Int)(i)) +} + +func (i *uint56) UnmarshalText(input []byte) error { + bi := (*big.Int)(i) + if _, ok := bi.SetString(string(input), 10); !ok { + return types.ErrInvalidType + } + + return i.Verify() +} + +func (i *uint56) MarshalText() ([]byte, error) { + bi := (*big.Int)(i) + return []byte(bi.String()), nil +} + +func (i *uint56) Verify() error { + bi := (*big.Int)(i) + + if bi.BitLen() > 56 || bi.Sign() < 0 { + return types.ErrInvalidType + } + + return nil +} + +func (i *uint56) private() {} + +func init() { + typeMap["uint56"] = &ABIEncodingType{ + native: reflect.TypeOf((*big.Int)(nil)), + checked: reflect.TypeOf((*uint56)(nil)), + } +} + +type int72 big.Int + +func (i *int72) UnmarshalCBOR(input []byte) error { + bi := (*big.Int)(i) + if err := cbor.Unmarshal(input, bi); err != nil { + return err + } + + return i.Verify() +} + +func (i *int72) MarshalCBOR() ([]byte, error) { + return cbor.Marshal((*big.Int)(i)) +} + +func (i *int72) UnmarshalText(input []byte) error { + bi := (*big.Int)(i) + if _, ok := bi.SetString(string(input), 10); !ok { + return types.ErrInvalidType + } + + return i.Verify() +} + +func (i *int72) MarshalText() ([]byte, error) { + bi := (*big.Int)(i) + return []byte(bi.String()), nil +} + +func (i *int72) Verify() error { + bi := (*big.Int)(i) + + if !codec.FitsInNBitsSigned(72, bi) { + return types.ErrInvalidType + } + + return nil +} + +func (i *int72) private() {} + +func init() { + typeMap["int72"] = &ABIEncodingType{ + native: reflect.TypeOf((*big.Int)(nil)), + checked: reflect.TypeOf((*int72)(nil)), + } +} + +type uint72 big.Int + +func (i *uint72) UnmarshalCBOR(input []byte) error { + bi := (*big.Int)(i) + if err := cbor.Unmarshal(input, bi); err != nil { + return err + } + + return i.Verify() +} + +func (i *uint72) MarshalCBOR() ([]byte, error) { + return cbor.Marshal((*big.Int)(i)) +} + +func (i *uint72) UnmarshalText(input []byte) error { + bi := (*big.Int)(i) + if _, ok := bi.SetString(string(input), 10); !ok { + return types.ErrInvalidType + } + + return i.Verify() +} + +func (i *uint72) MarshalText() ([]byte, error) { + bi := (*big.Int)(i) + return []byte(bi.String()), nil +} + +func (i *uint72) Verify() error { + bi := (*big.Int)(i) + + if bi.BitLen() > 72 || bi.Sign() < 0 { + return types.ErrInvalidType + } + + return nil +} + +func (i *uint72) private() {} + +func init() { + typeMap["uint72"] = &ABIEncodingType{ + native: reflect.TypeOf((*big.Int)(nil)), + checked: reflect.TypeOf((*uint72)(nil)), + } +} + +type int80 big.Int + +func (i *int80) UnmarshalCBOR(input []byte) error { + bi := (*big.Int)(i) + if err := cbor.Unmarshal(input, bi); err != nil { + return err + } + + return i.Verify() +} + +func (i *int80) MarshalCBOR() ([]byte, error) { + return cbor.Marshal((*big.Int)(i)) +} + +func (i *int80) UnmarshalText(input []byte) error { + bi := (*big.Int)(i) + if _, ok := bi.SetString(string(input), 10); !ok { + return types.ErrInvalidType + } + + return i.Verify() +} + +func (i *int80) MarshalText() ([]byte, error) { + bi := (*big.Int)(i) + return []byte(bi.String()), nil +} + +func (i *int80) Verify() error { + bi := (*big.Int)(i) + + if !codec.FitsInNBitsSigned(80, bi) { + return types.ErrInvalidType + } + + return nil +} + +func (i *int80) private() {} + +func init() { + typeMap["int80"] = &ABIEncodingType{ + native: reflect.TypeOf((*big.Int)(nil)), + checked: reflect.TypeOf((*int80)(nil)), + } +} + +type uint80 big.Int + +func (i *uint80) UnmarshalCBOR(input []byte) error { + bi := (*big.Int)(i) + if err := cbor.Unmarshal(input, bi); err != nil { + return err + } + + return i.Verify() +} + +func (i *uint80) MarshalCBOR() ([]byte, error) { + return cbor.Marshal((*big.Int)(i)) +} + +func (i *uint80) UnmarshalText(input []byte) error { + bi := (*big.Int)(i) + if _, ok := bi.SetString(string(input), 10); !ok { + return types.ErrInvalidType + } + + return i.Verify() +} + +func (i *uint80) MarshalText() ([]byte, error) { + bi := (*big.Int)(i) + return []byte(bi.String()), nil +} + +func (i *uint80) Verify() error { + bi := (*big.Int)(i) + + if bi.BitLen() > 80 || bi.Sign() < 0 { + return types.ErrInvalidType + } + + return nil +} + +func (i *uint80) private() {} + +func init() { + typeMap["uint80"] = &ABIEncodingType{ + native: reflect.TypeOf((*big.Int)(nil)), + checked: reflect.TypeOf((*uint80)(nil)), + } +} + +type int88 big.Int + +func (i *int88) UnmarshalCBOR(input []byte) error { + bi := (*big.Int)(i) + if err := cbor.Unmarshal(input, bi); err != nil { + return err + } + + return i.Verify() +} + +func (i *int88) MarshalCBOR() ([]byte, error) { + return cbor.Marshal((*big.Int)(i)) +} + +func (i *int88) UnmarshalText(input []byte) error { + bi := (*big.Int)(i) + if _, ok := bi.SetString(string(input), 10); !ok { + return types.ErrInvalidType + } + + return i.Verify() +} + +func (i *int88) MarshalText() ([]byte, error) { + bi := (*big.Int)(i) + return []byte(bi.String()), nil +} + +func (i *int88) Verify() error { + bi := (*big.Int)(i) + + if !codec.FitsInNBitsSigned(88, bi) { + return types.ErrInvalidType + } + + return nil +} + +func (i *int88) private() {} + +func init() { + typeMap["int88"] = &ABIEncodingType{ + native: reflect.TypeOf((*big.Int)(nil)), + checked: reflect.TypeOf((*int88)(nil)), + } +} + +type uint88 big.Int + +func (i *uint88) UnmarshalCBOR(input []byte) error { + bi := (*big.Int)(i) + if err := cbor.Unmarshal(input, bi); err != nil { + return err + } + + return i.Verify() +} + +func (i *uint88) MarshalCBOR() ([]byte, error) { + return cbor.Marshal((*big.Int)(i)) +} + +func (i *uint88) UnmarshalText(input []byte) error { + bi := (*big.Int)(i) + if _, ok := bi.SetString(string(input), 10); !ok { + return types.ErrInvalidType + } + + return i.Verify() +} + +func (i *uint88) MarshalText() ([]byte, error) { + bi := (*big.Int)(i) + return []byte(bi.String()), nil +} + +func (i *uint88) Verify() error { + bi := (*big.Int)(i) + + if bi.BitLen() > 88 || bi.Sign() < 0 { + return types.ErrInvalidType + } + + return nil +} + +func (i *uint88) private() {} + +func init() { + typeMap["uint88"] = &ABIEncodingType{ + native: reflect.TypeOf((*big.Int)(nil)), + checked: reflect.TypeOf((*uint88)(nil)), + } +} + +type int96 big.Int + +func (i *int96) UnmarshalCBOR(input []byte) error { + bi := (*big.Int)(i) + if err := cbor.Unmarshal(input, bi); err != nil { + return err + } + + return i.Verify() +} + +func (i *int96) MarshalCBOR() ([]byte, error) { + return cbor.Marshal((*big.Int)(i)) +} + +func (i *int96) UnmarshalText(input []byte) error { + bi := (*big.Int)(i) + if _, ok := bi.SetString(string(input), 10); !ok { + return types.ErrInvalidType + } + + return i.Verify() +} + +func (i *int96) MarshalText() ([]byte, error) { + bi := (*big.Int)(i) + return []byte(bi.String()), nil +} + +func (i *int96) Verify() error { + bi := (*big.Int)(i) + + if !codec.FitsInNBitsSigned(96, bi) { + return types.ErrInvalidType + } + + return nil +} + +func (i *int96) private() {} + +func init() { + typeMap["int96"] = &ABIEncodingType{ + native: reflect.TypeOf((*big.Int)(nil)), + checked: reflect.TypeOf((*int96)(nil)), + } +} + +type uint96 big.Int + +func (i *uint96) UnmarshalCBOR(input []byte) error { + bi := (*big.Int)(i) + if err := cbor.Unmarshal(input, bi); err != nil { + return err + } + + return i.Verify() +} + +func (i *uint96) MarshalCBOR() ([]byte, error) { + return cbor.Marshal((*big.Int)(i)) +} + +func (i *uint96) UnmarshalText(input []byte) error { + bi := (*big.Int)(i) + if _, ok := bi.SetString(string(input), 10); !ok { + return types.ErrInvalidType + } + + return i.Verify() +} + +func (i *uint96) MarshalText() ([]byte, error) { + bi := (*big.Int)(i) + return []byte(bi.String()), nil +} + +func (i *uint96) Verify() error { + bi := (*big.Int)(i) + + if bi.BitLen() > 96 || bi.Sign() < 0 { + return types.ErrInvalidType + } + + return nil +} + +func (i *uint96) private() {} + +func init() { + typeMap["uint96"] = &ABIEncodingType{ + native: reflect.TypeOf((*big.Int)(nil)), + checked: reflect.TypeOf((*uint96)(nil)), + } +} + +type int104 big.Int + +func (i *int104) UnmarshalCBOR(input []byte) error { + bi := (*big.Int)(i) + if err := cbor.Unmarshal(input, bi); err != nil { + return err + } + + return i.Verify() +} + +func (i *int104) MarshalCBOR() ([]byte, error) { + return cbor.Marshal((*big.Int)(i)) +} + +func (i *int104) UnmarshalText(input []byte) error { + bi := (*big.Int)(i) + if _, ok := bi.SetString(string(input), 10); !ok { + return types.ErrInvalidType + } + + return i.Verify() +} + +func (i *int104) MarshalText() ([]byte, error) { + bi := (*big.Int)(i) + return []byte(bi.String()), nil +} + +func (i *int104) Verify() error { + bi := (*big.Int)(i) + + if !codec.FitsInNBitsSigned(104, bi) { + return types.ErrInvalidType + } + + return nil +} + +func (i *int104) private() {} + +func init() { + typeMap["int104"] = &ABIEncodingType{ + native: reflect.TypeOf((*big.Int)(nil)), + checked: reflect.TypeOf((*int104)(nil)), + } +} + +type uint104 big.Int + +func (i *uint104) UnmarshalCBOR(input []byte) error { + bi := (*big.Int)(i) + if err := cbor.Unmarshal(input, bi); err != nil { + return err + } + + return i.Verify() +} + +func (i *uint104) MarshalCBOR() ([]byte, error) { + return cbor.Marshal((*big.Int)(i)) +} + +func (i *uint104) UnmarshalText(input []byte) error { + bi := (*big.Int)(i) + if _, ok := bi.SetString(string(input), 10); !ok { + return types.ErrInvalidType + } + + return i.Verify() +} + +func (i *uint104) MarshalText() ([]byte, error) { + bi := (*big.Int)(i) + return []byte(bi.String()), nil +} + +func (i *uint104) Verify() error { + bi := (*big.Int)(i) + + if bi.BitLen() > 104 || bi.Sign() < 0 { + return types.ErrInvalidType + } + + return nil +} + +func (i *uint104) private() {} + +func init() { + typeMap["uint104"] = &ABIEncodingType{ + native: reflect.TypeOf((*big.Int)(nil)), + checked: reflect.TypeOf((*uint104)(nil)), + } +} + +type int112 big.Int + +func (i *int112) UnmarshalCBOR(input []byte) error { + bi := (*big.Int)(i) + if err := cbor.Unmarshal(input, bi); err != nil { + return err + } + + return i.Verify() +} + +func (i *int112) MarshalCBOR() ([]byte, error) { + return cbor.Marshal((*big.Int)(i)) +} + +func (i *int112) UnmarshalText(input []byte) error { + bi := (*big.Int)(i) + if _, ok := bi.SetString(string(input), 10); !ok { + return types.ErrInvalidType + } + + return i.Verify() +} + +func (i *int112) MarshalText() ([]byte, error) { + bi := (*big.Int)(i) + return []byte(bi.String()), nil +} + +func (i *int112) Verify() error { + bi := (*big.Int)(i) + + if !codec.FitsInNBitsSigned(112, bi) { + return types.ErrInvalidType + } + + return nil +} + +func (i *int112) private() {} + +func init() { + typeMap["int112"] = &ABIEncodingType{ + native: reflect.TypeOf((*big.Int)(nil)), + checked: reflect.TypeOf((*int112)(nil)), + } +} + +type uint112 big.Int + +func (i *uint112) UnmarshalCBOR(input []byte) error { + bi := (*big.Int)(i) + if err := cbor.Unmarshal(input, bi); err != nil { + return err + } + + return i.Verify() +} + +func (i *uint112) MarshalCBOR() ([]byte, error) { + return cbor.Marshal((*big.Int)(i)) +} + +func (i *uint112) UnmarshalText(input []byte) error { + bi := (*big.Int)(i) + if _, ok := bi.SetString(string(input), 10); !ok { + return types.ErrInvalidType + } + + return i.Verify() +} + +func (i *uint112) MarshalText() ([]byte, error) { + bi := (*big.Int)(i) + return []byte(bi.String()), nil +} + +func (i *uint112) Verify() error { + bi := (*big.Int)(i) + + if bi.BitLen() > 112 || bi.Sign() < 0 { + return types.ErrInvalidType + } + + return nil +} + +func (i *uint112) private() {} + +func init() { + typeMap["uint112"] = &ABIEncodingType{ + native: reflect.TypeOf((*big.Int)(nil)), + checked: reflect.TypeOf((*uint112)(nil)), + } +} + +type int120 big.Int + +func (i *int120) UnmarshalCBOR(input []byte) error { + bi := (*big.Int)(i) + if err := cbor.Unmarshal(input, bi); err != nil { + return err + } + + return i.Verify() +} + +func (i *int120) MarshalCBOR() ([]byte, error) { + return cbor.Marshal((*big.Int)(i)) +} + +func (i *int120) UnmarshalText(input []byte) error { + bi := (*big.Int)(i) + if _, ok := bi.SetString(string(input), 10); !ok { + return types.ErrInvalidType + } + + return i.Verify() +} + +func (i *int120) MarshalText() ([]byte, error) { + bi := (*big.Int)(i) + return []byte(bi.String()), nil +} + +func (i *int120) Verify() error { + bi := (*big.Int)(i) + + if !codec.FitsInNBitsSigned(120, bi) { + return types.ErrInvalidType + } + + return nil +} + +func (i *int120) private() {} + +func init() { + typeMap["int120"] = &ABIEncodingType{ + native: reflect.TypeOf((*big.Int)(nil)), + checked: reflect.TypeOf((*int120)(nil)), + } +} + +type uint120 big.Int + +func (i *uint120) UnmarshalCBOR(input []byte) error { + bi := (*big.Int)(i) + if err := cbor.Unmarshal(input, bi); err != nil { + return err + } + + return i.Verify() +} + +func (i *uint120) MarshalCBOR() ([]byte, error) { + return cbor.Marshal((*big.Int)(i)) +} + +func (i *uint120) UnmarshalText(input []byte) error { + bi := (*big.Int)(i) + if _, ok := bi.SetString(string(input), 10); !ok { + return types.ErrInvalidType + } + + return i.Verify() +} + +func (i *uint120) MarshalText() ([]byte, error) { + bi := (*big.Int)(i) + return []byte(bi.String()), nil +} + +func (i *uint120) Verify() error { + bi := (*big.Int)(i) + + if bi.BitLen() > 120 || bi.Sign() < 0 { + return types.ErrInvalidType + } + + return nil +} + +func (i *uint120) private() {} + +func init() { + typeMap["uint120"] = &ABIEncodingType{ + native: reflect.TypeOf((*big.Int)(nil)), + checked: reflect.TypeOf((*uint120)(nil)), + } +} + +type int128 big.Int + +func (i *int128) UnmarshalCBOR(input []byte) error { + bi := (*big.Int)(i) + if err := cbor.Unmarshal(input, bi); err != nil { + return err + } + + return i.Verify() +} + +func (i *int128) MarshalCBOR() ([]byte, error) { + return cbor.Marshal((*big.Int)(i)) +} + +func (i *int128) UnmarshalText(input []byte) error { + bi := (*big.Int)(i) + if _, ok := bi.SetString(string(input), 10); !ok { + return types.ErrInvalidType + } + + return i.Verify() +} + +func (i *int128) MarshalText() ([]byte, error) { + bi := (*big.Int)(i) + return []byte(bi.String()), nil +} + +func (i *int128) Verify() error { + bi := (*big.Int)(i) + + if !codec.FitsInNBitsSigned(128, bi) { + return types.ErrInvalidType + } + + return nil +} + +func (i *int128) private() {} + +func init() { + typeMap["int128"] = &ABIEncodingType{ + native: reflect.TypeOf((*big.Int)(nil)), + checked: reflect.TypeOf((*int128)(nil)), + } +} + +type uint128 big.Int + +func (i *uint128) UnmarshalCBOR(input []byte) error { + bi := (*big.Int)(i) + if err := cbor.Unmarshal(input, bi); err != nil { + return err + } + + return i.Verify() +} + +func (i *uint128) MarshalCBOR() ([]byte, error) { + return cbor.Marshal((*big.Int)(i)) +} + +func (i *uint128) UnmarshalText(input []byte) error { + bi := (*big.Int)(i) + if _, ok := bi.SetString(string(input), 10); !ok { + return types.ErrInvalidType + } + + return i.Verify() +} + +func (i *uint128) MarshalText() ([]byte, error) { + bi := (*big.Int)(i) + return []byte(bi.String()), nil +} + +func (i *uint128) Verify() error { + bi := (*big.Int)(i) + + if bi.BitLen() > 128 || bi.Sign() < 0 { + return types.ErrInvalidType + } + + return nil +} + +func (i *uint128) private() {} + +func init() { + typeMap["uint128"] = &ABIEncodingType{ + native: reflect.TypeOf((*big.Int)(nil)), + checked: reflect.TypeOf((*uint128)(nil)), + } +} + +type int136 big.Int + +func (i *int136) UnmarshalCBOR(input []byte) error { + bi := (*big.Int)(i) + if err := cbor.Unmarshal(input, bi); err != nil { + return err + } + + return i.Verify() +} + +func (i *int136) MarshalCBOR() ([]byte, error) { + return cbor.Marshal((*big.Int)(i)) +} + +func (i *int136) UnmarshalText(input []byte) error { + bi := (*big.Int)(i) + if _, ok := bi.SetString(string(input), 10); !ok { + return types.ErrInvalidType + } + + return i.Verify() +} + +func (i *int136) MarshalText() ([]byte, error) { + bi := (*big.Int)(i) + return []byte(bi.String()), nil +} + +func (i *int136) Verify() error { + bi := (*big.Int)(i) + + if !codec.FitsInNBitsSigned(136, bi) { + return types.ErrInvalidType + } + + return nil +} + +func (i *int136) private() {} + +func init() { + typeMap["int136"] = &ABIEncodingType{ + native: reflect.TypeOf((*big.Int)(nil)), + checked: reflect.TypeOf((*int136)(nil)), + } +} + +type uint136 big.Int + +func (i *uint136) UnmarshalCBOR(input []byte) error { + bi := (*big.Int)(i) + if err := cbor.Unmarshal(input, bi); err != nil { + return err + } + + return i.Verify() +} + +func (i *uint136) MarshalCBOR() ([]byte, error) { + return cbor.Marshal((*big.Int)(i)) +} + +func (i *uint136) UnmarshalText(input []byte) error { + bi := (*big.Int)(i) + if _, ok := bi.SetString(string(input), 10); !ok { + return types.ErrInvalidType + } + + return i.Verify() +} + +func (i *uint136) MarshalText() ([]byte, error) { + bi := (*big.Int)(i) + return []byte(bi.String()), nil +} + +func (i *uint136) Verify() error { + bi := (*big.Int)(i) + + if bi.BitLen() > 136 || bi.Sign() < 0 { + return types.ErrInvalidType + } + + return nil +} + +func (i *uint136) private() {} + +func init() { + typeMap["uint136"] = &ABIEncodingType{ + native: reflect.TypeOf((*big.Int)(nil)), + checked: reflect.TypeOf((*uint136)(nil)), + } +} + +type int144 big.Int + +func (i *int144) UnmarshalCBOR(input []byte) error { + bi := (*big.Int)(i) + if err := cbor.Unmarshal(input, bi); err != nil { + return err + } + + return i.Verify() +} + +func (i *int144) MarshalCBOR() ([]byte, error) { + return cbor.Marshal((*big.Int)(i)) +} + +func (i *int144) UnmarshalText(input []byte) error { + bi := (*big.Int)(i) + if _, ok := bi.SetString(string(input), 10); !ok { + return types.ErrInvalidType + } + + return i.Verify() +} + +func (i *int144) MarshalText() ([]byte, error) { + bi := (*big.Int)(i) + return []byte(bi.String()), nil +} + +func (i *int144) Verify() error { + bi := (*big.Int)(i) + + if !codec.FitsInNBitsSigned(144, bi) { + return types.ErrInvalidType + } + + return nil +} + +func (i *int144) private() {} + +func init() { + typeMap["int144"] = &ABIEncodingType{ + native: reflect.TypeOf((*big.Int)(nil)), + checked: reflect.TypeOf((*int144)(nil)), + } +} + +type uint144 big.Int + +func (i *uint144) UnmarshalCBOR(input []byte) error { + bi := (*big.Int)(i) + if err := cbor.Unmarshal(input, bi); err != nil { + return err + } + + return i.Verify() +} + +func (i *uint144) MarshalCBOR() ([]byte, error) { + return cbor.Marshal((*big.Int)(i)) +} + +func (i *uint144) UnmarshalText(input []byte) error { + bi := (*big.Int)(i) + if _, ok := bi.SetString(string(input), 10); !ok { + return types.ErrInvalidType + } + + return i.Verify() +} + +func (i *uint144) MarshalText() ([]byte, error) { + bi := (*big.Int)(i) + return []byte(bi.String()), nil +} + +func (i *uint144) Verify() error { + bi := (*big.Int)(i) + + if bi.BitLen() > 144 || bi.Sign() < 0 { + return types.ErrInvalidType + } + + return nil +} + +func (i *uint144) private() {} + +func init() { + typeMap["uint144"] = &ABIEncodingType{ + native: reflect.TypeOf((*big.Int)(nil)), + checked: reflect.TypeOf((*uint144)(nil)), + } +} + +type int152 big.Int + +func (i *int152) UnmarshalCBOR(input []byte) error { + bi := (*big.Int)(i) + if err := cbor.Unmarshal(input, bi); err != nil { + return err + } + + return i.Verify() +} + +func (i *int152) MarshalCBOR() ([]byte, error) { + return cbor.Marshal((*big.Int)(i)) +} + +func (i *int152) UnmarshalText(input []byte) error { + bi := (*big.Int)(i) + if _, ok := bi.SetString(string(input), 10); !ok { + return types.ErrInvalidType + } + + return i.Verify() +} + +func (i *int152) MarshalText() ([]byte, error) { + bi := (*big.Int)(i) + return []byte(bi.String()), nil +} + +func (i *int152) Verify() error { + bi := (*big.Int)(i) + + if !codec.FitsInNBitsSigned(152, bi) { + return types.ErrInvalidType + } + + return nil +} + +func (i *int152) private() {} + +func init() { + typeMap["int152"] = &ABIEncodingType{ + native: reflect.TypeOf((*big.Int)(nil)), + checked: reflect.TypeOf((*int152)(nil)), + } +} + +type uint152 big.Int + +func (i *uint152) UnmarshalCBOR(input []byte) error { + bi := (*big.Int)(i) + if err := cbor.Unmarshal(input, bi); err != nil { + return err + } + + return i.Verify() +} + +func (i *uint152) MarshalCBOR() ([]byte, error) { + return cbor.Marshal((*big.Int)(i)) +} + +func (i *uint152) UnmarshalText(input []byte) error { + bi := (*big.Int)(i) + if _, ok := bi.SetString(string(input), 10); !ok { + return types.ErrInvalidType + } + + return i.Verify() +} + +func (i *uint152) MarshalText() ([]byte, error) { + bi := (*big.Int)(i) + return []byte(bi.String()), nil +} + +func (i *uint152) Verify() error { + bi := (*big.Int)(i) + + if bi.BitLen() > 152 || bi.Sign() < 0 { + return types.ErrInvalidType + } + + return nil +} + +func (i *uint152) private() {} + +func init() { + typeMap["uint152"] = &ABIEncodingType{ + native: reflect.TypeOf((*big.Int)(nil)), + checked: reflect.TypeOf((*uint152)(nil)), + } +} + +type int160 big.Int + +func (i *int160) UnmarshalCBOR(input []byte) error { + bi := (*big.Int)(i) + if err := cbor.Unmarshal(input, bi); err != nil { + return err + } + + return i.Verify() +} + +func (i *int160) MarshalCBOR() ([]byte, error) { + return cbor.Marshal((*big.Int)(i)) +} + +func (i *int160) UnmarshalText(input []byte) error { + bi := (*big.Int)(i) + if _, ok := bi.SetString(string(input), 10); !ok { + return types.ErrInvalidType + } + + return i.Verify() +} + +func (i *int160) MarshalText() ([]byte, error) { + bi := (*big.Int)(i) + return []byte(bi.String()), nil +} + +func (i *int160) Verify() error { + bi := (*big.Int)(i) + + if !codec.FitsInNBitsSigned(160, bi) { + return types.ErrInvalidType + } + + return nil +} + +func (i *int160) private() {} + +func init() { + typeMap["int160"] = &ABIEncodingType{ + native: reflect.TypeOf((*big.Int)(nil)), + checked: reflect.TypeOf((*int160)(nil)), + } +} + +type uint160 big.Int + +func (i *uint160) UnmarshalCBOR(input []byte) error { + bi := (*big.Int)(i) + if err := cbor.Unmarshal(input, bi); err != nil { + return err + } + + return i.Verify() +} + +func (i *uint160) MarshalCBOR() ([]byte, error) { + return cbor.Marshal((*big.Int)(i)) +} + +func (i *uint160) UnmarshalText(input []byte) error { + bi := (*big.Int)(i) + if _, ok := bi.SetString(string(input), 10); !ok { + return types.ErrInvalidType + } + + return i.Verify() +} + +func (i *uint160) MarshalText() ([]byte, error) { + bi := (*big.Int)(i) + return []byte(bi.String()), nil +} + +func (i *uint160) Verify() error { + bi := (*big.Int)(i) + + if bi.BitLen() > 160 || bi.Sign() < 0 { + return types.ErrInvalidType + } + + return nil +} + +func (i *uint160) private() {} + +func init() { + typeMap["uint160"] = &ABIEncodingType{ + native: reflect.TypeOf((*big.Int)(nil)), + checked: reflect.TypeOf((*uint160)(nil)), + } +} + +type int168 big.Int + +func (i *int168) UnmarshalCBOR(input []byte) error { + bi := (*big.Int)(i) + if err := cbor.Unmarshal(input, bi); err != nil { + return err + } + + return i.Verify() +} + +func (i *int168) MarshalCBOR() ([]byte, error) { + return cbor.Marshal((*big.Int)(i)) +} + +func (i *int168) UnmarshalText(input []byte) error { + bi := (*big.Int)(i) + if _, ok := bi.SetString(string(input), 10); !ok { + return types.ErrInvalidType + } + + return i.Verify() +} + +func (i *int168) MarshalText() ([]byte, error) { + bi := (*big.Int)(i) + return []byte(bi.String()), nil +} + +func (i *int168) Verify() error { + bi := (*big.Int)(i) + + if !codec.FitsInNBitsSigned(168, bi) { + return types.ErrInvalidType + } + + return nil +} + +func (i *int168) private() {} + +func init() { + typeMap["int168"] = &ABIEncodingType{ + native: reflect.TypeOf((*big.Int)(nil)), + checked: reflect.TypeOf((*int168)(nil)), + } +} + +type uint168 big.Int + +func (i *uint168) UnmarshalCBOR(input []byte) error { + bi := (*big.Int)(i) + if err := cbor.Unmarshal(input, bi); err != nil { + return err + } + + return i.Verify() +} + +func (i *uint168) MarshalCBOR() ([]byte, error) { + return cbor.Marshal((*big.Int)(i)) +} + +func (i *uint168) UnmarshalText(input []byte) error { + bi := (*big.Int)(i) + if _, ok := bi.SetString(string(input), 10); !ok { + return types.ErrInvalidType + } + + return i.Verify() +} + +func (i *uint168) MarshalText() ([]byte, error) { + bi := (*big.Int)(i) + return []byte(bi.String()), nil +} + +func (i *uint168) Verify() error { + bi := (*big.Int)(i) + + if bi.BitLen() > 168 || bi.Sign() < 0 { + return types.ErrInvalidType + } + + return nil +} + +func (i *uint168) private() {} + +func init() { + typeMap["uint168"] = &ABIEncodingType{ + native: reflect.TypeOf((*big.Int)(nil)), + checked: reflect.TypeOf((*uint168)(nil)), + } +} + +type int176 big.Int + +func (i *int176) UnmarshalCBOR(input []byte) error { + bi := (*big.Int)(i) + if err := cbor.Unmarshal(input, bi); err != nil { + return err + } + + return i.Verify() +} + +func (i *int176) MarshalCBOR() ([]byte, error) { + return cbor.Marshal((*big.Int)(i)) +} + +func (i *int176) UnmarshalText(input []byte) error { + bi := (*big.Int)(i) + if _, ok := bi.SetString(string(input), 10); !ok { + return types.ErrInvalidType + } + + return i.Verify() +} + +func (i *int176) MarshalText() ([]byte, error) { + bi := (*big.Int)(i) + return []byte(bi.String()), nil +} + +func (i *int176) Verify() error { + bi := (*big.Int)(i) + + if !codec.FitsInNBitsSigned(176, bi) { + return types.ErrInvalidType + } + + return nil +} + +func (i *int176) private() {} + +func init() { + typeMap["int176"] = &ABIEncodingType{ + native: reflect.TypeOf((*big.Int)(nil)), + checked: reflect.TypeOf((*int176)(nil)), + } +} + +type uint176 big.Int + +func (i *uint176) UnmarshalCBOR(input []byte) error { + bi := (*big.Int)(i) + if err := cbor.Unmarshal(input, bi); err != nil { + return err + } + + return i.Verify() +} + +func (i *uint176) MarshalCBOR() ([]byte, error) { + return cbor.Marshal((*big.Int)(i)) +} + +func (i *uint176) UnmarshalText(input []byte) error { + bi := (*big.Int)(i) + if _, ok := bi.SetString(string(input), 10); !ok { + return types.ErrInvalidType + } + + return i.Verify() +} + +func (i *uint176) MarshalText() ([]byte, error) { + bi := (*big.Int)(i) + return []byte(bi.String()), nil +} + +func (i *uint176) Verify() error { + bi := (*big.Int)(i) + + if bi.BitLen() > 176 || bi.Sign() < 0 { + return types.ErrInvalidType + } + + return nil +} + +func (i *uint176) private() {} + +func init() { + typeMap["uint176"] = &ABIEncodingType{ + native: reflect.TypeOf((*big.Int)(nil)), + checked: reflect.TypeOf((*uint176)(nil)), + } +} + +type int184 big.Int + +func (i *int184) UnmarshalCBOR(input []byte) error { + bi := (*big.Int)(i) + if err := cbor.Unmarshal(input, bi); err != nil { + return err + } + + return i.Verify() +} + +func (i *int184) MarshalCBOR() ([]byte, error) { + return cbor.Marshal((*big.Int)(i)) +} + +func (i *int184) UnmarshalText(input []byte) error { + bi := (*big.Int)(i) + if _, ok := bi.SetString(string(input), 10); !ok { + return types.ErrInvalidType + } + + return i.Verify() +} + +func (i *int184) MarshalText() ([]byte, error) { + bi := (*big.Int)(i) + return []byte(bi.String()), nil +} + +func (i *int184) Verify() error { + bi := (*big.Int)(i) + + if !codec.FitsInNBitsSigned(184, bi) { + return types.ErrInvalidType + } + + return nil +} + +func (i *int184) private() {} + +func init() { + typeMap["int184"] = &ABIEncodingType{ + native: reflect.TypeOf((*big.Int)(nil)), + checked: reflect.TypeOf((*int184)(nil)), + } +} + +type uint184 big.Int + +func (i *uint184) UnmarshalCBOR(input []byte) error { + bi := (*big.Int)(i) + if err := cbor.Unmarshal(input, bi); err != nil { + return err + } + + return i.Verify() +} + +func (i *uint184) MarshalCBOR() ([]byte, error) { + return cbor.Marshal((*big.Int)(i)) +} + +func (i *uint184) UnmarshalText(input []byte) error { + bi := (*big.Int)(i) + if _, ok := bi.SetString(string(input), 10); !ok { + return types.ErrInvalidType + } + + return i.Verify() +} + +func (i *uint184) MarshalText() ([]byte, error) { + bi := (*big.Int)(i) + return []byte(bi.String()), nil +} + +func (i *uint184) Verify() error { + bi := (*big.Int)(i) + + if bi.BitLen() > 184 || bi.Sign() < 0 { + return types.ErrInvalidType + } + + return nil +} + +func (i *uint184) private() {} + +func init() { + typeMap["uint184"] = &ABIEncodingType{ + native: reflect.TypeOf((*big.Int)(nil)), + checked: reflect.TypeOf((*uint184)(nil)), + } +} + +type int192 big.Int + +func (i *int192) UnmarshalCBOR(input []byte) error { + bi := (*big.Int)(i) + if err := cbor.Unmarshal(input, bi); err != nil { + return err + } + + return i.Verify() +} + +func (i *int192) MarshalCBOR() ([]byte, error) { + return cbor.Marshal((*big.Int)(i)) +} + +func (i *int192) UnmarshalText(input []byte) error { + bi := (*big.Int)(i) + if _, ok := bi.SetString(string(input), 10); !ok { + return types.ErrInvalidType + } + + return i.Verify() +} + +func (i *int192) MarshalText() ([]byte, error) { + bi := (*big.Int)(i) + return []byte(bi.String()), nil +} + +func (i *int192) Verify() error { + bi := (*big.Int)(i) + + if !codec.FitsInNBitsSigned(192, bi) { + return types.ErrInvalidType + } + + return nil +} + +func (i *int192) private() {} + +func init() { + typeMap["int192"] = &ABIEncodingType{ + native: reflect.TypeOf((*big.Int)(nil)), + checked: reflect.TypeOf((*int192)(nil)), + } +} + +type uint192 big.Int + +func (i *uint192) UnmarshalCBOR(input []byte) error { + bi := (*big.Int)(i) + if err := cbor.Unmarshal(input, bi); err != nil { + return err + } + + return i.Verify() +} + +func (i *uint192) MarshalCBOR() ([]byte, error) { + return cbor.Marshal((*big.Int)(i)) +} + +func (i *uint192) UnmarshalText(input []byte) error { + bi := (*big.Int)(i) + if _, ok := bi.SetString(string(input), 10); !ok { + return types.ErrInvalidType + } + + return i.Verify() +} + +func (i *uint192) MarshalText() ([]byte, error) { + bi := (*big.Int)(i) + return []byte(bi.String()), nil +} + +func (i *uint192) Verify() error { + bi := (*big.Int)(i) + + if bi.BitLen() > 192 || bi.Sign() < 0 { + return types.ErrInvalidType + } + + return nil +} + +func (i *uint192) private() {} + +func init() { + typeMap["uint192"] = &ABIEncodingType{ + native: reflect.TypeOf((*big.Int)(nil)), + checked: reflect.TypeOf((*uint192)(nil)), + } +} + +type int200 big.Int + +func (i *int200) UnmarshalCBOR(input []byte) error { + bi := (*big.Int)(i) + if err := cbor.Unmarshal(input, bi); err != nil { + return err + } + + return i.Verify() +} + +func (i *int200) MarshalCBOR() ([]byte, error) { + return cbor.Marshal((*big.Int)(i)) +} + +func (i *int200) UnmarshalText(input []byte) error { + bi := (*big.Int)(i) + if _, ok := bi.SetString(string(input), 10); !ok { + return types.ErrInvalidType + } + + return i.Verify() +} + +func (i *int200) MarshalText() ([]byte, error) { + bi := (*big.Int)(i) + return []byte(bi.String()), nil +} + +func (i *int200) Verify() error { + bi := (*big.Int)(i) + + if !codec.FitsInNBitsSigned(200, bi) { + return types.ErrInvalidType + } + + return nil +} + +func (i *int200) private() {} + +func init() { + typeMap["int200"] = &ABIEncodingType{ + native: reflect.TypeOf((*big.Int)(nil)), + checked: reflect.TypeOf((*int200)(nil)), + } +} + +type uint200 big.Int + +func (i *uint200) UnmarshalCBOR(input []byte) error { + bi := (*big.Int)(i) + if err := cbor.Unmarshal(input, bi); err != nil { + return err + } + + return i.Verify() +} + +func (i *uint200) MarshalCBOR() ([]byte, error) { + return cbor.Marshal((*big.Int)(i)) +} + +func (i *uint200) UnmarshalText(input []byte) error { + bi := (*big.Int)(i) + if _, ok := bi.SetString(string(input), 10); !ok { + return types.ErrInvalidType + } + + return i.Verify() +} + +func (i *uint200) MarshalText() ([]byte, error) { + bi := (*big.Int)(i) + return []byte(bi.String()), nil +} + +func (i *uint200) Verify() error { + bi := (*big.Int)(i) + + if bi.BitLen() > 200 || bi.Sign() < 0 { + return types.ErrInvalidType + } + + return nil +} + +func (i *uint200) private() {} + +func init() { + typeMap["uint200"] = &ABIEncodingType{ + native: reflect.TypeOf((*big.Int)(nil)), + checked: reflect.TypeOf((*uint200)(nil)), + } +} + +type int208 big.Int + +func (i *int208) UnmarshalCBOR(input []byte) error { + bi := (*big.Int)(i) + if err := cbor.Unmarshal(input, bi); err != nil { + return err + } + + return i.Verify() +} + +func (i *int208) MarshalCBOR() ([]byte, error) { + return cbor.Marshal((*big.Int)(i)) +} + +func (i *int208) UnmarshalText(input []byte) error { + bi := (*big.Int)(i) + if _, ok := bi.SetString(string(input), 10); !ok { + return types.ErrInvalidType + } + + return i.Verify() +} + +func (i *int208) MarshalText() ([]byte, error) { + bi := (*big.Int)(i) + return []byte(bi.String()), nil +} + +func (i *int208) Verify() error { + bi := (*big.Int)(i) + + if !codec.FitsInNBitsSigned(208, bi) { + return types.ErrInvalidType + } + + return nil +} + +func (i *int208) private() {} + +func init() { + typeMap["int208"] = &ABIEncodingType{ + native: reflect.TypeOf((*big.Int)(nil)), + checked: reflect.TypeOf((*int208)(nil)), + } +} + +type uint208 big.Int + +func (i *uint208) UnmarshalCBOR(input []byte) error { + bi := (*big.Int)(i) + if err := cbor.Unmarshal(input, bi); err != nil { + return err + } + + return i.Verify() +} + +func (i *uint208) MarshalCBOR() ([]byte, error) { + return cbor.Marshal((*big.Int)(i)) +} + +func (i *uint208) UnmarshalText(input []byte) error { + bi := (*big.Int)(i) + if _, ok := bi.SetString(string(input), 10); !ok { + return types.ErrInvalidType + } + + return i.Verify() +} + +func (i *uint208) MarshalText() ([]byte, error) { + bi := (*big.Int)(i) + return []byte(bi.String()), nil +} + +func (i *uint208) Verify() error { + bi := (*big.Int)(i) + + if bi.BitLen() > 208 || bi.Sign() < 0 { + return types.ErrInvalidType + } + + return nil +} + +func (i *uint208) private() {} + +func init() { + typeMap["uint208"] = &ABIEncodingType{ + native: reflect.TypeOf((*big.Int)(nil)), + checked: reflect.TypeOf((*uint208)(nil)), + } +} + +type int216 big.Int + +func (i *int216) UnmarshalCBOR(input []byte) error { + bi := (*big.Int)(i) + if err := cbor.Unmarshal(input, bi); err != nil { + return err + } + + return i.Verify() +} + +func (i *int216) MarshalCBOR() ([]byte, error) { + return cbor.Marshal((*big.Int)(i)) +} + +func (i *int216) UnmarshalText(input []byte) error { + bi := (*big.Int)(i) + if _, ok := bi.SetString(string(input), 10); !ok { + return types.ErrInvalidType + } + + return i.Verify() +} + +func (i *int216) MarshalText() ([]byte, error) { + bi := (*big.Int)(i) + return []byte(bi.String()), nil +} + +func (i *int216) Verify() error { + bi := (*big.Int)(i) + + if !codec.FitsInNBitsSigned(216, bi) { + return types.ErrInvalidType + } + + return nil +} + +func (i *int216) private() {} + +func init() { + typeMap["int216"] = &ABIEncodingType{ + native: reflect.TypeOf((*big.Int)(nil)), + checked: reflect.TypeOf((*int216)(nil)), + } +} + +type uint216 big.Int + +func (i *uint216) UnmarshalCBOR(input []byte) error { + bi := (*big.Int)(i) + if err := cbor.Unmarshal(input, bi); err != nil { + return err + } + + return i.Verify() +} + +func (i *uint216) MarshalCBOR() ([]byte, error) { + return cbor.Marshal((*big.Int)(i)) +} + +func (i *uint216) UnmarshalText(input []byte) error { + bi := (*big.Int)(i) + if _, ok := bi.SetString(string(input), 10); !ok { + return types.ErrInvalidType + } + + return i.Verify() +} + +func (i *uint216) MarshalText() ([]byte, error) { + bi := (*big.Int)(i) + return []byte(bi.String()), nil +} + +func (i *uint216) Verify() error { + bi := (*big.Int)(i) + + if bi.BitLen() > 216 || bi.Sign() < 0 { + return types.ErrInvalidType + } + + return nil +} + +func (i *uint216) private() {} + +func init() { + typeMap["uint216"] = &ABIEncodingType{ + native: reflect.TypeOf((*big.Int)(nil)), + checked: reflect.TypeOf((*uint216)(nil)), + } +} + +type int224 big.Int + +func (i *int224) UnmarshalCBOR(input []byte) error { + bi := (*big.Int)(i) + if err := cbor.Unmarshal(input, bi); err != nil { + return err + } + + return i.Verify() +} + +func (i *int224) MarshalCBOR() ([]byte, error) { + return cbor.Marshal((*big.Int)(i)) +} + +func (i *int224) UnmarshalText(input []byte) error { + bi := (*big.Int)(i) + if _, ok := bi.SetString(string(input), 10); !ok { + return types.ErrInvalidType + } + + return i.Verify() +} + +func (i *int224) MarshalText() ([]byte, error) { + bi := (*big.Int)(i) + return []byte(bi.String()), nil +} + +func (i *int224) Verify() error { + bi := (*big.Int)(i) + + if !codec.FitsInNBitsSigned(224, bi) { + return types.ErrInvalidType + } + + return nil +} + +func (i *int224) private() {} + +func init() { + typeMap["int224"] = &ABIEncodingType{ + native: reflect.TypeOf((*big.Int)(nil)), + checked: reflect.TypeOf((*int224)(nil)), + } +} + +type uint224 big.Int + +func (i *uint224) UnmarshalCBOR(input []byte) error { + bi := (*big.Int)(i) + if err := cbor.Unmarshal(input, bi); err != nil { + return err + } + + return i.Verify() +} + +func (i *uint224) MarshalCBOR() ([]byte, error) { + return cbor.Marshal((*big.Int)(i)) +} + +func (i *uint224) UnmarshalText(input []byte) error { + bi := (*big.Int)(i) + if _, ok := bi.SetString(string(input), 10); !ok { + return types.ErrInvalidType + } + + return i.Verify() +} + +func (i *uint224) MarshalText() ([]byte, error) { + bi := (*big.Int)(i) + return []byte(bi.String()), nil +} + +func (i *uint224) Verify() error { + bi := (*big.Int)(i) + + if bi.BitLen() > 224 || bi.Sign() < 0 { + return types.ErrInvalidType + } + + return nil +} + +func (i *uint224) private() {} + +func init() { + typeMap["uint224"] = &ABIEncodingType{ + native: reflect.TypeOf((*big.Int)(nil)), + checked: reflect.TypeOf((*uint224)(nil)), + } +} + +type int232 big.Int + +func (i *int232) UnmarshalCBOR(input []byte) error { + bi := (*big.Int)(i) + if err := cbor.Unmarshal(input, bi); err != nil { + return err + } + + return i.Verify() +} + +func (i *int232) MarshalCBOR() ([]byte, error) { + return cbor.Marshal((*big.Int)(i)) +} + +func (i *int232) UnmarshalText(input []byte) error { + bi := (*big.Int)(i) + if _, ok := bi.SetString(string(input), 10); !ok { + return types.ErrInvalidType + } + + return i.Verify() +} + +func (i *int232) MarshalText() ([]byte, error) { + bi := (*big.Int)(i) + return []byte(bi.String()), nil +} + +func (i *int232) Verify() error { + bi := (*big.Int)(i) + + if !codec.FitsInNBitsSigned(232, bi) { + return types.ErrInvalidType + } + + return nil +} + +func (i *int232) private() {} + +func init() { + typeMap["int232"] = &ABIEncodingType{ + native: reflect.TypeOf((*big.Int)(nil)), + checked: reflect.TypeOf((*int232)(nil)), + } +} + +type uint232 big.Int + +func (i *uint232) UnmarshalCBOR(input []byte) error { + bi := (*big.Int)(i) + if err := cbor.Unmarshal(input, bi); err != nil { + return err + } + + return i.Verify() +} + +func (i *uint232) MarshalCBOR() ([]byte, error) { + return cbor.Marshal((*big.Int)(i)) +} + +func (i *uint232) UnmarshalText(input []byte) error { + bi := (*big.Int)(i) + if _, ok := bi.SetString(string(input), 10); !ok { + return types.ErrInvalidType + } + + return i.Verify() +} + +func (i *uint232) MarshalText() ([]byte, error) { + bi := (*big.Int)(i) + return []byte(bi.String()), nil +} + +func (i *uint232) Verify() error { + bi := (*big.Int)(i) + + if bi.BitLen() > 232 || bi.Sign() < 0 { + return types.ErrInvalidType + } + + return nil +} + +func (i *uint232) private() {} + +func init() { + typeMap["uint232"] = &ABIEncodingType{ + native: reflect.TypeOf((*big.Int)(nil)), + checked: reflect.TypeOf((*uint232)(nil)), + } +} + +type int240 big.Int + +func (i *int240) UnmarshalCBOR(input []byte) error { + bi := (*big.Int)(i) + if err := cbor.Unmarshal(input, bi); err != nil { + return err + } + + return i.Verify() +} + +func (i *int240) MarshalCBOR() ([]byte, error) { + return cbor.Marshal((*big.Int)(i)) +} + +func (i *int240) UnmarshalText(input []byte) error { + bi := (*big.Int)(i) + if _, ok := bi.SetString(string(input), 10); !ok { + return types.ErrInvalidType + } + + return i.Verify() +} + +func (i *int240) MarshalText() ([]byte, error) { + bi := (*big.Int)(i) + return []byte(bi.String()), nil +} + +func (i *int240) Verify() error { + bi := (*big.Int)(i) + + if !codec.FitsInNBitsSigned(240, bi) { + return types.ErrInvalidType + } + + return nil +} + +func (i *int240) private() {} + +func init() { + typeMap["int240"] = &ABIEncodingType{ + native: reflect.TypeOf((*big.Int)(nil)), + checked: reflect.TypeOf((*int240)(nil)), + } +} + +type uint240 big.Int + +func (i *uint240) UnmarshalCBOR(input []byte) error { + bi := (*big.Int)(i) + if err := cbor.Unmarshal(input, bi); err != nil { + return err + } + + return i.Verify() +} + +func (i *uint240) MarshalCBOR() ([]byte, error) { + return cbor.Marshal((*big.Int)(i)) +} + +func (i *uint240) UnmarshalText(input []byte) error { + bi := (*big.Int)(i) + if _, ok := bi.SetString(string(input), 10); !ok { + return types.ErrInvalidType + } + + return i.Verify() +} + +func (i *uint240) MarshalText() ([]byte, error) { + bi := (*big.Int)(i) + return []byte(bi.String()), nil +} + +func (i *uint240) Verify() error { + bi := (*big.Int)(i) + + if bi.BitLen() > 240 || bi.Sign() < 0 { + return types.ErrInvalidType + } + + return nil +} + +func (i *uint240) private() {} + +func init() { + typeMap["uint240"] = &ABIEncodingType{ + native: reflect.TypeOf((*big.Int)(nil)), + checked: reflect.TypeOf((*uint240)(nil)), + } +} + +type int248 big.Int + +func (i *int248) UnmarshalCBOR(input []byte) error { + bi := (*big.Int)(i) + if err := cbor.Unmarshal(input, bi); err != nil { + return err + } + + return i.Verify() +} + +func (i *int248) MarshalCBOR() ([]byte, error) { + return cbor.Marshal((*big.Int)(i)) +} + +func (i *int248) UnmarshalText(input []byte) error { + bi := (*big.Int)(i) + if _, ok := bi.SetString(string(input), 10); !ok { + return types.ErrInvalidType + } + + return i.Verify() +} + +func (i *int248) MarshalText() ([]byte, error) { + bi := (*big.Int)(i) + return []byte(bi.String()), nil +} + +func (i *int248) Verify() error { + bi := (*big.Int)(i) + + if !codec.FitsInNBitsSigned(248, bi) { + return types.ErrInvalidType + } + + return nil +} + +func (i *int248) private() {} + +func init() { + typeMap["int248"] = &ABIEncodingType{ + native: reflect.TypeOf((*big.Int)(nil)), + checked: reflect.TypeOf((*int248)(nil)), + } +} + +type uint248 big.Int + +func (i *uint248) UnmarshalCBOR(input []byte) error { + bi := (*big.Int)(i) + if err := cbor.Unmarshal(input, bi); err != nil { + return err + } + + return i.Verify() +} + +func (i *uint248) MarshalCBOR() ([]byte, error) { + return cbor.Marshal((*big.Int)(i)) +} + +func (i *uint248) UnmarshalText(input []byte) error { + bi := (*big.Int)(i) + if _, ok := bi.SetString(string(input), 10); !ok { + return types.ErrInvalidType + } + + return i.Verify() +} + +func (i *uint248) MarshalText() ([]byte, error) { + bi := (*big.Int)(i) + return []byte(bi.String()), nil +} + +func (i *uint248) Verify() error { + bi := (*big.Int)(i) + + if bi.BitLen() > 248 || bi.Sign() < 0 { + return types.ErrInvalidType + } + + return nil +} + +func (i *uint248) private() {} + +func init() { + typeMap["uint248"] = &ABIEncodingType{ + native: reflect.TypeOf((*big.Int)(nil)), + checked: reflect.TypeOf((*uint248)(nil)), + } +} + +type int256 big.Int + +func (i *int256) UnmarshalCBOR(input []byte) error { + bi := (*big.Int)(i) + if err := cbor.Unmarshal(input, bi); err != nil { + return err + } + + return i.Verify() +} + +func (i *int256) MarshalCBOR() ([]byte, error) { + return cbor.Marshal((*big.Int)(i)) +} + +func (i *int256) UnmarshalText(input []byte) error { + bi := (*big.Int)(i) + if _, ok := bi.SetString(string(input), 10); !ok { + return types.ErrInvalidType + } + + return i.Verify() +} + +func (i *int256) MarshalText() ([]byte, error) { + bi := (*big.Int)(i) + return []byte(bi.String()), nil +} + +func (i *int256) Verify() error { + bi := (*big.Int)(i) + + if !codec.FitsInNBitsSigned(256, bi) { + return types.ErrInvalidType + } + + return nil +} + +func (i *int256) private() {} + +func init() { + typeMap["int256"] = &ABIEncodingType{ + native: reflect.TypeOf((*big.Int)(nil)), + checked: reflect.TypeOf((*int256)(nil)), + } +} + +type uint256 big.Int + +func (i *uint256) UnmarshalCBOR(input []byte) error { + bi := (*big.Int)(i) + if err := cbor.Unmarshal(input, bi); err != nil { + return err + } + + return i.Verify() +} + +func (i *uint256) MarshalCBOR() ([]byte, error) { + return cbor.Marshal((*big.Int)(i)) +} + +func (i *uint256) UnmarshalText(input []byte) error { + bi := (*big.Int)(i) + if _, ok := bi.SetString(string(input), 10); !ok { + return types.ErrInvalidType + } + + return i.Verify() +} + +func (i *uint256) MarshalText() ([]byte, error) { + bi := (*big.Int)(i) + return []byte(bi.String()), nil +} + +func (i *uint256) Verify() error { + bi := (*big.Int)(i) + + if bi.BitLen() > 256 || bi.Sign() < 0 { + return types.ErrInvalidType + } + + return nil +} + +func (i *uint256) private() {} + +func init() { + typeMap["uint256"] = &ABIEncodingType{ + native: reflect.TypeOf((*big.Int)(nil)), + checked: reflect.TypeOf((*uint256)(nil)), + } +} diff --git a/core/services/relay/evm/types/int_types_test.go b/core/services/relay/evm/types/int_types_test.go new file mode 100644 index 0000000000..6930287c86 --- /dev/null +++ b/core/services/relay/evm/types/int_types_test.go @@ -0,0 +1,54 @@ +package types + +import ( + "errors" + "fmt" + "math/big" + "reflect" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + "github.com/smartcontractkit/chainlink-common/pkg/types" +) + +func TestIntTypes(t *testing.T) { + t.Parallel() + for i := 24; i <= 256; i += 8 { + if i == 64 || i == 32 { + continue + } + t.Run(fmt.Sprintf("int%v", i), func(t *testing.T) { + tpe, ok := GetAbiEncodingType(fmt.Sprintf("int%v", i)) + require.True(t, ok) + minVal := new(big.Int).Neg(new(big.Int).Exp(big.NewInt(2), big.NewInt(int64(i-1)), nil)) + maxVal := new(big.Int).Sub(new(big.Int).Exp(big.NewInt(2), big.NewInt(int64(i-1)), nil), big.NewInt(1)) + assertBigIntBounds(t, tpe, minVal, maxVal) + }) + + t.Run(fmt.Sprintf("uint%v", i), func(t *testing.T) { + tep, ok := GetAbiEncodingType(fmt.Sprintf("uint%v", i)) + require.True(t, ok) + minVal := big.NewInt(0) + maxVal := new(big.Int).Sub(new(big.Int).Exp(big.NewInt(2), big.NewInt(int64(i)), nil), big.NewInt(1)) + assertBigIntBounds(t, tep, minVal, maxVal) + }) + } +} + +func assertBigIntBounds(t *testing.T, tpe *ABIEncodingType, min, max *big.Int) { + t.Helper() + assert.Equal(t, reflect.TypeOf(min), tpe.native) + assert.True(t, tpe.checked.ConvertibleTo(reflect.TypeOf(min))) + minMinusOne := new(big.Int).Sub(min, big.NewInt(1)) + maxPlusOne := new(big.Int).Add(max, big.NewInt(1)) + sbi := reflect.ValueOf(min).Convert(tpe.checked).Interface().(SizedBigInt) + assert.NoError(t, sbi.Verify()) + sbi = reflect.ValueOf(max).Convert(tpe.checked).Interface().(SizedBigInt) + assert.NoError(t, sbi.Verify()) + sbi = reflect.ValueOf(minMinusOne).Convert(tpe.checked).Interface().(SizedBigInt) + assert.True(t, errors.Is(types.ErrInvalidType, sbi.Verify())) + sbi = reflect.ValueOf(maxPlusOne).Convert(tpe.checked).Interface().(SizedBigInt) + assert.True(t, errors.Is(types.ErrInvalidType, sbi.Verify())) +} diff --git a/core/services/relay/evm/types/size_helper.go b/core/services/relay/evm/types/size_helper.go new file mode 100644 index 0000000000..921b8a2831 --- /dev/null +++ b/core/services/relay/evm/types/size_helper.go @@ -0,0 +1,69 @@ +package types + +import ( + "github.com/ethereum/go-ethereum/accounts/abi" + + commontypes "github.com/smartcontractkit/chainlink-common/pkg/types" +) + +func GetMaxSize(n int, args abi.Arguments) (int, error) { + size := 0 + for _, arg := range args { + tmp := arg.Type + argSize, _, err := getTypeSize(n, &tmp, true, false) + if err != nil { + return 0, err + } + size += argSize + } + + return size, nil +} + +func getTypeSize(n int, t *abi.Type, dynamicTypeAllowed bool, isNested bool) (int, bool, error) { + // See https://docs.soliditylang.org/en/latest/abi-spec.html#formal-specification-of-the-encoding + switch t.T { + case abi.ArrayTy: + elmSize, _, err := getTypeSize(n, t.Elem, false, true) + return t.Size * elmSize, false, err + case abi.SliceTy: + if !dynamicTypeAllowed { + return 0, false, commontypes.ErrInvalidType + } + elmSize, _, err := getTypeSize(n, t.Elem, false, true) + return 32 /*header*/ + 32 /*footer*/ + elmSize*n, true, err + case abi.BytesTy, abi.StringTy: + if !dynamicTypeAllowed { + return 0, false, commontypes.ErrInvalidType + } + totalSize := (n + 31) / 32 * 32 // strings and bytes are padded to 32 bytes + return 32 /*header*/ + 32 /*footer*/ + totalSize, true, nil + case abi.TupleTy: + return getTupleSize(n, t, isNested) + default: + // types are padded to 32 bytes + return 32, false, nil + } +} + +func getTupleSize(n int, t *abi.Type, isNested bool) (int, bool, error) { + // No header or footer, because if the tuple is dynamically sized we would need to know the inner slice sizes + // so it would return error for that element. + size := 0 + dynamic := false + for _, elm := range t.TupleElems { + argSize, dynamicArg, err := getTypeSize(n, elm, !isNested, true) + if err != nil { + return 0, false, err + } + dynamic = dynamic || dynamicArg + size += argSize + } + + if dynamic { + // offset for the element needs to be included there are dynamic elements + size += 32 + } + + return size, dynamic, nil +} diff --git a/core/services/relay/evm/types/size_helper_test.go b/core/services/relay/evm/types/size_helper_test.go new file mode 100644 index 0000000000..202269a453 --- /dev/null +++ b/core/services/relay/evm/types/size_helper_test.go @@ -0,0 +1,263 @@ +package types_test + +import ( + "math/big" + "testing" + + "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + commontypes "github.com/smartcontractkit/chainlink-common/pkg/types" + + "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/types" +) + +const anyNumElements = 10 + +func TestGetMaxSize(t *testing.T) { + t.Run("Basic types all encode to 32 bytes", func(t *testing.T) { + args := abi.Arguments{ + {Name: "I8", Type: mustType(t, "int8")}, + {Name: "I80", Type: mustType(t, "int80")}, + {Name: "I256", Type: mustType(t, "int256")}, + {Name: "B3", Type: mustType(t, "bytes3")}, + {Name: "B32", Type: mustType(t, "bytes32")}, + {Name: "TF", Type: mustType(t, "bool")}, + } + + runSizeTest(t, anyNumElements, args, int8(9), big.NewInt(3), big.NewInt(200), [3]byte{1, 3, 4}, make32Bytes(1), true) + }) + + t.Run("Slices of basic types all encode to 32 bytes each + header and footer", func(t *testing.T) { + args := abi.Arguments{ + {Name: "I8", Type: mustType(t, "int8[]")}, + {Name: "I80", Type: mustType(t, "int80[]")}, + {Name: "I256", Type: mustType(t, "int256[]")}, + {Name: "B3", Type: mustType(t, "bytes3[]")}, + {Name: "B32", Type: mustType(t, "bytes32[]")}, + {Name: "TF", Type: mustType(t, "bool[]")}, + } + + i8 := []int8{9, 2, 1, 3, 5, 6, 2, 1, 2, 3} + i80 := []*big.Int{big.NewInt(9), big.NewInt(2), big.NewInt(1), big.NewInt(3), big.NewInt(5), big.NewInt(6), big.NewInt(2), big.NewInt(1), big.NewInt(2), big.NewInt(3)} + i256 := []*big.Int{big.NewInt(119), big.NewInt(112), big.NewInt(1), big.NewInt(3), big.NewInt(5), big.NewInt(6), big.NewInt(2), big.NewInt(1), big.NewInt(2), big.NewInt(3)} + b3 := [][3]byte{{1, 2, 3}, {1, 2, 3}, {1, 2, 3}, {1, 2, 3}, {1, 2, 3}, {1, 2, 3}, {1, 2, 3}, {1, 2, 3}, {1, 2, 3}, {1, 2, 3}} + b32 := [][32]byte{make32Bytes(1), make32Bytes(2), make32Bytes(3), make32Bytes(4), make32Bytes(5), make32Bytes(6), make32Bytes(7), make32Bytes(8), make32Bytes(9), make32Bytes(10)} + tf := []bool{true, false, true, false, true, false, true, false, true, false} + runSizeTest(t, anyNumElements, args, i8, i80, i256, b3, b32, tf) + }) + + t.Run("Arrays of basic types all encode to 32 bytes each", func(t *testing.T) { + args := abi.Arguments{ + {Name: "I8", Type: mustType(t, "int8[3]")}, + {Name: "I80", Type: mustType(t, "int80[3]")}, + {Name: "I256", Type: mustType(t, "int256[3]")}, + {Name: "B3", Type: mustType(t, "bytes3[3]")}, + {Name: "B32", Type: mustType(t, "bytes32[3]")}, + {Name: "TF", Type: mustType(t, "bool[3]")}, + } + + i8 := [3]int8{9, 2, 1} + i80 := [3]*big.Int{big.NewInt(9), big.NewInt(2), big.NewInt(1)} + i256 := [3]*big.Int{big.NewInt(119), big.NewInt(112), big.NewInt(1)} + b3 := [3][3]byte{{1, 2, 3}, {1, 2, 3}, {1, 2, 3}} + b32 := [3][32]byte{make32Bytes(1), make32Bytes(2), make32Bytes(3)} + tf := [3]bool{true, false, true} + runSizeTest(t, anyNumElements, args, i8, i80, i256, b3, b32, tf) + }) + + t.Run("Tuples are a sum of their elements", func(t *testing.T) { + tuple1 := []abi.ArgumentMarshaling{ + {Name: "I8", Type: "int8"}, + {Name: "I80", Type: "int80"}, + {Name: "I256", Type: "int256"}, + {Name: "B3", Type: "bytes3"}, + {Name: "B32", Type: "bytes32"}, + {Name: "TF", Type: "bool"}, + } + t1, err := abi.NewType("tuple", "", tuple1) + require.NoError(t, err) + + tuple2 := []abi.ArgumentMarshaling{ + {Name: "I80", Type: "int80"}, + {Name: "TF", Type: "bool"}, + } + t2, err := abi.NewType("tuple", "", tuple2) + require.NoError(t, err) + + args := abi.Arguments{ + {Name: "t1", Type: t1}, + {Name: "t2", Type: t2}, + } + arg1 := struct { + I8 int8 + I80 *big.Int + I256 *big.Int + B3 [3]byte + B32 [32]byte + TF bool + }{ + int8(9), big.NewInt(3), big.NewInt(200), [3]byte{1, 3, 4}, make32Bytes(1), true, + } + + arg2 := struct { + I80 *big.Int + TF bool + }{ + big.NewInt(3), true, + } + runSizeTest(t, anyNumElements, args, arg1, arg2) + }) + + t.Run("Slices of tuples are a sum of their elements with header and footer", func(t *testing.T) { + tuple1 := []abi.ArgumentMarshaling{ + {Name: "I80", Type: "int80"}, + {Name: "TF", Type: "bool"}, + } + t1, err := abi.NewType("tuple[]", "", tuple1) + require.NoError(t, err) + + args := abi.Arguments{ + {Name: "t1", Type: t1}, + } + arg1 := []struct { + I80 *big.Int + TF bool + }{ + {big.NewInt(1), true}, + {big.NewInt(2), true}, + {big.NewInt(3), true}, + {big.NewInt(4), false}, + {big.NewInt(5), true}, + {big.NewInt(6), true}, + {big.NewInt(7), true}, + {big.NewInt(8), false}, + {big.NewInt(9), true}, + {big.NewInt(10), true}, + } + runSizeTest(t, anyNumElements, args, arg1) + }) + + t.Run("Arrays of tuples are a sum of their elements", func(t *testing.T) { + tuple1 := []abi.ArgumentMarshaling{ + {Name: "I80", Type: "int80"}, + {Name: "TF", Type: "bool"}, + } + t1, err := abi.NewType("tuple[3]", "", tuple1) + require.NoError(t, err) + + args := abi.Arguments{ + {Name: "t1", Type: t1}, + } + arg1 := []struct { + I80 *big.Int + TF bool + }{ + {big.NewInt(1), true}, + {big.NewInt(2), true}, + {big.NewInt(3), true}, + } + runSizeTest(t, anyNumElements, args, arg1) + + }) + + t.Run("Bytes pack themselves", func(t *testing.T) { + args := abi.Arguments{{Name: "B", Type: mustType(t, "bytes")}} + t.Run("No padding needed", func(t *testing.T) { + padded := []byte("12345789022345678903234567890412345678905123456789061234") + runSizeTest(t, 64, args, padded) + }) + t.Run("Padding needed", func(t *testing.T) { + needsPadding := []byte("12345789022345678903234567890412345678905123456") + runSizeTest(t, 56, args, needsPadding) + }) + }) + + t.Run("Strings pack themselves", func(t *testing.T) { + args := abi.Arguments{{Name: "B", Type: mustType(t, "string")}} + t.Run("No padding needed", func(t *testing.T) { + padded := "12345789022345678903234567890412345678905123456789061234" + runSizeTest(t, 64, args, padded) + }) + t.Run("Padding needed", func(t *testing.T) { + needsPadding := "12345789022345678903234567890412345678905123456" + runSizeTest(t, 56, args, needsPadding) + }) + }) + + t.Run("Nested dynamic types return errors", func(t *testing.T) { + t.Run("Slice in slice", func(t *testing.T) { + args := abi.Arguments{{Name: "B", Type: mustType(t, "int32[][]")}} + _, err := types.GetMaxSize(anyNumElements, args) + assert.IsType(t, commontypes.ErrInvalidType, err) + }) + t.Run("Slice in array", func(t *testing.T) { + args := abi.Arguments{{Name: "B", Type: mustType(t, "int32[][2]")}} + _, err := types.GetMaxSize(anyNumElements, args) + assert.IsType(t, commontypes.ErrInvalidType, err) + }) + }) + + t.Run("Slices in a top level tuple works as-if they are the sized element", func(t *testing.T) { + tuple1 := []abi.ArgumentMarshaling{ + {Name: "I80", Type: "int80[]"}, + {Name: "TF", Type: "bool[]"}, + } + t1, err := abi.NewType("tuple", "", tuple1) + require.NoError(t, err) + args := abi.Arguments{{Name: "tuple", Type: t1}} + + arg1 := struct { + I80 []*big.Int + TF []bool + }{ + I80: []*big.Int{big.NewInt(1), big.NewInt(2), big.NewInt(3), big.NewInt(4), big.NewInt(5), big.NewInt(6), big.NewInt(7), big.NewInt(8), big.NewInt(9), big.NewInt(10)}, + TF: []bool{true, true, true, false, true, true, true, false, true, true}, + } + + runSizeTest(t, anyNumElements, args, arg1) + }) + + t.Run("Nested dynamic tuples return errors", func(t *testing.T) { + tuple1 := []abi.ArgumentMarshaling{ + {Name: "I8", Type: "int8"}, + {Name: "I80", Type: "int80"}, + {Name: "I256", Type: "int256"}, + {Name: "B3", Type: "bytes3"}, + {Name: "B32", Type: "bytes32"}, + {Name: "TF", Type: "bool[]"}, + } + + tuple2 := []abi.ArgumentMarshaling{ + {Name: "I80", Type: "int80"}, + {Name: "T1", Type: "tuple", Components: tuple1}, + } + t2, err := abi.NewType("tuple", "", tuple2) + require.NoError(t, err) + + args := abi.Arguments{{Name: "t2", Type: t2}} + _, err = types.GetMaxSize(anyNumElements, args) + assert.IsType(t, commontypes.ErrInvalidType, err) + }) +} + +func runSizeTest(t *testing.T, n int, args abi.Arguments, params ...any) { + + actual, err := types.GetMaxSize(n, args) + require.NoError(t, err) + + expected, err := args.Pack(params...) + require.NoError(t, err) + assert.Equal(t, len(expected), actual) +} + +func mustType(t *testing.T, name string) abi.Type { + aType, err := abi.NewType(name, "", []abi.ArgumentMarshaling{}) + require.NoError(t, err) + return aType +} + +func make32Bytes(firstByte byte) [32]byte { + return [32]byte{firstByte, 2, 3, 4, 5, 6, 7, 8, 9, 10, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 1, 2, 3} +} diff --git a/core/services/relay/evm/types/types.go b/core/services/relay/evm/types/types.go index eb35546880..6c8c48ca0f 100644 --- a/core/services/relay/evm/types/types.go +++ b/core/services/relay/evm/types/types.go @@ -1,6 +1,7 @@ package types import ( + "bytes" "context" "encoding/json" "errors" @@ -8,50 +9,108 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/lib/pq" - - "gopkg.in/guregu/null.v2" - ocrtypes "github.com/smartcontractkit/libocr/offchainreporting2plus/types" + "gopkg.in/guregu/null.v2" + "github.com/smartcontractkit/chainlink-common/pkg/codec" "github.com/smartcontractkit/chainlink-common/pkg/services" "github.com/smartcontractkit/chainlink-common/pkg/types" - commontypes "github.com/smartcontractkit/chainlink-common/pkg/types" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" ) type ChainReaderConfig struct { - // ChainContractReaders key is contract name - ChainContractReaders map[string]ChainContractReader `json:"chainContractReaders"` + // Contracts key is contract name + Contracts map[string]ChainContractReader `json:"contracts" toml:"contracts"` +} + +type CodecConfig struct { + // Configs key is the type's name for the codec + Configs map[string]ChainCodecConfig `json:"configs" toml:"configs"` +} + +type ChainCodecConfig struct { + TypeABI string `json:"typeAbi" toml:"typeABI"` + ModifierConfigs codec.ModifiersConfig `toml:"modifierConfigs,omitempty"` } type ChainContractReader struct { - ContractABI string `json:"contractABI"` - // ChainReaderDefinitions key is chainAgnostic read name. - ChainReaderDefinitions map[string]ChainReaderDefinition `json:"chainReaderDefinitions"` + ContractABI string `json:"contractABI" toml:"contractABI"` + // key is genericName from config + Configs map[string]*ChainReaderDefinition `json:"configs" toml:"configs"` +} + +type ChainReaderDefinition chainReaderDefinitionFields + +// chainReaderDefinitionFields has the fields for ChainReaderDefinition but no methods. +// This is necessary because package json recognizes the text encoding methods used for TOML, +// and would infinitely recurse on itself. +type chainReaderDefinitionFields struct { + CacheEnabled bool `json:"cacheEnabled,omitempty"` + // chain specific contract method name or event type. + ChainSpecificName string `json:"chainSpecificName"` + ReadType ReadType `json:"readType,omitempty"` + InputModifications codec.ModifiersConfig `json:"inputModifications,omitempty"` + OutputModifications codec.ModifiersConfig `json:"outputModifications,omitempty"` + + // EventInputFields allows you to choose which indexed fields are expected from the input + EventInputFields []string `json:"eventInputFields,omitempty"` +} + +func (d *ChainReaderDefinition) MarshalText() ([]byte, error) { + var b bytes.Buffer + e := json.NewEncoder(&b) + e.SetIndent("", " ") + if err := e.Encode((*chainReaderDefinitionFields)(d)); err != nil { + return nil, err + } + return b.Bytes(), nil } -type ChainReaderDefinition struct { - ChainSpecificName string `json:"chainSpecificName"` // chain specific contract method name or event type. - Params map[string]any `json:"params"` - ReturnValues []string `json:"returnValues"` - CacheEnabled bool `json:"cacheEnabled"` - ReadType ReadType `json:"readType"` +func (d *ChainReaderDefinition) UnmarshalText(b []byte) error { + return json.Unmarshal(b, (*chainReaderDefinitionFields)(d)) } -type ReadType int64 +type ReadType int const ( - Method ReadType = 0 - Event ReadType = 1 + Method ReadType = iota + Event ) +func (r ReadType) String() string { + switch r { + case Method: + return "method" + case Event: + return "event" + } + return fmt.Sprintf("ReadType(%d)", r) +} + +func (r ReadType) MarshalText() ([]byte, error) { + return []byte(r.String()), nil +} + +func (r *ReadType) UnmarshalText(text []byte) error { + switch string(text) { + case "method": + *r = Method + return nil + case "event": + *r = Event + return nil + } + return fmt.Errorf("unrecognized ReadType: %s", string(text)) +} + type RelayConfig struct { ChainID *big.Big `json:"chainID"` FromBlock uint64 `json:"fromBlock"` EffectiveTransmitterID null.String `json:"effectiveTransmitterID"` ConfigContractAddress *common.Address `json:"configContractAddress"` ChainReader *ChainReaderConfig `json:"chainReader"` + Codec *CodecConfig `json:"codec"` // Contract-specific SendingKeys pq.StringArray `json:"sendingKeys"` @@ -64,15 +123,15 @@ type RelayConfig struct { FromBlocks map[string]int64 `json:"fromBlocks"` } +var ErrBadRelayConfig = errors.New("bad relay config") + type RelayOpts struct { // TODO BCF-2508 -- should anyone ever get the raw config bytes that are embedded in args? if not, // make this private and wrap the arg fields with funcs on RelayOpts - commontypes.RelayArgs + types.RelayArgs c *RelayConfig } -var ErrBadRelayConfig = errors.New("bad relay config") - func NewRelayOpts(args types.RelayArgs) *RelayOpts { return &RelayOpts{ RelayArgs: args, @@ -102,9 +161,9 @@ type ConfigPoller interface { Replay(ctx context.Context, fromBlock int64) error } -// TODO(FUN-668): Migrate this fully into commontypes.FunctionsProvider +// TODO(FUN-668): Migrate this fully into types.FunctionsProvider type FunctionsProvider interface { - commontypes.FunctionsProvider + types.FunctionsProvider LogPollerWrapper() LogPollerWrapper } diff --git a/core/services/telemetry/manager.go b/core/services/telemetry/manager.go index c457aca5bf..228a997eec 100644 --- a/core/services/telemetry/manager.go +++ b/core/services/telemetry/manager.go @@ -18,13 +18,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/services/synchronization" ) -//// 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 { services.StateMachine bufferSize uint @@ -38,32 +31,6 @@ type Manager struct { 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 { @@ -87,30 +54,12 @@ func NewManager(cfg config.TelemetryIngress, csaKeyStore keystore.CSA, lggr logg 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 } @@ -165,11 +114,11 @@ func (m *Manager) GenMonitoringEndpoint(network string, chainID string, contract } func (m *Manager) addEndpoint(e config.TelemetryIngressEndpoint) error { - if e.Network() == "" && !m.legacyMode { + if e.Network() == "" { return errors.New("cannot add telemetry endpoint, network cannot be empty") } - if e.ChainID() == "" && !m.legacyMode { + if e.ChainID() == "" { return errors.New("cannot add telemetry endpoint, chainID cannot be empty") } @@ -205,11 +154,6 @@ func (m *Manager) addEndpoint(e config.TelemetryIngressEndpoint) error { } 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 diff --git a/core/services/telemetry/manager_test.go b/core/services/telemetry/manager_test.go index 0b1fbc6d87..2d3409ba56 100644 --- a/core/services/telemetry/manager_test.go +++ b/core/services/telemetry/manager_test.go @@ -13,7 +13,6 @@ import ( "github.com/stretchr/testify/require" "go.uber.org/zap/zapcore" - commonconfig "github.com/smartcontractkit/chainlink-common/pkg/config" "github.com/smartcontractkit/chainlink/v2/core/config" "github.com/smartcontractkit/chainlink/v2/core/config/mocks" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" @@ -200,7 +199,6 @@ func TestNewManager(t *testing.T) { 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) @@ -286,58 +284,3 @@ func TestCorrectEndpointRouting(t *testing.T) { } } - -func TestLegacyMode(t *testing.T) { - tic := setupMockConfig(t, true) - tic.On("Endpoints").Return(nil) - url, err := commonconfig.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) - - clientSent := make([]synchronization.TelemPayload, 0) - 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("unknown-network", "unknown-chainID", "some-contractID", "some-type") - 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-unknown-network", "another-unknown-chainID", "another-contractID", "another-type") - 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) - - require.Equal(t, 1, obsLogs.Len()) // Deprecation warning for TelemetryIngress.URL and TelemetryIngress.ServerPubKey - // disable false positive linter, it misses the size check above - // nolint: gosec - if len(clientSent) >= 6 { - require.Equal(t, []byte("endpoint-1-message-1"), clientSent[0].Telemetry) - require.Equal(t, []byte("endpoint-1-message-2"), clientSent[1].Telemetry) - require.Equal(t, []byte("endpoint-1-message-3"), clientSent[2].Telemetry) - require.Equal(t, []byte("endpoint-2-message-1"), clientSent[3].Telemetry) - require.Equal(t, []byte("endpoint-2-message-2"), clientSent[4].Telemetry) - require.Equal(t, []byte("endpoint-2-message-3"), clientSent[5].Telemetry) - } -} diff --git a/core/services/vrf/solidity_cross_tests/vrf_coordinator_interface_test.go b/core/services/vrf/solidity_cross_tests/vrf_coordinator_interface_test.go index 2601f800e9..47c47af7c9 100644 --- a/core/services/vrf/solidity_cross_tests/vrf_coordinator_interface_test.go +++ b/core/services/vrf/solidity_cross_tests/vrf_coordinator_interface_test.go @@ -31,7 +31,7 @@ var ( Data: append(append(append(append( keyHash.Bytes(), common.BigToHash(seed).Bytes()...), - sender.Hash().Bytes()...), + common.BytesToHash(sender.Bytes()).Bytes()...), common.BigToHash(fee).Bytes()...), requestID.Bytes()...), Topics: []common.Hash{{}, jobID}, diff --git a/core/services/vrf/solidity_cross_tests/vrf_coordinator_solidity_crosscheck_test.go b/core/services/vrf/solidity_cross_tests/vrf_coordinator_solidity_crosscheck_test.go index e758689593..946365e31a 100644 --- a/core/services/vrf/solidity_cross_tests/vrf_coordinator_solidity_crosscheck_test.go +++ b/core/services/vrf/solidity_cross_tests/vrf_coordinator_solidity_crosscheck_test.go @@ -170,7 +170,7 @@ func TestRandomnessRequestLog(t *testing.T) { golangSeed := utils.MustHash(string(append(append(append( keyHash[:], common.BigToHash(hardcodedSeed).Bytes()...), - tc.consumerAddress.Hash().Bytes()...), + common.BytesToHash(tc.consumerAddress.Bytes()).Bytes()...), common.BigToHash(nonce).Bytes()...))) assert.Equal(t, golangSeed, common.BigToHash((log.Seed)), "VRFCoordinator logged different actual input seed than expected by golang code!") assert.Equal(t, jobID, log.JobID, "VRFCoordinator logged different JobID from randomness request!") diff --git a/core/store/migrate/migrations/0221_functions_allowlist.sql b/core/store/migrate/migrations/0221_functions_allowlist.sql new file mode 100644 index 0000000000..e97b2fc407 --- /dev/null +++ b/core/store/migrate/migrations/0221_functions_allowlist.sql @@ -0,0 +1,22 @@ +-- +goose Up +-- +goose StatementBegin +CREATE TABLE functions_allowlist( + id BIGSERIAL, + router_contract_address bytea CHECK (octet_length(router_contract_address) = 20) NOT NULL, + allowed_address bytea CHECK (octet_length(allowed_address) = 20) NOT NULL, + PRIMARY KEY(router_contract_address, allowed_address) +); + +ALTER TABLE functions_subscriptions +ADD CONSTRAINT router_contract_address_octet_length CHECK (octet_length(router_contract_address) = 20); + +-- +goose StatementEnd + +-- +goose Down +-- +goose StatementBegin + +ALTER TABLE functions_subscriptions +DROP CONSTRAINT router_contract_address_octet_length; + +DROP TABLE IF EXISTS functions_allowlist; +-- +goose StatementEnd diff --git a/core/web/assets/9f6d832ef97e8493764e.svg.gz b/core/web/assets/9f6d832ef97e8493764e.svg.gz index 44cd870b0b..94a2aadef9 100644 Binary files a/core/web/assets/9f6d832ef97e8493764e.svg.gz and b/core/web/assets/9f6d832ef97e8493764e.svg.gz differ diff --git a/core/web/assets/ba8bbf16ebf8e1d05bef.svg.gz b/core/web/assets/ba8bbf16ebf8e1d05bef.svg.gz index 7e4f235f1b..36ce61e511 100644 Binary files a/core/web/assets/ba8bbf16ebf8e1d05bef.svg.gz and b/core/web/assets/ba8bbf16ebf8e1d05bef.svg.gz differ diff --git a/core/web/assets/index.html b/core/web/assets/index.html index f2257bfbfa..7733186151 100644 --- a/core/web/assets/index.html +++ b/core/web/assets/index.html @@ -1 +1 @@ -Operator UIChainlink
\ No newline at end of file +Operator UIChainlink
\ No newline at end of file diff --git a/core/web/assets/index.html.gz b/core/web/assets/index.html.gz index 4d09643ee1..afbd1b1a38 100644 Binary files a/core/web/assets/index.html.gz and b/core/web/assets/index.html.gz differ diff --git a/core/web/assets/main.8f602c136d4004a835ee.js b/core/web/assets/main.74b124ef5d2ef3614139.js similarity index 90% rename from core/web/assets/main.8f602c136d4004a835ee.js rename to core/web/assets/main.74b124ef5d2ef3614139.js index de75dc2b1c..74cfe38a5b 100644 --- a/core/web/assets/main.8f602c136d4004a835ee.js +++ b/core/web/assets/main.74b124ef5d2ef3614139.js @@ -17,7 +17,7 @@ PERFORMANCE OF THIS SOFTWARE. * * Copyright (c) 2014-2017, Jon Schlinkert. * Released under the MIT License. - */ var r=n(47798);function i(e){return!0===r(e)&&"[object Object]"===Object.prototype.toString.call(e)}e.exports=function(e){var t,n;return!1!==i(e)&&"function"==typeof(t=e.constructor)&&!1!==i(n=t.prototype)&&!1!==n.hasOwnProperty("isPrototypeOf")}},72366(e,t,n){"use strict";var r=n(20862),i=n(95318);Object.defineProperty(t,"__esModule",{value:!0}),t.default=t.MuiThemeProviderOld=void 0;var a=i(n(67154)),o=i(n(59713)),s=i(n(34575)),u=i(n(93913)),c=i(n(78585)),l=i(n(29754)),f=i(n(2205)),d=i(n(67294)),h=i(n(45697));i(n(42473));var p=i(n(43890)),b=n(55252),m=r(n(51067)),g=function(e){function t(e,n){var r;return(0,s.default)(this,t),(r=(0,c.default)(this,(0,l.default)(t).call(this))).broadcast=(0,p.default)(),r.outerTheme=m.default.initial(n),r.broadcast.setState(r.mergeOuterLocalTheme(e.theme)),r}return(0,f.default)(t,e),(0,u.default)(t,[{key:"getChildContext",value:function(){var e,t=this.props,n=t.disableStylesGeneration,r=t.sheetsCache,i=t.sheetsManager,a=this.context.muiThemeProviderOptions||{};return void 0!==n&&(a.disableStylesGeneration=n),void 0!==r&&(a.sheetsCache=r),void 0!==i&&(a.sheetsManager=i),e={},(0,o.default)(e,m.CHANNEL,this.broadcast),(0,o.default)(e,"muiThemeProviderOptions",a),e}},{key:"componentDidMount",value:function(){var e=this;this.unsubscribeId=m.default.subscribe(this.context,function(t){e.outerTheme=t,e.broadcast.setState(e.mergeOuterLocalTheme(e.props.theme))})}},{key:"componentDidUpdate",value:function(e){this.props.theme!==e.theme&&this.broadcast.setState(this.mergeOuterLocalTheme(this.props.theme))}},{key:"componentWillUnmount",value:function(){null!==this.unsubscribeId&&m.default.unsubscribe(this.context,this.unsubscribeId)}},{key:"mergeOuterLocalTheme",value:function(e){return"function"==typeof e?e(this.outerTheme):this.outerTheme?(0,a.default)({},this.outerTheme,e):e}},{key:"render",value:function(){return this.props.children}}]),t}(d.default.Component);t.MuiThemeProviderOld=g,g.childContextTypes=(0,a.default)({},m.default.contextTypes,{muiThemeProviderOptions:h.default.object}),g.contextTypes=(0,a.default)({},m.default.contextTypes,{muiThemeProviderOptions:h.default.object}),b.ponyfillGlobal.__MUI_STYLES__||(b.ponyfillGlobal.__MUI_STYLES__={}),b.ponyfillGlobal.__MUI_STYLES__.MuiThemeProvider||(b.ponyfillGlobal.__MUI_STYLES__.MuiThemeProvider=g);var v=b.ponyfillGlobal.__MUI_STYLES__.MuiThemeProvider;t.default=v},59114(e,t,n){"use strict";var r=n(95318);function i(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:0,n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:1;return en?n:e}function a(e){e=e.substr(1);var t=RegExp(".{1,".concat(e.length/3,"}"),"g"),n=e.match(t);return n&&1===n[0].length&&(n=n.map(function(e){return e+e})),n?"rgb(".concat(n.map(function(e){return parseInt(e,16)}).join(", "),")"):""}function o(e){if(0===e.indexOf("#"))return e;function t(e){var t=e.toString(16);return 1===t.length?"0".concat(t):t}var n=s(e).values;return n=n.map(function(e){return t(e)}),"#".concat(n.join(""))}function s(e){if("#"===e.charAt(0))return s(a(e));var t=e.indexOf("("),n=e.substring(0,t),r=e.substring(t+1,e.length-1).split(",");return r=r.map(function(e){return parseFloat(e)}),{type:n,values:r}}function u(e){var t=e.type,n=e.values;return -1!==t.indexOf("rgb")&&(n=n.map(function(e,t){return t<3?parseInt(e,10):e})),-1!==t.indexOf("hsl")&&(n[1]="".concat(n[1],"%"),n[2]="".concat(n[2],"%")),"".concat(e.type,"(").concat(n.join(", "),")")}function c(e,t){var n=l(e),r=l(t);return(Math.max(n,r)+.05)/(Math.min(n,r)+.05)}function l(e){var t=s(e);if(-1!==t.type.indexOf("rgb")){var n=t.values.map(function(e){return(e/=255)<=.03928?e/12.92:Math.pow((e+.055)/1.055,2.4)});return Number((.2126*n[0]+.7152*n[1]+.0722*n[2]).toFixed(3))}return t.values[2]/100}function f(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:.15;return l(e)>.5?h(e,t):p(e,t)}function d(e,t){return e?(e=s(e),t=i(t),("rgb"===e.type||"hsl"===e.type)&&(e.type+="a"),e.values[3]=t,u(e)):e}function h(e,t){if(!e)return e;if(e=s(e),t=i(t),-1!==e.type.indexOf("hsl"))e.values[2]*=1-t;else if(-1!==e.type.indexOf("rgb"))for(var n=0;n<3;n+=1)e.values[n]*=1-t;return u(e)}function p(e,t){if(!e)return e;if(e=s(e),t=i(t),-1!==e.type.indexOf("hsl"))e.values[2]+=(100-e.values[2])*t;else if(-1!==e.type.indexOf("rgb"))for(var n=0;n<3;n+=1)e.values[n]+=(255-e.values[n])*t;return u(e)}Object.defineProperty(t,"__esModule",{value:!0}),t.convertHexToRGB=a,t.rgbToHex=o,t.decomposeColor=s,t.recomposeColor=u,t.getContrastRatio=c,t.getLuminance=l,t.emphasize=f,t.fade=d,t.darken=h,t.lighten=p,r(n(42473))},94811(e,t,n){"use strict";var r=n(95318);Object.defineProperty(t,"__esModule",{value:!0}),t.default=s,t.keys=void 0;var i=r(n(67154)),a=r(n(6479)),o=["xs","sm","md","lg","xl"];function s(e){var t=e.values,n=void 0===t?{xs:0,sm:600,md:960,lg:1280,xl:1920}:t,r=e.unit,s=void 0===r?"px":r,u=e.step,c=void 0===u?5:u,l=(0,a.default)(e,["values","unit","step"]);function f(e){var t="number"==typeof n[e]?n[e]:e;return"@media (min-width:".concat(t).concat(s,")")}function d(e){var t=o.indexOf(e)+1,r=n[o[t]];if(t===o.length)return f("xs");var i="number"==typeof r&&t>0?r:e;return"@media (max-width:".concat(i-c/100).concat(s,")")}function h(e,t){var r=o.indexOf(t)+1;return r===o.length?f(e):"@media (min-width:".concat(n[e]).concat(s,") and ")+"(max-width:".concat(n[o[r]]-c/100).concat(s,")")}function p(e){return h(e,e)}function b(e){return n[e]}return(0,i.default)({keys:o,values:n,up:f,down:d,between:h,only:p,width:b},l)}t.keys=o},20237(e,t,n){"use strict";var r=n(95318);Object.defineProperty(t,"__esModule",{value:!0}),t.default=o,r(n(42473));var i=/([[\].#*$><+~=|^:(),"'`\s])/g;function a(e){var t;return String(e).replace(i,"-")}function o(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},t=e.dangerouslyUseGlobalCSS,n=void 0!==t&&t,r=e.productionPrefix,i=void 0===r?"jss":r,o=e.seed,s=void 0===o?"":o,u=0;return function(e,t){return(u+=1,n&&t&&t.options.name)?"".concat(a(t.options.name),"-").concat(e.key):"".concat(i).concat(s).concat(u)}}},40226(e,t,n){"use strict";var r=n(95318);Object.defineProperty(t,"__esModule",{value:!0}),t.default=o;var i=r(n(59713)),a=r(n(67154));function o(e,t,n){var r;return(0,a.default)({gutters:function(){var n=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};return(0,a.default)({paddingLeft:2*t.unit,paddingRight:2*t.unit},n,(0,i.default)({},e.up("sm"),(0,a.default)({paddingLeft:3*t.unit,paddingRight:3*t.unit},n[e.up("sm")])))},toolbar:(r={minHeight:56},(0,i.default)(r,"".concat(e.up("xs")," and (orientation: landscape)"),{minHeight:48}),(0,i.default)(r,e.up("sm"),{minHeight:64}),r)},n)}},71615(e,t,n){"use strict";var r=n(95318);Object.defineProperty(t,"__esModule",{value:!0}),t.default=void 0,r(n(59713));var i=r(n(67154)),a=r(n(6479)),o=r(n(94863)),s=r(n(93078));r(n(42473));var u=r(n(94811)),c=r(n(40226)),l=r(n(21091)),f=r(n(45184)),d=r(n(80743)),h=r(n(59591)),p=r(n(5324)),b=r(n(15406)),m=r(n(88676));function g(){var e,t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},n=t.breakpoints,r=void 0===n?{}:n,g=t.mixins,v=void 0===g?{}:g,y=t.palette,w=void 0===y?{}:y,_=t.shadows,E=t.spacing,S=void 0===E?{}:E,k=t.typography,x=void 0===k?{}:k,T=(0,a.default)(t,["breakpoints","mixins","palette","shadows","spacing","typography"]),M=(0,l.default)(w),O=(0,u.default)(r),A=(0,i.default)({},p.default,S);return(0,i.default)({breakpoints:O,direction:"ltr",mixins:(0,c.default)(O,A,v),overrides:{},palette:M,props:{},shadows:_||d.default,typography:(0,f.default)(M,x)},(0,o.default)({shape:h.default,spacing:A,transitions:b.default,zIndex:m.default},T,{isMergeableObject:s.default}))}var v=g;t.default=v},21091(e,t,n){"use strict";var r=n(95318);Object.defineProperty(t,"__esModule",{value:!0}),t.default=m,t.dark=t.light=void 0;var i=r(n(67154)),a=r(n(6479));r(n(42473));var o=r(n(94863)),s=r(n(78768)),u=r(n(124)),c=r(n(70167)),l=r(n(83165)),f=r(n(515)),d=n(59114),h={text:{primary:"rgba(0, 0, 0, 0.87)",secondary:"rgba(0, 0, 0, 0.54)",disabled:"rgba(0, 0, 0, 0.38)",hint:"rgba(0, 0, 0, 0.38)"},divider:"rgba(0, 0, 0, 0.12)",background:{paper:f.default.white,default:c.default[50]},action:{active:"rgba(0, 0, 0, 0.54)",hover:"rgba(0, 0, 0, 0.08)",hoverOpacity:.08,selected:"rgba(0, 0, 0, 0.14)",disabled:"rgba(0, 0, 0, 0.26)",disabledBackground:"rgba(0, 0, 0, 0.12)"}};t.light=h;var p={text:{primary:f.default.white,secondary:"rgba(255, 255, 255, 0.7)",disabled:"rgba(255, 255, 255, 0.5)",hint:"rgba(255, 255, 255, 0.5)",icon:"rgba(255, 255, 255, 0.5)"},divider:"rgba(255, 255, 255, 0.12)",background:{paper:c.default[800],default:"#303030"},action:{active:f.default.white,hover:"rgba(255, 255, 255, 0.1)",hoverOpacity:.1,selected:"rgba(255, 255, 255, 0.2)",disabled:"rgba(255, 255, 255, 0.3)",disabledBackground:"rgba(255, 255, 255, 0.12)"}};function b(e,t,n,r){e[t]||(e.hasOwnProperty(n)?e[t]=e[n]:"light"===t?e.light=(0,d.lighten)(e.main,r):"dark"===t&&(e.dark=(0,d.darken)(e.main,1.5*r)))}function m(e){var t=e.primary,n=void 0===t?{light:s.default[300],main:s.default[500],dark:s.default[700]}:t,r=e.secondary,m=void 0===r?{light:u.default.A200,main:u.default.A400,dark:u.default.A700}:r,g=e.error,v=void 0===g?{light:l.default[300],main:l.default[500],dark:l.default[700]}:g,y=e.type,w=void 0===y?"light":y,_=e.contrastThreshold,E=void 0===_?3:_,S=e.tonalOffset,k=void 0===S?.2:S,x=(0,a.default)(e,["primary","secondary","error","type","contrastThreshold","tonalOffset"]);function T(e){var t;return(0,d.getContrastRatio)(e,p.text.primary)>=E?p.text.primary:h.text.primary}function M(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:500,n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:300,r=arguments.length>3&&void 0!==arguments[3]?arguments[3]:700;return!e.main&&e[t]&&(e.main=e[t]),b(e,"light",n,k),b(e,"dark",r,k),e.contrastText||(e.contrastText=T(e.main)),e}M(n),M(m,"A400","A200","A700"),M(v);var O={dark:p,light:h};return(0,o.default)((0,i.default)({common:f.default,type:w,primary:n,secondary:m,error:v,grey:c.default,contrastThreshold:E,getContrastText:T,augmentColor:M,tonalOffset:k},O[w]),x,{clone:!1})}t.dark=p},16059(e,t){"use strict";function n(e){return e}Object.defineProperty(t,"__esModule",{value:!0}),t.default=n},45184(e,t,n){"use strict";var r=n(95318);Object.defineProperty(t,"__esModule",{value:!0}),t.default=f;var i=r(n(67154)),a=r(n(6479)),o=r(n(94863));r(n(42473));var s=n(55252);function u(e){return Math.round(1e5*e)/1e5}var c={textTransform:"uppercase"},l='"Roboto", "Helvetica", "Arial", sans-serif';function f(e,t){var n="function"==typeof t?t(e):t,r=n.fontFamily,f=void 0===r?l:r,d=n.fontSize,h=void 0===d?14:d,p=n.fontWeightLight,b=void 0===p?300:p,m=n.fontWeightRegular,g=void 0===m?400:m,v=n.fontWeightMedium,y=void 0===v?500:v,w=n.htmlFontSize,_=void 0===w?16:w,E=n.useNextVariants,S=void 0===E?Boolean(s.ponyfillGlobal.__MUI_USE_NEXT_TYPOGRAPHY_VARIANTS__):E,k=(n.suppressWarning,n.allVariants),x=(0,a.default)(n,["fontFamily","fontSize","fontWeightLight","fontWeightRegular","fontWeightMedium","htmlFontSize","useNextVariants","suppressWarning","allVariants"]),T=h/14,M=function(e){return"".concat(e/_*T,"rem")},O=function(t,n,r,a,o){return(0,i.default)({color:e.text.primary,fontFamily:f,fontWeight:t,fontSize:M(n),lineHeight:r},f===l?{letterSpacing:"".concat(u(a/n),"em")}:{},o,k)},A={h1:O(b,96,1,-1.5),h2:O(b,60,1,-.5),h3:O(g,48,1.04,0),h4:O(g,34,1.17,.25),h5:O(g,24,1.33,0),h6:O(y,20,1.6,.15),subtitle1:O(g,16,1.75,.15),subtitle2:O(y,14,1.57,.1),body1Next:O(g,16,1.5,.15),body2Next:O(g,14,1.5,.15),buttonNext:O(y,14,1.75,.4,c),captionNext:O(g,12,1.66,.4),overline:O(g,12,2.66,1,c)},L={display4:(0,i.default)({fontSize:M(112),fontWeight:b,fontFamily:f,letterSpacing:"-.04em",lineHeight:"".concat(u(128/112),"em"),marginLeft:"-.04em",color:e.text.secondary},k),display3:(0,i.default)({fontSize:M(56),fontWeight:g,fontFamily:f,letterSpacing:"-.02em",lineHeight:"".concat(u(73/56),"em"),marginLeft:"-.02em",color:e.text.secondary},k),display2:(0,i.default)({fontSize:M(45),fontWeight:g,fontFamily:f,lineHeight:"".concat(u(51/45),"em"),marginLeft:"-.02em",color:e.text.secondary},k),display1:(0,i.default)({fontSize:M(34),fontWeight:g,fontFamily:f,lineHeight:"".concat(u(41/34),"em"),color:e.text.secondary},k),headline:(0,i.default)({fontSize:M(24),fontWeight:g,fontFamily:f,lineHeight:"".concat(u(32.5/24),"em"),color:e.text.primary},k),title:(0,i.default)({fontSize:M(21),fontWeight:y,fontFamily:f,lineHeight:"".concat(u(24.5/21),"em"),color:e.text.primary},k),subheading:(0,i.default)({fontSize:M(16),fontWeight:g,fontFamily:f,lineHeight:"".concat(u(1.5),"em"),color:e.text.primary},k),body2:(0,i.default)({fontSize:M(14),fontWeight:y,fontFamily:f,lineHeight:"".concat(u(24/14),"em"),color:e.text.primary},k),body1:(0,i.default)({fontSize:M(14),fontWeight:g,fontFamily:f,lineHeight:"".concat(u(20.5/14),"em"),color:e.text.primary},k),caption:(0,i.default)({fontSize:M(12),fontWeight:g,fontFamily:f,lineHeight:"".concat(u(1.375),"em"),color:e.text.secondary},k),button:(0,i.default)({fontSize:M(14),textTransform:"uppercase",fontWeight:y,fontFamily:f,color:e.text.primary},k)};return(0,o.default)((0,i.default)({pxToRem:M,round:u,fontFamily:f,fontSize:h,fontWeightLight:b,fontWeightRegular:g,fontWeightMedium:y},L,A,S?{body1:A.body1Next,body2:A.body2Next,button:A.buttonNext,caption:A.captionNext}:{},{useNextVariants:S}),x,{clone:!1})}},42458(e,t,n){"use strict";var r=n(95318);Object.defineProperty(t,"__esModule",{value:!0}),t.default=void 0;var i=r(n(67154));r(n(50008)),r(n(42473));var a=r(n(94863));function o(e,t){return t}function s(e){var t="function"==typeof e;function n(n,r){var s=t?e(n):e;if(!r||!n.overrides||!n.overrides[r])return s;var u=n.overrides[r],c=(0,i.default)({},s);return Object.keys(u).forEach(function(e){c[e]=(0,a.default)(c[e],u[e],{arrayMerge:o})}),c}return{create:n,options:{},themingEnabled:t}}var u=s;t.default=u},58057(e,t){"use strict";function n(e){var t,n=e.theme,r=e.name,i=e.props;if(!n.props||!r||!n.props[r])return i;var a=n.props[r];for(t in a)void 0===i[t]&&(i[t]=a[t]);return i}Object.defineProperty(t,"__esModule",{value:!0}),t.default=void 0;var r=n;t.default=r},32316(e,t,n){"use strict";var r=n(95318);Object.defineProperty(t,"__esModule",{value:!0}),Object.defineProperty(t,"createGenerateClassName",{enumerable:!0,get:function(){return i.default}}),Object.defineProperty(t,"createMuiTheme",{enumerable:!0,get:function(){return a.default}}),Object.defineProperty(t,"jssPreset",{enumerable:!0,get:function(){return o.default}}),Object.defineProperty(t,"MuiThemeProvider",{enumerable:!0,get:function(){return s.default}}),Object.defineProperty(t,"createStyles",{enumerable:!0,get:function(){return u.default}}),Object.defineProperty(t,"withStyles",{enumerable:!0,get:function(){return c.default}}),Object.defineProperty(t,"withTheme",{enumerable:!0,get:function(){return l.default}});var i=r(n(20237)),a=r(n(71615)),o=r(n(9399)),s=r(n(72366)),u=r(n(16059)),c=r(n(78252)),l=r(n(82313))},9399(e,t,n){"use strict";var r=n(95318);Object.defineProperty(t,"__esModule",{value:!0}),t.default=void 0;var i=r(n(29059)),a=r(n(28752)),o=r(n(35828)),s=r(n(50462)),u=r(n(65926)),c=r(n(89347));function l(){return{plugins:[(0,i.default)(),(0,a.default)(),(0,o.default)(),(0,s.default)(),"undefined"==typeof window?null:(0,u.default)(),(0,c.default)()]}}var f=l;t.default=f},35199(e,t,n){"use strict";var r=n(95318);Object.defineProperty(t,"__esModule",{value:!0}),t.default=void 0;var i=r(n(67154));function a(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},t=e.baseClasses,n=e.newClasses;if(e.Component,!n)return t;var r=(0,i.default)({},t);return Object.keys(n).forEach(function(e){n[e]&&(r[e]="".concat(t[e]," ").concat(n[e]))}),r}r(n(42473)),n(55252);var o=a;t.default=o},88693(e,t){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.default=void 0;var n={set:function(e,t,n,r){var i=e.get(t);i||(i=new Map,e.set(t,i)),i.set(n,r)},get:function(e,t,n){var r=e.get(t);return r?r.get(n):void 0},delete:function(e,t,n){e.get(t).delete(n)}};t.default=n},31898(e,t){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.default=void 0;var n={jss:"64a55d578f856d258dc345b094a2a2b3",sheetsRegistry:"d4bd0baacbc52bbd48bbb9eb24344ecd",sheetOptions:"6fc570d6bd61383819d0f9e7407c452d"};t.default=n},80743(e,t){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.default=void 0;var n=.2,r=.14,i=.12;function a(){return["".concat(arguments.length<=0?void 0:arguments[0],"px ").concat(arguments.length<=1?void 0:arguments[1],"px ").concat(arguments.length<=2?void 0:arguments[2],"px ").concat(arguments.length<=3?void 0:arguments[3],"px rgba(0,0,0,").concat(n,")"),"".concat(arguments.length<=4?void 0:arguments[4],"px ").concat(arguments.length<=5?void 0:arguments[5],"px ").concat(arguments.length<=6?void 0:arguments[6],"px ").concat(arguments.length<=7?void 0:arguments[7],"px rgba(0,0,0,").concat(r,")"),"".concat(arguments.length<=8?void 0:arguments[8],"px ").concat(arguments.length<=9?void 0:arguments[9],"px ").concat(arguments.length<=10?void 0:arguments[10],"px ").concat(arguments.length<=11?void 0:arguments[11],"px rgba(0,0,0,").concat(i,")")].join(",")}var o=["none",a(0,1,3,0,0,1,1,0,0,2,1,-1),a(0,1,5,0,0,2,2,0,0,3,1,-2),a(0,1,8,0,0,3,4,0,0,3,3,-2),a(0,2,4,-1,0,4,5,0,0,1,10,0),a(0,3,5,-1,0,5,8,0,0,1,14,0),a(0,3,5,-1,0,6,10,0,0,1,18,0),a(0,4,5,-2,0,7,10,1,0,2,16,1),a(0,5,5,-3,0,8,10,1,0,3,14,2),a(0,5,6,-3,0,9,12,1,0,3,16,2),a(0,6,6,-3,0,10,14,1,0,4,18,3),a(0,6,7,-4,0,11,15,1,0,4,20,3),a(0,7,8,-4,0,12,17,2,0,5,22,4),a(0,7,8,-4,0,13,19,2,0,5,24,4),a(0,7,9,-4,0,14,21,2,0,5,26,4),a(0,8,9,-5,0,15,22,2,0,6,28,5),a(0,8,10,-5,0,16,24,2,0,6,30,5),a(0,8,11,-5,0,17,26,2,0,6,32,5),a(0,9,11,-5,0,18,28,2,0,7,34,6),a(0,9,12,-6,0,19,29,2,0,7,36,6),a(0,10,13,-6,0,20,31,3,0,8,38,7),a(0,10,13,-6,0,21,33,3,0,8,40,7),a(0,10,14,-6,0,22,35,3,0,8,42,7),a(0,11,14,-7,0,23,36,3,0,9,44,8),a(0,11,15,-7,0,24,38,3,0,9,46,8)];t.default=o},59591(e,t){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.default=void 0;var n={borderRadius:4};t.default=n},5324(e,t){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.default=void 0;var n={unit:8};t.default=n},51067(e,t,n){"use strict";var r=n(95318);Object.defineProperty(t,"__esModule",{value:!0}),t.default=t.CHANNEL=void 0;var i=r(n(59713)),a="__THEMING__";t.CHANNEL=a;var o={contextTypes:(0,i.default)({},a,function(){}),initial:function(e){return e[a]?e[a].getState():null},subscribe:function(e,t){return e[a]?e[a].subscribe(t):null},unsubscribe:function(e,t){e[a]&&e[a].unsubscribe(t)}};t.default=o},15406(e,t,n){"use strict";var r=n(95318);Object.defineProperty(t,"__esModule",{value:!0}),t.default=t.isNumber=t.isString=t.formatMs=t.duration=t.easing=void 0;var i=r(n(6479));r(n(42473));var a={easeInOut:"cubic-bezier(0.4, 0, 0.2, 1)",easeOut:"cubic-bezier(0.0, 0, 0.2, 1)",easeIn:"cubic-bezier(0.4, 0, 1, 1)",sharp:"cubic-bezier(0.4, 0, 0.6, 1)"};t.easing=a;var o={shortest:150,shorter:200,short:250,standard:300,complex:375,enteringScreen:225,leavingScreen:195};t.duration=o;var s=function(e){return"".concat(Math.round(e),"ms")};t.formatMs=s;var u=function(e){return"string"==typeof e};t.isString=u;var c=function(e){return!isNaN(parseFloat(e))};t.isNumber=c;var l={easing:a,duration:o,create:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:["all"],t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{},n=t.duration,r=void 0===n?o.standard:n,u=t.easing,c=void 0===u?a.easeInOut:u,l=t.delay,f=void 0===l?0:l;return(0,i.default)(t,["duration","easing","delay"]),(Array.isArray(e)?e:[e]).map(function(e){return"".concat(e," ").concat("string"==typeof r?r:s(r)," ").concat(c," ").concat("string"==typeof f?f:s(f))}).join(",")},getAutoHeightDuration:function(e){if(!e)return 0;var t=e/36;return Math.round((4+15*Math.pow(t,.25)+t/5)*10)}};t.default=l},78252(e,t,n){"use strict";var r=n(95318);Object.defineProperty(t,"__esModule",{value:!0}),t.default=t.sheetsManager=void 0;var i=r(n(59713)),a=r(n(67154)),o=r(n(34575)),s=r(n(93913)),u=r(n(78585)),c=r(n(29754)),l=r(n(2205)),f=r(n(6479)),d=r(n(67294)),h=r(n(45697));r(n(42473));var p=r(n(8679)),b=n(55252),m=n(55690),g=r(n(31898)),v=r(n(9399)),y=r(n(35199)),w=r(n(88693)),_=r(n(71615)),E=r(n(51067)),S=r(n(20237)),k=r(n(42458)),x=r(n(58057)),T=(0,m.create)((0,v.default)()),M=(0,S.default)(),O=-1e11,A=new Map;t.sheetsManager=A;var L={},C=(0,_.default)({typography:{suppressWarning:!0}}),I=function(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};return function(n){var r,b=t.withTheme,m=void 0!==b&&b,v=t.flip,_=void 0===v?null:v,S=t.name,I=(0,f.default)(t,["withTheme","flip","name"]),D=(0,k.default)(e),N=D.themingEnabled||"string"==typeof S||m;O+=1,D.options.index=O;var P=function(e){function t(e,n){(0,o.default)(this,t),(r=(0,u.default)(this,(0,c.default)(t).call(this,e,n))).jss=n[g.default.jss]||T,r.sheetsManager=A,r.unsubscribeId=null;var r,i=n.muiThemeProviderOptions;return i&&(i.sheetsManager&&(r.sheetsManager=i.sheetsManager),r.sheetsCache=i.sheetsCache,r.disableStylesGeneration=i.disableStylesGeneration),r.stylesCreatorSaved=D,r.sheetOptions=(0,a.default)({generateClassName:M},n[g.default.sheetOptions]),r.theme=N?E.default.initial(n)||C:L,r.attach(r.theme),r.cacheClasses={value:null,lastProp:null,lastJSS:{}},r}return(0,l.default)(t,e),(0,s.default)(t,[{key:"componentDidMount",value:function(){var e=this;N&&(this.unsubscribeId=E.default.subscribe(this.context,function(t){var n=e.theme;e.theme=t,e.attach(e.theme),e.setState({},function(){e.detach(n)})}))}},{key:"componentDidUpdate",value:function(){this.stylesCreatorSaved}},{key:"componentWillUnmount",value:function(){this.detach(this.theme),null!==this.unsubscribeId&&E.default.unsubscribe(this.context,this.unsubscribeId)}},{key:"getClasses",value:function(){if(this.disableStylesGeneration)return this.props.classes||{};var e=!1,t=w.default.get(this.sheetsManager,this.stylesCreatorSaved,this.theme);return t.sheet.classes!==this.cacheClasses.lastJSS&&(this.cacheClasses.lastJSS=t.sheet.classes,e=!0),this.props.classes!==this.cacheClasses.lastProp&&(this.cacheClasses.lastProp=this.props.classes,e=!0),e&&(this.cacheClasses.value=(0,y.default)({baseClasses:this.cacheClasses.lastJSS,newClasses:this.props.classes,Component:n})),this.cacheClasses.value}},{key:"attach",value:function(e){if(!this.disableStylesGeneration){var t=this.stylesCreatorSaved,n=w.default.get(this.sheetsManager,t,e);if(n||(n={refs:0,sheet:null},w.default.set(this.sheetsManager,t,e,n)),0===n.refs){this.sheetsCache&&(r=w.default.get(this.sheetsCache,t,e)),!r&&((r=this.createSheet(e)).attach(),this.sheetsCache&&w.default.set(this.sheetsCache,t,e,r)),n.sheet=r;var r,i=this.context[g.default.sheetsRegistry];i&&i.add(r)}n.refs+=1}}},{key:"createSheet",value:function(e){var t=this.stylesCreatorSaved.create(e,S),r=S;return this.jss.createStyleSheet(t,(0,a.default)({meta:r,classNamePrefix:r,flip:"boolean"==typeof _?_:"rtl"===e.direction,link:!1},this.sheetOptions,this.stylesCreatorSaved.options,{name:S||n.displayName},I))}},{key:"detach",value:function(e){if(!this.disableStylesGeneration){var t=w.default.get(this.sheetsManager,this.stylesCreatorSaved,e);if(t.refs-=1,0===t.refs){w.default.delete(this.sheetsManager,this.stylesCreatorSaved,e),this.jss.removeStyleSheet(t.sheet);var n=this.context[g.default.sheetsRegistry];n&&n.remove(t.sheet)}}}},{key:"render",value:function(){var e=this.props,t=(e.classes,e.innerRef),r=(0,f.default)(e,["classes","innerRef"]),i=(0,x.default)({theme:this.theme,name:S,props:r});return m&&!i.theme&&(i.theme=this.theme),d.default.createElement(n,(0,a.default)({},i,{classes:this.getClasses(),ref:t}))}}]),t}(d.default.Component);return P.contextTypes=(0,a.default)((r={muiThemeProviderOptions:h.default.object},(0,i.default)(r,g.default.jss,h.default.object),(0,i.default)(r,g.default.sheetOptions,h.default.object),(0,i.default)(r,g.default.sheetsRegistry,h.default.object),r),N?E.default.contextTypes:{}),(0,p.default)(P,n),P}};b.ponyfillGlobal.__MUI_STYLES__||(b.ponyfillGlobal.__MUI_STYLES__={}),b.ponyfillGlobal.__MUI_STYLES__.withStyles||(b.ponyfillGlobal.__MUI_STYLES__.withStyles=I);var D=function(e,t){return b.ponyfillGlobal.__MUI_STYLES__.withStyles(e,(0,a.default)({defaultTheme:C},t))};t.default=D},82313(e,t,n){"use strict";var r,i=n(95318);Object.defineProperty(t,"__esModule",{value:!0}),t.default=void 0;var a=i(n(67154)),o=i(n(6479)),s=i(n(34575)),u=i(n(93913)),c=i(n(78585)),l=i(n(29754)),f=i(n(2205)),d=i(n(67294));i(n(45697));var h=i(n(8679)),p=n(55252),b=i(n(71615)),m=i(n(51067));function g(){return r||(r=(0,b.default)({typography:{suppressWarning:!0}}))}var v=function(){return function(e){var t=function(t){function n(e,t){var r;return(0,s.default)(this,n),(r=(0,c.default)(this,(0,l.default)(n).call(this))).state={theme:m.default.initial(t)||g()},r}return(0,f.default)(n,t),(0,u.default)(n,[{key:"componentDidMount",value:function(){var e=this;this.unsubscribeId=m.default.subscribe(this.context,function(t){e.setState({theme:t})})}},{key:"componentWillUnmount",value:function(){null!==this.unsubscribeId&&m.default.unsubscribe(this.context,this.unsubscribeId)}},{key:"render",value:function(){var t=this.props,n=t.innerRef,r=(0,o.default)(t,["innerRef"]);return d.default.createElement(e,(0,a.default)({theme:this.state.theme,ref:n},r))}}]),n}(d.default.Component);return t.contextTypes=m.default.contextTypes,(0,h.default)(t,e),t}};p.ponyfillGlobal.__MUI_STYLES__||(p.ponyfillGlobal.__MUI_STYLES__={}),p.ponyfillGlobal.__MUI_STYLES__.withTheme||(p.ponyfillGlobal.__MUI_STYLES__.withTheme=v);var y=p.ponyfillGlobal.__MUI_STYLES__.withTheme;t.default=y},88676(e,t){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.default=void 0;var n={mobileStepper:1e3,appBar:1100,drawer:1200,modal:1300,snackbar:1400,tooltip:1500};t.default=n},41929(e,t){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.getTransitionProps=r,t.reflow=void 0;var n=function(e){return e.scrollTop};function r(e,t){var n=e.timeout,r=e.style,i=void 0===r?{}:r;return{duration:i.transitionDuration||"number"==typeof n?n:n[t.mode],delay:i.transitionDelay}}t.reflow=n},346(e,t){"use strict";function n(e,t){return function(){return null}}Object.defineProperty(t,"__esModule",{value:!0}),t.default=void 0;var r=n;t.default=r},98741(e,t,n){"use strict";var r=n(95318);Object.defineProperty(t,"__esModule",{value:!0}),t.capitalize=a,t.contains=o,t.findIndex=s,t.find=u,t.createChainedFunction=c;var i=r(n(50008));function a(e){return e.charAt(0).toUpperCase()+e.slice(1)}function o(e,t){return Object.keys(t).every(function(n){return e.hasOwnProperty(n)&&e[n]===t[n]})}function s(e,t){for(var n=(0,i.default)(t),r=0;r-1?e[n]:void 0}function c(){for(var e=arguments.length,t=Array(e),n=0;n1&&void 0!==arguments[1]?arguments[1]:window,n=(0,i.default)(e);return n.defaultView||n.parentView||t}var o=a;t.default=o},44370(e,t,n){"use strict";var r=n(95318);Object.defineProperty(t,"__esModule",{value:!0}),t.cloneElementWithClassName=o,t.cloneChildrenWithClassName=s,t.isMuiElement=u,t.setRef=c;var i=r(n(67294)),a=r(n(94184));function o(e,t){return i.default.cloneElement(e,{className:(0,a.default)(e.props.className,t)})}function s(e,t){return i.default.Children.map(e,function(e){return i.default.isValidElement(e)&&o(e,t)})}function u(e,t){return i.default.isValidElement(e)&&-1!==t.indexOf(e.type.muiName)}function c(e,t){"function"==typeof e?e(t):e&&(e.current=t)}},47348(e,t){"use strict";function n(e){return function(){return null}}Object.defineProperty(t,"__esModule",{value:!0}),t.default=void 0;var r=n;t.default=r},21677(e,t){"use strict";function n(e,t,n,r,i){return null}Object.defineProperty(t,"__esModule",{value:!0}),t.default=void 0;var r=n;t.default=r},78290(e,t,n){"use strict";var r=n(20862);Object.defineProperty(t,"__esModule",{value:!0});var i={};Object.defineProperty(t,"default",{enumerable:!0,get:function(){return a.default}});var a=r(n(88446));Object.keys(a).forEach(function(e){"default"!==e&&"__esModule"!==e&&(Object.prototype.hasOwnProperty.call(i,e)||Object.defineProperty(t,e,{enumerable:!0,get:function(){return a[e]}}))})},88446(e,t,n){"use strict";var r=n(95318);Object.defineProperty(t,"__esModule",{value:!0}),t.default=t.isWidthDown=t.isWidthUp=void 0;var i=r(n(67154)),a=r(n(6479)),o=r(n(34575)),s=r(n(93913)),u=r(n(78585)),c=r(n(29754)),l=r(n(2205)),f=r(n(67294));r(n(45697));var d=r(n(96421)),h=r(n(20296));n(55252);var p=r(n(8679)),b=r(n(82313)),m=n(94811),g=r(n(58057)),v=function(e,t){var n=!(arguments.length>2)||void 0===arguments[2]||arguments[2];return n?m.keys.indexOf(e)<=m.keys.indexOf(t):m.keys.indexOf(e)2)||void 0===arguments[2]||arguments[2];return n?m.keys.indexOf(t)<=m.keys.indexOf(e):m.keys.indexOf(t)0&&void 0!==arguments[0]?arguments[0]:{};return function(t){var n=e.withTheme,r=void 0!==n&&n,v=e.noSSR,y=void 0!==v&&v,w=e.initialWidth,_=e.resizeInterval,E=void 0===_?166:_,S=function(e){function n(e){var t;return(0,o.default)(this,n),(t=(0,u.default)(this,(0,c.default)(n).call(this,e))).state={width:y?t.getWidth():void 0},"undefined"!=typeof window&&(t.handleResize=(0,h.default)(function(){var e=t.getWidth();e!==t.state.width&&t.setState({width:e})},E)),t}return(0,l.default)(n,e),(0,s.default)(n,[{key:"componentDidMount",value:function(){var e=this.getWidth();e!==this.state.width&&this.setState({width:e})}},{key:"componentWillUnmount",value:function(){this.handleResize.clear()}},{key:"getWidth",value:function(){for(var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:window.innerWidth,t=this.props.theme.breakpoints,n=null,r=1;null===n&&ri.Z,componentPropType:()=>r.Z,exactProp:()=>a.ZP,getDisplayName:()=>o.ZP,ponyfillGlobal:()=>s.Z});var r=n(78728),i=n(5477),a=n(43781),o=n(25189),s=n(34712);/** @license Material-UI v3.0.0-alpha.3 + */ var r=n(47798);function i(e){return!0===r(e)&&"[object Object]"===Object.prototype.toString.call(e)}e.exports=function(e){var t,n;return!1!==i(e)&&"function"==typeof(t=e.constructor)&&!1!==i(n=t.prototype)&&!1!==n.hasOwnProperty("isPrototypeOf")}},72366(e,t,n){"use strict";var r=n(20862),i=n(95318);Object.defineProperty(t,"__esModule",{value:!0}),t.default=t.MuiThemeProviderOld=void 0;var a=i(n(67154)),o=i(n(59713)),s=i(n(34575)),u=i(n(93913)),c=i(n(78585)),l=i(n(29754)),f=i(n(2205)),d=i(n(67294)),h=i(n(45697));i(n(42473));var p=i(n(43890)),b=n(55252),m=r(n(51067)),g=function(e){function t(e,n){var r;return(0,s.default)(this,t),(r=(0,c.default)(this,(0,l.default)(t).call(this))).broadcast=(0,p.default)(),r.outerTheme=m.default.initial(n),r.broadcast.setState(r.mergeOuterLocalTheme(e.theme)),r}return(0,f.default)(t,e),(0,u.default)(t,[{key:"getChildContext",value:function(){var e,t=this.props,n=t.disableStylesGeneration,r=t.sheetsCache,i=t.sheetsManager,a=this.context.muiThemeProviderOptions||{};return void 0!==n&&(a.disableStylesGeneration=n),void 0!==r&&(a.sheetsCache=r),void 0!==i&&(a.sheetsManager=i),e={},(0,o.default)(e,m.CHANNEL,this.broadcast),(0,o.default)(e,"muiThemeProviderOptions",a),e}},{key:"componentDidMount",value:function(){var e=this;this.unsubscribeId=m.default.subscribe(this.context,function(t){e.outerTheme=t,e.broadcast.setState(e.mergeOuterLocalTheme(e.props.theme))})}},{key:"componentDidUpdate",value:function(e){this.props.theme!==e.theme&&this.broadcast.setState(this.mergeOuterLocalTheme(this.props.theme))}},{key:"componentWillUnmount",value:function(){null!==this.unsubscribeId&&m.default.unsubscribe(this.context,this.unsubscribeId)}},{key:"mergeOuterLocalTheme",value:function(e){return"function"==typeof e?e(this.outerTheme):this.outerTheme?(0,a.default)({},this.outerTheme,e):e}},{key:"render",value:function(){return this.props.children}}]),t}(d.default.Component);t.MuiThemeProviderOld=g,g.childContextTypes=(0,a.default)({},m.default.contextTypes,{muiThemeProviderOptions:h.default.object}),g.contextTypes=(0,a.default)({},m.default.contextTypes,{muiThemeProviderOptions:h.default.object}),b.ponyfillGlobal.__MUI_STYLES__||(b.ponyfillGlobal.__MUI_STYLES__={}),b.ponyfillGlobal.__MUI_STYLES__.MuiThemeProvider||(b.ponyfillGlobal.__MUI_STYLES__.MuiThemeProvider=g);var v=b.ponyfillGlobal.__MUI_STYLES__.MuiThemeProvider;t.default=v},59114(e,t,n){"use strict";var r=n(95318);function i(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:0,n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:1;return en?n:e}function a(e){e=e.substr(1);var t=RegExp(".{1,".concat(e.length/3,"}"),"g"),n=e.match(t);return n&&1===n[0].length&&(n=n.map(function(e){return e+e})),n?"rgb(".concat(n.map(function(e){return parseInt(e,16)}).join(", "),")"):""}function o(e){if(0===e.indexOf("#"))return e;function t(e){var t=e.toString(16);return 1===t.length?"0".concat(t):t}var n=s(e).values;return n=n.map(function(e){return t(e)}),"#".concat(n.join(""))}function s(e){if("#"===e.charAt(0))return s(a(e));var t=e.indexOf("("),n=e.substring(0,t),r=e.substring(t+1,e.length-1).split(",");return r=r.map(function(e){return parseFloat(e)}),{type:n,values:r}}function u(e){var t=e.type,n=e.values;return -1!==t.indexOf("rgb")&&(n=n.map(function(e,t){return t<3?parseInt(e,10):e})),-1!==t.indexOf("hsl")&&(n[1]="".concat(n[1],"%"),n[2]="".concat(n[2],"%")),"".concat(e.type,"(").concat(n.join(", "),")")}function c(e,t){var n=l(e),r=l(t);return(Math.max(n,r)+.05)/(Math.min(n,r)+.05)}function l(e){var t=s(e);if(-1!==t.type.indexOf("rgb")){var n=t.values.map(function(e){return(e/=255)<=.03928?e/12.92:Math.pow((e+.055)/1.055,2.4)});return Number((.2126*n[0]+.7152*n[1]+.0722*n[2]).toFixed(3))}return t.values[2]/100}function f(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:.15;return l(e)>.5?h(e,t):p(e,t)}function d(e,t){return e?(e=s(e),t=i(t),("rgb"===e.type||"hsl"===e.type)&&(e.type+="a"),e.values[3]=t,u(e)):e}function h(e,t){if(!e)return e;if(e=s(e),t=i(t),-1!==e.type.indexOf("hsl"))e.values[2]*=1-t;else if(-1!==e.type.indexOf("rgb"))for(var n=0;n<3;n+=1)e.values[n]*=1-t;return u(e)}function p(e,t){if(!e)return e;if(e=s(e),t=i(t),-1!==e.type.indexOf("hsl"))e.values[2]+=(100-e.values[2])*t;else if(-1!==e.type.indexOf("rgb"))for(var n=0;n<3;n+=1)e.values[n]+=(255-e.values[n])*t;return u(e)}Object.defineProperty(t,"__esModule",{value:!0}),t.convertHexToRGB=a,t.rgbToHex=o,t.decomposeColor=s,t.recomposeColor=u,t.getContrastRatio=c,t.getLuminance=l,t.emphasize=f,t.fade=d,t.darken=h,t.lighten=p,r(n(42473))},94811(e,t,n){"use strict";var r=n(95318);Object.defineProperty(t,"__esModule",{value:!0}),t.default=s,t.keys=void 0;var i=r(n(67154)),a=r(n(6479)),o=["xs","sm","md","lg","xl"];function s(e){var t=e.values,n=void 0===t?{xs:0,sm:600,md:960,lg:1280,xl:1920}:t,r=e.unit,s=void 0===r?"px":r,u=e.step,c=void 0===u?5:u,l=(0,a.default)(e,["values","unit","step"]);function f(e){var t="number"==typeof n[e]?n[e]:e;return"@media (min-width:".concat(t).concat(s,")")}function d(e){var t=o.indexOf(e)+1,r=n[o[t]];if(t===o.length)return f("xs");var i="number"==typeof r&&t>0?r:e;return"@media (max-width:".concat(i-c/100).concat(s,")")}function h(e,t){var r=o.indexOf(t)+1;return r===o.length?f(e):"@media (min-width:".concat(n[e]).concat(s,") and ")+"(max-width:".concat(n[o[r]]-c/100).concat(s,")")}function p(e){return h(e,e)}function b(e){return n[e]}return(0,i.default)({keys:o,values:n,up:f,down:d,between:h,only:p,width:b},l)}t.keys=o},20237(e,t,n){"use strict";var r=n(95318);Object.defineProperty(t,"__esModule",{value:!0}),t.default=o,r(n(42473));var i=/([[\].#*$><+~=|^:(),"'`\s])/g;function a(e){var t;return String(e).replace(i,"-")}function o(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},t=e.dangerouslyUseGlobalCSS,n=void 0!==t&&t,r=e.productionPrefix,i=void 0===r?"jss":r,o=e.seed,s=void 0===o?"":o,u=0;return function(e,t){return(u+=1,n&&t&&t.options.name)?"".concat(a(t.options.name),"-").concat(e.key):"".concat(i).concat(s).concat(u)}}},40226(e,t,n){"use strict";var r=n(95318);Object.defineProperty(t,"__esModule",{value:!0}),t.default=o;var i=r(n(59713)),a=r(n(67154));function o(e,t,n){var r;return(0,a.default)({gutters:function(){var n=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};return(0,a.default)({paddingLeft:2*t.unit,paddingRight:2*t.unit},n,(0,i.default)({},e.up("sm"),(0,a.default)({paddingLeft:3*t.unit,paddingRight:3*t.unit},n[e.up("sm")])))},toolbar:(r={minHeight:56},(0,i.default)(r,"".concat(e.up("xs")," and (orientation: landscape)"),{minHeight:48}),(0,i.default)(r,e.up("sm"),{minHeight:64}),r)},n)}},71615(e,t,n){"use strict";var r=n(95318);Object.defineProperty(t,"__esModule",{value:!0}),t.default=void 0,r(n(59713));var i=r(n(67154)),a=r(n(6479)),o=r(n(94863)),s=r(n(93078));r(n(42473));var u=r(n(94811)),c=r(n(40226)),l=r(n(21091)),f=r(n(45184)),d=r(n(80743)),h=r(n(59591)),p=r(n(5324)),b=r(n(15406)),m=r(n(88676));function g(){var e,t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},n=t.breakpoints,r=void 0===n?{}:n,g=t.mixins,v=void 0===g?{}:g,y=t.palette,w=void 0===y?{}:y,_=t.shadows,E=t.spacing,S=void 0===E?{}:E,k=t.typography,x=void 0===k?{}:k,T=(0,a.default)(t,["breakpoints","mixins","palette","shadows","spacing","typography"]),M=(0,l.default)(w),O=(0,u.default)(r),A=(0,i.default)({},p.default,S);return(0,i.default)({breakpoints:O,direction:"ltr",mixins:(0,c.default)(O,A,v),overrides:{},palette:M,props:{},shadows:_||d.default,typography:(0,f.default)(M,x)},(0,o.default)({shape:h.default,spacing:A,transitions:b.default,zIndex:m.default},T,{isMergeableObject:s.default}))}var v=g;t.default=v},21091(e,t,n){"use strict";var r=n(95318);Object.defineProperty(t,"__esModule",{value:!0}),t.default=m,t.dark=t.light=void 0;var i=r(n(67154)),a=r(n(6479));r(n(42473));var o=r(n(94863)),s=r(n(78768)),u=r(n(124)),c=r(n(70167)),l=r(n(83165)),f=r(n(515)),d=n(59114),h={text:{primary:"rgba(0, 0, 0, 0.87)",secondary:"rgba(0, 0, 0, 0.54)",disabled:"rgba(0, 0, 0, 0.38)",hint:"rgba(0, 0, 0, 0.38)"},divider:"rgba(0, 0, 0, 0.12)",background:{paper:f.default.white,default:c.default[50]},action:{active:"rgba(0, 0, 0, 0.54)",hover:"rgba(0, 0, 0, 0.08)",hoverOpacity:.08,selected:"rgba(0, 0, 0, 0.14)",disabled:"rgba(0, 0, 0, 0.26)",disabledBackground:"rgba(0, 0, 0, 0.12)"}};t.light=h;var p={text:{primary:f.default.white,secondary:"rgba(255, 255, 255, 0.7)",disabled:"rgba(255, 255, 255, 0.5)",hint:"rgba(255, 255, 255, 0.5)",icon:"rgba(255, 255, 255, 0.5)"},divider:"rgba(255, 255, 255, 0.12)",background:{paper:c.default[800],default:"#303030"},action:{active:f.default.white,hover:"rgba(255, 255, 255, 0.1)",hoverOpacity:.1,selected:"rgba(255, 255, 255, 0.2)",disabled:"rgba(255, 255, 255, 0.3)",disabledBackground:"rgba(255, 255, 255, 0.12)"}};function b(e,t,n,r){e[t]||(e.hasOwnProperty(n)?e[t]=e[n]:"light"===t?e.light=(0,d.lighten)(e.main,r):"dark"===t&&(e.dark=(0,d.darken)(e.main,1.5*r)))}function m(e){var t=e.primary,n=void 0===t?{light:s.default[300],main:s.default[500],dark:s.default[700]}:t,r=e.secondary,m=void 0===r?{light:u.default.A200,main:u.default.A400,dark:u.default.A700}:r,g=e.error,v=void 0===g?{light:l.default[300],main:l.default[500],dark:l.default[700]}:g,y=e.type,w=void 0===y?"light":y,_=e.contrastThreshold,E=void 0===_?3:_,S=e.tonalOffset,k=void 0===S?.2:S,x=(0,a.default)(e,["primary","secondary","error","type","contrastThreshold","tonalOffset"]);function T(e){var t;return(0,d.getContrastRatio)(e,p.text.primary)>=E?p.text.primary:h.text.primary}function M(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:500,n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:300,r=arguments.length>3&&void 0!==arguments[3]?arguments[3]:700;return!e.main&&e[t]&&(e.main=e[t]),b(e,"light",n,k),b(e,"dark",r,k),e.contrastText||(e.contrastText=T(e.main)),e}M(n),M(m,"A400","A200","A700"),M(v);var O={dark:p,light:h};return(0,o.default)((0,i.default)({common:f.default,type:w,primary:n,secondary:m,error:v,grey:c.default,contrastThreshold:E,getContrastText:T,augmentColor:M,tonalOffset:k},O[w]),x,{clone:!1})}t.dark=p},16059(e,t){"use strict";function n(e){return e}Object.defineProperty(t,"__esModule",{value:!0}),t.default=n},45184(e,t,n){"use strict";var r=n(95318);Object.defineProperty(t,"__esModule",{value:!0}),t.default=f;var i=r(n(67154)),a=r(n(6479)),o=r(n(94863));r(n(42473));var s=n(55252);function u(e){return Math.round(1e5*e)/1e5}var c={textTransform:"uppercase"},l='"Roboto", "Helvetica", "Arial", sans-serif';function f(e,t){var n="function"==typeof t?t(e):t,r=n.fontFamily,f=void 0===r?l:r,d=n.fontSize,h=void 0===d?14:d,p=n.fontWeightLight,b=void 0===p?300:p,m=n.fontWeightRegular,g=void 0===m?400:m,v=n.fontWeightMedium,y=void 0===v?500:v,w=n.htmlFontSize,_=void 0===w?16:w,E=n.useNextVariants,S=void 0===E?Boolean(s.ponyfillGlobal.__MUI_USE_NEXT_TYPOGRAPHY_VARIANTS__):E,k=(n.suppressWarning,n.allVariants),x=(0,a.default)(n,["fontFamily","fontSize","fontWeightLight","fontWeightRegular","fontWeightMedium","htmlFontSize","useNextVariants","suppressWarning","allVariants"]),T=h/14,M=function(e){return"".concat(e/_*T,"rem")},O=function(t,n,r,a,o){return(0,i.default)({color:e.text.primary,fontFamily:f,fontWeight:t,fontSize:M(n),lineHeight:r},f===l?{letterSpacing:"".concat(u(a/n),"em")}:{},o,k)},A={h1:O(b,96,1,-1.5),h2:O(b,60,1,-.5),h3:O(g,48,1.04,0),h4:O(g,34,1.17,.25),h5:O(g,24,1.33,0),h6:O(y,20,1.6,.15),subtitle1:O(g,16,1.75,.15),subtitle2:O(y,14,1.57,.1),body1Next:O(g,16,1.5,.15),body2Next:O(g,14,1.5,.15),buttonNext:O(y,14,1.75,.4,c),captionNext:O(g,12,1.66,.4),overline:O(g,12,2.66,1,c)},L={display4:(0,i.default)({fontSize:M(112),fontWeight:b,fontFamily:f,letterSpacing:"-.04em",lineHeight:"".concat(u(128/112),"em"),marginLeft:"-.04em",color:e.text.secondary},k),display3:(0,i.default)({fontSize:M(56),fontWeight:g,fontFamily:f,letterSpacing:"-.02em",lineHeight:"".concat(u(73/56),"em"),marginLeft:"-.02em",color:e.text.secondary},k),display2:(0,i.default)({fontSize:M(45),fontWeight:g,fontFamily:f,lineHeight:"".concat(u(51/45),"em"),marginLeft:"-.02em",color:e.text.secondary},k),display1:(0,i.default)({fontSize:M(34),fontWeight:g,fontFamily:f,lineHeight:"".concat(u(41/34),"em"),color:e.text.secondary},k),headline:(0,i.default)({fontSize:M(24),fontWeight:g,fontFamily:f,lineHeight:"".concat(u(32.5/24),"em"),color:e.text.primary},k),title:(0,i.default)({fontSize:M(21),fontWeight:y,fontFamily:f,lineHeight:"".concat(u(24.5/21),"em"),color:e.text.primary},k),subheading:(0,i.default)({fontSize:M(16),fontWeight:g,fontFamily:f,lineHeight:"".concat(u(1.5),"em"),color:e.text.primary},k),body2:(0,i.default)({fontSize:M(14),fontWeight:y,fontFamily:f,lineHeight:"".concat(u(24/14),"em"),color:e.text.primary},k),body1:(0,i.default)({fontSize:M(14),fontWeight:g,fontFamily:f,lineHeight:"".concat(u(20.5/14),"em"),color:e.text.primary},k),caption:(0,i.default)({fontSize:M(12),fontWeight:g,fontFamily:f,lineHeight:"".concat(u(1.375),"em"),color:e.text.secondary},k),button:(0,i.default)({fontSize:M(14),textTransform:"uppercase",fontWeight:y,fontFamily:f,color:e.text.primary},k)};return(0,o.default)((0,i.default)({pxToRem:M,round:u,fontFamily:f,fontSize:h,fontWeightLight:b,fontWeightRegular:g,fontWeightMedium:y},L,A,S?{body1:A.body1Next,body2:A.body2Next,button:A.buttonNext,caption:A.captionNext}:{},{useNextVariants:S}),x,{clone:!1})}},42458(e,t,n){"use strict";var r=n(95318);Object.defineProperty(t,"__esModule",{value:!0}),t.default=void 0;var i=r(n(67154));r(n(50008)),r(n(42473));var a=r(n(94863));function o(e,t){return t}function s(e){var t="function"==typeof e;function n(n,r){var s=t?e(n):e;if(!r||!n.overrides||!n.overrides[r])return s;var u=n.overrides[r],c=(0,i.default)({},s);return Object.keys(u).forEach(function(e){c[e]=(0,a.default)(c[e],u[e],{arrayMerge:o})}),c}return{create:n,options:{},themingEnabled:t}}var u=s;t.default=u},58057(e,t){"use strict";function n(e){var t,n=e.theme,r=e.name,i=e.props;if(!n.props||!r||!n.props[r])return i;var a=n.props[r];for(t in a)void 0===i[t]&&(i[t]=a[t]);return i}Object.defineProperty(t,"__esModule",{value:!0}),t.default=void 0;var r=n;t.default=r},32316(e,t,n){"use strict";var r=n(95318);Object.defineProperty(t,"__esModule",{value:!0}),Object.defineProperty(t,"createGenerateClassName",{enumerable:!0,get:function(){return i.default}}),Object.defineProperty(t,"createMuiTheme",{enumerable:!0,get:function(){return a.default}}),Object.defineProperty(t,"jssPreset",{enumerable:!0,get:function(){return o.default}}),Object.defineProperty(t,"MuiThemeProvider",{enumerable:!0,get:function(){return s.default}}),Object.defineProperty(t,"createStyles",{enumerable:!0,get:function(){return u.default}}),Object.defineProperty(t,"withStyles",{enumerable:!0,get:function(){return c.default}}),Object.defineProperty(t,"withTheme",{enumerable:!0,get:function(){return l.default}});var i=r(n(20237)),a=r(n(71615)),o=r(n(9399)),s=r(n(72366)),u=r(n(16059)),c=r(n(78252)),l=r(n(82313))},9399(e,t,n){"use strict";var r=n(95318);Object.defineProperty(t,"__esModule",{value:!0}),t.default=void 0;var i=r(n(29059)),a=r(n(28752)),o=r(n(35828)),s=r(n(50462)),u=r(n(65926)),c=r(n(89347));function l(){return{plugins:[(0,i.default)(),(0,a.default)(),(0,o.default)(),(0,s.default)(),"undefined"==typeof window?null:(0,u.default)(),(0,c.default)()]}}var f=l;t.default=f},35199(e,t,n){"use strict";var r=n(95318);Object.defineProperty(t,"__esModule",{value:!0}),t.default=void 0;var i=r(n(67154));function a(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},t=e.baseClasses,n=e.newClasses;if(e.Component,!n)return t;var r=(0,i.default)({},t);return Object.keys(n).forEach(function(e){n[e]&&(r[e]="".concat(t[e]," ").concat(n[e]))}),r}r(n(42473)),n(55252);var o=a;t.default=o},88693(e,t){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.default=void 0;var n={set:function(e,t,n,r){var i=e.get(t);i||(i=new Map,e.set(t,i)),i.set(n,r)},get:function(e,t,n){var r=e.get(t);return r?r.get(n):void 0},delete:function(e,t,n){e.get(t).delete(n)}};t.default=n},31898(e,t){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.default=void 0;var n={jss:"64a55d578f856d258dc345b094a2a2b3",sheetsRegistry:"d4bd0baacbc52bbd48bbb9eb24344ecd",sheetOptions:"6fc570d6bd61383819d0f9e7407c452d"};t.default=n},80743(e,t){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.default=void 0;var n=.2,r=.14,i=.12;function a(){return["".concat(arguments.length<=0?void 0:arguments[0],"px ").concat(arguments.length<=1?void 0:arguments[1],"px ").concat(arguments.length<=2?void 0:arguments[2],"px ").concat(arguments.length<=3?void 0:arguments[3],"px rgba(0,0,0,").concat(n,")"),"".concat(arguments.length<=4?void 0:arguments[4],"px ").concat(arguments.length<=5?void 0:arguments[5],"px ").concat(arguments.length<=6?void 0:arguments[6],"px ").concat(arguments.length<=7?void 0:arguments[7],"px rgba(0,0,0,").concat(r,")"),"".concat(arguments.length<=8?void 0:arguments[8],"px ").concat(arguments.length<=9?void 0:arguments[9],"px ").concat(arguments.length<=10?void 0:arguments[10],"px ").concat(arguments.length<=11?void 0:arguments[11],"px rgba(0,0,0,").concat(i,")")].join(",")}var o=["none",a(0,1,3,0,0,1,1,0,0,2,1,-1),a(0,1,5,0,0,2,2,0,0,3,1,-2),a(0,1,8,0,0,3,4,0,0,3,3,-2),a(0,2,4,-1,0,4,5,0,0,1,10,0),a(0,3,5,-1,0,5,8,0,0,1,14,0),a(0,3,5,-1,0,6,10,0,0,1,18,0),a(0,4,5,-2,0,7,10,1,0,2,16,1),a(0,5,5,-3,0,8,10,1,0,3,14,2),a(0,5,6,-3,0,9,12,1,0,3,16,2),a(0,6,6,-3,0,10,14,1,0,4,18,3),a(0,6,7,-4,0,11,15,1,0,4,20,3),a(0,7,8,-4,0,12,17,2,0,5,22,4),a(0,7,8,-4,0,13,19,2,0,5,24,4),a(0,7,9,-4,0,14,21,2,0,5,26,4),a(0,8,9,-5,0,15,22,2,0,6,28,5),a(0,8,10,-5,0,16,24,2,0,6,30,5),a(0,8,11,-5,0,17,26,2,0,6,32,5),a(0,9,11,-5,0,18,28,2,0,7,34,6),a(0,9,12,-6,0,19,29,2,0,7,36,6),a(0,10,13,-6,0,20,31,3,0,8,38,7),a(0,10,13,-6,0,21,33,3,0,8,40,7),a(0,10,14,-6,0,22,35,3,0,8,42,7),a(0,11,14,-7,0,23,36,3,0,9,44,8),a(0,11,15,-7,0,24,38,3,0,9,46,8)];t.default=o},59591(e,t){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.default=void 0;var n={borderRadius:4};t.default=n},5324(e,t){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.default=void 0;var n={unit:8};t.default=n},51067(e,t,n){"use strict";var r=n(95318);Object.defineProperty(t,"__esModule",{value:!0}),t.default=t.CHANNEL=void 0;var i=r(n(59713)),a="__THEMING__";t.CHANNEL=a;var o={contextTypes:(0,i.default)({},a,function(){}),initial:function(e){return e[a]?e[a].getState():null},subscribe:function(e,t){return e[a]?e[a].subscribe(t):null},unsubscribe:function(e,t){e[a]&&e[a].unsubscribe(t)}};t.default=o},15406(e,t,n){"use strict";var r=n(95318);Object.defineProperty(t,"__esModule",{value:!0}),t.default=t.isNumber=t.isString=t.formatMs=t.duration=t.easing=void 0;var i=r(n(6479));r(n(42473));var a={easeInOut:"cubic-bezier(0.4, 0, 0.2, 1)",easeOut:"cubic-bezier(0.0, 0, 0.2, 1)",easeIn:"cubic-bezier(0.4, 0, 1, 1)",sharp:"cubic-bezier(0.4, 0, 0.6, 1)"};t.easing=a;var o={shortest:150,shorter:200,short:250,standard:300,complex:375,enteringScreen:225,leavingScreen:195};t.duration=o;var s=function(e){return"".concat(Math.round(e),"ms")};t.formatMs=s;var u=function(e){return"string"==typeof e};t.isString=u;var c=function(e){return!isNaN(parseFloat(e))};t.isNumber=c;var l={easing:a,duration:o,create:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:["all"],t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{},n=t.duration,r=void 0===n?o.standard:n,u=t.easing,c=void 0===u?a.easeInOut:u,l=t.delay,f=void 0===l?0:l;return(0,i.default)(t,["duration","easing","delay"]),(Array.isArray(e)?e:[e]).map(function(e){return"".concat(e," ").concat("string"==typeof r?r:s(r)," ").concat(c," ").concat("string"==typeof f?f:s(f))}).join(",")},getAutoHeightDuration:function(e){if(!e)return 0;var t=e/36;return Math.round((4+15*Math.pow(t,.25)+t/5)*10)}};t.default=l},78252(e,t,n){"use strict";var r=n(95318);Object.defineProperty(t,"__esModule",{value:!0}),t.default=t.sheetsManager=void 0;var i=r(n(59713)),a=r(n(67154)),o=r(n(34575)),s=r(n(93913)),u=r(n(78585)),c=r(n(29754)),l=r(n(2205)),f=r(n(6479)),d=r(n(67294)),h=r(n(45697));r(n(42473));var p=r(n(8679)),b=n(55252),m=n(55690),g=r(n(31898)),v=r(n(9399)),y=r(n(35199)),w=r(n(88693)),_=r(n(71615)),E=r(n(51067)),S=r(n(20237)),k=r(n(42458)),x=r(n(58057)),T=(0,m.create)((0,v.default)()),M=(0,S.default)(),O=-1e11,A=new Map;t.sheetsManager=A;var L={},C=(0,_.default)({typography:{suppressWarning:!0}}),I=function(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};return function(n){var r,b=t.withTheme,m=void 0!==b&&b,v=t.flip,_=void 0===v?null:v,S=t.name,I=(0,f.default)(t,["withTheme","flip","name"]),D=(0,k.default)(e),N=D.themingEnabled||"string"==typeof S||m;O+=1,D.options.index=O;var P=function(e){function t(e,n){(0,o.default)(this,t),(r=(0,u.default)(this,(0,c.default)(t).call(this,e,n))).jss=n[g.default.jss]||T,r.sheetsManager=A,r.unsubscribeId=null;var r,i=n.muiThemeProviderOptions;return i&&(i.sheetsManager&&(r.sheetsManager=i.sheetsManager),r.sheetsCache=i.sheetsCache,r.disableStylesGeneration=i.disableStylesGeneration),r.stylesCreatorSaved=D,r.sheetOptions=(0,a.default)({generateClassName:M},n[g.default.sheetOptions]),r.theme=N?E.default.initial(n)||C:L,r.attach(r.theme),r.cacheClasses={value:null,lastProp:null,lastJSS:{}},r}return(0,l.default)(t,e),(0,s.default)(t,[{key:"componentDidMount",value:function(){var e=this;N&&(this.unsubscribeId=E.default.subscribe(this.context,function(t){var n=e.theme;e.theme=t,e.attach(e.theme),e.setState({},function(){e.detach(n)})}))}},{key:"componentDidUpdate",value:function(){this.stylesCreatorSaved}},{key:"componentWillUnmount",value:function(){this.detach(this.theme),null!==this.unsubscribeId&&E.default.unsubscribe(this.context,this.unsubscribeId)}},{key:"getClasses",value:function(){if(this.disableStylesGeneration)return this.props.classes||{};var e=!1,t=w.default.get(this.sheetsManager,this.stylesCreatorSaved,this.theme);return t.sheet.classes!==this.cacheClasses.lastJSS&&(this.cacheClasses.lastJSS=t.sheet.classes,e=!0),this.props.classes!==this.cacheClasses.lastProp&&(this.cacheClasses.lastProp=this.props.classes,e=!0),e&&(this.cacheClasses.value=(0,y.default)({baseClasses:this.cacheClasses.lastJSS,newClasses:this.props.classes,Component:n})),this.cacheClasses.value}},{key:"attach",value:function(e){if(!this.disableStylesGeneration){var t=this.stylesCreatorSaved,n=w.default.get(this.sheetsManager,t,e);if(n||(n={refs:0,sheet:null},w.default.set(this.sheetsManager,t,e,n)),0===n.refs){this.sheetsCache&&(r=w.default.get(this.sheetsCache,t,e)),!r&&((r=this.createSheet(e)).attach(),this.sheetsCache&&w.default.set(this.sheetsCache,t,e,r)),n.sheet=r;var r,i=this.context[g.default.sheetsRegistry];i&&i.add(r)}n.refs+=1}}},{key:"createSheet",value:function(e){var t=this.stylesCreatorSaved.create(e,S),r=S;return this.jss.createStyleSheet(t,(0,a.default)({meta:r,classNamePrefix:r,flip:"boolean"==typeof _?_:"rtl"===e.direction,link:!1},this.sheetOptions,this.stylesCreatorSaved.options,{name:S||n.displayName},I))}},{key:"detach",value:function(e){if(!this.disableStylesGeneration){var t=w.default.get(this.sheetsManager,this.stylesCreatorSaved,e);if(t.refs-=1,0===t.refs){w.default.delete(this.sheetsManager,this.stylesCreatorSaved,e),this.jss.removeStyleSheet(t.sheet);var n=this.context[g.default.sheetsRegistry];n&&n.remove(t.sheet)}}}},{key:"render",value:function(){var e=this.props,t=(e.classes,e.innerRef),r=(0,f.default)(e,["classes","innerRef"]),i=(0,x.default)({theme:this.theme,name:S,props:r});return m&&!i.theme&&(i.theme=this.theme),d.default.createElement(n,(0,a.default)({},i,{classes:this.getClasses(),ref:t}))}}]),t}(d.default.Component);return P.contextTypes=(0,a.default)((r={muiThemeProviderOptions:h.default.object},(0,i.default)(r,g.default.jss,h.default.object),(0,i.default)(r,g.default.sheetOptions,h.default.object),(0,i.default)(r,g.default.sheetsRegistry,h.default.object),r),N?E.default.contextTypes:{}),(0,p.default)(P,n),P}};b.ponyfillGlobal.__MUI_STYLES__||(b.ponyfillGlobal.__MUI_STYLES__={}),b.ponyfillGlobal.__MUI_STYLES__.withStyles||(b.ponyfillGlobal.__MUI_STYLES__.withStyles=I);var D=function(e,t){return b.ponyfillGlobal.__MUI_STYLES__.withStyles(e,(0,a.default)({defaultTheme:C},t))};t.default=D},82313(e,t,n){"use strict";var r,i=n(95318);Object.defineProperty(t,"__esModule",{value:!0}),t.default=void 0;var a=i(n(67154)),o=i(n(6479)),s=i(n(34575)),u=i(n(93913)),c=i(n(78585)),l=i(n(29754)),f=i(n(2205)),d=i(n(67294));i(n(45697));var h=i(n(8679)),p=n(55252),b=i(n(71615)),m=i(n(51067));function g(){return r||(r=(0,b.default)({typography:{suppressWarning:!0}}))}var v=function(){return function(e){var t=function(t){function n(e,t){var r;return(0,s.default)(this,n),(r=(0,c.default)(this,(0,l.default)(n).call(this))).state={theme:m.default.initial(t)||g()},r}return(0,f.default)(n,t),(0,u.default)(n,[{key:"componentDidMount",value:function(){var e=this;this.unsubscribeId=m.default.subscribe(this.context,function(t){e.setState({theme:t})})}},{key:"componentWillUnmount",value:function(){null!==this.unsubscribeId&&m.default.unsubscribe(this.context,this.unsubscribeId)}},{key:"render",value:function(){var t=this.props,n=t.innerRef,r=(0,o.default)(t,["innerRef"]);return d.default.createElement(e,(0,a.default)({theme:this.state.theme,ref:n},r))}}]),n}(d.default.Component);return t.contextTypes=m.default.contextTypes,(0,h.default)(t,e),t}};p.ponyfillGlobal.__MUI_STYLES__||(p.ponyfillGlobal.__MUI_STYLES__={}),p.ponyfillGlobal.__MUI_STYLES__.withTheme||(p.ponyfillGlobal.__MUI_STYLES__.withTheme=v);var y=p.ponyfillGlobal.__MUI_STYLES__.withTheme;t.default=y},88676(e,t){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.default=void 0;var n={mobileStepper:1e3,appBar:1100,drawer:1200,modal:1300,snackbar:1400,tooltip:1500};t.default=n},41929(e,t){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.getTransitionProps=r,t.reflow=void 0;var n=function(e){return e.scrollTop};function r(e,t){var n=e.timeout,r=e.style,i=void 0===r?{}:r;return{duration:i.transitionDuration||"number"==typeof n?n:n[t.mode],delay:i.transitionDelay}}t.reflow=n},346(e,t){"use strict";function n(e,t){return function(){return null}}Object.defineProperty(t,"__esModule",{value:!0}),t.default=void 0;var r=n;t.default=r},98741(e,t,n){"use strict";var r=n(95318);Object.defineProperty(t,"__esModule",{value:!0}),t.capitalize=a,t.contains=o,t.findIndex=s,t.find=u,t.createChainedFunction=c;var i=r(n(50008));function a(e){return e.charAt(0).toUpperCase()+e.slice(1)}function o(e,t){return Object.keys(t).every(function(n){return e.hasOwnProperty(n)&&e[n]===t[n]})}function s(e,t){for(var n=(0,i.default)(t),r=0;r-1?e[n]:void 0}function c(){for(var e=arguments.length,t=Array(e),n=0;n1&&void 0!==arguments[1]?arguments[1]:window,n=(0,i.default)(e);return n.defaultView||n.parentView||t}var o=a;t.default=o},44370(e,t,n){"use strict";var r=n(95318);Object.defineProperty(t,"__esModule",{value:!0}),t.cloneElementWithClassName=o,t.cloneChildrenWithClassName=s,t.isMuiElement=u,t.setRef=c;var i=r(n(67294)),a=r(n(94184));function o(e,t){return i.default.cloneElement(e,{className:(0,a.default)(e.props.className,t)})}function s(e,t){return i.default.Children.map(e,function(e){return i.default.isValidElement(e)&&o(e,t)})}function u(e,t){return i.default.isValidElement(e)&&-1!==t.indexOf(e.type.muiName)}function c(e,t){"function"==typeof e?e(t):e&&(e.current=t)}},47348(e,t){"use strict";function n(e){return function(){return null}}Object.defineProperty(t,"__esModule",{value:!0}),t.default=void 0;var r=n;t.default=r},21677(e,t){"use strict";function n(e,t,n,r,i){return null}Object.defineProperty(t,"__esModule",{value:!0}),t.default=void 0;var r=n;t.default=r},78290(e,t,n){"use strict";var r=n(20862);Object.defineProperty(t,"__esModule",{value:!0});var i={};Object.defineProperty(t,"default",{enumerable:!0,get:function(){return a.default}});var a=r(n(88446));Object.keys(a).forEach(function(e){"default"!==e&&"__esModule"!==e&&(Object.prototype.hasOwnProperty.call(i,e)||Object.defineProperty(t,e,{enumerable:!0,get:function(){return a[e]}}))})},88446(e,t,n){"use strict";var r=n(95318);Object.defineProperty(t,"__esModule",{value:!0}),t.default=t.isWidthDown=t.isWidthUp=void 0;var i=r(n(67154)),a=r(n(6479)),o=r(n(34575)),s=r(n(93913)),u=r(n(78585)),c=r(n(29754)),l=r(n(2205)),f=r(n(67294));r(n(45697));var d=r(n(96421)),h=r(n(20296));n(55252);var p=r(n(8679)),b=r(n(82313)),m=n(94811),g=r(n(58057)),v=function(e,t){var n=!(arguments.length>2)||void 0===arguments[2]||arguments[2];return n?m.keys.indexOf(e)<=m.keys.indexOf(t):m.keys.indexOf(e)2)||void 0===arguments[2]||arguments[2];return n?m.keys.indexOf(t)<=m.keys.indexOf(e):m.keys.indexOf(t)0&&void 0!==arguments[0]?arguments[0]:{};return function(t){var n=e.withTheme,r=void 0!==n&&n,v=e.noSSR,y=void 0!==v&&v,w=e.initialWidth,_=e.resizeInterval,E=void 0===_?166:_,S=function(e){function n(e){var t;return(0,o.default)(this,n),(t=(0,u.default)(this,(0,c.default)(n).call(this,e))).state={width:y?t.getWidth():void 0},"undefined"!=typeof window&&(t.handleResize=(0,h.default)(function(){var e=t.getWidth();e!==t.state.width&&t.setState({width:e})},E)),t}return(0,l.default)(n,e),(0,s.default)(n,[{key:"componentDidMount",value:function(){var e=this.getWidth();e!==this.state.width&&this.setState({width:e})}},{key:"componentWillUnmount",value:function(){this.handleResize.clear()}},{key:"getWidth",value:function(){for(var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:window.innerWidth,t=this.props.theme.breakpoints,n=null,r=1;null===n&&ri.Z,componentPropType:()=>r.Z,exactProp:()=>a.ZP,getDisplayName:()=>o.ZP,ponyfillGlobal:()=>s.Z});var r=n(78728),i=n(5477),a=n(43781),o=n(25189),s=n(34712);/** @license Material-UI v3.0.0-alpha.3 * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. @@ -181,7 +181,7 @@ object-assign * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. - */ Object.defineProperty(t,"__esModule",{value:!0}),"undefined"==typeof window||"function"!=typeof MessageChannel){var n,r,i,a,o,s=null,u=null,c=function(){if(null!==s)try{var e=t.unstable_now();s(!0,e),s=null}catch(n){throw setTimeout(c,0),n}},l=Date.now();t.unstable_now=function(){return Date.now()-l},n=function(e){null!==s?setTimeout(n,0,e):(s=e,setTimeout(c,0))},r=function(e,t){u=setTimeout(e,t)},i=function(){clearTimeout(u)},a=function(){return!1},o=t.unstable_forceFrameRate=function(){}}else{var f=window.performance,d=window.Date,h=window.setTimeout,p=window.clearTimeout;if("undefined"!=typeof console){var b=window.cancelAnimationFrame;"function"!=typeof window.requestAnimationFrame&&console.error("This browser doesn't support requestAnimationFrame. Make sure that you load a polyfill in older browsers. https://fb.me/react-polyfills"),"function"!=typeof b&&console.error("This browser doesn't support cancelAnimationFrame. Make sure that you load a polyfill in older browsers. https://fb.me/react-polyfills")}if("object"==typeof f&&"function"==typeof f.now)t.unstable_now=function(){return f.now()};else{var m=d.now();t.unstable_now=function(){return d.now()-m}}var g=!1,v=null,y=-1,w=5,_=0;a=function(){return t.unstable_now()>=_},o=function(){},t.unstable_forceFrameRate=function(e){0>e||125M(o,n))void 0!==u&&0>M(u,o)?(e[r]=u,e[s]=n,r=s):(e[r]=o,e[a]=n,r=a);else if(void 0!==u&&0>M(u,n))e[r]=u,e[s]=n,r=s;else break a}}return t}return null}function M(e,t){var n=e.sortIndex-t.sortIndex;return 0!==n?n:e.id-t.id}var O=[],A=[],L=1,C=null,I=3,D=!1,N=!1,P=!1;function R(e){for(var t=x(A);null!==t;){if(null===t.callback)T(A);else if(t.startTime<=e)T(A),t.sortIndex=t.expirationTime,k(O,t);else break;t=x(A)}}function j(e){if(P=!1,R(e),!N){if(null!==x(O))N=!0,n(F);else{var t=x(A);null!==t&&r(j,t.startTime-e)}}}function F(e,n){N=!1,P&&(P=!1,i()),D=!0;var o=I;try{for(R(n),C=x(O);null!==C&&(!(C.expirationTime>n)||e&&!a());){var s=C.callback;if(null!==s){C.callback=null,I=C.priorityLevel;var u=s(C.expirationTime<=n);n=t.unstable_now(),"function"==typeof u?C.callback=u:C===x(O)&&T(O),R(n)}else T(O);C=x(O)}if(null!==C)var c=!0;else{var l=x(A);null!==l&&r(j,l.startTime-n),c=!1}return c}finally{C=null,I=o,D=!1}}function Y(e){switch(e){case 1:return -1;case 2:return 250;case 5:return 1073741823;case 4:return 1e4;default:return 5e3}}var B=o;t.unstable_ImmediatePriority=1,t.unstable_UserBlockingPriority=2,t.unstable_NormalPriority=3,t.unstable_IdlePriority=5,t.unstable_LowPriority=4,t.unstable_runWithPriority=function(e,t){switch(e){case 1:case 2:case 3:case 4:case 5:break;default:e=3}var n=I;I=e;try{return t()}finally{I=n}},t.unstable_next=function(e){switch(I){case 1:case 2:case 3:var t=3;break;default:t=I}var n=I;I=t;try{return e()}finally{I=n}},t.unstable_scheduleCallback=function(e,a,o){var s=t.unstable_now();if("object"==typeof o&&null!==o){var u=o.delay;u="number"==typeof u&&0s?(e.sortIndex=u,k(A,e),null===x(O)&&e===x(A)&&(P?i():P=!0,r(j,u-s))):(e.sortIndex=o,k(O,e),N||D||(N=!0,n(F))),e},t.unstable_cancelCallback=function(e){e.callback=null},t.unstable_wrapCallback=function(e){var t=I;return function(){var n=I;I=t;try{return e.apply(this,arguments)}finally{I=n}}},t.unstable_getCurrentPriorityLevel=function(){return I},t.unstable_shouldYield=function(){var e=t.unstable_now();R(e);var n=x(O);return n!==C&&null!==C&&null!==n&&null!==n.callback&&n.startTime<=e&&n.expirationTime>5==6?2:e>>4==14?3:e>>3==30?4:e>>6==2?-1:-2}function c(e,t,n){var r=t.length-1;if(r=0?(i>0&&(e.lastNeed=i-1),i):--r=0?(i>0&&(e.lastNeed=i-2),i):--r=0?(i>0&&(2===i?i=0:e.lastNeed=i-3),i):0}function l(e,t,n){if((192&t[0])!=128)return e.lastNeed=0,"�";if(e.lastNeed>1&&t.length>1){if((192&t[1])!=128)return e.lastNeed=1,"�";if(e.lastNeed>2&&t.length>2&&(192&t[2])!=128)return e.lastNeed=2,"�"}}function f(e){var t=this.lastTotal-this.lastNeed,n=l(this,e,t);return void 0!==n?n:this.lastNeed<=e.length?(e.copy(this.lastChar,t,0,this.lastNeed),this.lastChar.toString(this.encoding,0,this.lastTotal)):void(e.copy(this.lastChar,t,0,e.length),this.lastNeed-=e.length)}function d(e,t){var n=c(this,e,t);if(!this.lastNeed)return e.toString("utf8",t);this.lastTotal=n;var r=e.length-(n-this.lastNeed);return e.copy(this.lastChar,0,r),e.toString("utf8",t,r)}function h(e){var t=e&&e.length?this.write(e):"";return this.lastNeed?t+"�":t}function p(e,t){if((e.length-t)%2==0){var n=e.toString("utf16le",t);if(n){var r=n.charCodeAt(n.length-1);if(r>=55296&&r<=56319)return this.lastNeed=2,this.lastTotal=4,this.lastChar[0]=e[e.length-2],this.lastChar[1]=e[e.length-1],n.slice(0,-1)}return n}return this.lastNeed=1,this.lastTotal=2,this.lastChar[0]=e[e.length-1],e.toString("utf16le",t,e.length-1)}function b(e){var t=e&&e.length?this.write(e):"";if(this.lastNeed){var n=this.lastTotal-this.lastNeed;return t+this.lastChar.toString("utf16le",0,n)}return t}function m(e,t){var n=(e.length-t)%3;return 0===n?e.toString("base64",t):(this.lastNeed=3-n,this.lastTotal=3,1===n?this.lastChar[0]=e[e.length-1]:(this.lastChar[0]=e[e.length-2],this.lastChar[1]=e[e.length-1]),e.toString("base64",t,e.length-n))}function g(e){var t=e&&e.length?this.write(e):"";return this.lastNeed?t+this.lastChar.toString("base64",0,3-this.lastNeed):t}function v(e){return e.toString(this.encoding)}function y(e){return e&&e.length?this.write(e):""}t.s=s,s.prototype.write=function(e){var t,n;if(0===e.length)return"";if(this.lastNeed){if(void 0===(t=this.fillLast(e)))return"";n=this.lastNeed,this.lastNeed=0}else n=0;return nOB});var r,i,a,o,s,u,c,l=n(67294),f=n.t(l,2),d=n(97779),h=n(47886),p=n(57209),b=n(32316),m=n(95880),g=n(17051),v=n(71381),y=n(81701),w=n(3022),_=n(60323),E=n(87591),S=n(25649),k=n(28902),x=n(71426),T=n(48884),M=n(94184),O=n.n(M),A=n(55977),L=n(73935),C=function(){if("undefined"!=typeof Map)return Map;function e(e,t){var n=-1;return e.some(function(e,r){return e[0]===t&&(n=r,!0)}),n}return function(){function t(){this.__entries__=[]}return Object.defineProperty(t.prototype,"size",{get:function(){return this.__entries__.length},enumerable:!0,configurable:!0}),t.prototype.get=function(t){var n=e(this.__entries__,t),r=this.__entries__[n];return r&&r[1]},t.prototype.set=function(t,n){var r=e(this.__entries__,t);~r?this.__entries__[r][1]=n:this.__entries__.push([t,n])},t.prototype.delete=function(t){var n=this.__entries__,r=e(n,t);~r&&n.splice(r,1)},t.prototype.has=function(t){return!!~e(this.__entries__,t)},t.prototype.clear=function(){this.__entries__.splice(0)},t.prototype.forEach=function(e,t){void 0===t&&(t=null);for(var n=0,r=this.__entries__;n0},e.prototype.connect_=function(){I&&!this.connected_&&(document.addEventListener("transitionend",this.onTransitionEnd_),window.addEventListener("resize",this.refresh),Y?(this.mutationsObserver_=new MutationObserver(this.refresh),this.mutationsObserver_.observe(document,{attributes:!0,childList:!0,characterData:!0,subtree:!0})):(document.addEventListener("DOMSubtreeModified",this.refresh),this.mutationEventsAdded_=!0),this.connected_=!0)},e.prototype.disconnect_=function(){I&&this.connected_&&(document.removeEventListener("transitionend",this.onTransitionEnd_),window.removeEventListener("resize",this.refresh),this.mutationsObserver_&&this.mutationsObserver_.disconnect(),this.mutationEventsAdded_&&document.removeEventListener("DOMSubtreeModified",this.refresh),this.mutationsObserver_=null,this.mutationEventsAdded_=!1,this.connected_=!1)},e.prototype.onTransitionEnd_=function(e){var t=e.propertyName,n=void 0===t?"":t;F.some(function(e){return!!~n.indexOf(e)})&&this.refresh()},e.getInstance=function(){return this.instance_||(this.instance_=new e),this.instance_},e.instance_=null,e}(),U=function(e,t){for(var n=0,r=Object.keys(t);n0},e}(),er="undefined"!=typeof WeakMap?new WeakMap:new C,ei=function(){function e(t){if(!(this instanceof e))throw TypeError("Cannot call a class as a function.");if(!arguments.length)throw TypeError("1 argument required, but only 0 present.");var n=B.getInstance(),r=new en(t,n,this);er.set(this,r)}return e}();["observe","unobserve","disconnect"].forEach(function(e){ei.prototype[e]=function(){var t;return(t=er.get(this))[e].apply(t,arguments)}});var ea=void 0!==D.ResizeObserver?D.ResizeObserver:ei;let eo=ea;var es=function(e){var t=[],n=null,r=function(){for(var r=arguments.length,i=Array(r),a=0;a=t||n<0||f&&r>=a}function g(){var e=eb();if(m(e))return v(e);s=setTimeout(g,b(e))}function v(e){return(s=void 0,d&&r)?h(e):(r=i=void 0,o)}function y(){void 0!==s&&clearTimeout(s),c=0,r=u=i=s=void 0}function w(){return void 0===s?o:v(eb())}function _(){var e=eb(),n=m(e);if(r=arguments,i=this,u=e,n){if(void 0===s)return p(u);if(f)return clearTimeout(s),s=setTimeout(g,t),h(u)}return void 0===s&&(s=setTimeout(g,t)),o}return t=ez(t)||0,ed(n)&&(l=!!n.leading,a=(f="maxWait"in n)?eW(ez(n.maxWait)||0,t):a,d="trailing"in n?!!n.trailing:d),_.cancel=y,_.flush=w,_}let eq=eV;var eZ="Expected a function";function eX(e,t,n){var r=!0,i=!0;if("function"!=typeof e)throw TypeError(eZ);return ed(n)&&(r="leading"in n?!!n.leading:r,i="trailing"in n?!!n.trailing:i),eq(e,t,{leading:r,maxWait:t,trailing:i})}let eJ=eX;var eQ={debounce:eq,throttle:eJ},e1=function(e){return eQ[e]},e0=function(e){return"function"==typeof e},e2=function(){return"undefined"==typeof window},e3=function(e){return e instanceof Element||e instanceof HTMLDocument};function e4(e){return(e4="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e})(e)}function e5(e,t){if(!(e instanceof t))throw TypeError("Cannot call a class as a function")}function e6(e,t){for(var n=0;ne.length)&&(t=e.length);for(var n=0,r=Array(t);ne.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&l.createElement(tG.Z,{variant:"indeterminate",classes:r}))};tK.propTypes={fetchCount:el().number.isRequired};let tV=(0,b.withStyles)(tW)(tK);var tq=n(5536);let tZ=n.p+"ba8bbf16ebf8e1d05bef.svg";function tX(){return(tX=Object.assign||function(e){for(var t=1;t120){for(var d=Math.floor(u/80),h=u%80,p=[],b=0;b0},name:{enumerable:!1},nodes:{enumerable:!1},source:{enumerable:!1},positions:{enumerable:!1},originalError:{enumerable:!1}}),null!=s&&s.stack)?(Object.defineProperty(nf(b),"stack",{value:s.stack,writable:!0,configurable:!0}),nl(b)):(Error.captureStackTrace?Error.captureStackTrace(nf(b),n):Object.defineProperty(nf(b),"stack",{value:Error().stack,writable:!0,configurable:!0}),b)}return ns(n,[{key:"toString",value:function(){return nw(this)}},{key:t4.YF,get:function(){return"Object"}}]),n}(nd(Error));function ny(e){return void 0===e||0===e.length?void 0:e}function nw(e){var t=e.message;if(e.nodes)for(var n=0,r=e.nodes;n",EOF:"",BANG:"!",DOLLAR:"$",AMP:"&",PAREN_L:"(",PAREN_R:")",SPREAD:"...",COLON:":",EQUALS:"=",AT:"@",BRACKET_L:"[",BRACKET_R:"]",BRACE_L:"{",PIPE:"|",BRACE_R:"}",NAME:"Name",INT:"Int",FLOAT:"Float",STRING:"String",BLOCK_STRING:"BlockString",COMMENT:"Comment"}),nx=n(10143),nT=Object.freeze({QUERY:"QUERY",MUTATION:"MUTATION",SUBSCRIPTION:"SUBSCRIPTION",FIELD:"FIELD",FRAGMENT_DEFINITION:"FRAGMENT_DEFINITION",FRAGMENT_SPREAD:"FRAGMENT_SPREAD",INLINE_FRAGMENT:"INLINE_FRAGMENT",VARIABLE_DEFINITION:"VARIABLE_DEFINITION",SCHEMA:"SCHEMA",SCALAR:"SCALAR",OBJECT:"OBJECT",FIELD_DEFINITION:"FIELD_DEFINITION",ARGUMENT_DEFINITION:"ARGUMENT_DEFINITION",INTERFACE:"INTERFACE",UNION:"UNION",ENUM:"ENUM",ENUM_VALUE:"ENUM_VALUE",INPUT_OBJECT:"INPUT_OBJECT",INPUT_FIELD_DEFINITION:"INPUT_FIELD_DEFINITION"}),nM=n(87392),nO=function(){function e(e){var t=new nS.WU(nk.SOF,0,0,0,0,null);this.source=e,this.lastToken=t,this.token=t,this.line=1,this.lineStart=0}var t=e.prototype;return t.advance=function(){return this.lastToken=this.token,this.token=this.lookahead()},t.lookahead=function(){var e,t=this.token;if(t.kind!==nk.EOF)do t=null!==(e=t.next)&&void 0!==e?e:t.next=nC(this,t);while(t.kind===nk.COMMENT)return t},e}();function nA(e){return e===nk.BANG||e===nk.DOLLAR||e===nk.AMP||e===nk.PAREN_L||e===nk.PAREN_R||e===nk.SPREAD||e===nk.COLON||e===nk.EQUALS||e===nk.AT||e===nk.BRACKET_L||e===nk.BRACKET_R||e===nk.BRACE_L||e===nk.PIPE||e===nk.BRACE_R}function nL(e){return isNaN(e)?nk.EOF:e<127?JSON.stringify(String.fromCharCode(e)):'"\\u'.concat(("00"+e.toString(16).toUpperCase()).slice(-4),'"')}function nC(e,t){for(var n=e.source,r=n.body,i=r.length,a=t.end;a31||9===a))return new nS.WU(nk.COMMENT,t,s,n,r,i,o.slice(t+1,s))}function nN(e,t,n,r,i,a){var o=e.body,s=n,u=t,c=!1;if(45===s&&(s=o.charCodeAt(++u)),48===s){if((s=o.charCodeAt(++u))>=48&&s<=57)throw n_(e,u,"Invalid number, unexpected digit after 0: ".concat(nL(s),"."))}else u=nP(e,u,s),s=o.charCodeAt(u);if(46===s&&(c=!0,s=o.charCodeAt(++u),u=nP(e,u,s),s=o.charCodeAt(u)),(69===s||101===s)&&(c=!0,(43===(s=o.charCodeAt(++u))||45===s)&&(s=o.charCodeAt(++u)),u=nP(e,u,s),s=o.charCodeAt(u)),46===s||nU(s))throw n_(e,u,"Invalid number, expected digit but got: ".concat(nL(s),"."));return new nS.WU(c?nk.FLOAT:nk.INT,t,u,r,i,a,o.slice(t,u))}function nP(e,t,n){var r=e.body,i=t,a=n;if(a>=48&&a<=57){do a=r.charCodeAt(++i);while(a>=48&&a<=57)return i}throw n_(e,i,"Invalid number, expected digit but got: ".concat(nL(a),"."))}function nR(e,t,n,r,i){for(var a=e.body,o=t+1,s=o,u=0,c="";o=48&&e<=57?e-48:e>=65&&e<=70?e-55:e>=97&&e<=102?e-87:-1}function nB(e,t,n,r,i){for(var a=e.body,o=a.length,s=t+1,u=0;s!==o&&!isNaN(u=a.charCodeAt(s))&&(95===u||u>=48&&u<=57||u>=65&&u<=90||u>=97&&u<=122);)++s;return new nS.WU(nk.NAME,t,s,n,r,i,a.slice(t,s))}function nU(e){return 95===e||e>=65&&e<=90||e>=97&&e<=122}function nH(e,t){return new n$(e,t).parseDocument()}var n$=function(){function e(e,t){var n=(0,nx.T)(e)?e:new nx.H(e);this._lexer=new nO(n),this._options=t}var t=e.prototype;return t.parseName=function(){var e=this.expectToken(nk.NAME);return{kind:nE.h.NAME,value:e.value,loc:this.loc(e)}},t.parseDocument=function(){var e=this._lexer.token;return{kind:nE.h.DOCUMENT,definitions:this.many(nk.SOF,this.parseDefinition,nk.EOF),loc:this.loc(e)}},t.parseDefinition=function(){if(this.peek(nk.NAME))switch(this._lexer.token.value){case"query":case"mutation":case"subscription":return this.parseOperationDefinition();case"fragment":return this.parseFragmentDefinition();case"schema":case"scalar":case"type":case"interface":case"union":case"enum":case"input":case"directive":return this.parseTypeSystemDefinition();case"extend":return this.parseTypeSystemExtension()}else if(this.peek(nk.BRACE_L))return this.parseOperationDefinition();else if(this.peekDescription())return this.parseTypeSystemDefinition();throw this.unexpected()},t.parseOperationDefinition=function(){var e,t=this._lexer.token;if(this.peek(nk.BRACE_L))return{kind:nE.h.OPERATION_DEFINITION,operation:"query",name:void 0,variableDefinitions:[],directives:[],selectionSet:this.parseSelectionSet(),loc:this.loc(t)};var n=this.parseOperationType();return this.peek(nk.NAME)&&(e=this.parseName()),{kind:nE.h.OPERATION_DEFINITION,operation:n,name:e,variableDefinitions:this.parseVariableDefinitions(),directives:this.parseDirectives(!1),selectionSet:this.parseSelectionSet(),loc:this.loc(t)}},t.parseOperationType=function(){var e=this.expectToken(nk.NAME);switch(e.value){case"query":return"query";case"mutation":return"mutation";case"subscription":return"subscription"}throw this.unexpected(e)},t.parseVariableDefinitions=function(){return this.optionalMany(nk.PAREN_L,this.parseVariableDefinition,nk.PAREN_R)},t.parseVariableDefinition=function(){var e=this._lexer.token;return{kind:nE.h.VARIABLE_DEFINITION,variable:this.parseVariable(),type:(this.expectToken(nk.COLON),this.parseTypeReference()),defaultValue:this.expectOptionalToken(nk.EQUALS)?this.parseValueLiteral(!0):void 0,directives:this.parseDirectives(!0),loc:this.loc(e)}},t.parseVariable=function(){var e=this._lexer.token;return this.expectToken(nk.DOLLAR),{kind:nE.h.VARIABLE,name:this.parseName(),loc:this.loc(e)}},t.parseSelectionSet=function(){var e=this._lexer.token;return{kind:nE.h.SELECTION_SET,selections:this.many(nk.BRACE_L,this.parseSelection,nk.BRACE_R),loc:this.loc(e)}},t.parseSelection=function(){return this.peek(nk.SPREAD)?this.parseFragment():this.parseField()},t.parseField=function(){var e,t,n=this._lexer.token,r=this.parseName();return this.expectOptionalToken(nk.COLON)?(e=r,t=this.parseName()):t=r,{kind:nE.h.FIELD,alias:e,name:t,arguments:this.parseArguments(!1),directives:this.parseDirectives(!1),selectionSet:this.peek(nk.BRACE_L)?this.parseSelectionSet():void 0,loc:this.loc(n)}},t.parseArguments=function(e){var t=e?this.parseConstArgument:this.parseArgument;return this.optionalMany(nk.PAREN_L,t,nk.PAREN_R)},t.parseArgument=function(){var e=this._lexer.token,t=this.parseName();return this.expectToken(nk.COLON),{kind:nE.h.ARGUMENT,name:t,value:this.parseValueLiteral(!1),loc:this.loc(e)}},t.parseConstArgument=function(){var e=this._lexer.token;return{kind:nE.h.ARGUMENT,name:this.parseName(),value:(this.expectToken(nk.COLON),this.parseValueLiteral(!0)),loc:this.loc(e)}},t.parseFragment=function(){var e=this._lexer.token;this.expectToken(nk.SPREAD);var t=this.expectOptionalKeyword("on");return!t&&this.peek(nk.NAME)?{kind:nE.h.FRAGMENT_SPREAD,name:this.parseFragmentName(),directives:this.parseDirectives(!1),loc:this.loc(e)}:{kind:nE.h.INLINE_FRAGMENT,typeCondition:t?this.parseNamedType():void 0,directives:this.parseDirectives(!1),selectionSet:this.parseSelectionSet(),loc:this.loc(e)}},t.parseFragmentDefinition=function(){var e,t=this._lexer.token;return(this.expectKeyword("fragment"),(null===(e=this._options)||void 0===e?void 0:e.experimentalFragmentVariables)===!0)?{kind:nE.h.FRAGMENT_DEFINITION,name:this.parseFragmentName(),variableDefinitions:this.parseVariableDefinitions(),typeCondition:(this.expectKeyword("on"),this.parseNamedType()),directives:this.parseDirectives(!1),selectionSet:this.parseSelectionSet(),loc:this.loc(t)}:{kind:nE.h.FRAGMENT_DEFINITION,name:this.parseFragmentName(),typeCondition:(this.expectKeyword("on"),this.parseNamedType()),directives:this.parseDirectives(!1),selectionSet:this.parseSelectionSet(),loc:this.loc(t)}},t.parseFragmentName=function(){if("on"===this._lexer.token.value)throw this.unexpected();return this.parseName()},t.parseValueLiteral=function(e){var t=this._lexer.token;switch(t.kind){case nk.BRACKET_L:return this.parseList(e);case nk.BRACE_L:return this.parseObject(e);case nk.INT:return this._lexer.advance(),{kind:nE.h.INT,value:t.value,loc:this.loc(t)};case nk.FLOAT:return this._lexer.advance(),{kind:nE.h.FLOAT,value:t.value,loc:this.loc(t)};case nk.STRING:case nk.BLOCK_STRING:return this.parseStringLiteral();case nk.NAME:switch(this._lexer.advance(),t.value){case"true":return{kind:nE.h.BOOLEAN,value:!0,loc:this.loc(t)};case"false":return{kind:nE.h.BOOLEAN,value:!1,loc:this.loc(t)};case"null":return{kind:nE.h.NULL,loc:this.loc(t)};default:return{kind:nE.h.ENUM,value:t.value,loc:this.loc(t)}}case nk.DOLLAR:if(!e)return this.parseVariable()}throw this.unexpected()},t.parseStringLiteral=function(){var e=this._lexer.token;return this._lexer.advance(),{kind:nE.h.STRING,value:e.value,block:e.kind===nk.BLOCK_STRING,loc:this.loc(e)}},t.parseList=function(e){var t=this,n=this._lexer.token,r=function(){return t.parseValueLiteral(e)};return{kind:nE.h.LIST,values:this.any(nk.BRACKET_L,r,nk.BRACKET_R),loc:this.loc(n)}},t.parseObject=function(e){var t=this,n=this._lexer.token,r=function(){return t.parseObjectField(e)};return{kind:nE.h.OBJECT,fields:this.any(nk.BRACE_L,r,nk.BRACE_R),loc:this.loc(n)}},t.parseObjectField=function(e){var t=this._lexer.token,n=this.parseName();return this.expectToken(nk.COLON),{kind:nE.h.OBJECT_FIELD,name:n,value:this.parseValueLiteral(e),loc:this.loc(t)}},t.parseDirectives=function(e){for(var t=[];this.peek(nk.AT);)t.push(this.parseDirective(e));return t},t.parseDirective=function(e){var t=this._lexer.token;return this.expectToken(nk.AT),{kind:nE.h.DIRECTIVE,name:this.parseName(),arguments:this.parseArguments(e),loc:this.loc(t)}},t.parseTypeReference=function(){var e,t=this._lexer.token;return(this.expectOptionalToken(nk.BRACKET_L)?(e=this.parseTypeReference(),this.expectToken(nk.BRACKET_R),e={kind:nE.h.LIST_TYPE,type:e,loc:this.loc(t)}):e=this.parseNamedType(),this.expectOptionalToken(nk.BANG))?{kind:nE.h.NON_NULL_TYPE,type:e,loc:this.loc(t)}:e},t.parseNamedType=function(){var e=this._lexer.token;return{kind:nE.h.NAMED_TYPE,name:this.parseName(),loc:this.loc(e)}},t.parseTypeSystemDefinition=function(){var e=this.peekDescription()?this._lexer.lookahead():this._lexer.token;if(e.kind===nk.NAME)switch(e.value){case"schema":return this.parseSchemaDefinition();case"scalar":return this.parseScalarTypeDefinition();case"type":return this.parseObjectTypeDefinition();case"interface":return this.parseInterfaceTypeDefinition();case"union":return this.parseUnionTypeDefinition();case"enum":return this.parseEnumTypeDefinition();case"input":return this.parseInputObjectTypeDefinition();case"directive":return this.parseDirectiveDefinition()}throw this.unexpected(e)},t.peekDescription=function(){return this.peek(nk.STRING)||this.peek(nk.BLOCK_STRING)},t.parseDescription=function(){if(this.peekDescription())return this.parseStringLiteral()},t.parseSchemaDefinition=function(){var e=this._lexer.token,t=this.parseDescription();this.expectKeyword("schema");var n=this.parseDirectives(!0),r=this.many(nk.BRACE_L,this.parseOperationTypeDefinition,nk.BRACE_R);return{kind:nE.h.SCHEMA_DEFINITION,description:t,directives:n,operationTypes:r,loc:this.loc(e)}},t.parseOperationTypeDefinition=function(){var e=this._lexer.token,t=this.parseOperationType();this.expectToken(nk.COLON);var n=this.parseNamedType();return{kind:nE.h.OPERATION_TYPE_DEFINITION,operation:t,type:n,loc:this.loc(e)}},t.parseScalarTypeDefinition=function(){var e=this._lexer.token,t=this.parseDescription();this.expectKeyword("scalar");var n=this.parseName(),r=this.parseDirectives(!0);return{kind:nE.h.SCALAR_TYPE_DEFINITION,description:t,name:n,directives:r,loc:this.loc(e)}},t.parseObjectTypeDefinition=function(){var e=this._lexer.token,t=this.parseDescription();this.expectKeyword("type");var n=this.parseName(),r=this.parseImplementsInterfaces(),i=this.parseDirectives(!0),a=this.parseFieldsDefinition();return{kind:nE.h.OBJECT_TYPE_DEFINITION,description:t,name:n,interfaces:r,directives:i,fields:a,loc:this.loc(e)}},t.parseImplementsInterfaces=function(){var e;if(!this.expectOptionalKeyword("implements"))return[];if((null===(e=this._options)||void 0===e?void 0:e.allowLegacySDLImplementsInterfaces)===!0){var t=[];this.expectOptionalToken(nk.AMP);do t.push(this.parseNamedType());while(this.expectOptionalToken(nk.AMP)||this.peek(nk.NAME))return t}return this.delimitedMany(nk.AMP,this.parseNamedType)},t.parseFieldsDefinition=function(){var e;return(null===(e=this._options)||void 0===e?void 0:e.allowLegacySDLEmptyFields)===!0&&this.peek(nk.BRACE_L)&&this._lexer.lookahead().kind===nk.BRACE_R?(this._lexer.advance(),this._lexer.advance(),[]):this.optionalMany(nk.BRACE_L,this.parseFieldDefinition,nk.BRACE_R)},t.parseFieldDefinition=function(){var e=this._lexer.token,t=this.parseDescription(),n=this.parseName(),r=this.parseArgumentDefs();this.expectToken(nk.COLON);var i=this.parseTypeReference(),a=this.parseDirectives(!0);return{kind:nE.h.FIELD_DEFINITION,description:t,name:n,arguments:r,type:i,directives:a,loc:this.loc(e)}},t.parseArgumentDefs=function(){return this.optionalMany(nk.PAREN_L,this.parseInputValueDef,nk.PAREN_R)},t.parseInputValueDef=function(){var e,t=this._lexer.token,n=this.parseDescription(),r=this.parseName();this.expectToken(nk.COLON);var i=this.parseTypeReference();this.expectOptionalToken(nk.EQUALS)&&(e=this.parseValueLiteral(!0));var a=this.parseDirectives(!0);return{kind:nE.h.INPUT_VALUE_DEFINITION,description:n,name:r,type:i,defaultValue:e,directives:a,loc:this.loc(t)}},t.parseInterfaceTypeDefinition=function(){var e=this._lexer.token,t=this.parseDescription();this.expectKeyword("interface");var n=this.parseName(),r=this.parseImplementsInterfaces(),i=this.parseDirectives(!0),a=this.parseFieldsDefinition();return{kind:nE.h.INTERFACE_TYPE_DEFINITION,description:t,name:n,interfaces:r,directives:i,fields:a,loc:this.loc(e)}},t.parseUnionTypeDefinition=function(){var e=this._lexer.token,t=this.parseDescription();this.expectKeyword("union");var n=this.parseName(),r=this.parseDirectives(!0),i=this.parseUnionMemberTypes();return{kind:nE.h.UNION_TYPE_DEFINITION,description:t,name:n,directives:r,types:i,loc:this.loc(e)}},t.parseUnionMemberTypes=function(){return this.expectOptionalToken(nk.EQUALS)?this.delimitedMany(nk.PIPE,this.parseNamedType):[]},t.parseEnumTypeDefinition=function(){var e=this._lexer.token,t=this.parseDescription();this.expectKeyword("enum");var n=this.parseName(),r=this.parseDirectives(!0),i=this.parseEnumValuesDefinition();return{kind:nE.h.ENUM_TYPE_DEFINITION,description:t,name:n,directives:r,values:i,loc:this.loc(e)}},t.parseEnumValuesDefinition=function(){return this.optionalMany(nk.BRACE_L,this.parseEnumValueDefinition,nk.BRACE_R)},t.parseEnumValueDefinition=function(){var e=this._lexer.token,t=this.parseDescription(),n=this.parseName(),r=this.parseDirectives(!0);return{kind:nE.h.ENUM_VALUE_DEFINITION,description:t,name:n,directives:r,loc:this.loc(e)}},t.parseInputObjectTypeDefinition=function(){var e=this._lexer.token,t=this.parseDescription();this.expectKeyword("input");var n=this.parseName(),r=this.parseDirectives(!0),i=this.parseInputFieldsDefinition();return{kind:nE.h.INPUT_OBJECT_TYPE_DEFINITION,description:t,name:n,directives:r,fields:i,loc:this.loc(e)}},t.parseInputFieldsDefinition=function(){return this.optionalMany(nk.BRACE_L,this.parseInputValueDef,nk.BRACE_R)},t.parseTypeSystemExtension=function(){var e=this._lexer.lookahead();if(e.kind===nk.NAME)switch(e.value){case"schema":return this.parseSchemaExtension();case"scalar":return this.parseScalarTypeExtension();case"type":return this.parseObjectTypeExtension();case"interface":return this.parseInterfaceTypeExtension();case"union":return this.parseUnionTypeExtension();case"enum":return this.parseEnumTypeExtension();case"input":return this.parseInputObjectTypeExtension()}throw this.unexpected(e)},t.parseSchemaExtension=function(){var e=this._lexer.token;this.expectKeyword("extend"),this.expectKeyword("schema");var t=this.parseDirectives(!0),n=this.optionalMany(nk.BRACE_L,this.parseOperationTypeDefinition,nk.BRACE_R);if(0===t.length&&0===n.length)throw this.unexpected();return{kind:nE.h.SCHEMA_EXTENSION,directives:t,operationTypes:n,loc:this.loc(e)}},t.parseScalarTypeExtension=function(){var e=this._lexer.token;this.expectKeyword("extend"),this.expectKeyword("scalar");var t=this.parseName(),n=this.parseDirectives(!0);if(0===n.length)throw this.unexpected();return{kind:nE.h.SCALAR_TYPE_EXTENSION,name:t,directives:n,loc:this.loc(e)}},t.parseObjectTypeExtension=function(){var e=this._lexer.token;this.expectKeyword("extend"),this.expectKeyword("type");var t=this.parseName(),n=this.parseImplementsInterfaces(),r=this.parseDirectives(!0),i=this.parseFieldsDefinition();if(0===n.length&&0===r.length&&0===i.length)throw this.unexpected();return{kind:nE.h.OBJECT_TYPE_EXTENSION,name:t,interfaces:n,directives:r,fields:i,loc:this.loc(e)}},t.parseInterfaceTypeExtension=function(){var e=this._lexer.token;this.expectKeyword("extend"),this.expectKeyword("interface");var t=this.parseName(),n=this.parseImplementsInterfaces(),r=this.parseDirectives(!0),i=this.parseFieldsDefinition();if(0===n.length&&0===r.length&&0===i.length)throw this.unexpected();return{kind:nE.h.INTERFACE_TYPE_EXTENSION,name:t,interfaces:n,directives:r,fields:i,loc:this.loc(e)}},t.parseUnionTypeExtension=function(){var e=this._lexer.token;this.expectKeyword("extend"),this.expectKeyword("union");var t=this.parseName(),n=this.parseDirectives(!0),r=this.parseUnionMemberTypes();if(0===n.length&&0===r.length)throw this.unexpected();return{kind:nE.h.UNION_TYPE_EXTENSION,name:t,directives:n,types:r,loc:this.loc(e)}},t.parseEnumTypeExtension=function(){var e=this._lexer.token;this.expectKeyword("extend"),this.expectKeyword("enum");var t=this.parseName(),n=this.parseDirectives(!0),r=this.parseEnumValuesDefinition();if(0===n.length&&0===r.length)throw this.unexpected();return{kind:nE.h.ENUM_TYPE_EXTENSION,name:t,directives:n,values:r,loc:this.loc(e)}},t.parseInputObjectTypeExtension=function(){var e=this._lexer.token;this.expectKeyword("extend"),this.expectKeyword("input");var t=this.parseName(),n=this.parseDirectives(!0),r=this.parseInputFieldsDefinition();if(0===n.length&&0===r.length)throw this.unexpected();return{kind:nE.h.INPUT_OBJECT_TYPE_EXTENSION,name:t,directives:n,fields:r,loc:this.loc(e)}},t.parseDirectiveDefinition=function(){var e=this._lexer.token,t=this.parseDescription();this.expectKeyword("directive"),this.expectToken(nk.AT);var n=this.parseName(),r=this.parseArgumentDefs(),i=this.expectOptionalKeyword("repeatable");this.expectKeyword("on");var a=this.parseDirectiveLocations();return{kind:nE.h.DIRECTIVE_DEFINITION,description:t,name:n,arguments:r,repeatable:i,locations:a,loc:this.loc(e)}},t.parseDirectiveLocations=function(){return this.delimitedMany(nk.PIPE,this.parseDirectiveLocation)},t.parseDirectiveLocation=function(){var e=this._lexer.token,t=this.parseName();if(void 0!==nT[t.value])return t;throw this.unexpected(e)},t.loc=function(e){var t;if((null===(t=this._options)||void 0===t?void 0:t.noLocation)!==!0)return new nS.Ye(e,this._lexer.lastToken,this._lexer.source)},t.peek=function(e){return this._lexer.token.kind===e},t.expectToken=function(e){var t=this._lexer.token;if(t.kind===e)return this._lexer.advance(),t;throw n_(this._lexer.source,t.start,"Expected ".concat(nG(e),", found ").concat(nz(t),"."))},t.expectOptionalToken=function(e){var t=this._lexer.token;if(t.kind===e)return this._lexer.advance(),t},t.expectKeyword=function(e){var t=this._lexer.token;if(t.kind===nk.NAME&&t.value===e)this._lexer.advance();else throw n_(this._lexer.source,t.start,'Expected "'.concat(e,'", found ').concat(nz(t),"."))},t.expectOptionalKeyword=function(e){var t=this._lexer.token;return t.kind===nk.NAME&&t.value===e&&(this._lexer.advance(),!0)},t.unexpected=function(e){var t=null!=e?e:this._lexer.token;return n_(this._lexer.source,t.start,"Unexpected ".concat(nz(t),"."))},t.any=function(e,t,n){this.expectToken(e);for(var r=[];!this.expectOptionalToken(n);)r.push(t.call(this));return r},t.optionalMany=function(e,t,n){if(this.expectOptionalToken(e)){var r=[];do r.push(t.call(this));while(!this.expectOptionalToken(n))return r}return[]},t.many=function(e,t,n){this.expectToken(e);var r=[];do r.push(t.call(this));while(!this.expectOptionalToken(n))return r},t.delimitedMany=function(e,t){this.expectOptionalToken(e);var n=[];do n.push(t.call(this));while(this.expectOptionalToken(e))return n},e}();function nz(e){var t=e.value;return nG(e.kind)+(null!=t?' "'.concat(t,'"'):"")}function nG(e){return nA(e)?'"'.concat(e,'"'):e}var nW=new Map,nK=new Map,nV=!0,nq=!1;function nZ(e){return e.replace(/[\s,]+/g," ").trim()}function nX(e){return nZ(e.source.body.substring(e.start,e.end))}function nJ(e){var t=new Set,n=[];return e.definitions.forEach(function(e){if("FragmentDefinition"===e.kind){var r=e.name.value,i=nX(e.loc),a=nK.get(r);a&&!a.has(i)?nV&&console.warn("Warning: fragment with name "+r+" already exists.\ngraphql-tag enforces all fragment names across your application to be unique; read more about\nthis in the docs: http://dev.apollodata.com/core/fragments.html#unique-names"):a||nK.set(r,a=new Set),a.add(i),t.has(i)||(t.add(i),n.push(e))}else n.push(e)}),(0,t0.pi)((0,t0.pi)({},e),{definitions:n})}function nQ(e){var t=new Set(e.definitions);t.forEach(function(e){e.loc&&delete e.loc,Object.keys(e).forEach(function(n){var r=e[n];r&&"object"==typeof r&&t.add(r)})});var n=e.loc;return n&&(delete n.startToken,delete n.endToken),e}function n1(e){var t=nZ(e);if(!nW.has(t)){var n=nH(e,{experimentalFragmentVariables:nq,allowLegacyFragmentVariables:nq});if(!n||"Document"!==n.kind)throw Error("Not a valid GraphQL document.");nW.set(t,nQ(nJ(n)))}return nW.get(t)}function n0(e){for(var t=[],n=1;n, or pass an ApolloClient instance in via options.'):(0,n7.kG)(!!n,32),n}var rb=n(10542),rm=n(53712),rg=n(21436),rv=Object.prototype.hasOwnProperty;function ry(e,t){return void 0===t&&(t=Object.create(null)),rw(rp(t.client),e).useQuery(t)}function rw(e,t){var n=(0,l.useRef)();n.current&&e===n.current.client&&t===n.current.query||(n.current=new r_(e,t,n.current));var r=n.current,i=(0,l.useState)(0),a=(i[0],i[1]);return r.forceUpdate=function(){a(function(e){return e+1})},r}var r_=function(){function e(e,t,n){this.client=e,this.query=t,this.ssrDisabledResult=(0,rb.J)({loading:!0,data:void 0,error:void 0,networkStatus:rc.I.loading}),this.skipStandbyResult=(0,rb.J)({loading:!1,data:void 0,error:void 0,networkStatus:rc.I.ready}),this.toQueryResultCache=new(re.mr?WeakMap:Map),rh(t,r.Query);var i=n&&n.result,a=i&&i.data;a&&(this.previousData=a)}return e.prototype.forceUpdate=function(){__DEV__&&n7.kG.warn("Calling default no-op implementation of InternalState#forceUpdate")},e.prototype.executeQuery=function(e){var t,n=this;e.query&&Object.assign(this,{query:e.query}),this.watchQueryOptions=this.createWatchQueryOptions(this.queryHookOptions=e);var r=this.observable.reobserveAsConcast(this.getObsQueryOptions());return this.previousData=(null===(t=this.result)||void 0===t?void 0:t.data)||this.previousData,this.result=void 0,this.forceUpdate(),new Promise(function(e){var t;r.subscribe({next:function(e){t=e},error:function(){e(n.toQueryResult(n.observable.getCurrentResult()))},complete:function(){e(n.toQueryResult(t))}})})},e.prototype.useQuery=function(e){var t=this;this.renderPromises=(0,l.useContext)((0,rs.K)()).renderPromises,this.useOptions(e);var n=this.useObservableQuery(),r=rn((0,l.useCallback)(function(){if(t.renderPromises)return function(){};var e=function(){var e=t.result,r=n.getCurrentResult();!(e&&e.loading===r.loading&&e.networkStatus===r.networkStatus&&(0,ra.D)(e.data,r.data))&&t.setResult(r)},r=function(a){var o=n.last;i.unsubscribe();try{n.resetLastResults(),i=n.subscribe(e,r)}finally{n.last=o}if(!rv.call(a,"graphQLErrors"))throw a;var s=t.result;(!s||s&&s.loading||!(0,ra.D)(a,s.error))&&t.setResult({data:s&&s.data,error:a,loading:!1,networkStatus:rc.I.error})},i=n.subscribe(e,r);return function(){return setTimeout(function(){return i.unsubscribe()})}},[n,this.renderPromises,this.client.disableNetworkFetches,]),function(){return t.getCurrentResult()},function(){return t.getCurrentResult()});return this.unsafeHandlePartialRefetch(r),this.toQueryResult(r)},e.prototype.useOptions=function(t){var n,r=this.createWatchQueryOptions(this.queryHookOptions=t),i=this.watchQueryOptions;!(0,ra.D)(r,i)&&(this.watchQueryOptions=r,i&&this.observable&&(this.observable.reobserve(this.getObsQueryOptions()),this.previousData=(null===(n=this.result)||void 0===n?void 0:n.data)||this.previousData,this.result=void 0)),this.onCompleted=t.onCompleted||e.prototype.onCompleted,this.onError=t.onError||e.prototype.onError,(this.renderPromises||this.client.disableNetworkFetches)&&!1===this.queryHookOptions.ssr&&!this.queryHookOptions.skip?this.result=this.ssrDisabledResult:this.queryHookOptions.skip||"standby"===this.watchQueryOptions.fetchPolicy?this.result=this.skipStandbyResult:(this.result===this.ssrDisabledResult||this.result===this.skipStandbyResult)&&(this.result=void 0)},e.prototype.getObsQueryOptions=function(){var e=[],t=this.client.defaultOptions.watchQuery;return t&&e.push(t),this.queryHookOptions.defaultOptions&&e.push(this.queryHookOptions.defaultOptions),e.push((0,rm.o)(this.observable&&this.observable.options,this.watchQueryOptions)),e.reduce(ro.J)},e.prototype.createWatchQueryOptions=function(e){void 0===e&&(e={});var t,n=e.skip,r=Object.assign((e.ssr,e.onCompleted,e.onError,e.defaultOptions,(0,n8._T)(e,["skip","ssr","onCompleted","onError","defaultOptions"])),{query:this.query});if(this.renderPromises&&("network-only"===r.fetchPolicy||"cache-and-network"===r.fetchPolicy)&&(r.fetchPolicy="cache-first"),r.variables||(r.variables={}),n){var i=r.fetchPolicy,a=void 0===i?this.getDefaultFetchPolicy():i,o=r.initialFetchPolicy;Object.assign(r,{initialFetchPolicy:void 0===o?a:o,fetchPolicy:"standby"})}else r.fetchPolicy||(r.fetchPolicy=(null===(t=this.observable)||void 0===t?void 0:t.options.initialFetchPolicy)||this.getDefaultFetchPolicy());return r},e.prototype.getDefaultFetchPolicy=function(){var e,t;return(null===(e=this.queryHookOptions.defaultOptions)||void 0===e?void 0:e.fetchPolicy)||(null===(t=this.client.defaultOptions.watchQuery)||void 0===t?void 0:t.fetchPolicy)||"cache-first"},e.prototype.onCompleted=function(e){},e.prototype.onError=function(e){},e.prototype.useObservableQuery=function(){var e=this.observable=this.renderPromises&&this.renderPromises.getSSRObservable(this.watchQueryOptions)||this.observable||this.client.watchQuery(this.getObsQueryOptions());this.obsQueryFields=(0,l.useMemo)(function(){return{refetch:e.refetch.bind(e),reobserve:e.reobserve.bind(e),fetchMore:e.fetchMore.bind(e),updateQuery:e.updateQuery.bind(e),startPolling:e.startPolling.bind(e),stopPolling:e.stopPolling.bind(e),subscribeToMore:e.subscribeToMore.bind(e)}},[e]);var t=!(!1===this.queryHookOptions.ssr||this.queryHookOptions.skip);return this.renderPromises&&t&&(this.renderPromises.registerSSRObservable(e),e.getCurrentResult().loading&&this.renderPromises.addObservableQueryPromise(e)),e},e.prototype.setResult=function(e){var t=this.result;t&&t.data&&(this.previousData=t.data),this.result=e,this.forceUpdate(),this.handleErrorOrCompleted(e)},e.prototype.handleErrorOrCompleted=function(e){var t=this;if(!e.loading){var n=this.toApolloError(e);Promise.resolve().then(function(){n?t.onError(n):e.data&&t.onCompleted(e.data)}).catch(function(e){__DEV__&&n7.kG.warn(e)})}},e.prototype.toApolloError=function(e){return(0,rg.O)(e.errors)?new ru.cA({graphQLErrors:e.errors}):e.error},e.prototype.getCurrentResult=function(){return this.result||this.handleErrorOrCompleted(this.result=this.observable.getCurrentResult()),this.result},e.prototype.toQueryResult=function(e){var t=this.toQueryResultCache.get(e);if(t)return t;var n=e.data,r=(e.partial,(0,n8._T)(e,["data","partial"]));return this.toQueryResultCache.set(e,t=(0,n8.pi)((0,n8.pi)((0,n8.pi)({data:n},r),this.obsQueryFields),{client:this.client,observable:this.observable,variables:this.observable.variables,called:!this.queryHookOptions.skip,previousData:this.previousData})),!t.error&&(0,rg.O)(e.errors)&&(t.error=new ru.cA({graphQLErrors:e.errors})),t},e.prototype.unsafeHandlePartialRefetch=function(e){e.partial&&this.queryHookOptions.partialRefetch&&!e.loading&&(!e.data||0===Object.keys(e.data).length)&&"cache-only"!==this.observable.options.fetchPolicy&&(Object.assign(e,{loading:!0,networkStatus:rc.I.refetch}),this.observable.refetch())},e}();function rE(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=Array(t);ne.length)&&(t=e.length);for(var n=0,r=Array(t);ne.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&void 0!==arguments[0]?arguments[0]:{};return ry(i$,e)},iG=function(){var e=iF(),t=parseInt(e.get("page")||"1",10),n=parseInt(e.get("per")||"50",10),r=iz({variables:{offset:(t-1)*n,limit:n},fetchPolicy:"network-only"}),i=r.data,a=r.loading,o=r.error;return a?l.createElement(ij,null):o?l.createElement(iN,{error:o}):i?l.createElement(iD,{chains:i.chains.results,page:t,pageSize:n,total:i.chains.metadata.total}):null},iW=n(67932),iK=n(8126),iV="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e};function iq(e){if(iZ())return Intl.DateTimeFormat.supportedLocalesOf(e)[0]}function iZ(){return("undefined"==typeof Intl?"undefined":iV(Intl))==="object"&&"function"==typeof Intl.DateTimeFormat}var iX="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e},iJ=function(){function e(e,t){for(var n=0;n=i.length)break;s=i[o++]}else{if((o=i.next()).done)break;s=o.value}var s,u=s;if((void 0===e?"undefined":iX(e))!=="object")return;e=e[u]}return e}},{key:"put",value:function(){for(var e=arguments.length,t=Array(e),n=0;n=o.length)break;c=o[u++]}else{if((u=o.next()).done)break;c=u.value}var c,l=c;"object"!==iX(a[l])&&(a[l]={}),a=a[l]}return a[i]=r}}]),e}();let i0=i1;var i2=new i0;function i3(e,t){if(!iZ())return function(e){return e.toString()};var n=i5(e),r=JSON.stringify(t),i=i2.get(String(n),r)||i2.put(String(n),r,new Intl.DateTimeFormat(n,t));return function(e){return i.format(e)}}var i4={};function i5(e){var t=e.toString();return i4[t]?i4[t]:i4[t]=iq(e)}var i6="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e};function i9(e){return i8(e)?e:new Date(e)}function i8(e){return e instanceof Date||i7(e)}function i7(e){return(void 0===e?"undefined":i6(e))==="object"&&"function"==typeof e.getTime}var ae=n(54087),at=n.n(ae);function an(e,t){if(0===e.length)return 0;for(var n=0,r=e.length-1,i=void 0;n<=r;){var a=t(e[i=Math.floor((r+n)/2)]);if(0===a)return i;if(a<0){if((n=i+1)>r)return n}else if((r=i-1)=t.nextUpdateTime)ao(t,this.instances);else break}},scheduleNextTick:function(){var e=this;this.scheduledTick=at()(function(){e.tick(),e.scheduleNextTick()})},start:function(){this.scheduleNextTick()},stop:function(){at().cancel(this.scheduledTick)}};function aa(e){var t=ar(e.getNextValue(),2),n=t[0],r=t[1];e.setValue(n),e.nextUpdateTime=r}function ao(e,t){aa(e),au(t,e),as(t,e)}function as(e,t){var n=ac(e,t);e.splice(n,0,t)}function au(e,t){var n=e.indexOf(t);e.splice(n,1)}function ac(e,t){var n=t.nextUpdateTime;return an(e,function(e){return e.nextUpdateTime===n?0:e.nextUpdateTime>n?1:-1})}var al=(0,ec.oneOfType)([(0,ec.shape)({minTime:ec.number,formatAs:ec.string.isRequired}),(0,ec.shape)({test:ec.func,formatAs:ec.string.isRequired}),(0,ec.shape)({minTime:ec.number,format:ec.func.isRequired}),(0,ec.shape)({test:ec.func,format:ec.func.isRequired})]),af=(0,ec.oneOfType)([ec.string,(0,ec.shape)({steps:(0,ec.arrayOf)(al).isRequired,labels:(0,ec.oneOfType)([ec.string,(0,ec.arrayOf)(ec.string)]).isRequired,round:ec.string})]),ad=Object.assign||function(e){for(var t=1;t=0)&&Object.prototype.hasOwnProperty.call(e,r)&&(n[r]=e[r]);return n}function ab(e){var t=e.date,n=e.future,r=e.timeStyle,i=e.round,a=e.minTimeLeft,o=e.tooltip,s=e.component,u=e.container,c=e.wrapperComponent,f=e.wrapperProps,d=e.locale,h=e.locales,p=e.formatVerboseDate,b=e.verboseDateFormat,m=e.updateInterval,g=e.tick,v=ap(e,["date","future","timeStyle","round","minTimeLeft","tooltip","component","container","wrapperComponent","wrapperProps","locale","locales","formatVerboseDate","verboseDateFormat","updateInterval","tick"]),y=(0,l.useMemo)(function(){return d&&(h=[d]),h.concat(iK.Z.getDefaultLocale())},[d,h]),w=(0,l.useMemo)(function(){return new iK.Z(y)},[y]);t=(0,l.useMemo)(function(){return i9(t)},[t]);var _=(0,l.useCallback)(function(){var e=Date.now(),o=void 0;if(n&&e>=t.getTime()&&(e=t.getTime(),o=!0),void 0!==a){var s=t.getTime()-1e3*a;e>s&&(e=s,o=!0)}var u=w.format(t,r,{getTimeToNextUpdate:!0,now:e,future:n,round:i}),c=ah(u,2),l=c[0],f=c[1];return f=o?av:m||f||6e4,[l,e+f]},[t,n,r,m,i,a,w]),E=(0,l.useRef)();E.current=_;var S=(0,l.useMemo)(_,[]),k=ah(S,2),x=k[0],T=k[1],M=(0,l.useState)(x),O=ah(M,2),A=O[0],L=O[1],C=ah((0,l.useState)(),2),I=C[0],D=C[1],N=(0,l.useRef)();(0,l.useEffect)(function(){if(g)return N.current=ai.add({getNextValue:function(){return E.current()},setValue:L,nextUpdateTime:T}),function(){return N.current.stop()}},[g]),(0,l.useEffect)(function(){if(N.current)N.current.forceUpdate();else{var e=_(),t=ah(e,1)[0];L(t)}},[_]),(0,l.useEffect)(function(){D(!0)},[]);var P=(0,l.useMemo)(function(){if("undefined"!=typeof window)return i3(y,b)},[y,b]),R=(0,l.useMemo)(function(){if("undefined"!=typeof window)return p?p(t):P(t)},[t,p,P]),j=l.createElement(s,ad({date:t,verboseDate:I?R:void 0,tooltip:o},v),A),F=c||u;return F?l.createElement(F,ad({},f,{verboseDate:I?R:void 0}),j):j}ab.propTypes={date:el().oneOfType([el().instanceOf(Date),el().number]).isRequired,locale:el().string,locales:el().arrayOf(el().string),future:el().bool,timeStyle:af,round:el().string,minTimeLeft:el().number,component:el().elementType.isRequired,tooltip:el().bool.isRequired,formatVerboseDate:el().func,verboseDateFormat:el().object,updateInterval:el().oneOfType([el().number,el().arrayOf(el().shape({threshold:el().number,interval:el().number.isRequired}))]),tick:el().bool,wrapperComponent:el().func,wrapperProps:el().object},ab.defaultProps={locales:[],component:ay,tooltip:!0,verboseDateFormat:{weekday:"long",day:"numeric",month:"long",year:"numeric",hour:"numeric",minute:"2-digit",second:"2-digit"},tick:!0},ab=l.memo(ab);let am=ab;var ag,av=31536e9;function ay(e){var t=e.date,n=e.verboseDate,r=e.tooltip,i=e.children,a=ap(e,["date","verboseDate","tooltip","children"]),o=(0,l.useMemo)(function(){return t.toISOString()},[t]);return l.createElement("time",ad({},a,{dateTime:o,title:r?n:void 0}),i)}ay.propTypes={date:el().instanceOf(Date).isRequired,verboseDate:el().string,tooltip:el().bool.isRequired,children:el().string.isRequired};var aw=n(30381),a_=n.n(aw),aE=n(31657);function aS(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function ak(e){for(var t=1;te.length)&&(t=e.length);for(var n=0,r=Array(t);ne.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&i[i.length-1])&&(6===a[0]||2===a[0])){o=0;continue}if(3===a[0]&&(!i||a[1]>i[0]&&a[1]0?new ru.cA({graphQLErrors:i}):void 0;if(u===s.current.mutationId&&!c.ignoreResults){var f={called:!0,loading:!1,data:r,error:l,client:a};s.current.isMounted&&!(0,ra.D)(s.current.result,f)&&o(s.current.result=f)}var d=e.onCompleted||(null===(n=s.current.options)||void 0===n?void 0:n.onCompleted);return null==d||d(t.data,c),t}).catch(function(t){if(u===s.current.mutationId&&s.current.isMounted){var n,r={loading:!1,error:t,data:void 0,called:!0,client:a};(0,ra.D)(s.current.result,r)||o(s.current.result=r)}var i=e.onError||(null===(n=s.current.options)||void 0===n?void 0:n.onError);if(i)return i(t,c),{data:void 0,errors:t};throw t})},[]),c=(0,l.useCallback)(function(){s.current.isMounted&&o({called:!1,loading:!1,client:n})},[]);return(0,l.useEffect)(function(){return s.current.isMounted=!0,function(){s.current.isMounted=!1}},[]),[u,(0,n8.pi)({reset:c},a)]}var ou=n(59067),oc=n(28428),ol=n(11186),of=n(78513);function od(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}var oh=function(e){return(0,b.createStyles)({paper:{display:"flex",margin:"".concat(2.5*e.spacing.unit,"px 0"),padding:"".concat(3*e.spacing.unit,"px ").concat(3.5*e.spacing.unit,"px")},content:{flex:1,width:"100%"},actions:od({marginTop:-(1.5*e.spacing.unit),marginLeft:-(4*e.spacing.unit)},e.breakpoints.up("sm"),{marginLeft:0,marginRight:-(1.5*e.spacing.unit)}),itemBlock:{border:"1px solid rgba(224, 224, 224, 1)",borderRadius:e.shape.borderRadius,padding:2*e.spacing.unit,marginTop:e.spacing.unit},itemBlockText:{overflowWrap:"anywhere"}})},op=(0,b.withStyles)(oh)(function(e){var t=e.actions,n=e.children,r=e.classes;return l.createElement(ia.default,{className:r.paper},l.createElement("div",{className:r.content},n),t&&l.createElement("div",{className:r.actions},t))}),ob=function(e){var t=e.title;return l.createElement(x.default,{variant:"subtitle2",gutterBottom:!0},t)},om=function(e){var t=e.children,n=e.value;return l.createElement(x.default,{variant:"body1",noWrap:!0},t||n)},og=(0,b.withStyles)(oh)(function(e){var t=e.children,n=e.classes,r=e.value;return l.createElement("div",{className:n.itemBlock},l.createElement(x.default,{variant:"body1",className:n.itemBlockText},t||r))});function ov(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=Array(t);ne.length)&&(t=e.length);for(var n=0,r=Array(t);ne.length)&&(t=e.length);for(var n=0,r=Array(t);ne.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&i[i.length-1])&&(6===a[0]||2===a[0])){o=0;continue}if(3===a[0]&&(!i||a[1]>i[0]&&a[1]-1}let sZ=sq;function sX(e,t){var n=this.__data__,r=s$(n,e);return r<0?(++this.size,n.push([e,t])):n[r][1]=t,this}let sJ=sX;function sQ(e){var t=-1,n=null==e?0:e.length;for(this.clear();++t-1&&e%1==0&&e-1&&e%1==0&&e<=cI}let cN=cD;var cP="[object Arguments]",cR="[object Array]",cj="[object Boolean]",cF="[object Date]",cY="[object Error]",cB="[object Function]",cU="[object Map]",cH="[object Number]",c$="[object Object]",cz="[object RegExp]",cG="[object Set]",cW="[object String]",cK="[object WeakMap]",cV="[object ArrayBuffer]",cq="[object DataView]",cZ="[object Float64Array]",cX="[object Int8Array]",cJ="[object Int16Array]",cQ="[object Int32Array]",c1="[object Uint8Array]",c0="[object Uint8ClampedArray]",c2="[object Uint16Array]",c3="[object Uint32Array]",c4={};function c5(e){return eD(e)&&cN(e.length)&&!!c4[eC(e)]}c4["[object Float32Array]"]=c4[cZ]=c4[cX]=c4[cJ]=c4[cQ]=c4[c1]=c4[c0]=c4[c2]=c4[c3]=!0,c4[cP]=c4[cR]=c4[cV]=c4[cj]=c4[cq]=c4[cF]=c4[cY]=c4[cB]=c4[cU]=c4[cH]=c4[c$]=c4[cz]=c4[cG]=c4[cW]=c4[cK]=!1;let c6=c5;function c9(e){return function(t){return e(t)}}let c8=c9;var c7=n(79730),le=c7.Z&&c7.Z.isTypedArray,lt=le?c8(le):c6;let ln=lt;var lr=Object.prototype.hasOwnProperty;function li(e,t){var n=cT(e),r=!n&&ck(e),i=!n&&!r&&(0,cM.Z)(e),a=!n&&!r&&!i&&ln(e),o=n||r||i||a,s=o?cm(e.length,String):[],u=s.length;for(var c in e)(t||lr.call(e,c))&&!(o&&("length"==c||i&&("offset"==c||"parent"==c)||a&&("buffer"==c||"byteLength"==c||"byteOffset"==c)||cC(c,u)))&&s.push(c);return s}let la=li;var lo=Object.prototype;function ls(e){var t=e&&e.constructor;return e===("function"==typeof t&&t.prototype||lo)}let lu=ls;var lc=sM(Object.keys,Object);let ll=lc;var lf=Object.prototype.hasOwnProperty;function ld(e){if(!lu(e))return ll(e);var t=[];for(var n in Object(e))lf.call(e,n)&&"constructor"!=n&&t.push(n);return t}let lh=ld;function lp(e){return null!=e&&cN(e.length)&&!ui(e)}let lb=lp;function lm(e){return lb(e)?la(e):lh(e)}let lg=lm;function lv(e,t){return e&&cp(t,lg(t),e)}let ly=lv;function lw(e){var t=[];if(null!=e)for(var n in Object(e))t.push(n);return t}let l_=lw;var lE=Object.prototype.hasOwnProperty;function lS(e){if(!ed(e))return l_(e);var t=lu(e),n=[];for(var r in e)"constructor"==r&&(t||!lE.call(e,r))||n.push(r);return n}let lk=lS;function lx(e){return lb(e)?la(e,!0):lk(e)}let lT=lx;function lM(e,t){return e&&cp(t,lT(t),e)}let lO=lM;var lA=n(42896);function lL(e,t){var n=-1,r=e.length;for(t||(t=Array(r));++n=0||(i[n]=e[n]);return i}function hc(e){if(void 0===e)throw ReferenceError("this hasn't been initialised - super() hasn't been called");return e}var hl=function(e){return Array.isArray(e)&&0===e.length},hf=function(e){return"function"==typeof e},hd=function(e){return null!==e&&"object"==typeof e},hh=function(e){return String(Math.floor(Number(e)))===e},hp=function(e){return"[object String]"===Object.prototype.toString.call(e)},hb=function(e){return 0===l.Children.count(e)},hm=function(e){return hd(e)&&hf(e.then)};function hg(e,t,n,r){void 0===r&&(r=0);for(var i=d8(t);e&&r=0?[]:{}}}return(0===a?e:i)[o[a]]===n?e:(void 0===n?delete i[o[a]]:i[o[a]]=n,0===a&&void 0===n&&delete r[o[a]],r)}function hy(e,t,n,r){void 0===n&&(n=new WeakMap),void 0===r&&(r={});for(var i=0,a=Object.keys(e);i0?t.map(function(t){return x(t,hg(e,t))}):[Promise.resolve("DO_NOT_DELETE_YOU_WILL_BE_FIRED")]).then(function(e){return e.reduce(function(e,n,r){return"DO_NOT_DELETE_YOU_WILL_BE_FIRED"===n||n&&(e=hv(e,t[r],n)),e},{})})},[x]),M=(0,l.useCallback)(function(e){return Promise.all([T(e),h.validationSchema?k(e):{},h.validate?S(e):{}]).then(function(e){var t=e[0],n=e[1],r=e[2];return sx.all([t,n,r],{arrayMerge:hC})})},[h.validate,h.validationSchema,T,S,k]),O=hP(function(e){return void 0===e&&(e=_.values),E({type:"SET_ISVALIDATING",payload:!0}),M(e).then(function(e){return v.current&&(E({type:"SET_ISVALIDATING",payload:!1}),sh()(_.errors,e)||E({type:"SET_ERRORS",payload:e})),e})});(0,l.useEffect)(function(){o&&!0===v.current&&sh()(p.current,h.initialValues)&&O(p.current)},[o,O]);var A=(0,l.useCallback)(function(e){var t=e&&e.values?e.values:p.current,n=e&&e.errors?e.errors:b.current?b.current:h.initialErrors||{},r=e&&e.touched?e.touched:m.current?m.current:h.initialTouched||{},i=e&&e.status?e.status:g.current?g.current:h.initialStatus;p.current=t,b.current=n,m.current=r,g.current=i;var a=function(){E({type:"RESET_FORM",payload:{isSubmitting:!!e&&!!e.isSubmitting,errors:n,touched:r,status:i,values:t,isValidating:!!e&&!!e.isValidating,submitCount:e&&e.submitCount&&"number"==typeof e.submitCount?e.submitCount:0}})};if(h.onReset){var o=h.onReset(_.values,V);hm(o)?o.then(a):a()}else a()},[h.initialErrors,h.initialStatus,h.initialTouched]);(0,l.useEffect)(function(){!0===v.current&&!sh()(p.current,h.initialValues)&&(c&&(p.current=h.initialValues,A()),o&&O(p.current))},[c,h.initialValues,A,o,O]),(0,l.useEffect)(function(){c&&!0===v.current&&!sh()(b.current,h.initialErrors)&&(b.current=h.initialErrors||hk,E({type:"SET_ERRORS",payload:h.initialErrors||hk}))},[c,h.initialErrors]),(0,l.useEffect)(function(){c&&!0===v.current&&!sh()(m.current,h.initialTouched)&&(m.current=h.initialTouched||hx,E({type:"SET_TOUCHED",payload:h.initialTouched||hx}))},[c,h.initialTouched]),(0,l.useEffect)(function(){c&&!0===v.current&&!sh()(g.current,h.initialStatus)&&(g.current=h.initialStatus,E({type:"SET_STATUS",payload:h.initialStatus}))},[c,h.initialStatus,h.initialTouched]);var L=hP(function(e){if(y.current[e]&&hf(y.current[e].validate)){var t=hg(_.values,e),n=y.current[e].validate(t);return hm(n)?(E({type:"SET_ISVALIDATING",payload:!0}),n.then(function(e){return e}).then(function(t){E({type:"SET_FIELD_ERROR",payload:{field:e,value:t}}),E({type:"SET_ISVALIDATING",payload:!1})})):(E({type:"SET_FIELD_ERROR",payload:{field:e,value:n}}),Promise.resolve(n))}return h.validationSchema?(E({type:"SET_ISVALIDATING",payload:!0}),k(_.values,e).then(function(e){return e}).then(function(t){E({type:"SET_FIELD_ERROR",payload:{field:e,value:t[e]}}),E({type:"SET_ISVALIDATING",payload:!1})})):Promise.resolve()}),C=(0,l.useCallback)(function(e,t){var n=t.validate;y.current[e]={validate:n}},[]),I=(0,l.useCallback)(function(e){delete y.current[e]},[]),D=hP(function(e,t){return E({type:"SET_TOUCHED",payload:e}),(void 0===t?i:t)?O(_.values):Promise.resolve()}),N=(0,l.useCallback)(function(e){E({type:"SET_ERRORS",payload:e})},[]),P=hP(function(e,t){var r=hf(e)?e(_.values):e;return E({type:"SET_VALUES",payload:r}),(void 0===t?n:t)?O(r):Promise.resolve()}),R=(0,l.useCallback)(function(e,t){E({type:"SET_FIELD_ERROR",payload:{field:e,value:t}})},[]),j=hP(function(e,t,r){return E({type:"SET_FIELD_VALUE",payload:{field:e,value:t}}),(void 0===r?n:r)?O(hv(_.values,e,t)):Promise.resolve()}),F=(0,l.useCallback)(function(e,t){var n,r=t,i=e;if(!hp(e)){e.persist&&e.persist();var a=e.target?e.target:e.currentTarget,o=a.type,s=a.name,u=a.id,c=a.value,l=a.checked,f=(a.outerHTML,a.options),d=a.multiple;r=t||s||u,i=/number|range/.test(o)?(n=parseFloat(c),isNaN(n)?"":n):/checkbox/.test(o)?hD(hg(_.values,r),l,c):d?hI(f):c}r&&j(r,i)},[j,_.values]),Y=hP(function(e){if(hp(e))return function(t){return F(t,e)};F(e)}),B=hP(function(e,t,n){return void 0===t&&(t=!0),E({type:"SET_FIELD_TOUCHED",payload:{field:e,value:t}}),(void 0===n?i:n)?O(_.values):Promise.resolve()}),U=(0,l.useCallback)(function(e,t){e.persist&&e.persist();var n,r=e.target,i=r.name,a=r.id;r.outerHTML,B(t||i||a,!0)},[B]),H=hP(function(e){if(hp(e))return function(t){return U(t,e)};U(e)}),$=(0,l.useCallback)(function(e){hf(e)?E({type:"SET_FORMIK_STATE",payload:e}):E({type:"SET_FORMIK_STATE",payload:function(){return e}})},[]),z=(0,l.useCallback)(function(e){E({type:"SET_STATUS",payload:e})},[]),G=(0,l.useCallback)(function(e){E({type:"SET_ISSUBMITTING",payload:e})},[]),W=hP(function(){return E({type:"SUBMIT_ATTEMPT"}),O().then(function(e){var t,n=e instanceof Error;if(!n&&0===Object.keys(e).length){try{if(void 0===(t=q()))return}catch(r){throw r}return Promise.resolve(t).then(function(e){return v.current&&E({type:"SUBMIT_SUCCESS"}),e}).catch(function(e){if(v.current)throw E({type:"SUBMIT_FAILURE"}),e})}if(v.current&&(E({type:"SUBMIT_FAILURE"}),n))throw e})}),K=hP(function(e){e&&e.preventDefault&&hf(e.preventDefault)&&e.preventDefault(),e&&e.stopPropagation&&hf(e.stopPropagation)&&e.stopPropagation(),W().catch(function(e){console.warn("Warning: An unhandled error was caught from submitForm()",e)})}),V={resetForm:A,validateForm:O,validateField:L,setErrors:N,setFieldError:R,setFieldTouched:B,setFieldValue:j,setStatus:z,setSubmitting:G,setTouched:D,setValues:P,setFormikState:$,submitForm:W},q=hP(function(){return f(_.values,V)}),Z=hP(function(e){e&&e.preventDefault&&hf(e.preventDefault)&&e.preventDefault(),e&&e.stopPropagation&&hf(e.stopPropagation)&&e.stopPropagation(),A()}),X=(0,l.useCallback)(function(e){return{value:hg(_.values,e),error:hg(_.errors,e),touched:!!hg(_.touched,e),initialValue:hg(p.current,e),initialTouched:!!hg(m.current,e),initialError:hg(b.current,e)}},[_.errors,_.touched,_.values]),J=(0,l.useCallback)(function(e){return{setValue:function(t,n){return j(e,t,n)},setTouched:function(t,n){return B(e,t,n)},setError:function(t){return R(e,t)}}},[j,B,R]),Q=(0,l.useCallback)(function(e){var t=hd(e),n=t?e.name:e,r=hg(_.values,n),i={name:n,value:r,onChange:Y,onBlur:H};if(t){var a=e.type,o=e.value,s=e.as,u=e.multiple;"checkbox"===a?void 0===o?i.checked=!!r:(i.checked=!!(Array.isArray(r)&&~r.indexOf(o)),i.value=o):"radio"===a?(i.checked=r===o,i.value=o):"select"===s&&u&&(i.value=i.value||[],i.multiple=!0)}return i},[H,Y,_.values]),ee=(0,l.useMemo)(function(){return!sh()(p.current,_.values)},[p.current,_.values]),et=(0,l.useMemo)(function(){return void 0!==s?ee?_.errors&&0===Object.keys(_.errors).length:!1!==s&&hf(s)?s(h):s:_.errors&&0===Object.keys(_.errors).length},[s,ee,_.errors,h]);return ho({},_,{initialValues:p.current,initialErrors:b.current,initialTouched:m.current,initialStatus:g.current,handleBlur:H,handleChange:Y,handleReset:Z,handleSubmit:K,resetForm:A,setErrors:N,setFormikState:$,setFieldTouched:B,setFieldValue:j,setFieldError:R,setStatus:z,setSubmitting:G,setTouched:D,setValues:P,submitForm:W,validateForm:O,validateField:L,isValid:et,dirty:ee,unregisterField:I,registerField:C,getFieldProps:Q,getFieldMeta:X,getFieldHelpers:J,validateOnBlur:i,validateOnChange:n,validateOnMount:o})}function hM(e){var t=hT(e),n=e.component,r=e.children,i=e.render,a=e.innerRef;return(0,l.useImperativeHandle)(a,function(){return t}),(0,l.createElement)(h_,{value:t},n?(0,l.createElement)(n,t):i?i(t):r?hf(r)?r(t):hb(r)?null:l.Children.only(r):null)}function hO(e){var t={};if(e.inner){if(0===e.inner.length)return hv(t,e.path,e.message);for(var n=e.inner,r=Array.isArray(n),i=0,n=r?n:n[Symbol.iterator]();;){if(r){if(i>=n.length)break;a=n[i++]}else{if((i=n.next()).done)break;a=i.value}var a,o=a;hg(t,o.path)||(t=hv(t,o.path,o.message))}}return t}function hA(e,t,n,r){void 0===n&&(n=!1),void 0===r&&(r={});var i=hL(e);return t[n?"validateSync":"validate"](i,{abortEarly:!1,context:r})}function hL(e){var t=Array.isArray(e)?[]:{};for(var n in e)if(Object.prototype.hasOwnProperty.call(e,n)){var r=String(n);!0===Array.isArray(e[r])?t[r]=e[r].map(function(e){return!0===Array.isArray(e)||sj(e)?hL(e):""!==e?e:void 0}):sj(e[r])?t[r]=hL(e[r]):t[r]=""!==e[r]?e[r]:void 0}return t}function hC(e,t,n){var r=e.slice();return t.forEach(function(t,i){if(void 0===r[i]){var a=!1!==n.clone&&n.isMergeableObject(t);r[i]=a?sx(Array.isArray(t)?[]:{},t,n):t}else n.isMergeableObject(t)?r[i]=sx(e[i],t,n):-1===e.indexOf(t)&&r.push(t)}),r}function hI(e){return Array.from(e).filter(function(e){return e.selected}).map(function(e){return e.value})}function hD(e,t,n){if("boolean"==typeof e)return Boolean(t);var r=[],i=!1,a=-1;if(Array.isArray(e))r=e,i=(a=e.indexOf(n))>=0;else if(!n||"true"==n||"false"==n)return Boolean(t);return t&&n&&!i?r.concat(n):i?r.slice(0,a).concat(r.slice(a+1)):r}var hN="undefined"!=typeof window&&void 0!==window.document&&void 0!==window.document.createElement?l.useLayoutEffect:l.useEffect;function hP(e){var t=(0,l.useRef)(e);return hN(function(){t.current=e}),(0,l.useCallback)(function(){for(var e=arguments.length,n=Array(e),r=0;re?t:e},0);return Array.from(ho({},e,{length:t+1}))};(function(e){function t(t){var n;return(n=e.call(this,t)||this).updateArrayField=function(e,t,r){var i=n.props,a=i.name;(0,i.formik.setFormikState)(function(n){var i="function"==typeof r?r:e,o="function"==typeof t?t:e,s=hv(n.values,a,e(hg(n.values,a))),u=r?i(hg(n.errors,a)):void 0,c=t?o(hg(n.touched,a)):void 0;return hl(u)&&(u=void 0),hl(c)&&(c=void 0),ho({},n,{values:s,errors:r?hv(n.errors,a,u):n.errors,touched:t?hv(n.touched,a,c):n.touched})})},n.push=function(e){return n.updateArrayField(function(t){return[].concat(hH(t),[ha(e)])},!1,!1)},n.handlePush=function(e){return function(){return n.push(e)}},n.swap=function(e,t){return n.updateArrayField(function(n){return hY(n,e,t)},!0,!0)},n.handleSwap=function(e,t){return function(){return n.swap(e,t)}},n.move=function(e,t){return n.updateArrayField(function(n){return hF(n,e,t)},!0,!0)},n.handleMove=function(e,t){return function(){return n.move(e,t)}},n.insert=function(e,t){return n.updateArrayField(function(n){return hB(n,e,t)},function(t){return hB(t,e,null)},function(t){return hB(t,e,null)})},n.handleInsert=function(e,t){return function(){return n.insert(e,t)}},n.replace=function(e,t){return n.updateArrayField(function(n){return hU(n,e,t)},!1,!1)},n.handleReplace=function(e,t){return function(){return n.replace(e,t)}},n.unshift=function(e){var t=-1;return n.updateArrayField(function(n){var r=n?[e].concat(n):[e];return t<0&&(t=r.length),r},function(e){var n=e?[null].concat(e):[null];return t<0&&(t=n.length),n},function(e){var n=e?[null].concat(e):[null];return t<0&&(t=n.length),n}),t},n.handleUnshift=function(e){return function(){return n.unshift(e)}},n.handleRemove=function(e){return function(){return n.remove(e)}},n.handlePop=function(){return function(){return n.pop()}},n.remove=n.remove.bind(hc(n)),n.pop=n.pop.bind(hc(n)),n}hs(t,e);var n=t.prototype;return n.componentDidUpdate=function(e){this.props.validateOnChange&&this.props.formik.validateOnChange&&!sh()(hg(e.formik.values,e.name),hg(this.props.formik.values,this.props.name))&&this.props.formik.validateForm(this.props.formik.values)},n.remove=function(e){var t;return this.updateArrayField(function(n){var r=n?hH(n):[];return t||(t=r[e]),hf(r.splice)&&r.splice(e,1),r},!0,!0),t},n.pop=function(){var e;return this.updateArrayField(function(t){var n=t;return e||(e=n&&n.pop&&n.pop()),n},!0,!0),e},n.render=function(){var e={push:this.push,pop:this.pop,swap:this.swap,move:this.move,insert:this.insert,replace:this.replace,unshift:this.unshift,remove:this.remove,handlePush:this.handlePush,handlePop:this.handlePop,handleSwap:this.handleSwap,handleMove:this.handleMove,handleInsert:this.handleInsert,handleReplace:this.handleReplace,handleUnshift:this.handleUnshift,handleRemove:this.handleRemove},t=this.props,n=t.component,r=t.render,i=t.children,a=t.name,o=hu(t.formik,["validate","validationSchema"]),s=ho({},e,{form:o,name:a});return n?(0,l.createElement)(n,s):r?r(s):i?"function"==typeof i?i(s):hb(i)?null:l.Children.only(i):null},t})(l.Component).defaultProps={validateOnChange:!0},l.Component,l.Component;var h$=n(24802),hz=n(71209),hG=n(91750),hW=n(11970),hK=n(4689),hV=n(67598),hq=function(){return(hq=Object.assign||function(e){for(var t,n=1,r=arguments.length;nt.indexOf(r)&&(n[r]=e[r]);if(null!=e&&"function"==typeof Object.getOwnPropertySymbols)for(var i=0,r=Object.getOwnPropertySymbols(e);it.indexOf(r[i])&&(n[r[i]]=e[r[i]]);return n}function hX(e){var t=e.disabled,n=e.field,r=n.onBlur,i=hZ(n,["onBlur"]),a=e.form,o=a.isSubmitting,s=a.touched,u=a.errors,c=e.onBlur,l=e.helperText,f=hZ(e,["disabled","field","form","onBlur","helperText"]),d=hg(u,i.name),h=hg(s,i.name)&&!!d;return hq(hq({variant:f.variant,error:h,helperText:h?d:l,disabled:null!=t?t:o,onBlur:null!=c?c:function(e){r(null!=e?e:i.name)}},i),f)}function hJ(e){var t=e.children,n=hZ(e,["children"]);return(0,l.createElement)(i_.Z,hq({},hX(n)),t)}function hQ(e){var t=e.disabled,n=e.field,r=n.onBlur,i=hZ(n,["onBlur"]),a=e.form.isSubmitting,o=(e.type,e.onBlur),s=hZ(e,["disabled","field","form","type","onBlur"]);return hq(hq({disabled:null!=t?t:a,onBlur:null!=o?o:function(e){r(null!=e?e:i.name)}},i),s)}function h1(e){return(0,l.createElement)(h$.Z,hq({},hQ(e)))}function h0(e){var t,n=e.disabled,r=e.field,i=r.onBlur,a=hZ(r,["onBlur"]),o=e.form.isSubmitting,s=(e.type,e.onBlur),u=hZ(e,["disabled","field","form","type","onBlur"]);return hq(hq({disabled:null!=n?n:o,indeterminate:!Array.isArray(a.value)&&null==a.value,onBlur:null!=s?s:function(e){i(null!=e?e:a.name)}},a),u)}function h2(e){return(0,l.createElement)(hz.Z,hq({},h0(e)))}function h3(e){var t=e.Label,n=hZ(e,["Label"]);return(0,l.createElement)(hG.Z,hq({control:(0,l.createElement)(hz.Z,hq({},h0(n)))},t))}function h4(e){var t=e.disabled,n=e.field,r=n.onBlur,i=hZ(n,["onBlur"]),a=e.form.isSubmitting,o=e.onBlur,s=hZ(e,["disabled","field","form","onBlur"]);return hq(hq({disabled:null!=t?t:a,onBlur:null!=o?o:function(e){r(null!=e?e:i.name)}},i),s)}function h5(e){return(0,l.createElement)(hW.default,hq({},h4(e)))}function h6(e){var t=e.field,n=t.onBlur,r=hZ(t,["onBlur"]),i=(e.form,e.onBlur),a=hZ(e,["field","form","onBlur"]);return hq(hq({onBlur:null!=i?i:function(e){n(null!=e?e:r.name)}},r),a)}function h9(e){return(0,l.createElement)(hK.Z,hq({},h6(e)))}function h8(e){var t=e.disabled,n=e.field,r=n.onBlur,i=hZ(n,["onBlur"]),a=e.form.isSubmitting,o=e.onBlur,s=hZ(e,["disabled","field","form","onBlur"]);return hq(hq({disabled:null!=t?t:a,onBlur:null!=o?o:function(e){r(null!=e?e:i.name)}},i),s)}function h7(e){return(0,l.createElement)(hV.default,hq({},h8(e)))}hJ.displayName="FormikMaterialUITextField",h1.displayName="FormikMaterialUISwitch",h2.displayName="FormikMaterialUICheckbox",h3.displayName="FormikMaterialUICheckboxWithLabel",h5.displayName="FormikMaterialUISelect",h9.displayName="FormikMaterialUIRadioGroup",h7.displayName="FormikMaterialUIInputBase";try{a=Map}catch(pe){}try{o=Set}catch(pt){}function pn(e,t,n){if(!e||"object"!=typeof e||"function"==typeof e)return e;if(e.nodeType&&"cloneNode"in e)return e.cloneNode(!0);if(e instanceof Date)return new Date(e.getTime());if(e instanceof RegExp)return RegExp(e);if(Array.isArray(e))return e.map(pr);if(a&&e instanceof a)return new Map(Array.from(e.entries()));if(o&&e instanceof o)return new Set(Array.from(e.values()));if(e instanceof Object){t.push(e);var r=Object.create(e);for(var i in n.push(r),e){var s=t.findIndex(function(t){return t===e[i]});r[i]=s>-1?n[s]:pn(e[i],t,n)}return r}return e}function pr(e){return pn(e,[],[])}let pi=Object.prototype.toString,pa=Error.prototype.toString,po=RegExp.prototype.toString,ps="undefined"!=typeof Symbol?Symbol.prototype.toString:()=>"",pu=/^Symbol\((.*)\)(.*)$/;function pc(e){if(e!=+e)return"NaN";let t=0===e&&1/e<0;return t?"-0":""+e}function pl(e,t=!1){if(null==e||!0===e||!1===e)return""+e;let n=typeof e;if("number"===n)return pc(e);if("string"===n)return t?`"${e}"`:e;if("function"===n)return"[Function "+(e.name||"anonymous")+"]";if("symbol"===n)return ps.call(e).replace(pu,"Symbol($1)");let r=pi.call(e).slice(8,-1);return"Date"===r?isNaN(e.getTime())?""+e:e.toISOString(e):"Error"===r||e instanceof Error?"["+pa.call(e)+"]":"RegExp"===r?po.call(e):null}function pf(e,t){let n=pl(e,t);return null!==n?n:JSON.stringify(e,function(e,n){let r=pl(this[e],t);return null!==r?r:n},2)}let pd={default:"${path} is invalid",required:"${path} is a required field",oneOf:"${path} must be one of the following values: ${values}",notOneOf:"${path} must not be one of the following values: ${values}",notType({path:e,type:t,value:n,originalValue:r}){let i=null!=r&&r!==n,a=`${e} must be a \`${t}\` type, but the final value was: \`${pf(n,!0)}\``+(i?` (cast from the value \`${pf(r,!0)}\`).`:".");return null===n&&(a+='\n If "null" is intended as an empty value be sure to mark the schema as `.nullable()`'),a},defined:"${path} must be defined"},ph={length:"${path} must be exactly ${length} characters",min:"${path} must be at least ${min} characters",max:"${path} must be at most ${max} characters",matches:'${path} must match the following: "${regex}"',email:"${path} must be a valid email",url:"${path} must be a valid URL",uuid:"${path} must be a valid UUID",trim:"${path} must be a trimmed string",lowercase:"${path} must be a lowercase string",uppercase:"${path} must be a upper case string"},pp={min:"${path} must be greater than or equal to ${min}",max:"${path} must be less than or equal to ${max}",lessThan:"${path} must be less than ${less}",moreThan:"${path} must be greater than ${more}",positive:"${path} must be a positive number",negative:"${path} must be a negative number",integer:"${path} must be an integer"},pb={min:"${path} field must be later than ${min}",max:"${path} field must be at earlier than ${max}"},pm={isValue:"${path} field must be ${value}"},pg={noUnknown:"${path} field has unspecified keys: ${unknown}"},pv={min:"${path} field must have at least ${min} items",max:"${path} field must have less than or equal to ${max} items",length:"${path} must be have ${length} items"};Object.assign(Object.create(null),{mixed:pd,string:ph,number:pp,date:pb,object:pg,array:pv,boolean:pm});var py=n(18721),pw=n.n(py);let p_=e=>e&&e.__isYupSchema__;class pE{constructor(e,t){if(this.refs=e,this.refs=e,"function"==typeof t){this.fn=t;return}if(!pw()(t,"is"))throw TypeError("`is:` is required for `when()` conditions");if(!t.then&&!t.otherwise)throw TypeError("either `then:` or `otherwise:` is required for `when()` conditions");let{is:n,then:r,otherwise:i}=t,a="function"==typeof n?n:(...e)=>e.every(e=>e===n);this.fn=function(...e){let t=e.pop(),n=e.pop(),o=a(...e)?r:i;if(o)return"function"==typeof o?o(n):n.concat(o.resolve(t))}}resolve(e,t){let n=this.refs.map(e=>e.getValue(null==t?void 0:t.value,null==t?void 0:t.parent,null==t?void 0:t.context)),r=this.fn.apply(e,n.concat(e,t));if(void 0===r||r===e)return e;if(!p_(r))throw TypeError("conditions must return a schema object");return r.resolve(t)}}let pS=pE;function pk(e){return null==e?[]:[].concat(e)}function px(){return(px=Object.assign||function(e){for(var t=1;tpf(t[n])):"function"==typeof e?e(t):e}static isError(e){return e&&"ValidationError"===e.name}constructor(e,t,n,r){super(),this.name="ValidationError",this.value=t,this.path=n,this.type=r,this.errors=[],this.inner=[],pk(e).forEach(e=>{pM.isError(e)?(this.errors.push(...e.errors),this.inner=this.inner.concat(e.inner.length?e.inner:e)):this.errors.push(e)}),this.message=this.errors.length>1?`${this.errors.length} errors occurred`:this.errors[0],Error.captureStackTrace&&Error.captureStackTrace(this,pM)}}let pO=e=>{let t=!1;return(...n)=>{t||(t=!0,e(...n))}};function pA(e,t){let{endEarly:n,tests:r,args:i,value:a,errors:o,sort:s,path:u}=e,c=pO(t),l=r.length,f=[];if(o=o||[],!l)return o.length?c(new pM(o,a,u)):c(null,a);for(let d=0;d=0||(i[n]=e[n]);return i}function pj(e){function t(t,n){let{value:r,path:i="",label:a,options:o,originalValue:s,sync:u}=t,c=pR(t,["value","path","label","options","originalValue","sync"]),{name:l,test:f,params:d,message:h}=e,{parent:p,context:b}=o;function m(e){return pN.isRef(e)?e.getValue(r,p,b):e}function g(e={}){let t=pC()(pP({value:r,originalValue:s,label:a,path:e.path||i},d,e.params),m),n=new pM(pM.formatError(e.message||h,t),r,t.path,e.type||l);return n.params=t,n}let v=pP({path:i,parent:p,type:l,createError:g,resolve:m,options:o,originalValue:s},c);if(!u){try{Promise.resolve(f.call(v,r,v)).then(e=>{pM.isError(e)?n(e):e?n(null,e):n(g())})}catch(y){n(y)}return}let w;try{var _;if(w=f.call(v,r,v),"function"==typeof(null==(_=w)?void 0:_.then))throw Error(`Validation test of type: "${v.type}" returned a Promise during a synchronous validate. This test will finish after the validate call has returned`)}catch(E){n(E);return}pM.isError(w)?n(w):w?n(null,w):n(g())}return t.OPTIONS=e,t}pN.prototype.__isYupRef=!0;let pF=e=>e.substr(0,e.length-1).substr(1);function pY(e,t,n,r=n){let i,a,o;return t?((0,pI.forEach)(t,(s,u,c)=>{let l=u?pF(s):s;if((e=e.resolve({context:r,parent:i,value:n})).innerType){let f=c?parseInt(l,10):0;if(n&&f>=n.length)throw Error(`Yup.reach cannot resolve an array item at index: ${s}, in the path: ${t}. because there is no value at that index. `);i=n,n=n&&n[f],e=e.innerType}if(!c){if(!e.fields||!e.fields[l])throw Error(`The schema does not contain the path: ${t}. (failed at: ${o} which is a type: "${e._type}")`);i=n,n=n&&n[l],e=e.fields[l]}a=l,o=u?"["+s+"]":"."+s}),{schema:e,parent:i,parentPath:a}):{parent:i,parentPath:t,schema:e}}class pB{constructor(){this.list=new Set,this.refs=new Map}get size(){return this.list.size+this.refs.size}describe(){let e=[];for(let t of this.list)e.push(t);for(let[,n]of this.refs)e.push(n.describe());return e}toArray(){return Array.from(this.list).concat(Array.from(this.refs.values()))}add(e){pN.isRef(e)?this.refs.set(e.key,e):this.list.add(e)}delete(e){pN.isRef(e)?this.refs.delete(e.key):this.list.delete(e)}has(e,t){if(this.list.has(e))return!0;let n,r=this.refs.values();for(;!(n=r.next()).done;)if(t(n.value)===e)return!0;return!1}clone(){let e=new pB;return e.list=new Set(this.list),e.refs=new Map(this.refs),e}merge(e,t){let n=this.clone();return e.list.forEach(e=>n.add(e)),e.refs.forEach(e=>n.add(e)),t.list.forEach(e=>n.delete(e)),t.refs.forEach(e=>n.delete(e)),n}}function pU(){return(pU=Object.assign||function(e){for(var t=1;t{this.typeError(pd.notType)}),this.type=(null==e?void 0:e.type)||"mixed",this.spec=pU({strip:!1,strict:!1,abortEarly:!0,recursive:!0,nullable:!1,presence:"optional"},null==e?void 0:e.spec)}get _type(){return this.type}_typeCheck(e){return!0}clone(e){if(this._mutate)return e&&Object.assign(this.spec,e),this;let t=Object.create(Object.getPrototypeOf(this));return t.type=this.type,t._typeError=this._typeError,t._whitelistError=this._whitelistError,t._blacklistError=this._blacklistError,t._whitelist=this._whitelist.clone(),t._blacklist=this._blacklist.clone(),t.exclusiveTests=pU({},this.exclusiveTests),t.deps=[...this.deps],t.conditions=[...this.conditions],t.tests=[...this.tests],t.transforms=[...this.transforms],t.spec=pr(pU({},this.spec,e)),t}label(e){var t=this.clone();return t.spec.label=e,t}meta(...e){if(0===e.length)return this.spec.meta;let t=this.clone();return t.spec.meta=Object.assign(t.spec.meta||{},e[0]),t}withMutation(e){let t=this._mutate;this._mutate=!0;let n=e(this);return this._mutate=t,n}concat(e){if(!e||e===this)return this;if(e.type!==this.type&&"mixed"!==this.type)throw TypeError(`You cannot \`concat()\` schema's of different types: ${this.type} and ${e.type}`);let t=this,n=e.clone(),r=pU({},t.spec,n.spec);return n.spec=r,n._typeError||(n._typeError=t._typeError),n._whitelistError||(n._whitelistError=t._whitelistError),n._blacklistError||(n._blacklistError=t._blacklistError),n._whitelist=t._whitelist.merge(e._whitelist,e._blacklist),n._blacklist=t._blacklist.merge(e._blacklist,e._whitelist),n.tests=t.tests,n.exclusiveTests=t.exclusiveTests,n.withMutation(t=>{e.tests.forEach(e=>{t.test(e.OPTIONS)})}),n}isType(e){return!!this.spec.nullable&&null===e||this._typeCheck(e)}resolve(e){let t=this;if(t.conditions.length){let n=t.conditions;(t=t.clone()).conditions=[],t=(t=n.reduce((t,n)=>n.resolve(t,e),t)).resolve(e)}return t}cast(e,t={}){let n=this.resolve(pU({value:e},t)),r=n._cast(e,t);if(void 0!==e&&!1!==t.assert&&!0!==n.isType(r)){let i=pf(e),a=pf(r);throw TypeError(`The value of ${t.path||"field"} could not be cast to a value that satisfies the schema type: "${n._type}". + */ Object.defineProperty(t,"__esModule",{value:!0}),"undefined"==typeof window||"function"!=typeof MessageChannel){var n,r,i,a,o,s=null,u=null,c=function(){if(null!==s)try{var e=t.unstable_now();s(!0,e),s=null}catch(n){throw setTimeout(c,0),n}},l=Date.now();t.unstable_now=function(){return Date.now()-l},n=function(e){null!==s?setTimeout(n,0,e):(s=e,setTimeout(c,0))},r=function(e,t){u=setTimeout(e,t)},i=function(){clearTimeout(u)},a=function(){return!1},o=t.unstable_forceFrameRate=function(){}}else{var f=window.performance,d=window.Date,h=window.setTimeout,p=window.clearTimeout;if("undefined"!=typeof console){var b=window.cancelAnimationFrame;"function"!=typeof window.requestAnimationFrame&&console.error("This browser doesn't support requestAnimationFrame. Make sure that you load a polyfill in older browsers. https://fb.me/react-polyfills"),"function"!=typeof b&&console.error("This browser doesn't support cancelAnimationFrame. Make sure that you load a polyfill in older browsers. https://fb.me/react-polyfills")}if("object"==typeof f&&"function"==typeof f.now)t.unstable_now=function(){return f.now()};else{var m=d.now();t.unstable_now=function(){return d.now()-m}}var g=!1,v=null,y=-1,w=5,_=0;a=function(){return t.unstable_now()>=_},o=function(){},t.unstable_forceFrameRate=function(e){0>e||125M(o,n))void 0!==u&&0>M(u,o)?(e[r]=u,e[s]=n,r=s):(e[r]=o,e[a]=n,r=a);else if(void 0!==u&&0>M(u,n))e[r]=u,e[s]=n,r=s;else break a}}return t}return null}function M(e,t){var n=e.sortIndex-t.sortIndex;return 0!==n?n:e.id-t.id}var O=[],A=[],L=1,C=null,I=3,D=!1,N=!1,P=!1;function R(e){for(var t=x(A);null!==t;){if(null===t.callback)T(A);else if(t.startTime<=e)T(A),t.sortIndex=t.expirationTime,k(O,t);else break;t=x(A)}}function j(e){if(P=!1,R(e),!N){if(null!==x(O))N=!0,n(F);else{var t=x(A);null!==t&&r(j,t.startTime-e)}}}function F(e,n){N=!1,P&&(P=!1,i()),D=!0;var o=I;try{for(R(n),C=x(O);null!==C&&(!(C.expirationTime>n)||e&&!a());){var s=C.callback;if(null!==s){C.callback=null,I=C.priorityLevel;var u=s(C.expirationTime<=n);n=t.unstable_now(),"function"==typeof u?C.callback=u:C===x(O)&&T(O),R(n)}else T(O);C=x(O)}if(null!==C)var c=!0;else{var l=x(A);null!==l&&r(j,l.startTime-n),c=!1}return c}finally{C=null,I=o,D=!1}}function Y(e){switch(e){case 1:return -1;case 2:return 250;case 5:return 1073741823;case 4:return 1e4;default:return 5e3}}var B=o;t.unstable_ImmediatePriority=1,t.unstable_UserBlockingPriority=2,t.unstable_NormalPriority=3,t.unstable_IdlePriority=5,t.unstable_LowPriority=4,t.unstable_runWithPriority=function(e,t){switch(e){case 1:case 2:case 3:case 4:case 5:break;default:e=3}var n=I;I=e;try{return t()}finally{I=n}},t.unstable_next=function(e){switch(I){case 1:case 2:case 3:var t=3;break;default:t=I}var n=I;I=t;try{return e()}finally{I=n}},t.unstable_scheduleCallback=function(e,a,o){var s=t.unstable_now();if("object"==typeof o&&null!==o){var u=o.delay;u="number"==typeof u&&0s?(e.sortIndex=u,k(A,e),null===x(O)&&e===x(A)&&(P?i():P=!0,r(j,u-s))):(e.sortIndex=o,k(O,e),N||D||(N=!0,n(F))),e},t.unstable_cancelCallback=function(e){e.callback=null},t.unstable_wrapCallback=function(e){var t=I;return function(){var n=I;I=t;try{return e.apply(this,arguments)}finally{I=n}}},t.unstable_getCurrentPriorityLevel=function(){return I},t.unstable_shouldYield=function(){var e=t.unstable_now();R(e);var n=x(O);return n!==C&&null!==C&&null!==n&&null!==n.callback&&n.startTime<=e&&n.expirationTime>5==6?2:e>>4==14?3:e>>3==30?4:e>>6==2?-1:-2}function c(e,t,n){var r=t.length-1;if(r=0?(i>0&&(e.lastNeed=i-1),i):--r=0?(i>0&&(e.lastNeed=i-2),i):--r=0?(i>0&&(2===i?i=0:e.lastNeed=i-3),i):0}function l(e,t,n){if((192&t[0])!=128)return e.lastNeed=0,"�";if(e.lastNeed>1&&t.length>1){if((192&t[1])!=128)return e.lastNeed=1,"�";if(e.lastNeed>2&&t.length>2&&(192&t[2])!=128)return e.lastNeed=2,"�"}}function f(e){var t=this.lastTotal-this.lastNeed,n=l(this,e,t);return void 0!==n?n:this.lastNeed<=e.length?(e.copy(this.lastChar,t,0,this.lastNeed),this.lastChar.toString(this.encoding,0,this.lastTotal)):void(e.copy(this.lastChar,t,0,e.length),this.lastNeed-=e.length)}function d(e,t){var n=c(this,e,t);if(!this.lastNeed)return e.toString("utf8",t);this.lastTotal=n;var r=e.length-(n-this.lastNeed);return e.copy(this.lastChar,0,r),e.toString("utf8",t,r)}function h(e){var t=e&&e.length?this.write(e):"";return this.lastNeed?t+"�":t}function p(e,t){if((e.length-t)%2==0){var n=e.toString("utf16le",t);if(n){var r=n.charCodeAt(n.length-1);if(r>=55296&&r<=56319)return this.lastNeed=2,this.lastTotal=4,this.lastChar[0]=e[e.length-2],this.lastChar[1]=e[e.length-1],n.slice(0,-1)}return n}return this.lastNeed=1,this.lastTotal=2,this.lastChar[0]=e[e.length-1],e.toString("utf16le",t,e.length-1)}function b(e){var t=e&&e.length?this.write(e):"";if(this.lastNeed){var n=this.lastTotal-this.lastNeed;return t+this.lastChar.toString("utf16le",0,n)}return t}function m(e,t){var n=(e.length-t)%3;return 0===n?e.toString("base64",t):(this.lastNeed=3-n,this.lastTotal=3,1===n?this.lastChar[0]=e[e.length-1]:(this.lastChar[0]=e[e.length-2],this.lastChar[1]=e[e.length-1]),e.toString("base64",t,e.length-n))}function g(e){var t=e&&e.length?this.write(e):"";return this.lastNeed?t+this.lastChar.toString("base64",0,3-this.lastNeed):t}function v(e){return e.toString(this.encoding)}function y(e){return e&&e.length?this.write(e):""}t.s=s,s.prototype.write=function(e){var t,n;if(0===e.length)return"";if(this.lastNeed){if(void 0===(t=this.fillLast(e)))return"";n=this.lastNeed,this.lastNeed=0}else n=0;return nOF});var r,i,a,o,s,u,c,l=n(67294),f=n.t(l,2),d=n(97779),h=n(47886),p=n(57209),b=n(32316),m=n(95880),g=n(17051),v=n(71381),y=n(81701),w=n(3022),_=n(60323),E=n(87591),S=n(25649),k=n(28902),x=n(71426),T=n(48884),M=n(94184),O=n.n(M),A=n(55977),L=n(73935),C=function(){if("undefined"!=typeof Map)return Map;function e(e,t){var n=-1;return e.some(function(e,r){return e[0]===t&&(n=r,!0)}),n}return function(){function t(){this.__entries__=[]}return Object.defineProperty(t.prototype,"size",{get:function(){return this.__entries__.length},enumerable:!0,configurable:!0}),t.prototype.get=function(t){var n=e(this.__entries__,t),r=this.__entries__[n];return r&&r[1]},t.prototype.set=function(t,n){var r=e(this.__entries__,t);~r?this.__entries__[r][1]=n:this.__entries__.push([t,n])},t.prototype.delete=function(t){var n=this.__entries__,r=e(n,t);~r&&n.splice(r,1)},t.prototype.has=function(t){return!!~e(this.__entries__,t)},t.prototype.clear=function(){this.__entries__.splice(0)},t.prototype.forEach=function(e,t){void 0===t&&(t=null);for(var n=0,r=this.__entries__;n0},e.prototype.connect_=function(){I&&!this.connected_&&(document.addEventListener("transitionend",this.onTransitionEnd_),window.addEventListener("resize",this.refresh),Y?(this.mutationsObserver_=new MutationObserver(this.refresh),this.mutationsObserver_.observe(document,{attributes:!0,childList:!0,characterData:!0,subtree:!0})):(document.addEventListener("DOMSubtreeModified",this.refresh),this.mutationEventsAdded_=!0),this.connected_=!0)},e.prototype.disconnect_=function(){I&&this.connected_&&(document.removeEventListener("transitionend",this.onTransitionEnd_),window.removeEventListener("resize",this.refresh),this.mutationsObserver_&&this.mutationsObserver_.disconnect(),this.mutationEventsAdded_&&document.removeEventListener("DOMSubtreeModified",this.refresh),this.mutationsObserver_=null,this.mutationEventsAdded_=!1,this.connected_=!1)},e.prototype.onTransitionEnd_=function(e){var t=e.propertyName,n=void 0===t?"":t;F.some(function(e){return!!~n.indexOf(e)})&&this.refresh()},e.getInstance=function(){return this.instance_||(this.instance_=new e),this.instance_},e.instance_=null,e}(),U=function(e,t){for(var n=0,r=Object.keys(t);n0},e}(),er="undefined"!=typeof WeakMap?new WeakMap:new C,ei=function(){function e(t){if(!(this instanceof e))throw TypeError("Cannot call a class as a function.");if(!arguments.length)throw TypeError("1 argument required, but only 0 present.");var n=B.getInstance(),r=new en(t,n,this);er.set(this,r)}return e}();["observe","unobserve","disconnect"].forEach(function(e){ei.prototype[e]=function(){var t;return(t=er.get(this))[e].apply(t,arguments)}});var ea=void 0!==D.ResizeObserver?D.ResizeObserver:ei;let eo=ea;var es=function(e){var t=[],n=null,r=function(){for(var r=arguments.length,i=Array(r),a=0;a=t||n<0||f&&r>=a}function g(){var e=eb();if(m(e))return v(e);s=setTimeout(g,b(e))}function v(e){return(s=void 0,d&&r)?h(e):(r=i=void 0,o)}function y(){void 0!==s&&clearTimeout(s),c=0,r=u=i=s=void 0}function w(){return void 0===s?o:v(eb())}function _(){var e=eb(),n=m(e);if(r=arguments,i=this,u=e,n){if(void 0===s)return p(u);if(f)return clearTimeout(s),s=setTimeout(g,t),h(u)}return void 0===s&&(s=setTimeout(g,t)),o}return t=ez(t)||0,ed(n)&&(l=!!n.leading,a=(f="maxWait"in n)?eW(ez(n.maxWait)||0,t):a,d="trailing"in n?!!n.trailing:d),_.cancel=y,_.flush=w,_}let eq=eV;var eZ="Expected a function";function eX(e,t,n){var r=!0,i=!0;if("function"!=typeof e)throw TypeError(eZ);return ed(n)&&(r="leading"in n?!!n.leading:r,i="trailing"in n?!!n.trailing:i),eq(e,t,{leading:r,maxWait:t,trailing:i})}let eJ=eX;var eQ={debounce:eq,throttle:eJ},e1=function(e){return eQ[e]},e0=function(e){return"function"==typeof e},e2=function(){return"undefined"==typeof window},e3=function(e){return e instanceof Element||e instanceof HTMLDocument};function e4(e){return(e4="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e})(e)}function e5(e,t){if(!(e instanceof t))throw TypeError("Cannot call a class as a function")}function e6(e,t){for(var n=0;ne.length)&&(t=e.length);for(var n=0,r=Array(t);ne.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&l.createElement(tG.Z,{variant:"indeterminate",classes:r}))};tK.propTypes={fetchCount:el().number.isRequired};let tV=(0,b.withStyles)(tW)(tK);var tq=n(5536);let tZ=n.p+"ba8bbf16ebf8e1d05bef.svg";function tX(){return(tX=Object.assign||function(e){for(var t=1;t120){for(var d=Math.floor(u/80),h=u%80,p=[],b=0;b0},name:{enumerable:!1},nodes:{enumerable:!1},source:{enumerable:!1},positions:{enumerable:!1},originalError:{enumerable:!1}}),null!=s&&s.stack)?(Object.defineProperty(nf(b),"stack",{value:s.stack,writable:!0,configurable:!0}),nl(b)):(Error.captureStackTrace?Error.captureStackTrace(nf(b),n):Object.defineProperty(nf(b),"stack",{value:Error().stack,writable:!0,configurable:!0}),b)}return ns(n,[{key:"toString",value:function(){return nw(this)}},{key:t4.YF,get:function(){return"Object"}}]),n}(nd(Error));function ny(e){return void 0===e||0===e.length?void 0:e}function nw(e){var t=e.message;if(e.nodes)for(var n=0,r=e.nodes;n",EOF:"",BANG:"!",DOLLAR:"$",AMP:"&",PAREN_L:"(",PAREN_R:")",SPREAD:"...",COLON:":",EQUALS:"=",AT:"@",BRACKET_L:"[",BRACKET_R:"]",BRACE_L:"{",PIPE:"|",BRACE_R:"}",NAME:"Name",INT:"Int",FLOAT:"Float",STRING:"String",BLOCK_STRING:"BlockString",COMMENT:"Comment"}),nx=n(10143),nT=Object.freeze({QUERY:"QUERY",MUTATION:"MUTATION",SUBSCRIPTION:"SUBSCRIPTION",FIELD:"FIELD",FRAGMENT_DEFINITION:"FRAGMENT_DEFINITION",FRAGMENT_SPREAD:"FRAGMENT_SPREAD",INLINE_FRAGMENT:"INLINE_FRAGMENT",VARIABLE_DEFINITION:"VARIABLE_DEFINITION",SCHEMA:"SCHEMA",SCALAR:"SCALAR",OBJECT:"OBJECT",FIELD_DEFINITION:"FIELD_DEFINITION",ARGUMENT_DEFINITION:"ARGUMENT_DEFINITION",INTERFACE:"INTERFACE",UNION:"UNION",ENUM:"ENUM",ENUM_VALUE:"ENUM_VALUE",INPUT_OBJECT:"INPUT_OBJECT",INPUT_FIELD_DEFINITION:"INPUT_FIELD_DEFINITION"}),nM=n(87392),nO=function(){function e(e){var t=new nS.WU(nk.SOF,0,0,0,0,null);this.source=e,this.lastToken=t,this.token=t,this.line=1,this.lineStart=0}var t=e.prototype;return t.advance=function(){return this.lastToken=this.token,this.token=this.lookahead()},t.lookahead=function(){var e,t=this.token;if(t.kind!==nk.EOF)do t=null!==(e=t.next)&&void 0!==e?e:t.next=nC(this,t);while(t.kind===nk.COMMENT)return t},e}();function nA(e){return e===nk.BANG||e===nk.DOLLAR||e===nk.AMP||e===nk.PAREN_L||e===nk.PAREN_R||e===nk.SPREAD||e===nk.COLON||e===nk.EQUALS||e===nk.AT||e===nk.BRACKET_L||e===nk.BRACKET_R||e===nk.BRACE_L||e===nk.PIPE||e===nk.BRACE_R}function nL(e){return isNaN(e)?nk.EOF:e<127?JSON.stringify(String.fromCharCode(e)):'"\\u'.concat(("00"+e.toString(16).toUpperCase()).slice(-4),'"')}function nC(e,t){for(var n=e.source,r=n.body,i=r.length,a=t.end;a31||9===a))return new nS.WU(nk.COMMENT,t,s,n,r,i,o.slice(t+1,s))}function nN(e,t,n,r,i,a){var o=e.body,s=n,u=t,c=!1;if(45===s&&(s=o.charCodeAt(++u)),48===s){if((s=o.charCodeAt(++u))>=48&&s<=57)throw n_(e,u,"Invalid number, unexpected digit after 0: ".concat(nL(s),"."))}else u=nP(e,u,s),s=o.charCodeAt(u);if(46===s&&(c=!0,s=o.charCodeAt(++u),u=nP(e,u,s),s=o.charCodeAt(u)),(69===s||101===s)&&(c=!0,(43===(s=o.charCodeAt(++u))||45===s)&&(s=o.charCodeAt(++u)),u=nP(e,u,s),s=o.charCodeAt(u)),46===s||nU(s))throw n_(e,u,"Invalid number, expected digit but got: ".concat(nL(s),"."));return new nS.WU(c?nk.FLOAT:nk.INT,t,u,r,i,a,o.slice(t,u))}function nP(e,t,n){var r=e.body,i=t,a=n;if(a>=48&&a<=57){do a=r.charCodeAt(++i);while(a>=48&&a<=57)return i}throw n_(e,i,"Invalid number, expected digit but got: ".concat(nL(a),"."))}function nR(e,t,n,r,i){for(var a=e.body,o=t+1,s=o,u=0,c="";o=48&&e<=57?e-48:e>=65&&e<=70?e-55:e>=97&&e<=102?e-87:-1}function nB(e,t,n,r,i){for(var a=e.body,o=a.length,s=t+1,u=0;s!==o&&!isNaN(u=a.charCodeAt(s))&&(95===u||u>=48&&u<=57||u>=65&&u<=90||u>=97&&u<=122);)++s;return new nS.WU(nk.NAME,t,s,n,r,i,a.slice(t,s))}function nU(e){return 95===e||e>=65&&e<=90||e>=97&&e<=122}function nH(e,t){return new n$(e,t).parseDocument()}var n$=function(){function e(e,t){var n=(0,nx.T)(e)?e:new nx.H(e);this._lexer=new nO(n),this._options=t}var t=e.prototype;return t.parseName=function(){var e=this.expectToken(nk.NAME);return{kind:nE.h.NAME,value:e.value,loc:this.loc(e)}},t.parseDocument=function(){var e=this._lexer.token;return{kind:nE.h.DOCUMENT,definitions:this.many(nk.SOF,this.parseDefinition,nk.EOF),loc:this.loc(e)}},t.parseDefinition=function(){if(this.peek(nk.NAME))switch(this._lexer.token.value){case"query":case"mutation":case"subscription":return this.parseOperationDefinition();case"fragment":return this.parseFragmentDefinition();case"schema":case"scalar":case"type":case"interface":case"union":case"enum":case"input":case"directive":return this.parseTypeSystemDefinition();case"extend":return this.parseTypeSystemExtension()}else if(this.peek(nk.BRACE_L))return this.parseOperationDefinition();else if(this.peekDescription())return this.parseTypeSystemDefinition();throw this.unexpected()},t.parseOperationDefinition=function(){var e,t=this._lexer.token;if(this.peek(nk.BRACE_L))return{kind:nE.h.OPERATION_DEFINITION,operation:"query",name:void 0,variableDefinitions:[],directives:[],selectionSet:this.parseSelectionSet(),loc:this.loc(t)};var n=this.parseOperationType();return this.peek(nk.NAME)&&(e=this.parseName()),{kind:nE.h.OPERATION_DEFINITION,operation:n,name:e,variableDefinitions:this.parseVariableDefinitions(),directives:this.parseDirectives(!1),selectionSet:this.parseSelectionSet(),loc:this.loc(t)}},t.parseOperationType=function(){var e=this.expectToken(nk.NAME);switch(e.value){case"query":return"query";case"mutation":return"mutation";case"subscription":return"subscription"}throw this.unexpected(e)},t.parseVariableDefinitions=function(){return this.optionalMany(nk.PAREN_L,this.parseVariableDefinition,nk.PAREN_R)},t.parseVariableDefinition=function(){var e=this._lexer.token;return{kind:nE.h.VARIABLE_DEFINITION,variable:this.parseVariable(),type:(this.expectToken(nk.COLON),this.parseTypeReference()),defaultValue:this.expectOptionalToken(nk.EQUALS)?this.parseValueLiteral(!0):void 0,directives:this.parseDirectives(!0),loc:this.loc(e)}},t.parseVariable=function(){var e=this._lexer.token;return this.expectToken(nk.DOLLAR),{kind:nE.h.VARIABLE,name:this.parseName(),loc:this.loc(e)}},t.parseSelectionSet=function(){var e=this._lexer.token;return{kind:nE.h.SELECTION_SET,selections:this.many(nk.BRACE_L,this.parseSelection,nk.BRACE_R),loc:this.loc(e)}},t.parseSelection=function(){return this.peek(nk.SPREAD)?this.parseFragment():this.parseField()},t.parseField=function(){var e,t,n=this._lexer.token,r=this.parseName();return this.expectOptionalToken(nk.COLON)?(e=r,t=this.parseName()):t=r,{kind:nE.h.FIELD,alias:e,name:t,arguments:this.parseArguments(!1),directives:this.parseDirectives(!1),selectionSet:this.peek(nk.BRACE_L)?this.parseSelectionSet():void 0,loc:this.loc(n)}},t.parseArguments=function(e){var t=e?this.parseConstArgument:this.parseArgument;return this.optionalMany(nk.PAREN_L,t,nk.PAREN_R)},t.parseArgument=function(){var e=this._lexer.token,t=this.parseName();return this.expectToken(nk.COLON),{kind:nE.h.ARGUMENT,name:t,value:this.parseValueLiteral(!1),loc:this.loc(e)}},t.parseConstArgument=function(){var e=this._lexer.token;return{kind:nE.h.ARGUMENT,name:this.parseName(),value:(this.expectToken(nk.COLON),this.parseValueLiteral(!0)),loc:this.loc(e)}},t.parseFragment=function(){var e=this._lexer.token;this.expectToken(nk.SPREAD);var t=this.expectOptionalKeyword("on");return!t&&this.peek(nk.NAME)?{kind:nE.h.FRAGMENT_SPREAD,name:this.parseFragmentName(),directives:this.parseDirectives(!1),loc:this.loc(e)}:{kind:nE.h.INLINE_FRAGMENT,typeCondition:t?this.parseNamedType():void 0,directives:this.parseDirectives(!1),selectionSet:this.parseSelectionSet(),loc:this.loc(e)}},t.parseFragmentDefinition=function(){var e,t=this._lexer.token;return(this.expectKeyword("fragment"),(null===(e=this._options)||void 0===e?void 0:e.experimentalFragmentVariables)===!0)?{kind:nE.h.FRAGMENT_DEFINITION,name:this.parseFragmentName(),variableDefinitions:this.parseVariableDefinitions(),typeCondition:(this.expectKeyword("on"),this.parseNamedType()),directives:this.parseDirectives(!1),selectionSet:this.parseSelectionSet(),loc:this.loc(t)}:{kind:nE.h.FRAGMENT_DEFINITION,name:this.parseFragmentName(),typeCondition:(this.expectKeyword("on"),this.parseNamedType()),directives:this.parseDirectives(!1),selectionSet:this.parseSelectionSet(),loc:this.loc(t)}},t.parseFragmentName=function(){if("on"===this._lexer.token.value)throw this.unexpected();return this.parseName()},t.parseValueLiteral=function(e){var t=this._lexer.token;switch(t.kind){case nk.BRACKET_L:return this.parseList(e);case nk.BRACE_L:return this.parseObject(e);case nk.INT:return this._lexer.advance(),{kind:nE.h.INT,value:t.value,loc:this.loc(t)};case nk.FLOAT:return this._lexer.advance(),{kind:nE.h.FLOAT,value:t.value,loc:this.loc(t)};case nk.STRING:case nk.BLOCK_STRING:return this.parseStringLiteral();case nk.NAME:switch(this._lexer.advance(),t.value){case"true":return{kind:nE.h.BOOLEAN,value:!0,loc:this.loc(t)};case"false":return{kind:nE.h.BOOLEAN,value:!1,loc:this.loc(t)};case"null":return{kind:nE.h.NULL,loc:this.loc(t)};default:return{kind:nE.h.ENUM,value:t.value,loc:this.loc(t)}}case nk.DOLLAR:if(!e)return this.parseVariable()}throw this.unexpected()},t.parseStringLiteral=function(){var e=this._lexer.token;return this._lexer.advance(),{kind:nE.h.STRING,value:e.value,block:e.kind===nk.BLOCK_STRING,loc:this.loc(e)}},t.parseList=function(e){var t=this,n=this._lexer.token,r=function(){return t.parseValueLiteral(e)};return{kind:nE.h.LIST,values:this.any(nk.BRACKET_L,r,nk.BRACKET_R),loc:this.loc(n)}},t.parseObject=function(e){var t=this,n=this._lexer.token,r=function(){return t.parseObjectField(e)};return{kind:nE.h.OBJECT,fields:this.any(nk.BRACE_L,r,nk.BRACE_R),loc:this.loc(n)}},t.parseObjectField=function(e){var t=this._lexer.token,n=this.parseName();return this.expectToken(nk.COLON),{kind:nE.h.OBJECT_FIELD,name:n,value:this.parseValueLiteral(e),loc:this.loc(t)}},t.parseDirectives=function(e){for(var t=[];this.peek(nk.AT);)t.push(this.parseDirective(e));return t},t.parseDirective=function(e){var t=this._lexer.token;return this.expectToken(nk.AT),{kind:nE.h.DIRECTIVE,name:this.parseName(),arguments:this.parseArguments(e),loc:this.loc(t)}},t.parseTypeReference=function(){var e,t=this._lexer.token;return(this.expectOptionalToken(nk.BRACKET_L)?(e=this.parseTypeReference(),this.expectToken(nk.BRACKET_R),e={kind:nE.h.LIST_TYPE,type:e,loc:this.loc(t)}):e=this.parseNamedType(),this.expectOptionalToken(nk.BANG))?{kind:nE.h.NON_NULL_TYPE,type:e,loc:this.loc(t)}:e},t.parseNamedType=function(){var e=this._lexer.token;return{kind:nE.h.NAMED_TYPE,name:this.parseName(),loc:this.loc(e)}},t.parseTypeSystemDefinition=function(){var e=this.peekDescription()?this._lexer.lookahead():this._lexer.token;if(e.kind===nk.NAME)switch(e.value){case"schema":return this.parseSchemaDefinition();case"scalar":return this.parseScalarTypeDefinition();case"type":return this.parseObjectTypeDefinition();case"interface":return this.parseInterfaceTypeDefinition();case"union":return this.parseUnionTypeDefinition();case"enum":return this.parseEnumTypeDefinition();case"input":return this.parseInputObjectTypeDefinition();case"directive":return this.parseDirectiveDefinition()}throw this.unexpected(e)},t.peekDescription=function(){return this.peek(nk.STRING)||this.peek(nk.BLOCK_STRING)},t.parseDescription=function(){if(this.peekDescription())return this.parseStringLiteral()},t.parseSchemaDefinition=function(){var e=this._lexer.token,t=this.parseDescription();this.expectKeyword("schema");var n=this.parseDirectives(!0),r=this.many(nk.BRACE_L,this.parseOperationTypeDefinition,nk.BRACE_R);return{kind:nE.h.SCHEMA_DEFINITION,description:t,directives:n,operationTypes:r,loc:this.loc(e)}},t.parseOperationTypeDefinition=function(){var e=this._lexer.token,t=this.parseOperationType();this.expectToken(nk.COLON);var n=this.parseNamedType();return{kind:nE.h.OPERATION_TYPE_DEFINITION,operation:t,type:n,loc:this.loc(e)}},t.parseScalarTypeDefinition=function(){var e=this._lexer.token,t=this.parseDescription();this.expectKeyword("scalar");var n=this.parseName(),r=this.parseDirectives(!0);return{kind:nE.h.SCALAR_TYPE_DEFINITION,description:t,name:n,directives:r,loc:this.loc(e)}},t.parseObjectTypeDefinition=function(){var e=this._lexer.token,t=this.parseDescription();this.expectKeyword("type");var n=this.parseName(),r=this.parseImplementsInterfaces(),i=this.parseDirectives(!0),a=this.parseFieldsDefinition();return{kind:nE.h.OBJECT_TYPE_DEFINITION,description:t,name:n,interfaces:r,directives:i,fields:a,loc:this.loc(e)}},t.parseImplementsInterfaces=function(){var e;if(!this.expectOptionalKeyword("implements"))return[];if((null===(e=this._options)||void 0===e?void 0:e.allowLegacySDLImplementsInterfaces)===!0){var t=[];this.expectOptionalToken(nk.AMP);do t.push(this.parseNamedType());while(this.expectOptionalToken(nk.AMP)||this.peek(nk.NAME))return t}return this.delimitedMany(nk.AMP,this.parseNamedType)},t.parseFieldsDefinition=function(){var e;return(null===(e=this._options)||void 0===e?void 0:e.allowLegacySDLEmptyFields)===!0&&this.peek(nk.BRACE_L)&&this._lexer.lookahead().kind===nk.BRACE_R?(this._lexer.advance(),this._lexer.advance(),[]):this.optionalMany(nk.BRACE_L,this.parseFieldDefinition,nk.BRACE_R)},t.parseFieldDefinition=function(){var e=this._lexer.token,t=this.parseDescription(),n=this.parseName(),r=this.parseArgumentDefs();this.expectToken(nk.COLON);var i=this.parseTypeReference(),a=this.parseDirectives(!0);return{kind:nE.h.FIELD_DEFINITION,description:t,name:n,arguments:r,type:i,directives:a,loc:this.loc(e)}},t.parseArgumentDefs=function(){return this.optionalMany(nk.PAREN_L,this.parseInputValueDef,nk.PAREN_R)},t.parseInputValueDef=function(){var e,t=this._lexer.token,n=this.parseDescription(),r=this.parseName();this.expectToken(nk.COLON);var i=this.parseTypeReference();this.expectOptionalToken(nk.EQUALS)&&(e=this.parseValueLiteral(!0));var a=this.parseDirectives(!0);return{kind:nE.h.INPUT_VALUE_DEFINITION,description:n,name:r,type:i,defaultValue:e,directives:a,loc:this.loc(t)}},t.parseInterfaceTypeDefinition=function(){var e=this._lexer.token,t=this.parseDescription();this.expectKeyword("interface");var n=this.parseName(),r=this.parseImplementsInterfaces(),i=this.parseDirectives(!0),a=this.parseFieldsDefinition();return{kind:nE.h.INTERFACE_TYPE_DEFINITION,description:t,name:n,interfaces:r,directives:i,fields:a,loc:this.loc(e)}},t.parseUnionTypeDefinition=function(){var e=this._lexer.token,t=this.parseDescription();this.expectKeyword("union");var n=this.parseName(),r=this.parseDirectives(!0),i=this.parseUnionMemberTypes();return{kind:nE.h.UNION_TYPE_DEFINITION,description:t,name:n,directives:r,types:i,loc:this.loc(e)}},t.parseUnionMemberTypes=function(){return this.expectOptionalToken(nk.EQUALS)?this.delimitedMany(nk.PIPE,this.parseNamedType):[]},t.parseEnumTypeDefinition=function(){var e=this._lexer.token,t=this.parseDescription();this.expectKeyword("enum");var n=this.parseName(),r=this.parseDirectives(!0),i=this.parseEnumValuesDefinition();return{kind:nE.h.ENUM_TYPE_DEFINITION,description:t,name:n,directives:r,values:i,loc:this.loc(e)}},t.parseEnumValuesDefinition=function(){return this.optionalMany(nk.BRACE_L,this.parseEnumValueDefinition,nk.BRACE_R)},t.parseEnumValueDefinition=function(){var e=this._lexer.token,t=this.parseDescription(),n=this.parseName(),r=this.parseDirectives(!0);return{kind:nE.h.ENUM_VALUE_DEFINITION,description:t,name:n,directives:r,loc:this.loc(e)}},t.parseInputObjectTypeDefinition=function(){var e=this._lexer.token,t=this.parseDescription();this.expectKeyword("input");var n=this.parseName(),r=this.parseDirectives(!0),i=this.parseInputFieldsDefinition();return{kind:nE.h.INPUT_OBJECT_TYPE_DEFINITION,description:t,name:n,directives:r,fields:i,loc:this.loc(e)}},t.parseInputFieldsDefinition=function(){return this.optionalMany(nk.BRACE_L,this.parseInputValueDef,nk.BRACE_R)},t.parseTypeSystemExtension=function(){var e=this._lexer.lookahead();if(e.kind===nk.NAME)switch(e.value){case"schema":return this.parseSchemaExtension();case"scalar":return this.parseScalarTypeExtension();case"type":return this.parseObjectTypeExtension();case"interface":return this.parseInterfaceTypeExtension();case"union":return this.parseUnionTypeExtension();case"enum":return this.parseEnumTypeExtension();case"input":return this.parseInputObjectTypeExtension()}throw this.unexpected(e)},t.parseSchemaExtension=function(){var e=this._lexer.token;this.expectKeyword("extend"),this.expectKeyword("schema");var t=this.parseDirectives(!0),n=this.optionalMany(nk.BRACE_L,this.parseOperationTypeDefinition,nk.BRACE_R);if(0===t.length&&0===n.length)throw this.unexpected();return{kind:nE.h.SCHEMA_EXTENSION,directives:t,operationTypes:n,loc:this.loc(e)}},t.parseScalarTypeExtension=function(){var e=this._lexer.token;this.expectKeyword("extend"),this.expectKeyword("scalar");var t=this.parseName(),n=this.parseDirectives(!0);if(0===n.length)throw this.unexpected();return{kind:nE.h.SCALAR_TYPE_EXTENSION,name:t,directives:n,loc:this.loc(e)}},t.parseObjectTypeExtension=function(){var e=this._lexer.token;this.expectKeyword("extend"),this.expectKeyword("type");var t=this.parseName(),n=this.parseImplementsInterfaces(),r=this.parseDirectives(!0),i=this.parseFieldsDefinition();if(0===n.length&&0===r.length&&0===i.length)throw this.unexpected();return{kind:nE.h.OBJECT_TYPE_EXTENSION,name:t,interfaces:n,directives:r,fields:i,loc:this.loc(e)}},t.parseInterfaceTypeExtension=function(){var e=this._lexer.token;this.expectKeyword("extend"),this.expectKeyword("interface");var t=this.parseName(),n=this.parseImplementsInterfaces(),r=this.parseDirectives(!0),i=this.parseFieldsDefinition();if(0===n.length&&0===r.length&&0===i.length)throw this.unexpected();return{kind:nE.h.INTERFACE_TYPE_EXTENSION,name:t,interfaces:n,directives:r,fields:i,loc:this.loc(e)}},t.parseUnionTypeExtension=function(){var e=this._lexer.token;this.expectKeyword("extend"),this.expectKeyword("union");var t=this.parseName(),n=this.parseDirectives(!0),r=this.parseUnionMemberTypes();if(0===n.length&&0===r.length)throw this.unexpected();return{kind:nE.h.UNION_TYPE_EXTENSION,name:t,directives:n,types:r,loc:this.loc(e)}},t.parseEnumTypeExtension=function(){var e=this._lexer.token;this.expectKeyword("extend"),this.expectKeyword("enum");var t=this.parseName(),n=this.parseDirectives(!0),r=this.parseEnumValuesDefinition();if(0===n.length&&0===r.length)throw this.unexpected();return{kind:nE.h.ENUM_TYPE_EXTENSION,name:t,directives:n,values:r,loc:this.loc(e)}},t.parseInputObjectTypeExtension=function(){var e=this._lexer.token;this.expectKeyword("extend"),this.expectKeyword("input");var t=this.parseName(),n=this.parseDirectives(!0),r=this.parseInputFieldsDefinition();if(0===n.length&&0===r.length)throw this.unexpected();return{kind:nE.h.INPUT_OBJECT_TYPE_EXTENSION,name:t,directives:n,fields:r,loc:this.loc(e)}},t.parseDirectiveDefinition=function(){var e=this._lexer.token,t=this.parseDescription();this.expectKeyword("directive"),this.expectToken(nk.AT);var n=this.parseName(),r=this.parseArgumentDefs(),i=this.expectOptionalKeyword("repeatable");this.expectKeyword("on");var a=this.parseDirectiveLocations();return{kind:nE.h.DIRECTIVE_DEFINITION,description:t,name:n,arguments:r,repeatable:i,locations:a,loc:this.loc(e)}},t.parseDirectiveLocations=function(){return this.delimitedMany(nk.PIPE,this.parseDirectiveLocation)},t.parseDirectiveLocation=function(){var e=this._lexer.token,t=this.parseName();if(void 0!==nT[t.value])return t;throw this.unexpected(e)},t.loc=function(e){var t;if((null===(t=this._options)||void 0===t?void 0:t.noLocation)!==!0)return new nS.Ye(e,this._lexer.lastToken,this._lexer.source)},t.peek=function(e){return this._lexer.token.kind===e},t.expectToken=function(e){var t=this._lexer.token;if(t.kind===e)return this._lexer.advance(),t;throw n_(this._lexer.source,t.start,"Expected ".concat(nG(e),", found ").concat(nz(t),"."))},t.expectOptionalToken=function(e){var t=this._lexer.token;if(t.kind===e)return this._lexer.advance(),t},t.expectKeyword=function(e){var t=this._lexer.token;if(t.kind===nk.NAME&&t.value===e)this._lexer.advance();else throw n_(this._lexer.source,t.start,'Expected "'.concat(e,'", found ').concat(nz(t),"."))},t.expectOptionalKeyword=function(e){var t=this._lexer.token;return t.kind===nk.NAME&&t.value===e&&(this._lexer.advance(),!0)},t.unexpected=function(e){var t=null!=e?e:this._lexer.token;return n_(this._lexer.source,t.start,"Unexpected ".concat(nz(t),"."))},t.any=function(e,t,n){this.expectToken(e);for(var r=[];!this.expectOptionalToken(n);)r.push(t.call(this));return r},t.optionalMany=function(e,t,n){if(this.expectOptionalToken(e)){var r=[];do r.push(t.call(this));while(!this.expectOptionalToken(n))return r}return[]},t.many=function(e,t,n){this.expectToken(e);var r=[];do r.push(t.call(this));while(!this.expectOptionalToken(n))return r},t.delimitedMany=function(e,t){this.expectOptionalToken(e);var n=[];do n.push(t.call(this));while(this.expectOptionalToken(e))return n},e}();function nz(e){var t=e.value;return nG(e.kind)+(null!=t?' "'.concat(t,'"'):"")}function nG(e){return nA(e)?'"'.concat(e,'"'):e}var nW=new Map,nK=new Map,nV=!0,nq=!1;function nZ(e){return e.replace(/[\s,]+/g," ").trim()}function nX(e){return nZ(e.source.body.substring(e.start,e.end))}function nJ(e){var t=new Set,n=[];return e.definitions.forEach(function(e){if("FragmentDefinition"===e.kind){var r=e.name.value,i=nX(e.loc),a=nK.get(r);a&&!a.has(i)?nV&&console.warn("Warning: fragment with name "+r+" already exists.\ngraphql-tag enforces all fragment names across your application to be unique; read more about\nthis in the docs: http://dev.apollodata.com/core/fragments.html#unique-names"):a||nK.set(r,a=new Set),a.add(i),t.has(i)||(t.add(i),n.push(e))}else n.push(e)}),(0,t0.pi)((0,t0.pi)({},e),{definitions:n})}function nQ(e){var t=new Set(e.definitions);t.forEach(function(e){e.loc&&delete e.loc,Object.keys(e).forEach(function(n){var r=e[n];r&&"object"==typeof r&&t.add(r)})});var n=e.loc;return n&&(delete n.startToken,delete n.endToken),e}function n1(e){var t=nZ(e);if(!nW.has(t)){var n=nH(e,{experimentalFragmentVariables:nq,allowLegacyFragmentVariables:nq});if(!n||"Document"!==n.kind)throw Error("Not a valid GraphQL document.");nW.set(t,nQ(nJ(n)))}return nW.get(t)}function n0(e){for(var t=[],n=1;n, or pass an ApolloClient instance in via options.'):(0,n7.kG)(!!n,32),n}var rb=n(10542),rm=n(53712),rg=n(21436),rv=Object.prototype.hasOwnProperty;function ry(e,t){return void 0===t&&(t=Object.create(null)),rw(rp(t.client),e).useQuery(t)}function rw(e,t){var n=(0,l.useRef)();n.current&&e===n.current.client&&t===n.current.query||(n.current=new r_(e,t,n.current));var r=n.current,i=(0,l.useState)(0),a=(i[0],i[1]);return r.forceUpdate=function(){a(function(e){return e+1})},r}var r_=function(){function e(e,t,n){this.client=e,this.query=t,this.ssrDisabledResult=(0,rb.J)({loading:!0,data:void 0,error:void 0,networkStatus:rc.I.loading}),this.skipStandbyResult=(0,rb.J)({loading:!1,data:void 0,error:void 0,networkStatus:rc.I.ready}),this.toQueryResultCache=new(re.mr?WeakMap:Map),rh(t,r.Query);var i=n&&n.result,a=i&&i.data;a&&(this.previousData=a)}return e.prototype.forceUpdate=function(){__DEV__&&n7.kG.warn("Calling default no-op implementation of InternalState#forceUpdate")},e.prototype.executeQuery=function(e){var t,n=this;e.query&&Object.assign(this,{query:e.query}),this.watchQueryOptions=this.createWatchQueryOptions(this.queryHookOptions=e);var r=this.observable.reobserveAsConcast(this.getObsQueryOptions());return this.previousData=(null===(t=this.result)||void 0===t?void 0:t.data)||this.previousData,this.result=void 0,this.forceUpdate(),new Promise(function(e){var t;r.subscribe({next:function(e){t=e},error:function(){e(n.toQueryResult(n.observable.getCurrentResult()))},complete:function(){e(n.toQueryResult(t))}})})},e.prototype.useQuery=function(e){var t=this;this.renderPromises=(0,l.useContext)((0,rs.K)()).renderPromises,this.useOptions(e);var n=this.useObservableQuery(),r=rn((0,l.useCallback)(function(){if(t.renderPromises)return function(){};var e=function(){var e=t.result,r=n.getCurrentResult();!(e&&e.loading===r.loading&&e.networkStatus===r.networkStatus&&(0,ra.D)(e.data,r.data))&&t.setResult(r)},r=function(a){var o=n.last;i.unsubscribe();try{n.resetLastResults(),i=n.subscribe(e,r)}finally{n.last=o}if(!rv.call(a,"graphQLErrors"))throw a;var s=t.result;(!s||s&&s.loading||!(0,ra.D)(a,s.error))&&t.setResult({data:s&&s.data,error:a,loading:!1,networkStatus:rc.I.error})},i=n.subscribe(e,r);return function(){return setTimeout(function(){return i.unsubscribe()})}},[n,this.renderPromises,this.client.disableNetworkFetches,]),function(){return t.getCurrentResult()},function(){return t.getCurrentResult()});return this.unsafeHandlePartialRefetch(r),this.toQueryResult(r)},e.prototype.useOptions=function(t){var n,r=this.createWatchQueryOptions(this.queryHookOptions=t),i=this.watchQueryOptions;!(0,ra.D)(r,i)&&(this.watchQueryOptions=r,i&&this.observable&&(this.observable.reobserve(this.getObsQueryOptions()),this.previousData=(null===(n=this.result)||void 0===n?void 0:n.data)||this.previousData,this.result=void 0)),this.onCompleted=t.onCompleted||e.prototype.onCompleted,this.onError=t.onError||e.prototype.onError,(this.renderPromises||this.client.disableNetworkFetches)&&!1===this.queryHookOptions.ssr&&!this.queryHookOptions.skip?this.result=this.ssrDisabledResult:this.queryHookOptions.skip||"standby"===this.watchQueryOptions.fetchPolicy?this.result=this.skipStandbyResult:(this.result===this.ssrDisabledResult||this.result===this.skipStandbyResult)&&(this.result=void 0)},e.prototype.getObsQueryOptions=function(){var e=[],t=this.client.defaultOptions.watchQuery;return t&&e.push(t),this.queryHookOptions.defaultOptions&&e.push(this.queryHookOptions.defaultOptions),e.push((0,rm.o)(this.observable&&this.observable.options,this.watchQueryOptions)),e.reduce(ro.J)},e.prototype.createWatchQueryOptions=function(e){void 0===e&&(e={});var t,n=e.skip,r=Object.assign((e.ssr,e.onCompleted,e.onError,e.defaultOptions,(0,n8._T)(e,["skip","ssr","onCompleted","onError","defaultOptions"])),{query:this.query});if(this.renderPromises&&("network-only"===r.fetchPolicy||"cache-and-network"===r.fetchPolicy)&&(r.fetchPolicy="cache-first"),r.variables||(r.variables={}),n){var i=r.fetchPolicy,a=void 0===i?this.getDefaultFetchPolicy():i,o=r.initialFetchPolicy;Object.assign(r,{initialFetchPolicy:void 0===o?a:o,fetchPolicy:"standby"})}else r.fetchPolicy||(r.fetchPolicy=(null===(t=this.observable)||void 0===t?void 0:t.options.initialFetchPolicy)||this.getDefaultFetchPolicy());return r},e.prototype.getDefaultFetchPolicy=function(){var e,t;return(null===(e=this.queryHookOptions.defaultOptions)||void 0===e?void 0:e.fetchPolicy)||(null===(t=this.client.defaultOptions.watchQuery)||void 0===t?void 0:t.fetchPolicy)||"cache-first"},e.prototype.onCompleted=function(e){},e.prototype.onError=function(e){},e.prototype.useObservableQuery=function(){var e=this.observable=this.renderPromises&&this.renderPromises.getSSRObservable(this.watchQueryOptions)||this.observable||this.client.watchQuery(this.getObsQueryOptions());this.obsQueryFields=(0,l.useMemo)(function(){return{refetch:e.refetch.bind(e),reobserve:e.reobserve.bind(e),fetchMore:e.fetchMore.bind(e),updateQuery:e.updateQuery.bind(e),startPolling:e.startPolling.bind(e),stopPolling:e.stopPolling.bind(e),subscribeToMore:e.subscribeToMore.bind(e)}},[e]);var t=!(!1===this.queryHookOptions.ssr||this.queryHookOptions.skip);return this.renderPromises&&t&&(this.renderPromises.registerSSRObservable(e),e.getCurrentResult().loading&&this.renderPromises.addObservableQueryPromise(e)),e},e.prototype.setResult=function(e){var t=this.result;t&&t.data&&(this.previousData=t.data),this.result=e,this.forceUpdate(),this.handleErrorOrCompleted(e)},e.prototype.handleErrorOrCompleted=function(e){var t=this;if(!e.loading){var n=this.toApolloError(e);Promise.resolve().then(function(){n?t.onError(n):e.data&&t.onCompleted(e.data)}).catch(function(e){__DEV__&&n7.kG.warn(e)})}},e.prototype.toApolloError=function(e){return(0,rg.O)(e.errors)?new ru.cA({graphQLErrors:e.errors}):e.error},e.prototype.getCurrentResult=function(){return this.result||this.handleErrorOrCompleted(this.result=this.observable.getCurrentResult()),this.result},e.prototype.toQueryResult=function(e){var t=this.toQueryResultCache.get(e);if(t)return t;var n=e.data,r=(e.partial,(0,n8._T)(e,["data","partial"]));return this.toQueryResultCache.set(e,t=(0,n8.pi)((0,n8.pi)((0,n8.pi)({data:n},r),this.obsQueryFields),{client:this.client,observable:this.observable,variables:this.observable.variables,called:!this.queryHookOptions.skip,previousData:this.previousData})),!t.error&&(0,rg.O)(e.errors)&&(t.error=new ru.cA({graphQLErrors:e.errors})),t},e.prototype.unsafeHandlePartialRefetch=function(e){e.partial&&this.queryHookOptions.partialRefetch&&!e.loading&&(!e.data||0===Object.keys(e.data).length)&&"cache-only"!==this.observable.options.fetchPolicy&&(Object.assign(e,{loading:!0,networkStatus:rc.I.refetch}),this.observable.refetch())},e}();function rE(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=Array(t);ne.length)&&(t=e.length);for(var n=0,r=Array(t);ne.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&void 0!==arguments[0]?arguments[0]:{};return ry(i$,e)},iG=function(){var e=iF(),t=parseInt(e.get("page")||"1",10),n=parseInt(e.get("per")||"50",10),r=iz({variables:{offset:(t-1)*n,limit:n},fetchPolicy:"network-only"}),i=r.data,a=r.loading,o=r.error;return a?l.createElement(ij,null):o?l.createElement(iN,{error:o}):i?l.createElement(iD,{chains:i.chains.results,page:t,pageSize:n,total:i.chains.metadata.total}):null},iW=n(67932),iK=n(8126),iV="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e};function iq(e){if(iZ())return Intl.DateTimeFormat.supportedLocalesOf(e)[0]}function iZ(){return("undefined"==typeof Intl?"undefined":iV(Intl))==="object"&&"function"==typeof Intl.DateTimeFormat}var iX="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e},iJ=function(){function e(e,t){for(var n=0;n=i.length)break;s=i[o++]}else{if((o=i.next()).done)break;s=o.value}var s,u=s;if((void 0===e?"undefined":iX(e))!=="object")return;e=e[u]}return e}},{key:"put",value:function(){for(var e=arguments.length,t=Array(e),n=0;n=o.length)break;c=o[u++]}else{if((u=o.next()).done)break;c=u.value}var c,l=c;"object"!==iX(a[l])&&(a[l]={}),a=a[l]}return a[i]=r}}]),e}();let i0=i1;var i2=new i0;function i3(e,t){if(!iZ())return function(e){return e.toString()};var n=i5(e),r=JSON.stringify(t),i=i2.get(String(n),r)||i2.put(String(n),r,new Intl.DateTimeFormat(n,t));return function(e){return i.format(e)}}var i4={};function i5(e){var t=e.toString();return i4[t]?i4[t]:i4[t]=iq(e)}var i6="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e};function i9(e){return i8(e)?e:new Date(e)}function i8(e){return e instanceof Date||i7(e)}function i7(e){return(void 0===e?"undefined":i6(e))==="object"&&"function"==typeof e.getTime}var ae=n(54087),at=n.n(ae);function an(e,t){if(0===e.length)return 0;for(var n=0,r=e.length-1,i=void 0;n<=r;){var a=t(e[i=Math.floor((r+n)/2)]);if(0===a)return i;if(a<0){if((n=i+1)>r)return n}else if((r=i-1)=t.nextUpdateTime)ao(t,this.instances);else break}},scheduleNextTick:function(){var e=this;this.scheduledTick=at()(function(){e.tick(),e.scheduleNextTick()})},start:function(){this.scheduleNextTick()},stop:function(){at().cancel(this.scheduledTick)}};function aa(e){var t=ar(e.getNextValue(),2),n=t[0],r=t[1];e.setValue(n),e.nextUpdateTime=r}function ao(e,t){aa(e),au(t,e),as(t,e)}function as(e,t){var n=ac(e,t);e.splice(n,0,t)}function au(e,t){var n=e.indexOf(t);e.splice(n,1)}function ac(e,t){var n=t.nextUpdateTime;return an(e,function(e){return e.nextUpdateTime===n?0:e.nextUpdateTime>n?1:-1})}var al=(0,ec.oneOfType)([(0,ec.shape)({minTime:ec.number,formatAs:ec.string.isRequired}),(0,ec.shape)({test:ec.func,formatAs:ec.string.isRequired}),(0,ec.shape)({minTime:ec.number,format:ec.func.isRequired}),(0,ec.shape)({test:ec.func,format:ec.func.isRequired})]),af=(0,ec.oneOfType)([ec.string,(0,ec.shape)({steps:(0,ec.arrayOf)(al).isRequired,labels:(0,ec.oneOfType)([ec.string,(0,ec.arrayOf)(ec.string)]).isRequired,round:ec.string})]),ad=Object.assign||function(e){for(var t=1;t=0)&&Object.prototype.hasOwnProperty.call(e,r)&&(n[r]=e[r]);return n}function ab(e){var t=e.date,n=e.future,r=e.timeStyle,i=e.round,a=e.minTimeLeft,o=e.tooltip,s=e.component,u=e.container,c=e.wrapperComponent,f=e.wrapperProps,d=e.locale,h=e.locales,p=e.formatVerboseDate,b=e.verboseDateFormat,m=e.updateInterval,g=e.tick,v=ap(e,["date","future","timeStyle","round","minTimeLeft","tooltip","component","container","wrapperComponent","wrapperProps","locale","locales","formatVerboseDate","verboseDateFormat","updateInterval","tick"]),y=(0,l.useMemo)(function(){return d&&(h=[d]),h.concat(iK.Z.getDefaultLocale())},[d,h]),w=(0,l.useMemo)(function(){return new iK.Z(y)},[y]);t=(0,l.useMemo)(function(){return i9(t)},[t]);var _=(0,l.useCallback)(function(){var e=Date.now(),o=void 0;if(n&&e>=t.getTime()&&(e=t.getTime(),o=!0),void 0!==a){var s=t.getTime()-1e3*a;e>s&&(e=s,o=!0)}var u=w.format(t,r,{getTimeToNextUpdate:!0,now:e,future:n,round:i}),c=ah(u,2),l=c[0],f=c[1];return f=o?av:m||f||6e4,[l,e+f]},[t,n,r,m,i,a,w]),E=(0,l.useRef)();E.current=_;var S=(0,l.useMemo)(_,[]),k=ah(S,2),x=k[0],T=k[1],M=(0,l.useState)(x),O=ah(M,2),A=O[0],L=O[1],C=ah((0,l.useState)(),2),I=C[0],D=C[1],N=(0,l.useRef)();(0,l.useEffect)(function(){if(g)return N.current=ai.add({getNextValue:function(){return E.current()},setValue:L,nextUpdateTime:T}),function(){return N.current.stop()}},[g]),(0,l.useEffect)(function(){if(N.current)N.current.forceUpdate();else{var e=_(),t=ah(e,1)[0];L(t)}},[_]),(0,l.useEffect)(function(){D(!0)},[]);var P=(0,l.useMemo)(function(){if("undefined"!=typeof window)return i3(y,b)},[y,b]),R=(0,l.useMemo)(function(){if("undefined"!=typeof window)return p?p(t):P(t)},[t,p,P]),j=l.createElement(s,ad({date:t,verboseDate:I?R:void 0,tooltip:o},v),A),F=c||u;return F?l.createElement(F,ad({},f,{verboseDate:I?R:void 0}),j):j}ab.propTypes={date:el().oneOfType([el().instanceOf(Date),el().number]).isRequired,locale:el().string,locales:el().arrayOf(el().string),future:el().bool,timeStyle:af,round:el().string,minTimeLeft:el().number,component:el().elementType.isRequired,tooltip:el().bool.isRequired,formatVerboseDate:el().func,verboseDateFormat:el().object,updateInterval:el().oneOfType([el().number,el().arrayOf(el().shape({threshold:el().number,interval:el().number.isRequired}))]),tick:el().bool,wrapperComponent:el().func,wrapperProps:el().object},ab.defaultProps={locales:[],component:ay,tooltip:!0,verboseDateFormat:{weekday:"long",day:"numeric",month:"long",year:"numeric",hour:"numeric",minute:"2-digit",second:"2-digit"},tick:!0},ab=l.memo(ab);let am=ab;var ag,av=31536e9;function ay(e){var t=e.date,n=e.verboseDate,r=e.tooltip,i=e.children,a=ap(e,["date","verboseDate","tooltip","children"]),o=(0,l.useMemo)(function(){return t.toISOString()},[t]);return l.createElement("time",ad({},a,{dateTime:o,title:r?n:void 0}),i)}ay.propTypes={date:el().instanceOf(Date).isRequired,verboseDate:el().string,tooltip:el().bool.isRequired,children:el().string.isRequired};var aw=n(30381),a_=n.n(aw),aE=n(31657);function aS(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function ak(e){for(var t=1;te.length)&&(t=e.length);for(var n=0,r=Array(t);ne.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&i[i.length-1])&&(6===a[0]||2===a[0])){o=0;continue}if(3===a[0]&&(!i||a[1]>i[0]&&a[1]0?new ru.cA({graphQLErrors:i}):void 0;if(u===s.current.mutationId&&!c.ignoreResults){var f={called:!0,loading:!1,data:r,error:l,client:a};s.current.isMounted&&!(0,ra.D)(s.current.result,f)&&o(s.current.result=f)}var d=e.onCompleted||(null===(n=s.current.options)||void 0===n?void 0:n.onCompleted);return null==d||d(t.data,c),t}).catch(function(t){if(u===s.current.mutationId&&s.current.isMounted){var n,r={loading:!1,error:t,data:void 0,called:!0,client:a};(0,ra.D)(s.current.result,r)||o(s.current.result=r)}var i=e.onError||(null===(n=s.current.options)||void 0===n?void 0:n.onError);if(i)return i(t,c),{data:void 0,errors:t};throw t})},[]),c=(0,l.useCallback)(function(){s.current.isMounted&&o({called:!1,loading:!1,client:n})},[]);return(0,l.useEffect)(function(){return s.current.isMounted=!0,function(){s.current.isMounted=!1}},[]),[u,(0,n8.pi)({reset:c},a)]}var ou=n(59067),oc=n(28428),ol=n(11186),of=n(78513);function od(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}var oh=function(e){return(0,b.createStyles)({paper:{display:"flex",margin:"".concat(2.5*e.spacing.unit,"px 0"),padding:"".concat(3*e.spacing.unit,"px ").concat(3.5*e.spacing.unit,"px")},content:{flex:1,width:"100%"},actions:od({marginTop:-(1.5*e.spacing.unit),marginLeft:-(4*e.spacing.unit)},e.breakpoints.up("sm"),{marginLeft:0,marginRight:-(1.5*e.spacing.unit)}),itemBlock:{border:"1px solid rgba(224, 224, 224, 1)",borderRadius:e.shape.borderRadius,padding:2*e.spacing.unit,marginTop:e.spacing.unit},itemBlockText:{overflowWrap:"anywhere"}})},op=(0,b.withStyles)(oh)(function(e){var t=e.actions,n=e.children,r=e.classes;return l.createElement(ia.default,{className:r.paper},l.createElement("div",{className:r.content},n),t&&l.createElement("div",{className:r.actions},t))}),ob=function(e){var t=e.title;return l.createElement(x.default,{variant:"subtitle2",gutterBottom:!0},t)},om=function(e){var t=e.children,n=e.value;return l.createElement(x.default,{variant:"body1",noWrap:!0},t||n)},og=(0,b.withStyles)(oh)(function(e){var t=e.children,n=e.classes,r=e.value;return l.createElement("div",{className:n.itemBlock},l.createElement(x.default,{variant:"body1",className:n.itemBlockText},t||r))});function ov(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=Array(t);ne.length)&&(t=e.length);for(var n=0,r=Array(t);ne.length)&&(t=e.length);for(var n=0,r=Array(t);ne.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&i[i.length-1])&&(6===a[0]||2===a[0])){o=0;continue}if(3===a[0]&&(!i||a[1]>i[0]&&a[1]-1}let sZ=sq;function sX(e,t){var n=this.__data__,r=s$(n,e);return r<0?(++this.size,n.push([e,t])):n[r][1]=t,this}let sJ=sX;function sQ(e){var t=-1,n=null==e?0:e.length;for(this.clear();++t-1&&e%1==0&&e-1&&e%1==0&&e<=cI}let cN=cD;var cP="[object Arguments]",cR="[object Array]",cj="[object Boolean]",cF="[object Date]",cY="[object Error]",cB="[object Function]",cU="[object Map]",cH="[object Number]",c$="[object Object]",cz="[object RegExp]",cG="[object Set]",cW="[object String]",cK="[object WeakMap]",cV="[object ArrayBuffer]",cq="[object DataView]",cZ="[object Float64Array]",cX="[object Int8Array]",cJ="[object Int16Array]",cQ="[object Int32Array]",c1="[object Uint8Array]",c0="[object Uint8ClampedArray]",c2="[object Uint16Array]",c3="[object Uint32Array]",c4={};function c5(e){return eD(e)&&cN(e.length)&&!!c4[eC(e)]}c4["[object Float32Array]"]=c4[cZ]=c4[cX]=c4[cJ]=c4[cQ]=c4[c1]=c4[c0]=c4[c2]=c4[c3]=!0,c4[cP]=c4[cR]=c4[cV]=c4[cj]=c4[cq]=c4[cF]=c4[cY]=c4[cB]=c4[cU]=c4[cH]=c4[c$]=c4[cz]=c4[cG]=c4[cW]=c4[cK]=!1;let c6=c5;function c9(e){return function(t){return e(t)}}let c8=c9;var c7=n(79730),le=c7.Z&&c7.Z.isTypedArray,lt=le?c8(le):c6;let ln=lt;var lr=Object.prototype.hasOwnProperty;function li(e,t){var n=cT(e),r=!n&&ck(e),i=!n&&!r&&(0,cM.Z)(e),a=!n&&!r&&!i&&ln(e),o=n||r||i||a,s=o?cm(e.length,String):[],u=s.length;for(var c in e)(t||lr.call(e,c))&&!(o&&("length"==c||i&&("offset"==c||"parent"==c)||a&&("buffer"==c||"byteLength"==c||"byteOffset"==c)||cC(c,u)))&&s.push(c);return s}let la=li;var lo=Object.prototype;function ls(e){var t=e&&e.constructor;return e===("function"==typeof t&&t.prototype||lo)}let lu=ls;var lc=sM(Object.keys,Object);let ll=lc;var lf=Object.prototype.hasOwnProperty;function ld(e){if(!lu(e))return ll(e);var t=[];for(var n in Object(e))lf.call(e,n)&&"constructor"!=n&&t.push(n);return t}let lh=ld;function lp(e){return null!=e&&cN(e.length)&&!ui(e)}let lb=lp;function lm(e){return lb(e)?la(e):lh(e)}let lg=lm;function lv(e,t){return e&&cp(t,lg(t),e)}let ly=lv;function lw(e){var t=[];if(null!=e)for(var n in Object(e))t.push(n);return t}let l_=lw;var lE=Object.prototype.hasOwnProperty;function lS(e){if(!ed(e))return l_(e);var t=lu(e),n=[];for(var r in e)"constructor"==r&&(t||!lE.call(e,r))||n.push(r);return n}let lk=lS;function lx(e){return lb(e)?la(e,!0):lk(e)}let lT=lx;function lM(e,t){return e&&cp(t,lT(t),e)}let lO=lM;var lA=n(42896);function lL(e,t){var n=-1,r=e.length;for(t||(t=Array(r));++n=0||(i[n]=e[n]);return i}function hc(e){if(void 0===e)throw ReferenceError("this hasn't been initialised - super() hasn't been called");return e}var hl=function(e){return Array.isArray(e)&&0===e.length},hf=function(e){return"function"==typeof e},hd=function(e){return null!==e&&"object"==typeof e},hh=function(e){return String(Math.floor(Number(e)))===e},hp=function(e){return"[object String]"===Object.prototype.toString.call(e)},hb=function(e){return 0===l.Children.count(e)},hm=function(e){return hd(e)&&hf(e.then)};function hg(e,t,n,r){void 0===r&&(r=0);for(var i=d8(t);e&&r=0?[]:{}}}return(0===a?e:i)[o[a]]===n?e:(void 0===n?delete i[o[a]]:i[o[a]]=n,0===a&&void 0===n&&delete r[o[a]],r)}function hy(e,t,n,r){void 0===n&&(n=new WeakMap),void 0===r&&(r={});for(var i=0,a=Object.keys(e);i0?t.map(function(t){return x(t,hg(e,t))}):[Promise.resolve("DO_NOT_DELETE_YOU_WILL_BE_FIRED")]).then(function(e){return e.reduce(function(e,n,r){return"DO_NOT_DELETE_YOU_WILL_BE_FIRED"===n||n&&(e=hv(e,t[r],n)),e},{})})},[x]),M=(0,l.useCallback)(function(e){return Promise.all([T(e),h.validationSchema?k(e):{},h.validate?S(e):{}]).then(function(e){var t=e[0],n=e[1],r=e[2];return sx.all([t,n,r],{arrayMerge:hC})})},[h.validate,h.validationSchema,T,S,k]),O=hP(function(e){return void 0===e&&(e=_.values),E({type:"SET_ISVALIDATING",payload:!0}),M(e).then(function(e){return v.current&&(E({type:"SET_ISVALIDATING",payload:!1}),sh()(_.errors,e)||E({type:"SET_ERRORS",payload:e})),e})});(0,l.useEffect)(function(){o&&!0===v.current&&sh()(p.current,h.initialValues)&&O(p.current)},[o,O]);var A=(0,l.useCallback)(function(e){var t=e&&e.values?e.values:p.current,n=e&&e.errors?e.errors:b.current?b.current:h.initialErrors||{},r=e&&e.touched?e.touched:m.current?m.current:h.initialTouched||{},i=e&&e.status?e.status:g.current?g.current:h.initialStatus;p.current=t,b.current=n,m.current=r,g.current=i;var a=function(){E({type:"RESET_FORM",payload:{isSubmitting:!!e&&!!e.isSubmitting,errors:n,touched:r,status:i,values:t,isValidating:!!e&&!!e.isValidating,submitCount:e&&e.submitCount&&"number"==typeof e.submitCount?e.submitCount:0}})};if(h.onReset){var o=h.onReset(_.values,V);hm(o)?o.then(a):a()}else a()},[h.initialErrors,h.initialStatus,h.initialTouched]);(0,l.useEffect)(function(){!0===v.current&&!sh()(p.current,h.initialValues)&&(c&&(p.current=h.initialValues,A()),o&&O(p.current))},[c,h.initialValues,A,o,O]),(0,l.useEffect)(function(){c&&!0===v.current&&!sh()(b.current,h.initialErrors)&&(b.current=h.initialErrors||hk,E({type:"SET_ERRORS",payload:h.initialErrors||hk}))},[c,h.initialErrors]),(0,l.useEffect)(function(){c&&!0===v.current&&!sh()(m.current,h.initialTouched)&&(m.current=h.initialTouched||hx,E({type:"SET_TOUCHED",payload:h.initialTouched||hx}))},[c,h.initialTouched]),(0,l.useEffect)(function(){c&&!0===v.current&&!sh()(g.current,h.initialStatus)&&(g.current=h.initialStatus,E({type:"SET_STATUS",payload:h.initialStatus}))},[c,h.initialStatus,h.initialTouched]);var L=hP(function(e){if(y.current[e]&&hf(y.current[e].validate)){var t=hg(_.values,e),n=y.current[e].validate(t);return hm(n)?(E({type:"SET_ISVALIDATING",payload:!0}),n.then(function(e){return e}).then(function(t){E({type:"SET_FIELD_ERROR",payload:{field:e,value:t}}),E({type:"SET_ISVALIDATING",payload:!1})})):(E({type:"SET_FIELD_ERROR",payload:{field:e,value:n}}),Promise.resolve(n))}return h.validationSchema?(E({type:"SET_ISVALIDATING",payload:!0}),k(_.values,e).then(function(e){return e}).then(function(t){E({type:"SET_FIELD_ERROR",payload:{field:e,value:t[e]}}),E({type:"SET_ISVALIDATING",payload:!1})})):Promise.resolve()}),C=(0,l.useCallback)(function(e,t){var n=t.validate;y.current[e]={validate:n}},[]),I=(0,l.useCallback)(function(e){delete y.current[e]},[]),D=hP(function(e,t){return E({type:"SET_TOUCHED",payload:e}),(void 0===t?i:t)?O(_.values):Promise.resolve()}),N=(0,l.useCallback)(function(e){E({type:"SET_ERRORS",payload:e})},[]),P=hP(function(e,t){var r=hf(e)?e(_.values):e;return E({type:"SET_VALUES",payload:r}),(void 0===t?n:t)?O(r):Promise.resolve()}),R=(0,l.useCallback)(function(e,t){E({type:"SET_FIELD_ERROR",payload:{field:e,value:t}})},[]),j=hP(function(e,t,r){return E({type:"SET_FIELD_VALUE",payload:{field:e,value:t}}),(void 0===r?n:r)?O(hv(_.values,e,t)):Promise.resolve()}),F=(0,l.useCallback)(function(e,t){var n,r=t,i=e;if(!hp(e)){e.persist&&e.persist();var a=e.target?e.target:e.currentTarget,o=a.type,s=a.name,u=a.id,c=a.value,l=a.checked,f=(a.outerHTML,a.options),d=a.multiple;r=t||s||u,i=/number|range/.test(o)?(n=parseFloat(c),isNaN(n)?"":n):/checkbox/.test(o)?hD(hg(_.values,r),l,c):d?hI(f):c}r&&j(r,i)},[j,_.values]),Y=hP(function(e){if(hp(e))return function(t){return F(t,e)};F(e)}),B=hP(function(e,t,n){return void 0===t&&(t=!0),E({type:"SET_FIELD_TOUCHED",payload:{field:e,value:t}}),(void 0===n?i:n)?O(_.values):Promise.resolve()}),U=(0,l.useCallback)(function(e,t){e.persist&&e.persist();var n,r=e.target,i=r.name,a=r.id;r.outerHTML,B(t||i||a,!0)},[B]),H=hP(function(e){if(hp(e))return function(t){return U(t,e)};U(e)}),$=(0,l.useCallback)(function(e){hf(e)?E({type:"SET_FORMIK_STATE",payload:e}):E({type:"SET_FORMIK_STATE",payload:function(){return e}})},[]),z=(0,l.useCallback)(function(e){E({type:"SET_STATUS",payload:e})},[]),G=(0,l.useCallback)(function(e){E({type:"SET_ISSUBMITTING",payload:e})},[]),W=hP(function(){return E({type:"SUBMIT_ATTEMPT"}),O().then(function(e){var t,n=e instanceof Error;if(!n&&0===Object.keys(e).length){try{if(void 0===(t=q()))return}catch(r){throw r}return Promise.resolve(t).then(function(e){return v.current&&E({type:"SUBMIT_SUCCESS"}),e}).catch(function(e){if(v.current)throw E({type:"SUBMIT_FAILURE"}),e})}if(v.current&&(E({type:"SUBMIT_FAILURE"}),n))throw e})}),K=hP(function(e){e&&e.preventDefault&&hf(e.preventDefault)&&e.preventDefault(),e&&e.stopPropagation&&hf(e.stopPropagation)&&e.stopPropagation(),W().catch(function(e){console.warn("Warning: An unhandled error was caught from submitForm()",e)})}),V={resetForm:A,validateForm:O,validateField:L,setErrors:N,setFieldError:R,setFieldTouched:B,setFieldValue:j,setStatus:z,setSubmitting:G,setTouched:D,setValues:P,setFormikState:$,submitForm:W},q=hP(function(){return f(_.values,V)}),Z=hP(function(e){e&&e.preventDefault&&hf(e.preventDefault)&&e.preventDefault(),e&&e.stopPropagation&&hf(e.stopPropagation)&&e.stopPropagation(),A()}),X=(0,l.useCallback)(function(e){return{value:hg(_.values,e),error:hg(_.errors,e),touched:!!hg(_.touched,e),initialValue:hg(p.current,e),initialTouched:!!hg(m.current,e),initialError:hg(b.current,e)}},[_.errors,_.touched,_.values]),J=(0,l.useCallback)(function(e){return{setValue:function(t,n){return j(e,t,n)},setTouched:function(t,n){return B(e,t,n)},setError:function(t){return R(e,t)}}},[j,B,R]),Q=(0,l.useCallback)(function(e){var t=hd(e),n=t?e.name:e,r=hg(_.values,n),i={name:n,value:r,onChange:Y,onBlur:H};if(t){var a=e.type,o=e.value,s=e.as,u=e.multiple;"checkbox"===a?void 0===o?i.checked=!!r:(i.checked=!!(Array.isArray(r)&&~r.indexOf(o)),i.value=o):"radio"===a?(i.checked=r===o,i.value=o):"select"===s&&u&&(i.value=i.value||[],i.multiple=!0)}return i},[H,Y,_.values]),ee=(0,l.useMemo)(function(){return!sh()(p.current,_.values)},[p.current,_.values]),et=(0,l.useMemo)(function(){return void 0!==s?ee?_.errors&&0===Object.keys(_.errors).length:!1!==s&&hf(s)?s(h):s:_.errors&&0===Object.keys(_.errors).length},[s,ee,_.errors,h]);return ho({},_,{initialValues:p.current,initialErrors:b.current,initialTouched:m.current,initialStatus:g.current,handleBlur:H,handleChange:Y,handleReset:Z,handleSubmit:K,resetForm:A,setErrors:N,setFormikState:$,setFieldTouched:B,setFieldValue:j,setFieldError:R,setStatus:z,setSubmitting:G,setTouched:D,setValues:P,submitForm:W,validateForm:O,validateField:L,isValid:et,dirty:ee,unregisterField:I,registerField:C,getFieldProps:Q,getFieldMeta:X,getFieldHelpers:J,validateOnBlur:i,validateOnChange:n,validateOnMount:o})}function hM(e){var t=hT(e),n=e.component,r=e.children,i=e.render,a=e.innerRef;return(0,l.useImperativeHandle)(a,function(){return t}),(0,l.createElement)(h_,{value:t},n?(0,l.createElement)(n,t):i?i(t):r?hf(r)?r(t):hb(r)?null:l.Children.only(r):null)}function hO(e){var t={};if(e.inner){if(0===e.inner.length)return hv(t,e.path,e.message);for(var n=e.inner,r=Array.isArray(n),i=0,n=r?n:n[Symbol.iterator]();;){if(r){if(i>=n.length)break;a=n[i++]}else{if((i=n.next()).done)break;a=i.value}var a,o=a;hg(t,o.path)||(t=hv(t,o.path,o.message))}}return t}function hA(e,t,n,r){void 0===n&&(n=!1),void 0===r&&(r={});var i=hL(e);return t[n?"validateSync":"validate"](i,{abortEarly:!1,context:r})}function hL(e){var t=Array.isArray(e)?[]:{};for(var n in e)if(Object.prototype.hasOwnProperty.call(e,n)){var r=String(n);!0===Array.isArray(e[r])?t[r]=e[r].map(function(e){return!0===Array.isArray(e)||sj(e)?hL(e):""!==e?e:void 0}):sj(e[r])?t[r]=hL(e[r]):t[r]=""!==e[r]?e[r]:void 0}return t}function hC(e,t,n){var r=e.slice();return t.forEach(function(t,i){if(void 0===r[i]){var a=!1!==n.clone&&n.isMergeableObject(t);r[i]=a?sx(Array.isArray(t)?[]:{},t,n):t}else n.isMergeableObject(t)?r[i]=sx(e[i],t,n):-1===e.indexOf(t)&&r.push(t)}),r}function hI(e){return Array.from(e).filter(function(e){return e.selected}).map(function(e){return e.value})}function hD(e,t,n){if("boolean"==typeof e)return Boolean(t);var r=[],i=!1,a=-1;if(Array.isArray(e))r=e,i=(a=e.indexOf(n))>=0;else if(!n||"true"==n||"false"==n)return Boolean(t);return t&&n&&!i?r.concat(n):i?r.slice(0,a).concat(r.slice(a+1)):r}var hN="undefined"!=typeof window&&void 0!==window.document&&void 0!==window.document.createElement?l.useLayoutEffect:l.useEffect;function hP(e){var t=(0,l.useRef)(e);return hN(function(){t.current=e}),(0,l.useCallback)(function(){for(var e=arguments.length,n=Array(e),r=0;re?t:e},0);return Array.from(ho({},e,{length:t+1}))};(function(e){function t(t){var n;return(n=e.call(this,t)||this).updateArrayField=function(e,t,r){var i=n.props,a=i.name;(0,i.formik.setFormikState)(function(n){var i="function"==typeof r?r:e,o="function"==typeof t?t:e,s=hv(n.values,a,e(hg(n.values,a))),u=r?i(hg(n.errors,a)):void 0,c=t?o(hg(n.touched,a)):void 0;return hl(u)&&(u=void 0),hl(c)&&(c=void 0),ho({},n,{values:s,errors:r?hv(n.errors,a,u):n.errors,touched:t?hv(n.touched,a,c):n.touched})})},n.push=function(e){return n.updateArrayField(function(t){return[].concat(hH(t),[ha(e)])},!1,!1)},n.handlePush=function(e){return function(){return n.push(e)}},n.swap=function(e,t){return n.updateArrayField(function(n){return hY(n,e,t)},!0,!0)},n.handleSwap=function(e,t){return function(){return n.swap(e,t)}},n.move=function(e,t){return n.updateArrayField(function(n){return hF(n,e,t)},!0,!0)},n.handleMove=function(e,t){return function(){return n.move(e,t)}},n.insert=function(e,t){return n.updateArrayField(function(n){return hB(n,e,t)},function(t){return hB(t,e,null)},function(t){return hB(t,e,null)})},n.handleInsert=function(e,t){return function(){return n.insert(e,t)}},n.replace=function(e,t){return n.updateArrayField(function(n){return hU(n,e,t)},!1,!1)},n.handleReplace=function(e,t){return function(){return n.replace(e,t)}},n.unshift=function(e){var t=-1;return n.updateArrayField(function(n){var r=n?[e].concat(n):[e];return t<0&&(t=r.length),r},function(e){var n=e?[null].concat(e):[null];return t<0&&(t=n.length),n},function(e){var n=e?[null].concat(e):[null];return t<0&&(t=n.length),n}),t},n.handleUnshift=function(e){return function(){return n.unshift(e)}},n.handleRemove=function(e){return function(){return n.remove(e)}},n.handlePop=function(){return function(){return n.pop()}},n.remove=n.remove.bind(hc(n)),n.pop=n.pop.bind(hc(n)),n}hs(t,e);var n=t.prototype;return n.componentDidUpdate=function(e){this.props.validateOnChange&&this.props.formik.validateOnChange&&!sh()(hg(e.formik.values,e.name),hg(this.props.formik.values,this.props.name))&&this.props.formik.validateForm(this.props.formik.values)},n.remove=function(e){var t;return this.updateArrayField(function(n){var r=n?hH(n):[];return t||(t=r[e]),hf(r.splice)&&r.splice(e,1),r},!0,!0),t},n.pop=function(){var e;return this.updateArrayField(function(t){var n=t;return e||(e=n&&n.pop&&n.pop()),n},!0,!0),e},n.render=function(){var e={push:this.push,pop:this.pop,swap:this.swap,move:this.move,insert:this.insert,replace:this.replace,unshift:this.unshift,remove:this.remove,handlePush:this.handlePush,handlePop:this.handlePop,handleSwap:this.handleSwap,handleMove:this.handleMove,handleInsert:this.handleInsert,handleReplace:this.handleReplace,handleUnshift:this.handleUnshift,handleRemove:this.handleRemove},t=this.props,n=t.component,r=t.render,i=t.children,a=t.name,o=hu(t.formik,["validate","validationSchema"]),s=ho({},e,{form:o,name:a});return n?(0,l.createElement)(n,s):r?r(s):i?"function"==typeof i?i(s):hb(i)?null:l.Children.only(i):null},t})(l.Component).defaultProps={validateOnChange:!0},l.Component,l.Component;var h$=n(24802),hz=n(71209),hG=n(91750),hW=n(11970),hK=n(4689),hV=n(67598),hq=function(){return(hq=Object.assign||function(e){for(var t,n=1,r=arguments.length;nt.indexOf(r)&&(n[r]=e[r]);if(null!=e&&"function"==typeof Object.getOwnPropertySymbols)for(var i=0,r=Object.getOwnPropertySymbols(e);it.indexOf(r[i])&&(n[r[i]]=e[r[i]]);return n}function hX(e){var t=e.disabled,n=e.field,r=n.onBlur,i=hZ(n,["onBlur"]),a=e.form,o=a.isSubmitting,s=a.touched,u=a.errors,c=e.onBlur,l=e.helperText,f=hZ(e,["disabled","field","form","onBlur","helperText"]),d=hg(u,i.name),h=hg(s,i.name)&&!!d;return hq(hq({variant:f.variant,error:h,helperText:h?d:l,disabled:null!=t?t:o,onBlur:null!=c?c:function(e){r(null!=e?e:i.name)}},i),f)}function hJ(e){var t=e.children,n=hZ(e,["children"]);return(0,l.createElement)(i_.Z,hq({},hX(n)),t)}function hQ(e){var t=e.disabled,n=e.field,r=n.onBlur,i=hZ(n,["onBlur"]),a=e.form.isSubmitting,o=(e.type,e.onBlur),s=hZ(e,["disabled","field","form","type","onBlur"]);return hq(hq({disabled:null!=t?t:a,onBlur:null!=o?o:function(e){r(null!=e?e:i.name)}},i),s)}function h1(e){return(0,l.createElement)(h$.Z,hq({},hQ(e)))}function h0(e){var t,n=e.disabled,r=e.field,i=r.onBlur,a=hZ(r,["onBlur"]),o=e.form.isSubmitting,s=(e.type,e.onBlur),u=hZ(e,["disabled","field","form","type","onBlur"]);return hq(hq({disabled:null!=n?n:o,indeterminate:!Array.isArray(a.value)&&null==a.value,onBlur:null!=s?s:function(e){i(null!=e?e:a.name)}},a),u)}function h2(e){return(0,l.createElement)(hz.Z,hq({},h0(e)))}function h3(e){var t=e.Label,n=hZ(e,["Label"]);return(0,l.createElement)(hG.Z,hq({control:(0,l.createElement)(hz.Z,hq({},h0(n)))},t))}function h4(e){var t=e.disabled,n=e.field,r=n.onBlur,i=hZ(n,["onBlur"]),a=e.form.isSubmitting,o=e.onBlur,s=hZ(e,["disabled","field","form","onBlur"]);return hq(hq({disabled:null!=t?t:a,onBlur:null!=o?o:function(e){r(null!=e?e:i.name)}},i),s)}function h5(e){return(0,l.createElement)(hW.default,hq({},h4(e)))}function h6(e){var t=e.field,n=t.onBlur,r=hZ(t,["onBlur"]),i=(e.form,e.onBlur),a=hZ(e,["field","form","onBlur"]);return hq(hq({onBlur:null!=i?i:function(e){n(null!=e?e:r.name)}},r),a)}function h9(e){return(0,l.createElement)(hK.Z,hq({},h6(e)))}function h8(e){var t=e.disabled,n=e.field,r=n.onBlur,i=hZ(n,["onBlur"]),a=e.form.isSubmitting,o=e.onBlur,s=hZ(e,["disabled","field","form","onBlur"]);return hq(hq({disabled:null!=t?t:a,onBlur:null!=o?o:function(e){r(null!=e?e:i.name)}},i),s)}function h7(e){return(0,l.createElement)(hV.default,hq({},h8(e)))}hJ.displayName="FormikMaterialUITextField",h1.displayName="FormikMaterialUISwitch",h2.displayName="FormikMaterialUICheckbox",h3.displayName="FormikMaterialUICheckboxWithLabel",h5.displayName="FormikMaterialUISelect",h9.displayName="FormikMaterialUIRadioGroup",h7.displayName="FormikMaterialUIInputBase";try{a=Map}catch(pe){}try{o=Set}catch(pt){}function pn(e,t,n){if(!e||"object"!=typeof e||"function"==typeof e)return e;if(e.nodeType&&"cloneNode"in e)return e.cloneNode(!0);if(e instanceof Date)return new Date(e.getTime());if(e instanceof RegExp)return RegExp(e);if(Array.isArray(e))return e.map(pr);if(a&&e instanceof a)return new Map(Array.from(e.entries()));if(o&&e instanceof o)return new Set(Array.from(e.values()));if(e instanceof Object){t.push(e);var r=Object.create(e);for(var i in n.push(r),e){var s=t.findIndex(function(t){return t===e[i]});r[i]=s>-1?n[s]:pn(e[i],t,n)}return r}return e}function pr(e){return pn(e,[],[])}let pi=Object.prototype.toString,pa=Error.prototype.toString,po=RegExp.prototype.toString,ps="undefined"!=typeof Symbol?Symbol.prototype.toString:()=>"",pu=/^Symbol\((.*)\)(.*)$/;function pc(e){if(e!=+e)return"NaN";let t=0===e&&1/e<0;return t?"-0":""+e}function pl(e,t=!1){if(null==e||!0===e||!1===e)return""+e;let n=typeof e;if("number"===n)return pc(e);if("string"===n)return t?`"${e}"`:e;if("function"===n)return"[Function "+(e.name||"anonymous")+"]";if("symbol"===n)return ps.call(e).replace(pu,"Symbol($1)");let r=pi.call(e).slice(8,-1);return"Date"===r?isNaN(e.getTime())?""+e:e.toISOString(e):"Error"===r||e instanceof Error?"["+pa.call(e)+"]":"RegExp"===r?po.call(e):null}function pf(e,t){let n=pl(e,t);return null!==n?n:JSON.stringify(e,function(e,n){let r=pl(this[e],t);return null!==r?r:n},2)}let pd={default:"${path} is invalid",required:"${path} is a required field",oneOf:"${path} must be one of the following values: ${values}",notOneOf:"${path} must not be one of the following values: ${values}",notType({path:e,type:t,value:n,originalValue:r}){let i=null!=r&&r!==n,a=`${e} must be a \`${t}\` type, but the final value was: \`${pf(n,!0)}\``+(i?` (cast from the value \`${pf(r,!0)}\`).`:".");return null===n&&(a+='\n If "null" is intended as an empty value be sure to mark the schema as `.nullable()`'),a},defined:"${path} must be defined"},ph={length:"${path} must be exactly ${length} characters",min:"${path} must be at least ${min} characters",max:"${path} must be at most ${max} characters",matches:'${path} must match the following: "${regex}"',email:"${path} must be a valid email",url:"${path} must be a valid URL",uuid:"${path} must be a valid UUID",trim:"${path} must be a trimmed string",lowercase:"${path} must be a lowercase string",uppercase:"${path} must be a upper case string"},pp={min:"${path} must be greater than or equal to ${min}",max:"${path} must be less than or equal to ${max}",lessThan:"${path} must be less than ${less}",moreThan:"${path} must be greater than ${more}",positive:"${path} must be a positive number",negative:"${path} must be a negative number",integer:"${path} must be an integer"},pb={min:"${path} field must be later than ${min}",max:"${path} field must be at earlier than ${max}"},pm={isValue:"${path} field must be ${value}"},pg={noUnknown:"${path} field has unspecified keys: ${unknown}"},pv={min:"${path} field must have at least ${min} items",max:"${path} field must have less than or equal to ${max} items",length:"${path} must be have ${length} items"};Object.assign(Object.create(null),{mixed:pd,string:ph,number:pp,date:pb,object:pg,array:pv,boolean:pm});var py=n(18721),pw=n.n(py);let p_=e=>e&&e.__isYupSchema__;class pE{constructor(e,t){if(this.refs=e,this.refs=e,"function"==typeof t){this.fn=t;return}if(!pw()(t,"is"))throw TypeError("`is:` is required for `when()` conditions");if(!t.then&&!t.otherwise)throw TypeError("either `then:` or `otherwise:` is required for `when()` conditions");let{is:n,then:r,otherwise:i}=t,a="function"==typeof n?n:(...e)=>e.every(e=>e===n);this.fn=function(...e){let t=e.pop(),n=e.pop(),o=a(...e)?r:i;if(o)return"function"==typeof o?o(n):n.concat(o.resolve(t))}}resolve(e,t){let n=this.refs.map(e=>e.getValue(null==t?void 0:t.value,null==t?void 0:t.parent,null==t?void 0:t.context)),r=this.fn.apply(e,n.concat(e,t));if(void 0===r||r===e)return e;if(!p_(r))throw TypeError("conditions must return a schema object");return r.resolve(t)}}let pS=pE;function pk(e){return null==e?[]:[].concat(e)}function px(){return(px=Object.assign||function(e){for(var t=1;tpf(t[n])):"function"==typeof e?e(t):e}static isError(e){return e&&"ValidationError"===e.name}constructor(e,t,n,r){super(),this.name="ValidationError",this.value=t,this.path=n,this.type=r,this.errors=[],this.inner=[],pk(e).forEach(e=>{pM.isError(e)?(this.errors.push(...e.errors),this.inner=this.inner.concat(e.inner.length?e.inner:e)):this.errors.push(e)}),this.message=this.errors.length>1?`${this.errors.length} errors occurred`:this.errors[0],Error.captureStackTrace&&Error.captureStackTrace(this,pM)}}let pO=e=>{let t=!1;return(...n)=>{t||(t=!0,e(...n))}};function pA(e,t){let{endEarly:n,tests:r,args:i,value:a,errors:o,sort:s,path:u}=e,c=pO(t),l=r.length,f=[];if(o=o||[],!l)return o.length?c(new pM(o,a,u)):c(null,a);for(let d=0;d=0||(i[n]=e[n]);return i}function pj(e){function t(t,n){let{value:r,path:i="",label:a,options:o,originalValue:s,sync:u}=t,c=pR(t,["value","path","label","options","originalValue","sync"]),{name:l,test:f,params:d,message:h}=e,{parent:p,context:b}=o;function m(e){return pN.isRef(e)?e.getValue(r,p,b):e}function g(e={}){let t=pC()(pP({value:r,originalValue:s,label:a,path:e.path||i},d,e.params),m),n=new pM(pM.formatError(e.message||h,t),r,t.path,e.type||l);return n.params=t,n}let v=pP({path:i,parent:p,type:l,createError:g,resolve:m,options:o,originalValue:s},c);if(!u){try{Promise.resolve(f.call(v,r,v)).then(e=>{pM.isError(e)?n(e):e?n(null,e):n(g())})}catch(y){n(y)}return}let w;try{var _;if(w=f.call(v,r,v),"function"==typeof(null==(_=w)?void 0:_.then))throw Error(`Validation test of type: "${v.type}" returned a Promise during a synchronous validate. This test will finish after the validate call has returned`)}catch(E){n(E);return}pM.isError(w)?n(w):w?n(null,w):n(g())}return t.OPTIONS=e,t}pN.prototype.__isYupRef=!0;let pF=e=>e.substr(0,e.length-1).substr(1);function pY(e,t,n,r=n){let i,a,o;return t?((0,pI.forEach)(t,(s,u,c)=>{let l=u?pF(s):s;if((e=e.resolve({context:r,parent:i,value:n})).innerType){let f=c?parseInt(l,10):0;if(n&&f>=n.length)throw Error(`Yup.reach cannot resolve an array item at index: ${s}, in the path: ${t}. because there is no value at that index. `);i=n,n=n&&n[f],e=e.innerType}if(!c){if(!e.fields||!e.fields[l])throw Error(`The schema does not contain the path: ${t}. (failed at: ${o} which is a type: "${e._type}")`);i=n,n=n&&n[l],e=e.fields[l]}a=l,o=u?"["+s+"]":"."+s}),{schema:e,parent:i,parentPath:a}):{parent:i,parentPath:t,schema:e}}class pB{constructor(){this.list=new Set,this.refs=new Map}get size(){return this.list.size+this.refs.size}describe(){let e=[];for(let t of this.list)e.push(t);for(let[,n]of this.refs)e.push(n.describe());return e}toArray(){return Array.from(this.list).concat(Array.from(this.refs.values()))}add(e){pN.isRef(e)?this.refs.set(e.key,e):this.list.add(e)}delete(e){pN.isRef(e)?this.refs.delete(e.key):this.list.delete(e)}has(e,t){if(this.list.has(e))return!0;let n,r=this.refs.values();for(;!(n=r.next()).done;)if(t(n.value)===e)return!0;return!1}clone(){let e=new pB;return e.list=new Set(this.list),e.refs=new Map(this.refs),e}merge(e,t){let n=this.clone();return e.list.forEach(e=>n.add(e)),e.refs.forEach(e=>n.add(e)),t.list.forEach(e=>n.delete(e)),t.refs.forEach(e=>n.delete(e)),n}}function pU(){return(pU=Object.assign||function(e){for(var t=1;t{this.typeError(pd.notType)}),this.type=(null==e?void 0:e.type)||"mixed",this.spec=pU({strip:!1,strict:!1,abortEarly:!0,recursive:!0,nullable:!1,presence:"optional"},null==e?void 0:e.spec)}get _type(){return this.type}_typeCheck(e){return!0}clone(e){if(this._mutate)return e&&Object.assign(this.spec,e),this;let t=Object.create(Object.getPrototypeOf(this));return t.type=this.type,t._typeError=this._typeError,t._whitelistError=this._whitelistError,t._blacklistError=this._blacklistError,t._whitelist=this._whitelist.clone(),t._blacklist=this._blacklist.clone(),t.exclusiveTests=pU({},this.exclusiveTests),t.deps=[...this.deps],t.conditions=[...this.conditions],t.tests=[...this.tests],t.transforms=[...this.transforms],t.spec=pr(pU({},this.spec,e)),t}label(e){var t=this.clone();return t.spec.label=e,t}meta(...e){if(0===e.length)return this.spec.meta;let t=this.clone();return t.spec.meta=Object.assign(t.spec.meta||{},e[0]),t}withMutation(e){let t=this._mutate;this._mutate=!0;let n=e(this);return this._mutate=t,n}concat(e){if(!e||e===this)return this;if(e.type!==this.type&&"mixed"!==this.type)throw TypeError(`You cannot \`concat()\` schema's of different types: ${this.type} and ${e.type}`);let t=this,n=e.clone(),r=pU({},t.spec,n.spec);return n.spec=r,n._typeError||(n._typeError=t._typeError),n._whitelistError||(n._whitelistError=t._whitelistError),n._blacklistError||(n._blacklistError=t._blacklistError),n._whitelist=t._whitelist.merge(e._whitelist,e._blacklist),n._blacklist=t._blacklist.merge(e._blacklist,e._whitelist),n.tests=t.tests,n.exclusiveTests=t.exclusiveTests,n.withMutation(t=>{e.tests.forEach(e=>{t.test(e.OPTIONS)})}),n}isType(e){return!!this.spec.nullable&&null===e||this._typeCheck(e)}resolve(e){let t=this;if(t.conditions.length){let n=t.conditions;(t=t.clone()).conditions=[],t=(t=n.reduce((t,n)=>n.resolve(t,e),t)).resolve(e)}return t}cast(e,t={}){let n=this.resolve(pU({value:e},t)),r=n._cast(e,t);if(void 0!==e&&!1!==t.assert&&!0!==n.isType(r)){let i=pf(e),a=pf(r);throw TypeError(`The value of ${t.path||"field"} could not be cast to a value that satisfies the schema type: "${n._type}". attempted value: ${i} -`+(a!==i?`result of cast: ${a}`:""))}return r}_cast(e,t){let n=void 0===e?e:this.transforms.reduce((t,n)=>n.call(this,t,e,this),e);return void 0===n&&(n=this.getDefault()),n}_validate(e,t={},n){let{sync:r,path:i,from:a=[],originalValue:o=e,strict:s=this.spec.strict,abortEarly:u=this.spec.abortEarly}=t,c=e;s||(c=this._cast(c,pU({assert:!1},t)));let l={value:c,path:i,options:t,originalValue:o,schema:this,label:this.spec.label,sync:r,from:a},f=[];this._typeError&&f.push(this._typeError),this._whitelistError&&f.push(this._whitelistError),this._blacklistError&&f.push(this._blacklistError),pA({args:l,value:c,path:i,sync:r,tests:f,endEarly:u},e=>{if(e)return void n(e,c);pA({tests:this.tests,args:l,path:i,sync:r,value:c,endEarly:u},n)})}validate(e,t,n){let r=this.resolve(pU({},t,{value:e}));return"function"==typeof n?r._validate(e,t,n):new Promise((n,i)=>r._validate(e,t,(e,t)=>{e?i(e):n(t)}))}validateSync(e,t){let n;return this.resolve(pU({},t,{value:e}))._validate(e,pU({},t,{sync:!0}),(e,t)=>{if(e)throw e;n=t}),n}isValid(e,t){return this.validate(e,t).then(()=>!0,e=>{if(pM.isError(e))return!1;throw e})}isValidSync(e,t){try{return this.validateSync(e,t),!0}catch(n){if(pM.isError(n))return!1;throw n}}_getDefault(){let e=this.spec.default;return null==e?e:"function"==typeof e?e.call(this):pr(e)}getDefault(e){return this.resolve(e||{})._getDefault()}default(e){return 0===arguments.length?this._getDefault():this.clone({default:e})}strict(e=!0){var t=this.clone();return t.spec.strict=e,t}_isPresent(e){return null!=e}defined(e=pd.defined){return this.test({message:e,name:"defined",exclusive:!0,test:e=>void 0!==e})}required(e=pd.required){return this.clone({presence:"required"}).withMutation(t=>t.test({message:e,name:"required",exclusive:!0,test(e){return this.schema._isPresent(e)}}))}notRequired(){var e=this.clone({presence:"optional"});return e.tests=e.tests.filter(e=>"required"!==e.OPTIONS.name),e}nullable(e=!0){return this.clone({nullable:!1!==e})}transform(e){var t=this.clone();return t.transforms.push(e),t}test(...e){let t;if(void 0===(t=1===e.length?"function"==typeof e[0]?{test:e[0]}:e[0]:2===e.length?{name:e[0],test:e[1]}:{name:e[0],message:e[1],test:e[2]}).message&&(t.message=pd.default),"function"!=typeof t.test)throw TypeError("`test` is a required parameters");let n=this.clone(),r=pj(t),i=t.exclusive||t.name&&!0===n.exclusiveTests[t.name];if(t.exclusive&&!t.name)throw TypeError("Exclusive tests must provide a unique `name` identifying the test");return t.name&&(n.exclusiveTests[t.name]=!!t.exclusive),n.tests=n.tests.filter(e=>e.OPTIONS.name!==t.name||!i&&e.OPTIONS.test!==r.OPTIONS.test),n.tests.push(r),n}when(e,t){Array.isArray(e)||"string"==typeof e||(t=e,e=".");let n=this.clone(),r=pk(e).map(e=>new pN(e));return r.forEach(e=>{e.isSibling&&n.deps.push(e.key)}),n.conditions.push(new pS(r,t)),n}typeError(e){var t=this.clone();return t._typeError=pj({message:e,name:"typeError",test(e){return!!(void 0===e||this.schema.isType(e))||this.createError({params:{type:this.schema._type}})}}),t}oneOf(e,t=pd.oneOf){var n=this.clone();return e.forEach(e=>{n._whitelist.add(e),n._blacklist.delete(e)}),n._whitelistError=pj({message:t,name:"oneOf",test(e){if(void 0===e)return!0;let t=this.schema._whitelist;return!!t.has(e,this.resolve)||this.createError({params:{values:t.toArray().join(", ")}})}}),n}notOneOf(e,t=pd.notOneOf){var n=this.clone();return e.forEach(e=>{n._blacklist.add(e),n._whitelist.delete(e)}),n._blacklistError=pj({message:t,name:"notOneOf",test(e){let t=this.schema._blacklist;return!t.has(e,this.resolve)||this.createError({params:{values:t.toArray().join(", ")}})}}),n}strip(e=!0){let t=this.clone();return t.spec.strip=e,t}describe(){let e=this.clone(),{label:t,meta:n}=e.spec,r={meta:n,label:t,type:e.type,oneOf:e._whitelist.describe(),notOneOf:e._blacklist.describe(),tests:e.tests.map(e=>({name:e.OPTIONS.name,params:e.OPTIONS.params})).filter((e,t,n)=>n.findIndex(t=>t.name===e.name)===t)};return r}}for(let p$ of(pH.prototype.__isYupSchema__=!0,["validate","validateSync"]))pH.prototype[`${p$}At`]=function(e,t,n={}){let{parent:r,parentPath:i,schema:a}=pY(this,e,t,n.context);return a[p$](r&&r[i],pU({},n,{parent:r,path:e}))};for(let pz of["equals","is"])pH.prototype[pz]=pH.prototype.oneOf;for(let pG of["not","nope"])pH.prototype[pG]=pH.prototype.notOneOf;pH.prototype.optional=pH.prototype.notRequired;let pW=pH;function pK(){return new pW}pK.prototype=pW.prototype;let pV=e=>null==e;function pq(){return new pZ}class pZ extends pH{constructor(){super({type:"boolean"}),this.withMutation(()=>{this.transform(function(e){if(!this.isType(e)){if(/^(true|1)$/i.test(String(e)))return!0;if(/^(false|0)$/i.test(String(e)))return!1}return e})})}_typeCheck(e){return e instanceof Boolean&&(e=e.valueOf()),"boolean"==typeof e}isTrue(e=pm.isValue){return this.test({message:e,name:"is-value",exclusive:!0,params:{value:"true"},test:e=>pV(e)||!0===e})}isFalse(e=pm.isValue){return this.test({message:e,name:"is-value",exclusive:!0,params:{value:"false"},test:e=>pV(e)||!1===e})}}pq.prototype=pZ.prototype;let pX=/^((([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+(\.([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+)*)|((\x22)((((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(([\x01-\x08\x0b\x0c\x0e-\x1f\x7f]|\x21|[\x23-\x5b]|[\x5d-\x7e]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(\\([\x01-\x09\x0b\x0c\x0d-\x7f]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]))))*(((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(\x22)))@((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))$/i,pJ=/^((https?|ftp):)?\/\/(((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:)*@)?(((\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5]))|((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.?)(:\d*)?)(\/((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)+(\/(([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)*)*)?)?(\?((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|[\uE000-\uF8FF]|\/|\?)*)?(\#((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|\/|\?)*)?$/i,pQ=/^(?:[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}|00000000-0000-0000-0000-000000000000)$/i,p1=e=>pV(e)||e===e.trim(),p0=({}).toString();function p2(){return new p3}class p3 extends pH{constructor(){super({type:"string"}),this.withMutation(()=>{this.transform(function(e){if(this.isType(e)||Array.isArray(e))return e;let t=null!=e&&e.toString?e.toString():e;return t===p0?e:t})})}_typeCheck(e){return e instanceof String&&(e=e.valueOf()),"string"==typeof e}_isPresent(e){return super._isPresent(e)&&!!e.length}length(e,t=ph.length){return this.test({message:t,name:"length",exclusive:!0,params:{length:e},test(t){return pV(t)||t.length===this.resolve(e)}})}min(e,t=ph.min){return this.test({message:t,name:"min",exclusive:!0,params:{min:e},test(t){return pV(t)||t.length>=this.resolve(e)}})}max(e,t=ph.max){return this.test({name:"max",exclusive:!0,message:t,params:{max:e},test(t){return pV(t)||t.length<=this.resolve(e)}})}matches(e,t){let n=!1,r,i;return t&&("object"==typeof t?{excludeEmptyString:n=!1,message:r,name:i}=t:r=t),this.test({name:i||"matches",message:r||ph.matches,params:{regex:e},test:t=>pV(t)||""===t&&n||-1!==t.search(e)})}email(e=ph.email){return this.matches(pX,{name:"email",message:e,excludeEmptyString:!0})}url(e=ph.url){return this.matches(pJ,{name:"url",message:e,excludeEmptyString:!0})}uuid(e=ph.uuid){return this.matches(pQ,{name:"uuid",message:e,excludeEmptyString:!1})}ensure(){return this.default("").transform(e=>null===e?"":e)}trim(e=ph.trim){return this.transform(e=>null!=e?e.trim():e).test({message:e,name:"trim",test:p1})}lowercase(e=ph.lowercase){return this.transform(e=>pV(e)?e:e.toLowerCase()).test({message:e,name:"string_case",exclusive:!0,test:e=>pV(e)||e===e.toLowerCase()})}uppercase(e=ph.uppercase){return this.transform(e=>pV(e)?e:e.toUpperCase()).test({message:e,name:"string_case",exclusive:!0,test:e=>pV(e)||e===e.toUpperCase()})}}p2.prototype=p3.prototype;let p4=e=>e!=+e;function p5(){return new p6}class p6 extends pH{constructor(){super({type:"number"}),this.withMutation(()=>{this.transform(function(e){let t=e;if("string"==typeof t){if(""===(t=t.replace(/\s/g,"")))return NaN;t=+t}return this.isType(t)?t:parseFloat(t)})})}_typeCheck(e){return e instanceof Number&&(e=e.valueOf()),"number"==typeof e&&!p4(e)}min(e,t=pp.min){return this.test({message:t,name:"min",exclusive:!0,params:{min:e},test(t){return pV(t)||t>=this.resolve(e)}})}max(e,t=pp.max){return this.test({message:t,name:"max",exclusive:!0,params:{max:e},test(t){return pV(t)||t<=this.resolve(e)}})}lessThan(e,t=pp.lessThan){return this.test({message:t,name:"max",exclusive:!0,params:{less:e},test(t){return pV(t)||tthis.resolve(e)}})}positive(e=pp.positive){return this.moreThan(0,e)}negative(e=pp.negative){return this.lessThan(0,e)}integer(e=pp.integer){return this.test({name:"integer",message:e,test:e=>pV(e)||Number.isInteger(e)})}truncate(){return this.transform(e=>pV(e)?e:0|e)}round(e){var t,n=["ceil","floor","round","trunc"];if("trunc"===(e=(null==(t=e)?void 0:t.toLowerCase())||"round"))return this.truncate();if(-1===n.indexOf(e.toLowerCase()))throw TypeError("Only valid options for round() are: "+n.join(", "));return this.transform(t=>pV(t)?t:Math[e](t))}}p5.prototype=p6.prototype;var p9=/^(\d{4}|[+\-]\d{6})(?:-?(\d{2})(?:-?(\d{2}))?)?(?:[ T]?(\d{2}):?(\d{2})(?::?(\d{2})(?:[,\.](\d{1,}))?)?(?:(Z)|([+\-])(\d{2})(?::?(\d{2}))?)?)?$/;function p8(e){var t,n,r=[1,4,5,6,7,10,11],i=0;if(n=p9.exec(e)){for(var a,o=0;a=r[o];++o)n[a]=+n[a]||0;n[2]=(+n[2]||1)-1,n[3]=+n[3]||1,n[7]=n[7]?String(n[7]).substr(0,3):0,(void 0===n[8]||""===n[8])&&(void 0===n[9]||""===n[9])?t=+new Date(n[1],n[2],n[3],n[4],n[5],n[6],n[7]):("Z"!==n[8]&&void 0!==n[9]&&(i=60*n[10]+n[11],"+"===n[9]&&(i=0-i)),t=Date.UTC(n[1],n[2],n[3],n[4],n[5]+i,n[6],n[7]))}else t=Date.parse?Date.parse(e):NaN;return t}let p7=new Date(""),be=e=>"[object Date]"===Object.prototype.toString.call(e);function bt(){return new bn}class bn extends pH{constructor(){super({type:"date"}),this.withMutation(()=>{this.transform(function(e){return this.isType(e)?e:(e=p8(e),isNaN(e)?p7:new Date(e))})})}_typeCheck(e){return be(e)&&!isNaN(e.getTime())}prepareParam(e,t){let n;if(pN.isRef(e))n=e;else{let r=this.cast(e);if(!this._typeCheck(r))throw TypeError(`\`${t}\` must be a Date or a value that can be \`cast()\` to a Date`);n=r}return n}min(e,t=pb.min){let n=this.prepareParam(e,"min");return this.test({message:t,name:"min",exclusive:!0,params:{min:e},test(e){return pV(e)||e>=this.resolve(n)}})}max(e,t=pb.max){var n=this.prepareParam(e,"max");return this.test({message:t,name:"max",exclusive:!0,params:{max:e},test(e){return pV(e)||e<=this.resolve(n)}})}}bn.INVALID_DATE=p7,bt.prototype=bn.prototype,bt.INVALID_DATE=p7;var br=n(11865),bi=n.n(br),ba=n(68929),bo=n.n(ba),bs=n(67523),bu=n.n(bs),bc=n(94633),bl=n.n(bc);function bf(e,t=[]){let n=[],r=[];function i(e,i){var a=(0,pI.split)(e)[0];~r.indexOf(a)||r.push(a),~t.indexOf(`${i}-${a}`)||n.push([i,a])}for(let a in e)if(pw()(e,a)){let o=e[a];~r.indexOf(a)||r.push(a),pN.isRef(o)&&o.isSibling?i(o.path,a):p_(o)&&"deps"in o&&o.deps.forEach(e=>i(e,a))}return bl().array(r,n).reverse()}function bd(e,t){let n=1/0;return e.some((e,r)=>{var i;if((null==(i=t.path)?void 0:i.indexOf(e))!==-1)return n=r,!0}),n}function bh(e){return(t,n)=>bd(e,t)-bd(e,n)}function bp(){return(bp=Object.assign||function(e){for(var t=1;t"[object Object]"===Object.prototype.toString.call(e);function bm(e,t){let n=Object.keys(e.fields);return Object.keys(t).filter(e=>-1===n.indexOf(e))}let bg=bh([]);class bv extends pH{constructor(e){super({type:"object"}),this.fields=Object.create(null),this._sortErrors=bg,this._nodes=[],this._excludedEdges=[],this.withMutation(()=>{this.transform(function(e){if("string"==typeof e)try{e=JSON.parse(e)}catch(t){e=null}return this.isType(e)?e:null}),e&&this.shape(e)})}_typeCheck(e){return bb(e)||"function"==typeof e}_cast(e,t={}){var n;let r=super._cast(e,t);if(void 0===r)return this.getDefault();if(!this._typeCheck(r))return r;let i=this.fields,a=null!=(n=t.stripUnknown)?n:this.spec.noUnknown,o=this._nodes.concat(Object.keys(r).filter(e=>-1===this._nodes.indexOf(e))),s={},u=bp({},t,{parent:s,__validating:t.__validating||!1}),c=!1;for(let l of o){let f=i[l],d=pw()(r,l);if(f){let h,p=r[l];u.path=(t.path?`${t.path}.`:"")+l;let b="spec"in(f=f.resolve({value:p,context:t.context,parent:s}))?f.spec:void 0,m=null==b?void 0:b.strict;if(null==b?void 0:b.strip){c=c||l in r;continue}void 0!==(h=t.__validating&&m?r[l]:f.cast(r[l],u))&&(s[l]=h)}else d&&!a&&(s[l]=r[l]);s[l]!==r[l]&&(c=!0)}return c?s:r}_validate(e,t={},n){let r=[],{sync:i,from:a=[],originalValue:o=e,abortEarly:s=this.spec.abortEarly,recursive:u=this.spec.recursive}=t;a=[{schema:this,value:o},...a],t.__validating=!0,t.originalValue=o,t.from=a,super._validate(e,t,(e,c)=>{if(e){if(!pM.isError(e)||s)return void n(e,c);r.push(e)}if(!u||!bb(c)){n(r[0]||null,c);return}o=o||c;let l=this._nodes.map(e=>(n,r)=>{let i=-1===e.indexOf(".")?(t.path?`${t.path}.`:"")+e:`${t.path||""}["${e}"]`,s=this.fields[e];if(s&&"validate"in s){s.validate(c[e],bp({},t,{path:i,from:a,strict:!0,parent:c,originalValue:o[e]}),r);return}r(null)});pA({sync:i,tests:l,value:c,errors:r,endEarly:s,sort:this._sortErrors,path:t.path},n)})}clone(e){let t=super.clone(e);return t.fields=bp({},this.fields),t._nodes=this._nodes,t._excludedEdges=this._excludedEdges,t._sortErrors=this._sortErrors,t}concat(e){let t=super.concat(e),n=t.fields;for(let[r,i]of Object.entries(this.fields)){let a=n[r];void 0===a?n[r]=i:a instanceof pH&&i instanceof pH&&(n[r]=i.concat(a))}return t.withMutation(()=>t.shape(n))}getDefaultFromShape(){let e={};return this._nodes.forEach(t=>{let n=this.fields[t];e[t]="default"in n?n.getDefault():void 0}),e}_getDefault(){return"default"in this.spec?super._getDefault():this._nodes.length?this.getDefaultFromShape():void 0}shape(e,t=[]){let n=this.clone(),r=Object.assign(n.fields,e);if(n.fields=r,n._sortErrors=bh(Object.keys(r)),t.length){Array.isArray(t[0])||(t=[t]);let i=t.map(([e,t])=>`${e}-${t}`);n._excludedEdges=n._excludedEdges.concat(i)}return n._nodes=bf(r,n._excludedEdges),n}pick(e){let t={};for(let n of e)this.fields[n]&&(t[n]=this.fields[n]);return this.clone().withMutation(e=>(e.fields={},e.shape(t)))}omit(e){let t=this.clone(),n=t.fields;for(let r of(t.fields={},e))delete n[r];return t.withMutation(()=>t.shape(n))}from(e,t,n){let r=(0,pI.getter)(e,!0);return this.transform(i=>{if(null==i)return i;let a=i;return pw()(i,e)&&(a=bp({},i),n||delete a[e],a[t]=r(i)),a})}noUnknown(e=!0,t=pg.noUnknown){"string"==typeof e&&(t=e,e=!0);let n=this.test({name:"noUnknown",exclusive:!0,message:t,test(t){if(null==t)return!0;let n=bm(this.schema,t);return!e||0===n.length||this.createError({params:{unknown:n.join(", ")}})}});return n.spec.noUnknown=e,n}unknown(e=!0,t=pg.noUnknown){return this.noUnknown(!e,t)}transformKeys(e){return this.transform(t=>t&&bu()(t,(t,n)=>e(n)))}camelCase(){return this.transformKeys(bo())}snakeCase(){return this.transformKeys(bi())}constantCase(){return this.transformKeys(e=>bi()(e).toUpperCase())}describe(){let e=super.describe();return e.fields=pC()(this.fields,e=>e.describe()),e}}function by(e){return new bv(e)}function bw(){return(bw=Object.assign||function(e){for(var t=1;t{this.transform(function(e){if("string"==typeof e)try{e=JSON.parse(e)}catch(t){e=null}return this.isType(e)?e:null})})}_typeCheck(e){return Array.isArray(e)}get _subType(){return this.innerType}_cast(e,t){let n=super._cast(e,t);if(!this._typeCheck(n)||!this.innerType)return n;let r=!1,i=n.map((e,n)=>{let i=this.innerType.cast(e,bw({},t,{path:`${t.path||""}[${n}]`}));return i!==e&&(r=!0),i});return r?i:n}_validate(e,t={},n){var r,i;let a=[],o=t.sync,s=t.path,u=this.innerType,c=null!=(r=t.abortEarly)?r:this.spec.abortEarly,l=null!=(i=t.recursive)?i:this.spec.recursive,f=null!=t.originalValue?t.originalValue:e;super._validate(e,t,(e,r)=>{if(e){if(!pM.isError(e)||c)return void n(e,r);a.push(e)}if(!l||!u||!this._typeCheck(r)){n(a[0]||null,r);return}f=f||r;let i=Array(r.length);for(let d=0;du.validate(h,b,t)}pA({sync:o,path:s,value:r,errors:a,endEarly:c,tests:i},n)})}clone(e){let t=super.clone(e);return t.innerType=this.innerType,t}concat(e){let t=super.concat(e);return t.innerType=this.innerType,e.innerType&&(t.innerType=t.innerType?t.innerType.concat(e.innerType):e.innerType),t}of(e){let t=this.clone();if(!p_(e))throw TypeError("`array.of()` sub-schema must be a valid yup schema not: "+pf(e));return t.innerType=e,t}length(e,t=pv.length){return this.test({message:t,name:"length",exclusive:!0,params:{length:e},test(t){return pV(t)||t.length===this.resolve(e)}})}min(e,t){return t=t||pv.min,this.test({message:t,name:"min",exclusive:!0,params:{min:e},test(t){return pV(t)||t.length>=this.resolve(e)}})}max(e,t){return t=t||pv.max,this.test({message:t,name:"max",exclusive:!0,params:{max:e},test(t){return pV(t)||t.length<=this.resolve(e)}})}ensure(){return this.default(()=>[]).transform((e,t)=>this._typeCheck(e)?e:null==t?[]:[].concat(t))}compact(e){let t=e?(t,n,r)=>!e(t,n,r):e=>!!e;return this.transform(e=>null!=e?e.filter(t):e)}describe(){let e=super.describe();return this.innerType&&(e.innerType=this.innerType.describe()),e}nullable(e=!0){return super.nullable(e)}defined(){return super.defined()}required(e){return super.required(e)}}b_.prototype=bE.prototype;var bS=by().shape({name:p2().required("Required"),url:p2().required("Required")}),bk=function(e){var t=e.initialValues,n=e.onSubmit,r=e.submitButtonText,i=e.nameDisabled,a=void 0!==i&&i;return l.createElement(hM,{initialValues:t,validationSchema:bS,onSubmit:n},function(e){var t=e.isSubmitting;return l.createElement(l.Fragment,null,l.createElement(hj,{"data-testid":"bridge-form",noValidate:!0},l.createElement(d.Z,{container:!0,spacing:16},l.createElement(d.Z,{item:!0,xs:12,md:7},l.createElement(hR,{component:hJ,id:"name",name:"name",label:"Name",disabled:a,required:!0,fullWidth:!0,FormHelperTextProps:{"data-testid":"name-helper-text"}})),l.createElement(d.Z,{item:!0,xs:12,md:7},l.createElement(hR,{component:hJ,id:"url",name:"url",label:"Bridge URL",placeholder:"https://",required:!0,fullWidth:!0,FormHelperTextProps:{"data-testid":"url-helper-text"}})),l.createElement(d.Z,{item:!0,xs:12,md:7},l.createElement(d.Z,{container:!0,spacing:16},l.createElement(d.Z,{item:!0,xs:7},l.createElement(hR,{component:hJ,id:"minimumContractPayment",name:"minimumContractPayment",label:"Minimum Contract Payment",placeholder:"0",fullWidth:!0,inputProps:{min:0},FormHelperTextProps:{"data-testid":"minimumContractPayment-helper-text"}})),l.createElement(d.Z,{item:!0,xs:7},l.createElement(hR,{component:hJ,id:"confirmations",name:"confirmations",label:"Confirmations",placeholder:"0",type:"number",fullWidth:!0,inputProps:{min:0},FormHelperTextProps:{"data-testid":"confirmations-helper-text"}})))),l.createElement(d.Z,{item:!0,xs:12,md:7},l.createElement(ox.default,{variant:"contained",color:"primary",type:"submit",disabled:t,size:"large"},r)))))})},bx=function(e){var t=e.bridge,n=e.onSubmit,r={name:t.name,url:t.url,minimumContractPayment:t.minimumContractPayment,confirmations:t.confirmations};return l.createElement(iv,null,l.createElement(d.Z,{container:!0,spacing:40},l.createElement(d.Z,{item:!0,xs:12,md:11,lg:9},l.createElement(r9.Z,null,l.createElement(sf.Z,{title:"Edit Bridge",action:l.createElement(aL.Z,{component:tz,href:"/bridges/".concat(t.id)},"Cancel")}),l.createElement(aK.Z,null,l.createElement(bk,{nameDisabled:!0,initialValues:r,onSubmit:n,submitButtonText:"Save Bridge"}))))))};function bT(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&i[i.length-1])&&(6===a[0]||2===a[0])){o=0;continue}if(3===a[0]&&(!i||a[1]>i[0]&&a[1]e.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&i[i.length-1])&&(6===a[0]||2===a[0])){o=0;continue}if(3===a[0]&&(!i||a[1]>i[0]&&a[1]e.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&void 0!==arguments[0]&&arguments[0],t=e?function(){return l.createElement(x.default,{variant:"body1"},"Loading...")}:function(){return null};return{isLoading:e,LoadingPlaceholder:t}},ml=n(76023);function mf(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&i[i.length-1])&&(6===a[0]||2===a[0])){o=0;continue}if(3===a[0]&&(!i||a[1]>i[0]&&a[1]e.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&i[i.length-1])&&(6===a[0]||2===a[0])){o=0;continue}if(3===a[0]&&(!i||a[1]>i[0]&&a[1]=0||(i[n]=e[n]);return i}function mB(e,t){if(null==e)return{};var n,r,i=mY(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(r=0;r=0)&&Object.prototype.propertyIsEnumerable.call(e,n)&&(i[n]=e[n])}return i}function mU(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=Array(t);n=4?[e[0],e[1],e[2],e[3],"".concat(e[0],".").concat(e[1]),"".concat(e[0],".").concat(e[2]),"".concat(e[0],".").concat(e[3]),"".concat(e[1],".").concat(e[0]),"".concat(e[1],".").concat(e[2]),"".concat(e[1],".").concat(e[3]),"".concat(e[2],".").concat(e[0]),"".concat(e[2],".").concat(e[1]),"".concat(e[2],".").concat(e[3]),"".concat(e[3],".").concat(e[0]),"".concat(e[3],".").concat(e[1]),"".concat(e[3],".").concat(e[2]),"".concat(e[0],".").concat(e[1],".").concat(e[2]),"".concat(e[0],".").concat(e[1],".").concat(e[3]),"".concat(e[0],".").concat(e[2],".").concat(e[1]),"".concat(e[0],".").concat(e[2],".").concat(e[3]),"".concat(e[0],".").concat(e[3],".").concat(e[1]),"".concat(e[0],".").concat(e[3],".").concat(e[2]),"".concat(e[1],".").concat(e[0],".").concat(e[2]),"".concat(e[1],".").concat(e[0],".").concat(e[3]),"".concat(e[1],".").concat(e[2],".").concat(e[0]),"".concat(e[1],".").concat(e[2],".").concat(e[3]),"".concat(e[1],".").concat(e[3],".").concat(e[0]),"".concat(e[1],".").concat(e[3],".").concat(e[2]),"".concat(e[2],".").concat(e[0],".").concat(e[1]),"".concat(e[2],".").concat(e[0],".").concat(e[3]),"".concat(e[2],".").concat(e[1],".").concat(e[0]),"".concat(e[2],".").concat(e[1],".").concat(e[3]),"".concat(e[2],".").concat(e[3],".").concat(e[0]),"".concat(e[2],".").concat(e[3],".").concat(e[1]),"".concat(e[3],".").concat(e[0],".").concat(e[1]),"".concat(e[3],".").concat(e[0],".").concat(e[2]),"".concat(e[3],".").concat(e[1],".").concat(e[0]),"".concat(e[3],".").concat(e[1],".").concat(e[2]),"".concat(e[3],".").concat(e[2],".").concat(e[0]),"".concat(e[3],".").concat(e[2],".").concat(e[1]),"".concat(e[0],".").concat(e[1],".").concat(e[2],".").concat(e[3]),"".concat(e[0],".").concat(e[1],".").concat(e[3],".").concat(e[2]),"".concat(e[0],".").concat(e[2],".").concat(e[1],".").concat(e[3]),"".concat(e[0],".").concat(e[2],".").concat(e[3],".").concat(e[1]),"".concat(e[0],".").concat(e[3],".").concat(e[1],".").concat(e[2]),"".concat(e[0],".").concat(e[3],".").concat(e[2],".").concat(e[1]),"".concat(e[1],".").concat(e[0],".").concat(e[2],".").concat(e[3]),"".concat(e[1],".").concat(e[0],".").concat(e[3],".").concat(e[2]),"".concat(e[1],".").concat(e[2],".").concat(e[0],".").concat(e[3]),"".concat(e[1],".").concat(e[2],".").concat(e[3],".").concat(e[0]),"".concat(e[1],".").concat(e[3],".").concat(e[0],".").concat(e[2]),"".concat(e[1],".").concat(e[3],".").concat(e[2],".").concat(e[0]),"".concat(e[2],".").concat(e[0],".").concat(e[1],".").concat(e[3]),"".concat(e[2],".").concat(e[0],".").concat(e[3],".").concat(e[1]),"".concat(e[2],".").concat(e[1],".").concat(e[0],".").concat(e[3]),"".concat(e[2],".").concat(e[1],".").concat(e[3],".").concat(e[0]),"".concat(e[2],".").concat(e[3],".").concat(e[0],".").concat(e[1]),"".concat(e[2],".").concat(e[3],".").concat(e[1],".").concat(e[0]),"".concat(e[3],".").concat(e[0],".").concat(e[1],".").concat(e[2]),"".concat(e[3],".").concat(e[0],".").concat(e[2],".").concat(e[1]),"".concat(e[3],".").concat(e[1],".").concat(e[0],".").concat(e[2]),"".concat(e[3],".").concat(e[1],".").concat(e[2],".").concat(e[0]),"".concat(e[3],".").concat(e[2],".").concat(e[0],".").concat(e[1]),"".concat(e[3],".").concat(e[2],".").concat(e[1],".").concat(e[0])]:void 0}var mX={};function mJ(e){if(0===e.length||1===e.length)return e;var t=e.join(".");return mX[t]||(mX[t]=mZ(e)),mX[t]}function mQ(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{},n=arguments.length>2?arguments[2]:void 0;return mJ(e.filter(function(e){return"token"!==e})).reduce(function(e,t){return mV({},e,n[t])},t)}function m1(e){return e.join(" ")}function m0(e,t){var n=0;return function(r){return n+=1,r.map(function(r,i){return m2({node:r,stylesheet:e,useInlineStyles:t,key:"code-segment-".concat(n,"-").concat(i)})})}}function m2(e){var t=e.node,n=e.stylesheet,r=e.style,i=void 0===r?{}:r,a=e.useInlineStyles,o=e.key,s=t.properties,u=t.type,c=t.tagName,f=t.value;if("text"===u)return f;if(c){var d,h=m0(n,a);if(a){var p=Object.keys(n).reduce(function(e,t){return t.split(".").forEach(function(t){e.includes(t)||e.push(t)}),e},[]),b=s.className&&s.className.includes("token")?["token"]:[],m=s.className&&b.concat(s.className.filter(function(e){return!p.includes(e)}));d=mV({},s,{className:m1(m)||void 0,style:mQ(s.className,Object.assign({},s.style,i),n)})}else d=mV({},s,{className:m1(s.className)});var g=h(t.children);return l.createElement(c,mq({key:o},d),g)}}let m3=function(e,t){return -1!==e.listLanguages().indexOf(t)};var m4=/\n/g;function m5(e){return e.match(m4)}function m6(e){var t=e.lines,n=e.startingLineNumber,r=e.style;return t.map(function(e,t){var i=t+n;return l.createElement("span",{key:"line-".concat(t),className:"react-syntax-highlighter-line-number",style:"function"==typeof r?r(i):r},"".concat(i,"\n"))})}function m9(e){var t=e.codeString,n=e.codeStyle,r=e.containerStyle,i=void 0===r?{float:"left",paddingRight:"10px"}:r,a=e.numberStyle,o=void 0===a?{}:a,s=e.startingLineNumber;return l.createElement("code",{style:Object.assign({},n,i)},m6({lines:t.replace(/\n$/,"").split("\n"),style:o,startingLineNumber:s}))}function m8(e){return"".concat(e.toString().length,".25em")}function m7(e,t){return{type:"element",tagName:"span",properties:{key:"line-number--".concat(e),className:["comment","linenumber","react-syntax-highlighter-line-number"],style:t},children:[{type:"text",value:e}]}}function ge(e,t,n){var r,i={display:"inline-block",minWidth:m8(n),paddingRight:"1em",textAlign:"right",userSelect:"none"};return mV({},i,"function"==typeof e?e(t):e)}function gt(e){var t=e.children,n=e.lineNumber,r=e.lineNumberStyle,i=e.largestLineNumber,a=e.showInlineLineNumbers,o=e.lineProps,s=void 0===o?{}:o,u=e.className,c=void 0===u?[]:u,l=e.showLineNumbers,f=e.wrapLongLines,d="function"==typeof s?s(n):s;if(d.className=c,n&&a){var h=ge(r,n,i);t.unshift(m7(n,h))}return f&l&&(d.style=mV({},d.style,{display:"flex"})),{type:"element",tagName:"span",properties:d,children:t}}function gn(e){for(var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:[],n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:[],r=0;r2&&void 0!==arguments[2]?arguments[2]:[];return gt({children:e,lineNumber:t,lineNumberStyle:s,largestLineNumber:o,showInlineLineNumbers:i,lineProps:n,className:a,showLineNumbers:r,wrapLongLines:u})}function b(e,t){if(r&&t&&i){var n=ge(s,t,o);e.unshift(m7(t,n))}return e}function m(e,n){var r=arguments.length>2&&void 0!==arguments[2]?arguments[2]:[];return t||r.length>0?p(e,n,r):b(e,n)}for(var g=function(){var e=l[h],t=e.children[0].value;if(m5(t)){var n=t.split("\n");n.forEach(function(t,i){var o=r&&f.length+a,s={type:"text",value:"".concat(t,"\n")};if(0===i){var u=l.slice(d+1,h).concat(gt({children:[s],className:e.properties.className})),c=m(u,o);f.push(c)}else if(i===n.length-1){if(l[h+1]&&l[h+1].children&&l[h+1].children[0]){var p={type:"text",value:"".concat(t)},b=gt({children:[p],className:e.properties.className});l.splice(h+1,0,b)}else{var g=[s],v=m(g,o,e.properties.className);f.push(v)}}else{var y=[s],w=m(y,o,e.properties.className);f.push(w)}}),d=h}h++};h code[class*="language-"]':{background:"#f5f2f0",padding:".1em",borderRadius:".3em",whiteSpace:"normal"},comment:{color:"slategray"},prolog:{color:"slategray"},doctype:{color:"slategray"},cdata:{color:"slategray"},punctuation:{color:"#999"},namespace:{Opacity:".7"},property:{color:"#905"},tag:{color:"#905"},boolean:{color:"#905"},number:{color:"#905"},constant:{color:"#905"},symbol:{color:"#905"},deleted:{color:"#905"},selector:{color:"#690"},"attr-name":{color:"#690"},string:{color:"#690"},char:{color:"#690"},builtin:{color:"#690"},inserted:{color:"#690"},operator:{color:"#9a6e3a",background:"hsla(0, 0%, 100%, .5)"},entity:{color:"#9a6e3a",background:"hsla(0, 0%, 100%, .5)",cursor:"help"},url:{color:"#9a6e3a",background:"hsla(0, 0%, 100%, .5)"},".language-css .token.string":{color:"#9a6e3a",background:"hsla(0, 0%, 100%, .5)"},".style .token.string":{color:"#9a6e3a",background:"hsla(0, 0%, 100%, .5)"},atrule:{color:"#07a"},"attr-value":{color:"#07a"},keyword:{color:"#07a"},function:{color:"#DD4A68"},"class-name":{color:"#DD4A68"},regex:{color:"#e90"},important:{color:"#e90",fontWeight:"bold"},variable:{color:"#e90"},bold:{fontWeight:"bold"},italic:{fontStyle:"italic"}};var gc=n(98695),gl=n.n(gc);let gf=["abap","abnf","actionscript","ada","agda","al","antlr4","apacheconf","apl","applescript","aql","arduino","arff","asciidoc","asm6502","aspnet","autohotkey","autoit","bash","basic","batch","bbcode","birb","bison","bnf","brainfuck","brightscript","bro","bsl","c","cil","clike","clojure","cmake","coffeescript","concurnas","cpp","crystal","csharp","csp","css-extras","css","cypher","d","dart","dax","dhall","diff","django","dns-zone-file","docker","ebnf","editorconfig","eiffel","ejs","elixir","elm","erb","erlang","etlua","excel-formula","factor","firestore-security-rules","flow","fortran","fsharp","ftl","gcode","gdscript","gedcom","gherkin","git","glsl","gml","go","graphql","groovy","haml","handlebars","haskell","haxe","hcl","hlsl","hpkp","hsts","http","ichigojam","icon","iecst","ignore","inform7","ini","io","j","java","javadoc","javadoclike","javascript","javastacktrace","jolie","jq","js-extras","js-templates","jsdoc","json","json5","jsonp","jsstacktrace","jsx","julia","keyman","kotlin","latex","latte","less","lilypond","liquid","lisp","livescript","llvm","lolcode","lua","makefile","markdown","markup-templating","markup","matlab","mel","mizar","mongodb","monkey","moonscript","n1ql","n4js","nand2tetris-hdl","naniscript","nasm","neon","nginx","nim","nix","nsis","objectivec","ocaml","opencl","oz","parigp","parser","pascal","pascaligo","pcaxis","peoplecode","perl","php-extras","php","phpdoc","plsql","powerquery","powershell","processing","prolog","properties","protobuf","pug","puppet","pure","purebasic","purescript","python","q","qml","qore","r","racket","reason","regex","renpy","rest","rip","roboconf","robotframework","ruby","rust","sas","sass","scala","scheme","scss","shell-session","smali","smalltalk","smarty","sml","solidity","solution-file","soy","sparql","splunk-spl","sqf","sql","stan","stylus","swift","t4-cs","t4-templating","t4-vb","tap","tcl","textile","toml","tsx","tt2","turtle","twig","typescript","typoscript","unrealscript","vala","vbnet","velocity","verilog","vhdl","vim","visual-basic","warpscript","wasm","wiki","xeora","xml-doc","xojo","xquery","yaml","yang","zig"];var gd=gs(gl(),gu);gd.supportedLanguages=gf;let gh=gd;var gp=n(64566),gb=n(68239);function gm(e,t){return t||(t=e.slice(0)),Object.freeze(Object.defineProperties(e,{raw:{value:Object.freeze(t)}}))}function gg(){var e=gm(["\n query FetchConfigV2 {\n configv2 {\n user\n effective\n }\n }\n"]);return gg=function(){return e},e}var gv=function(){var e="[[TelemetryIngress.Endpoints]] \nNetwork = '...' # e.g. EVM. Solana, Starknet, Cosmos \nChainID = '...' # e.g. 1, 5, devnet, mainnet-beta URL\nURL = '...'\nServerPubKey = '...'";return l.createElement(r9.Z,null,l.createElement(sf.Z,{title:"Deprecation warning"}),l.createElement(aK.Z,null,l.createElement(x.default,{variant:"h5",gutterBottom:!0},"Starting in ",l.createElement("code",null,"v2.9.0"),":"),l.createElement(w.default,{dense:!0},l.createElement(_.default,null,l.createElement(ol.Z,null,l.createElement(gb.Z,null)),l.createElement(x.default,{variant:"subtitle2",gutterBottom:!0},l.createElement("code",null,"TelemetryIngress.URL")," and"," ",l.createElement("code",null,"TelemetryIngress.ServerPubKey")," will no longer be allowed. Please switch to ",l.createElement("code",null,"TelemetryIngress.Endpoints"),":",l.createElement(gh,{language:"toml",style:gu},e))),l.createElement(_.default,null,l.createElement(ol.Z,null,l.createElement(gb.Z,null)),l.createElement(x.default,{variant:"subtitle2",gutterBottom:!0},l.createElement("code",null,"P2P.V1")," will no longer be supported and must not be set in TOML configuration in order to boot. Use"," ",l.createElement("code",null,"P2P.V2")," instead. If you are using both,"," ",l.createElement("code",null,"V1")," can simply be removed.")))))},gy=n0(gg()),gw=function(e){var t=e.children;return l.createElement(ii.Z,null,l.createElement(ie.default,{component:"th",scope:"row",colSpan:3},t))},g_=function(){return l.createElement(gw,null,"...")},gE=function(e){var t=e.children;return l.createElement(gw,null,t)},gS=function(e){var t=e.loading,n=e.toml,r=e.error,i=void 0===r?"":r,a=e.title,o=e.expanded;if(i)return l.createElement(gE,null,i);if(t)return l.createElement(g_,null);a||(a="TOML");var s={display:"block"};return l.createElement(x.default,null,l.createElement(mR.Z,{defaultExpanded:o},l.createElement(mj.Z,{expandIcon:l.createElement(gp.Z,null)},a),l.createElement(mF.Z,{style:s},l.createElement(gh,{language:"toml",style:gu},n))))},gk=function(){var e=ry(gy,{fetchPolicy:"cache-and-network"}),t=e.data,n=e.loading,r=e.error;return(null==t?void 0:t.configv2.effective)=="N/A"?l.createElement(l.Fragment,null,l.createElement(d.Z,{item:!0,xs:12},l.createElement(r9.Z,null,l.createElement(sf.Z,{title:"TOML Configuration"}),l.createElement(gS,{title:"V2 config dump:",error:null==r?void 0:r.message,loading:n,toml:null==t?void 0:t.configv2.user,showHead:!0})))):l.createElement(l.Fragment,null,l.createElement(d.Z,{container:!0},l.createElement(d.Z,{item:!0,xs:12},l.createElement(gv,null)),l.createElement(d.Z,{item:!0,xs:12},l.createElement(r9.Z,null,l.createElement(sf.Z,{title:"TOML Configuration"}),l.createElement(gS,{title:"User specified:",error:null==r?void 0:r.message,loading:n,toml:null==t?void 0:t.configv2.user,showHead:!0,expanded:!0}),l.createElement(gS,{title:"Effective (with defaults):",error:null==r?void 0:r.message,loading:n,toml:null==t?void 0:t.configv2.effective,showHead:!0})))))},gx=n(34823),gT=function(e){return(0,b.createStyles)({cell:{paddingTop:1.5*e.spacing.unit,paddingBottom:1.5*e.spacing.unit}})},gM=(0,b.withStyles)(gT)(function(e){var t=e.classes,n=(0,A.I0)();(0,l.useEffect)(function(){n((0,ty.DQ)())});var r=(0,A.v9)(gx.N,A.wU);return l.createElement(r9.Z,null,l.createElement(sf.Z,{title:"Node"}),l.createElement(r8.Z,null,l.createElement(r7.Z,null,l.createElement(ii.Z,null,l.createElement(ie.default,{className:t.cell},l.createElement(x.default,null,"Version"),l.createElement(x.default,{variant:"subtitle1",color:"textSecondary"},r.version))),l.createElement(ii.Z,null,l.createElement(ie.default,{className:t.cell},l.createElement(x.default,null,"SHA"),l.createElement(x.default,{variant:"subtitle1",color:"textSecondary"},r.commitSHA))))))}),gO=function(){return l.createElement(iv,null,l.createElement(d.Z,{container:!0},l.createElement(d.Z,{item:!0,sm:12,md:8},l.createElement(d.Z,{container:!0},l.createElement(gk,null))),l.createElement(d.Z,{item:!0,sm:12,md:4},l.createElement(d.Z,{container:!0},l.createElement(d.Z,{item:!0,xs:12},l.createElement(gM,null)),l.createElement(d.Z,{item:!0,xs:12},l.createElement(mP,null)),l.createElement(d.Z,{item:!0,xs:12},l.createElement(mS,null))))))},gA=function(){return l.createElement(gO,null)},gL=function(){return l.createElement(gA,null)},gC=n(44431),gI=1e18,gD=function(e){return new gC.BigNumber(e).dividedBy(gI).toFixed(8)},gN=function(e){var t=e.keys,n=e.chainID,r=e.hideHeaderTitle;return l.createElement(l.Fragment,null,l.createElement(sf.Z,{title:!r&&"Account Balances",subheader:"Chain ID "+n}),l.createElement(aK.Z,null,l.createElement(w.default,{dense:!1,disablePadding:!0},t&&t.map(function(e,r){return l.createElement(l.Fragment,null,l.createElement(_.default,{disableGutters:!0,key:["acc-balance",n.toString(),r.toString()].join("-")},l.createElement(E.Z,{primary:l.createElement(l.Fragment,null,l.createElement(d.Z,{container:!0,spacing:16},l.createElement(d.Z,{item:!0,xs:12},l.createElement(ob,{title:"Address"}),l.createElement(om,{value:e.address})),l.createElement(d.Z,{item:!0,xs:6},l.createElement(ob,{title:"Native Token Balance"}),l.createElement(om,{value:e.ethBalance||"--"})),l.createElement(d.Z,{item:!0,xs:6},l.createElement(ob,{title:"LINK Balance"}),l.createElement(om,{value:e.linkBalance?gD(e.linkBalance):"--"}))))})),r+1s&&l.createElement(g$.Z,null,l.createElement(ii.Z,null,l.createElement(ie.default,{className:r.footer},l.createElement(aL.Z,{href:"/runs",component:tz},"View More"))))))});function vi(e,t){return t||(t=e.slice(0)),Object.freeze(Object.defineProperties(e,{raw:{value:Object.freeze(t)}}))}function va(){var e=vi(["\n ","\n query FetchRecentJobRuns($offset: Int, $limit: Int) {\n jobRuns(offset: $offset, limit: $limit) {\n results {\n ...RecentJobRunsPayload_ResultsFields\n }\n metadata {\n total\n }\n }\n }\n"]);return va=function(){return e},e}var vo=5,vs=n0(va(),vt),vu=function(){var e=ry(vs,{variables:{offset:0,limit:vo},fetchPolicy:"cache-and-network"}),t=e.data,n=e.loading,r=e.error;return l.createElement(vr,{data:t,errorMsg:null==r?void 0:r.message,loading:n,maxRunsSize:vo})},vc=function(e){return(0,b.createStyles)({style:{textAlign:"center",padding:2.5*e.spacing.unit,position:"fixed",left:"0",bottom:"0",width:"100%",borderRadius:0},bareAnchor:{color:e.palette.common.black,textDecoration:"none"}})},vl=(0,b.withStyles)(vc)(function(e){var t=e.classes,n=(0,A.v9)(gx.N,A.wU),r=(0,A.I0)();return(0,l.useEffect)(function(){r((0,ty.DQ)())}),l.createElement(ia.default,{className:t.style},l.createElement(x.default,null,"Chainlink Node ",n.version," at commit"," ",l.createElement("a",{target:"_blank",rel:"noopener noreferrer",href:"https://github.com/smartcontractkit/chainlink/commit/".concat(n.commitSHA),className:t.bareAnchor},n.commitSHA)))}),vf=function(e){return(0,b.createStyles)({cell:{borderColor:e.palette.divider,borderTop:"1px solid",borderBottom:"none",paddingTop:2*e.spacing.unit,paddingBottom:2*e.spacing.unit,paddingLeft:2*e.spacing.unit},block:{display:"block"},overflowEllipsis:{textOverflow:"ellipsis",overflow:"hidden"}})},vd=(0,b.withStyles)(vf)(function(e){var t=e.classes,n=e.job;return l.createElement(ii.Z,null,l.createElement(ie.default,{scope:"row",className:t.cell},l.createElement(d.Z,{container:!0,spacing:0},l.createElement(d.Z,{item:!0,xs:12},l.createElement(ip,{href:"/jobs/".concat(n.id),classes:{linkContent:t.block}},l.createElement(x.default,{className:t.overflowEllipsis,variant:"body1",component:"span",color:"primary"},n.name||n.id))),l.createElement(d.Z,{item:!0,xs:12},l.createElement(x.default,{variant:"body1",color:"textSecondary"},"Created ",l.createElement(aA,{tooltip:!0},n.createdAt))))))});function vh(e,t){return t||(t=e.slice(0)),Object.freeze(Object.defineProperties(e,{raw:{value:Object.freeze(t)}}))}function vp(){var e=vh(["\n fragment RecentJobsPayload_ResultsFields on Job {\n id\n name\n createdAt\n }\n"]);return vp=function(){return e},e}var vb=n0(vp()),vm=function(){return(0,b.createStyles)({cardHeader:{borderBottom:0},table:{tableLayout:"fixed"}})},vg=(0,b.withStyles)(vm)(function(e){var t,n,r=e.classes,i=e.data,a=e.errorMsg,o=e.loading;return l.createElement(r9.Z,null,l.createElement(sf.Z,{title:"Recent Jobs",className:r.cardHeader}),l.createElement(r8.Z,{className:r.table},l.createElement(r7.Z,null,l.createElement(gW,{visible:o}),l.createElement(gK,{visible:(null===(t=null==i?void 0:i.jobs.results)||void 0===t?void 0:t.length)===0},"No recently created jobs"),l.createElement(gz,{msg:a}),null===(n=null==i?void 0:i.jobs.results)||void 0===n?void 0:n.map(function(e,t){return l.createElement(vd,{job:e,key:t})}))))});function vv(e,t){return t||(t=e.slice(0)),Object.freeze(Object.defineProperties(e,{raw:{value:Object.freeze(t)}}))}function vy(){var e=vv(["\n ","\n query FetchRecentJobs($offset: Int, $limit: Int) {\n jobs(offset: $offset, limit: $limit) {\n results {\n ...RecentJobsPayload_ResultsFields\n }\n }\n }\n"]);return vy=function(){return e},e}var vw=5,v_=n0(vy(),vb),vE=function(){var e=ry(v_,{variables:{offset:0,limit:vw},fetchPolicy:"cache-and-network"}),t=e.data,n=e.loading,r=e.error;return l.createElement(vg,{data:t,errorMsg:null==r?void 0:r.message,loading:n})},vS=function(){return l.createElement(iv,null,l.createElement(d.Z,{container:!0},l.createElement(d.Z,{item:!0,xs:8},l.createElement(vu,null)),l.createElement(d.Z,{item:!0,xs:4},l.createElement(d.Z,{container:!0},l.createElement(d.Z,{item:!0,xs:12},l.createElement(gH,null)),l.createElement(d.Z,{item:!0,xs:12},l.createElement(vE,null))))),l.createElement(vl,null))},vk=function(){return l.createElement(vS,null)},vx=function(){return l.createElement(vk,null)},vT=n(87239),vM=function(e){switch(e){case"DirectRequestSpec":return"Direct Request";case"FluxMonitorSpec":return"Flux Monitor";default:return e.replace(/Spec$/,"")}},vO=n(5022),vA=n(78718),vL=n.n(vA);function vC(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=Array(t);n1?t-1:0),r=1;r1?t-1:0),r=1;re.length)&&(t=e.length);for(var n=0,r=Array(t);ne.length)&&(t=e.length);for(var n=0,r=Array(t);ne.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&n.map(function(e){return l.createElement(ii.Z,{key:e.id,style:{cursor:"pointer"},onClick:function(){return r.push("/runs/".concat(e.id))}},l.createElement(ie.default,{className:t.idCell,scope:"row"},l.createElement("div",{className:t.runDetails},l.createElement(x.default,{variant:"h5",color:"primary",component:"span"},e.id))),l.createElement(ie.default,{className:t.stampCell},l.createElement(x.default,{variant:"body1",color:"textSecondary",className:t.stamp},"Created ",l.createElement(aA,{tooltip:!0},e.createdAt))),l.createElement(ie.default,{className:t.statusCell,scope:"row"},l.createElement(x.default,{variant:"body1",className:O()(t.status,ym(t,e.status))},e.status.toLowerCase())))})))}),yv=n(16839),yy=n.n(yv);function yw(e){var t=e.replace(/\w+\s*=\s*<([^>]|[\r\n])*>/g,""),n=yy().read(t),r=n.edges();return n.nodes().map(function(e){var t={id:e,parentIds:r.filter(function(t){return t.w===e}).map(function(e){return e.v})};return Object.keys(n.node(e)).length>0&&(t.attributes=n.node(e)),t})}var y_=n(94164),yE=function(e){var t=e.data,n=[];return(null==t?void 0:t.attributes)&&Object.keys(t.attributes).forEach(function(e){var r;n.push(l.createElement("div",{key:e},l.createElement(x.default,{variant:"body1",color:"textSecondary",component:"div"},l.createElement("b",null,e,":")," ",null===(r=t.attributes)||void 0===r?void 0:r[e])))}),l.createElement("div",null,t&&l.createElement(x.default,{variant:"body1",color:"textPrimary"},l.createElement("b",null,t.id)),n)},yS=n(73343),yk=n(3379),yx=n.n(yk);function yT(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=Array(t);nwindow.innerWidth?u-r.getBoundingClientRect().width-a:u+a,n=c+r.getBoundingClientRect().height+i>window.innerHeight?c-r.getBoundingClientRect().height-a:c+a,r.style.opacity=String(1),r.style.top="".concat(n,"px"),r.style.left="".concat(t,"px"),r.style.zIndex=String(1)}},h=function(e){var t=document.getElementById("tooltip-d3-chart-".concat(e));t&&(t.style.opacity=String(0),t.style.zIndex=String(-1))};return l.createElement("div",{style:{fontFamily:"sans-serif",fontWeight:"normal"}},l.createElement(y_.kJ,{id:"task-list-graph-d3",data:i,config:s,onMouseOverNode:d,onMouseOutNode:h},"D3 chart"),n.map(function(e){return l.createElement("div",{key:"d3-tooltip-key-".concat(e.id),id:"tooltip-d3-chart-".concat(e.id),style:{position:"absolute",opacity:"0",border:"1px solid rgba(0, 0, 0, 0.1)",padding:yS.r.spacing.unit,background:"white",borderRadius:5,zIndex:-1,inlineSize:"min-content"}},l.createElement(yE,{data:e}))}))};function yD(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=Array(t);nyH&&l.createElement("div",{className:t.runDetails},l.createElement(aL.Z,{href:"/jobs/".concat(n.id,"/runs"),component:tz},"View more")))),l.createElement(d.Z,{item:!0,xs:12,sm:6},l.createElement(yU,{observationSource:n.observationSource})))});function yG(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=Array(t);ne.length)&&(t=e.length);for(var n=0,r=Array(t);ne.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&i[i.length-1])&&(6===a[0]||2===a[0])){o=0;continue}if(3===a[0]&&(!i||a[1]>i[0]&&a[1]e.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&void 0!==arguments[0]?arguments[0]:"";try{return vO.parse(e),!0}catch(t){return!1}})}),wq=function(e){var t=e.initialValues,n=e.onSubmit,r=e.onTOMLChange;return l.createElement(hM,{initialValues:t,validationSchema:wV,onSubmit:n},function(e){var t=e.isSubmitting,n=e.values;return r&&r(n.toml),l.createElement(hj,{"data-testid":"job-form",noValidate:!0},l.createElement(d.Z,{container:!0,spacing:16},l.createElement(d.Z,{item:!0,xs:12},l.createElement(hR,{component:hJ,id:"toml",name:"toml",label:"Job Spec (TOML)",required:!0,fullWidth:!0,multiline:!0,rows:10,rowsMax:25,variant:"outlined",autoComplete:"off",FormHelperTextProps:{"data-testid":"toml-helper-text"}})),l.createElement(d.Z,{item:!0,xs:12,md:7},l.createElement(ox.default,{variant:"contained",color:"primary",type:"submit",disabled:t,size:"large"},"Create Job"))))})},wZ=n(50109),wX="persistSpec";function wJ(e){var t=e.query,n=new URLSearchParams(t).get("definition");return n?(wZ.t8(wX,n),{toml:n}):{toml:wZ.U2(wX)||""}}var wQ=function(e){var t=e.onSubmit,n=e.onTOMLChange,r=wJ({query:(0,h.TH)().search}),i=function(e){var t=e.replace(/[\u200B-\u200D\uFEFF]/g,"");wZ.t8("".concat(wX),t),n&&n(t)};return l.createElement(r9.Z,null,l.createElement(sf.Z,{title:"New Job"}),l.createElement(aK.Z,null,l.createElement(wq,{initialValues:r,onSubmit:t,onTOMLChange:i})))};function w1(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=Array(t);ne.length)&&(t=e.length);for(var n=0,r=Array(t);ne.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&i[i.length-1])&&(6===a[0]||2===a[0])){o=0;continue}if(3===a[0]&&(!i||a[1]>i[0]&&a[1]e.length)&&(t=e.length);for(var n=0,r=Array(t);n1&&void 0!==arguments[1]?arguments[1]:{},n=t.start,r=void 0===n?6:n,i=t.end,a=void 0===i?4:i;return e.substring(0,r)+"..."+e.substring(e.length-a)}function _L(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&i[i.length-1])&&(6===a[0]||2===a[0])){o=0;continue}if(3===a[0]&&(!i||a[1]>i[0]&&a[1]0&&void 0!==arguments[0]?arguments[0]:{};return ry(_q,e)},_X=function(){var e=_Z({fetchPolicy:"cache-and-network"}),t=e.data,n=e.loading,r=e.error,i=e.refetch;return l.createElement(_z,{loading:n,data:t,errorMsg:null==r?void 0:r.message,refetch:i})},_J=function(e){var t=e.csaKey;return l.createElement(ii.Z,{hover:!0},l.createElement(ie.default,null,l.createElement(x.default,{variant:"body1"},t.publicKey," ",l.createElement(_O,{data:t.publicKey}))))};function _Q(e,t){return t||(t=e.slice(0)),Object.freeze(Object.defineProperties(e,{raw:{value:Object.freeze(t)}}))}function _1(){var e=_Q(["\n fragment CSAKeysPayload_ResultsFields on CSAKey {\n id\n publicKey\n }\n"]);return _1=function(){return e},e}var _0=n0(_1()),_2=function(e){var t,n,r,i=e.data,a=e.errorMsg,o=e.loading,s=e.onCreate;return l.createElement(r9.Z,null,l.createElement(sf.Z,{action:(null===(t=null==i?void 0:i.csaKeys.results)||void 0===t?void 0:t.length)===0&&l.createElement(ox.default,{variant:"outlined",color:"primary",onClick:s},"New CSA Key"),title:"CSA Key",subheader:"Manage your CSA Key"}),l.createElement(r8.Z,null,l.createElement(it.Z,null,l.createElement(ii.Z,null,l.createElement(ie.default,null,"Public Key"))),l.createElement(r7.Z,null,l.createElement(gW,{visible:o}),l.createElement(gK,{visible:(null===(n=null==i?void 0:i.csaKeys.results)||void 0===n?void 0:n.length)===0}),l.createElement(gz,{msg:a}),null===(r=null==i?void 0:i.csaKeys.results)||void 0===r?void 0:r.map(function(e,t){return l.createElement(_J,{csaKey:e,key:t})}))))};function _3(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&i[i.length-1])&&(6===a[0]||2===a[0])){o=0;continue}if(3===a[0]&&(!i||a[1]>i[0]&&a[1]e.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&i[i.length-1])&&(6===a[0]||2===a[0])){o=0;continue}if(3===a[0]&&(!i||a[1]>i[0]&&a[1]0&&void 0!==arguments[0]?arguments[0]:{};return ry(EL,e)};function EI(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&i[i.length-1])&&(6===a[0]||2===a[0])){o=0;continue}if(3===a[0]&&(!i||a[1]>i[0]&&a[1]0&&void 0!==arguments[0]?arguments[0]:{};return ry(E0,e)},E6=function(){return os(E2)},E9=function(){return os(E3)},E8=function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};return ry(E4,e)};function E7(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=Array(t);ne.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&i[i.length-1])&&(6===a[0]||2===a[0])){o=0;continue}if(3===a[0]&&(!i||a[1]>i[0]&&a[1]e.length)&&(t=e.length);for(var n=0,r=Array(t);ne.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&i[i.length-1])&&(6===a[0]||2===a[0])){o=0;continue}if(3===a[0]&&(!i||a[1]>i[0]&&a[1]e.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&i[i.length-1])&&(6===a[0]||2===a[0])){o=0;continue}if(3===a[0]&&(!i||a[1]>i[0]&&a[1]0&&void 0!==arguments[0]?arguments[0]:{};return ry(SZ,e)};function SJ(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&i[i.length-1])&&(6===a[0]||2===a[0])){o=0;continue}if(3===a[0]&&(!i||a[1]>i[0]&&a[1]e.length)&&(t=e.length);for(var n=0,r=Array(t);n=0)&&Object.prototype.propertyIsEnumerable.call(e,n)&&(i[n]=e[n])}return i}function kX(e,t){if(null==e)return{};var n,r,i={},a=Object.keys(e);for(r=0;r=0||(i[n]=e[n]);return i}var kJ=function(e){var t=e.run,n=l.useMemo(function(){var e=t.inputs,n=t.outputs,r=t.taskRuns,i=kZ(t,["inputs","outputs","taskRuns"]),a={};try{a=JSON.parse(e)}catch(o){a={}}return kq(kK({},i),{inputs:a,outputs:n,taskRuns:r})},[t]);return l.createElement(r9.Z,null,l.createElement(aK.Z,null,l.createElement(kG,{object:n})))};function kQ(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function k1(e){for(var t=1;t0&&l.createElement(ko,{errors:t.allErrors})),l.createElement(d.Z,{item:!0,xs:12},l.createElement(h.rs,null,l.createElement(h.AW,{path:"".concat(n,"/json")},l.createElement(kJ,{run:t})),l.createElement(h.AW,{path:n},t.taskRuns.length>0&&l.createElement(kj,{taskRuns:t.taskRuns,observationSource:t.job.observationSource}))))))))};function k7(e,t){return t||(t=e.slice(0)),Object.freeze(Object.defineProperties(e,{raw:{value:Object.freeze(t)}}))}function xe(){var e=k7(["\n ","\n query FetchJobRun($id: ID!) {\n jobRun(id: $id) {\n __typename\n ... on JobRun {\n ...JobRunPayload_Fields\n }\n ... on NotFoundError {\n message\n }\n }\n }\n"]);return xe=function(){return e},e}var xt=n0(xe(),k9),xn=function(){var e=ry(xt,{variables:{id:(0,h.UO)().id}}),t=e.data,n=e.loading,r=e.error;if(n)return l.createElement(ij,null);if(r)return l.createElement(iN,{error:r});var i=null==t?void 0:t.jobRun;switch(null==i?void 0:i.__typename){case"JobRun":return l.createElement(k8,{run:i});case"NotFoundError":return l.createElement(oo,null);default:return null}};function xr(e,t){return t||(t=e.slice(0)),Object.freeze(Object.defineProperties(e,{raw:{value:Object.freeze(t)}}))}function xi(){var e=xr(["\n fragment JobRunsPayload_ResultsFields on JobRun {\n id\n allErrors\n createdAt\n finishedAt\n status\n job {\n id\n }\n }\n"]);return xi=function(){return e},e}var xa=n0(xi()),xo=function(e){var t=e.loading,n=e.data,r=e.page,i=e.pageSize,a=(0,h.k6)(),o=l.useMemo(function(){return null==n?void 0:n.jobRuns.results.map(function(e){var t,n=e.allErrors,r=e.id,i=e.createdAt;return{id:r,createdAt:i,errors:n,finishedAt:e.finishedAt,status:e.status}})},[n]);return l.createElement(iv,null,l.createElement(d.Z,{container:!0,spacing:32},l.createElement(d.Z,{item:!0,xs:12},l.createElement(iw,null,"Job Runs")),t&&l.createElement(ij,null),n&&o&&l.createElement(d.Z,{item:!0,xs:12},l.createElement(r9.Z,null,l.createElement(yg,{runs:o}),l.createElement(ir.Z,{component:"div",count:n.jobRuns.metadata.total,rowsPerPage:i,rowsPerPageOptions:[i],page:r-1,onChangePage:function(e,t){a.push("/runs?page=".concat(t+1,"&per=").concat(i))},onChangeRowsPerPage:function(){},backIconButtonProps:{"aria-label":"prev-page"},nextIconButtonProps:{"aria-label":"next-page"}})))))};function xs(e,t){return t||(t=e.slice(0)),Object.freeze(Object.defineProperties(e,{raw:{value:Object.freeze(t)}}))}function xu(){var e=xs(["\n ","\n query FetchJobRuns($offset: Int, $limit: Int) {\n jobRuns(offset: $offset, limit: $limit) {\n results {\n ...JobRunsPayload_ResultsFields\n }\n metadata {\n total\n }\n }\n }\n"]);return xu=function(){return e},e}var xc=n0(xu(),xa),xl=function(){var e=iF(),t=parseInt(e.get("page")||"1",10),n=parseInt(e.get("per")||"25",10),r=ry(xc,{variables:{offset:(t-1)*n,limit:n},fetchPolicy:"cache-and-network"}),i=r.data,a=r.loading,o=r.error;return o?l.createElement(iN,{error:o}):l.createElement(xo,{loading:a,data:i,page:t,pageSize:n})},xf=function(){var e=(0,h.$B)().path;return l.createElement(h.rs,null,l.createElement(h.AW,{exact:!0,path:e},l.createElement(xl,null)),l.createElement(h.AW,{path:"".concat(e,"/:id")},l.createElement(xn,null)))},xd=by().shape({name:p2().required("Required"),uri:p2().required("Required"),publicKey:p2().required("Required")}),xh=function(e){var t=e.initialValues,n=e.onSubmit;return l.createElement(hM,{initialValues:t,validationSchema:xd,onSubmit:n},function(e){var t=e.isSubmitting,n=e.submitForm;return l.createElement(hj,{"data-testid":"feeds-manager-form"},l.createElement(d.Z,{container:!0,spacing:16},l.createElement(d.Z,{item:!0,xs:12,md:6},l.createElement(hR,{component:hJ,id:"name",name:"name",label:"Name",required:!0,fullWidth:!0,FormHelperTextProps:{"data-testid":"name-helper-text"}})),l.createElement(d.Z,{item:!0,xs:!1,md:6}),l.createElement(d.Z,{item:!0,xs:12,md:6},l.createElement(hR,{component:hJ,id:"uri",name:"uri",label:"URI",required:!0,fullWidth:!0,helperText:"Provided by the Feeds Manager operator",FormHelperTextProps:{"data-testid":"uri-helper-text"}})),l.createElement(d.Z,{item:!0,xs:12,md:6},l.createElement(hR,{component:hJ,id:"publicKey",name:"publicKey",label:"Public Key",required:!0,fullWidth:!0,helperText:"Provided by the Feeds Manager operator",FormHelperTextProps:{"data-testid":"publicKey-helper-text"}})),l.createElement(d.Z,{item:!0,xs:12},l.createElement(ox.default,{variant:"contained",color:"primary",disabled:t,onClick:n},"Submit"))))})},xp=function(e){var t=e.data,n=e.onSubmit,r={name:t.name,uri:t.uri,publicKey:t.publicKey};return l.createElement(d.Z,{container:!0},l.createElement(d.Z,{item:!0,xs:12,md:11,lg:9},l.createElement(r9.Z,null,l.createElement(sf.Z,{title:"Edit Feeds Manager"}),l.createElement(aK.Z,null,l.createElement(xh,{initialValues:r,onSubmit:n})))))};function xb(e,t){return t||(t=e.slice(0)),Object.freeze(Object.defineProperties(e,{raw:{value:Object.freeze(t)}}))}function xm(){var e=xb(["\n query FetchFeedsManagers {\n feedsManagers {\n results {\n __typename\n id\n name\n uri\n publicKey\n isConnectionActive\n createdAt\n }\n }\n }\n"]);return xm=function(){return e},e}var xg=n0(xm()),xv=function(){return ry(xg)};function xy(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&i[i.length-1])&&(6===a[0]||2===a[0])){o=0;continue}if(3===a[0]&&(!i||a[1]>i[0]&&a[1]0&&void 0!==arguments[0]?arguments[0]:{};return ry(xJ,e)};function x1(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&i[i.length-1])&&(6===a[0]||2===a[0])){o=0;continue}if(3===a[0]&&(!i||a[1]>i[0]&&a[1]e.length)&&(t=e.length);for(var n=0,r=Array(t);ne.length)&&(t=e.length);for(var n=0,r=Array(t);n0?n.feedsManagers.results[0]:void 0;return n&&a?l.createElement(Tz,{manager:a}):l.createElement(h.l_,{to:{pathname:"/feeds_manager/new",state:{from:e}}})},TW={name:"Chainlink Feeds Manager",uri:"",publicKey:""},TK=function(e){var t=e.onSubmit;return l.createElement(d.Z,{container:!0},l.createElement(d.Z,{item:!0,xs:12,md:11,lg:9},l.createElement(r9.Z,null,l.createElement(sf.Z,{title:"Register Feeds Manager"}),l.createElement(aK.Z,null,l.createElement(xh,{initialValues:TW,onSubmit:t})))))};function TV(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&i[i.length-1])&&(6===a[0]||2===a[0])){o=0;continue}if(3===a[0]&&(!i||a[1]>i[0]&&a[1]0&&i[i.length-1])&&(6===a[0]||2===a[0])){o=0;continue}if(3===a[0]&&(!i||a[1]>i[0]&&a[1]e.length)&&(t=e.length);for(var n=0,r=Array(t);nt.version?e:t})},[o]),g=l.useMemo(function(){return Mm(o).sort(function(e,t){return t.version-e.version})},[o]),v=function(e,t,n){switch(e){case"PENDING":return l.createElement(l.Fragment,null,l.createElement(ox.default,{variant:"text",color:"secondary",onClick:function(){return b("reject",t)}},"Reject"),m.id===t&&"DELETED"!==n.status&&"REVOKED"!==n.status&&l.createElement(ox.default,{variant:"contained",color:"primary",onClick:function(){return b("approve",t)}},"Approve"),m.id===t&&"DELETED"===n.status&&n.pendingUpdate&&l.createElement(l.Fragment,null,l.createElement(ox.default,{variant:"contained",color:"primary",onClick:function(){return b("cancel",t)}},"Cancel"),l.createElement(x.default,{color:"error"},"This proposal was deleted. Cancel the spec to delete any running jobs")));case"APPROVED":return l.createElement(l.Fragment,null,l.createElement(ox.default,{variant:"contained",onClick:function(){return b("cancel",t)}},"Cancel"),"DELETED"===n.status&&n.pendingUpdate&&l.createElement(x.default,{color:"error"},"This proposal was deleted. Cancel the spec to delete any running jobs"));case"CANCELLED":if(m.id===t&&"DELETED"!==n.status&&"REVOKED"!==n.status)return l.createElement(ox.default,{variant:"contained",color:"primary",onClick:function(){return b("approve",t)}},"Approve");return null;default:return null}};return l.createElement("div",null,g.map(function(e,n){return l.createElement(mR.Z,{defaultExpanded:0===n,key:n},l.createElement(mj.Z,{expandIcon:l.createElement(gp.Z,null)},l.createElement(x.default,{className:t.versionText},"Version ",e.version),l.createElement(El.Z,{label:e.status,color:"APPROVED"===e.status?"primary":"default",variant:"REJECTED"===e.status||"CANCELLED"===e.status?"outlined":"default"}),l.createElement("div",{className:t.proposedAtContainer},l.createElement(x.default,null,"Proposed ",l.createElement(aA,{tooltip:!0},e.createdAt)))),l.createElement(mF.Z,{className:t.expansionPanelDetails},l.createElement("div",{className:t.actions},l.createElement("div",{className:t.editContainer},0===n&&("PENDING"===e.status||"CANCELLED"===e.status)&&"DELETED"!==s.status&&"REVOKED"!==s.status&&l.createElement(ox.default,{variant:"contained",onClick:function(){return p(!0)}},"Edit")),l.createElement("div",{className:t.actionsContainer},v(e.status,e.id,s))),l.createElement(gh,{language:"toml",style:gu,"data-testid":"codeblock"},e.definition)))}),l.createElement(oI,{open:null!=c,title:c?M_[c.action].title:"",body:c?M_[c.action].body:"",onConfirm:function(){if(c){switch(c.action){case"approve":n(c.id);break;case"cancel":r(c.id);break;case"reject":i(c.id)}f(null)}},cancelButtonText:"Cancel",onCancel:function(){return f(null)}}),l.createElement(Mo,{open:h,onClose:function(){return p(!1)},initialValues:{definition:m.definition,id:m.id},onSubmit:a}))});function MS(e,t){return t||(t=e.slice(0)),Object.freeze(Object.defineProperties(e,{raw:{value:Object.freeze(t)}}))}function Mk(){var e=MS(["\n ","\n fragment JobProposalPayloadFields on JobProposal {\n id\n externalJobID\n remoteUUID\n jobID\n specs {\n ...JobProposal_SpecsFields\n }\n status\n pendingUpdate\n }\n"]);return Mk=function(){return e},e}var Mx=n0(Mk(),My),MT=function(e){var t=e.onApprove,n=e.onCancel,r=e.onReject,i=e.onUpdateSpec,a=e.proposal;return l.createElement(iv,null,l.createElement(d.Z,{container:!0,spacing:32},l.createElement(d.Z,{item:!0,xs:9},l.createElement(iw,null,"Job Proposal #",a.id))),l.createElement(Me,{proposal:a}),l.createElement(d.Z,{container:!0,spacing:32},l.createElement(d.Z,{item:!0,xs:9},l.createElement(T$,null,"Specs"))),l.createElement(d.Z,{container:!0,spacing:32},l.createElement(d.Z,{item:!0,xs:12},l.createElement(ME,{proposal:a,specs:a.specs,onReject:r,onApprove:t,onCancel:n,onUpdateSpec:i}))))};function MM(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&i[i.length-1])&&(6===a[0]||2===a[0])){o=0;continue}if(3===a[0]&&(!i||a[1]>i[0]&&a[1]e.length)&&(t=e.length);for(var n=0,r=Array(t);ne.length)&&(t=e.length);for(var n=0,r=Array(t);nU,tA:()=>$,KL:()=>H,Iw:()=>V,DQ:()=>W,cB:()=>T,LO:()=>M,t5:()=>k,qt:()=>x,Jc:()=>C,L7:()=>Y,EO:()=>B});var r,i,a=n(66289),o=n(41800),s=n.n(o),u=n(67932);(i=r||(r={})).IN_PROGRESS="in_progress",i.PENDING_INCOMING_CONFIRMATIONS="pending_incoming_confirmations",i.PENDING_CONNECTION="pending_connection",i.PENDING_BRIDGE="pending_bridge",i.PENDING_SLEEP="pending_sleep",i.ERRORED="errored",i.COMPLETED="completed";var c=n(87013),l=n(19084),f=n(34823);function d(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&i[i.length-1])&&(6===a[0]||2===a[0])){o=0;continue}if(3===a[0]&&(!i||a[1]>i[0]&&a[1]j,v2:()=>F});var r=n(66289);function i(e,t){if(!(e instanceof t))throw TypeError("Cannot call a class as a function")}var a="/sessions",o="/sessions",s=function e(t){var n=this;i(this,e),this.api=t,this.createSession=function(e){return n.create(e)},this.destroySession=function(){return n.destroy()},this.create=this.api.createResource(a),this.destroy=this.api.deleteResource(o)};function u(e,t){if(!(e instanceof t))throw TypeError("Cannot call a class as a function")}var c="/v2/bulk_delete_runs",l=function e(t){var n=this;u(this,e),this.api=t,this.bulkDeleteJobRuns=function(e){return n.destroy(e)},this.destroy=this.api.deleteResource(c)};function f(e,t){if(!(e instanceof t))throw TypeError("Cannot call a class as a function")}var d="/v2/chains/evm",h="".concat(d,"/:id"),p=function e(t){var n=this;f(this,e),this.api=t,this.getChains=function(){return n.index()},this.createChain=function(e){return n.create(e)},this.destroyChain=function(e){return n.destroy(void 0,{id:e})},this.updateChain=function(e,t){return n.update(t,{id:e})},this.index=this.api.fetchResource(d),this.create=this.api.createResource(d),this.destroy=this.api.deleteResource(h),this.update=this.api.updateResource(h)};function b(e,t){if(!(e instanceof t))throw TypeError("Cannot call a class as a function")}var m="/v2/keys/evm/chain",g=function e(t){var n=this;b(this,e),this.api=t,this.chain=function(e){var t=new URLSearchParams;t.append("address",e.address),t.append("evmChainID",e.evmChainID),null!==e.nextNonce&&t.append("nextNonce",e.nextNonce),null!==e.abandon&&t.append("abandon",String(e.abandon)),null!==e.enabled&&t.append("enabled",String(e.enabled));var r=m+"?"+t.toString();return n.api.createResource(r)()}};function v(e,t){if(!(e instanceof t))throw TypeError("Cannot call a class as a function")}var y="/v2/jobs",w="".concat(y,"/:specId/runs"),_=function e(t){var n=this;v(this,e),this.api=t,this.createJobRunV2=function(e,t){return n.post(t,{specId:e})},this.post=this.api.createResource(w,!0)};function E(e,t){if(!(e instanceof t))throw TypeError("Cannot call a class as a function")}var S="/v2/log",k=function e(t){var n=this;E(this,e),this.api=t,this.getLogConfig=function(){return n.show()},this.updateLogConfig=function(e){return n.update(e)},this.show=this.api.fetchResource(S),this.update=this.api.updateResource(S)};function x(e,t){if(!(e instanceof t))throw TypeError("Cannot call a class as a function")}var T="/v2/nodes",M=function e(t){var n=this;x(this,e),this.api=t,this.getNodes=function(){return n.index()},this.createNode=function(e){return n.create(e)},this.index=this.api.fetchResource(T),this.create=this.api.createResource(T)};function O(e,t){if(!(e instanceof t))throw TypeError("Cannot call a class as a function")}var A="/v2/enroll_webauthn",L=function e(t){var n=this;O(this,e),this.api=t,this.beginKeyRegistration=function(e){return n.create(e)},this.finishKeyRegistration=function(e){return n.put(e)},this.create=this.api.fetchResource(A),this.put=this.api.createResource(A)};function C(e,t){if(!(e instanceof t))throw TypeError("Cannot call a class as a function")}var I="/v2/build_info",D=function e(t){var n=this;C(this,e),this.api=t,this.show=function(){return n.api.GET(I)()}};function N(e,t){if(!(e instanceof t))throw TypeError("Cannot call a class as a function")}var P=function e(t){N(this,e),this.api=t,this.buildInfo=new D(this.api),this.bulkDeleteRuns=new l(this.api),this.chains=new p(this.api),this.logConfig=new k(this.api),this.nodes=new M(this.api),this.jobs=new _(this.api),this.webauthn=new L(this.api),this.evmKeys=new g(this.api)},R=new r.V0({base:void 0}),j=new s(R),F=new P(R)},1398(e,t,n){"use strict";n.d(t,{Z:()=>d});var r=n(67294),i=n(32316),a=n(83638),o=n(94184),s=n.n(o);function u(){return(u=Object.assign||function(e){for(var t=1;tc});var r=n(67294),i=n(32316);function a(){return(a=Object.assign||function(e){for(var t=1;tx,jK:()=>v});var r=n(67294),i=n(55977),a=n(45697),o=n.n(a),s=n(82204),u=n(71426),c=n(94184),l=n.n(c),f=n(32316),d=function(e){var t=e.palette.success||{},n=e.palette.warning||{};return{base:{paddingLeft:5*e.spacing.unit,paddingRight:5*e.spacing.unit},success:{backgroundColor:t.main,color:t.contrastText},error:{backgroundColor:e.palette.error.dark,color:e.palette.error.contrastText},warning:{backgroundColor:n.contrastText,color:n.main}}},h=function(e){var t,n=e.success,r=e.error,i=e.warning,a=e.classes,o=e.className;return n?t=a.success:r?t=a.error:i&&(t=a.warning),l()(a.base,o,t)},p=function(e){return r.createElement(s.Z,{className:h(e),square:!0},r.createElement(u.default,{variant:"body2",color:"inherit",component:"div"},e.children))};p.defaultProps={success:!1,error:!1,warning:!1},p.propTypes={success:o().bool,error:o().bool,warning:o().bool};let b=(0,f.withStyles)(d)(p);var m=function(){return r.createElement(r.Fragment,null,"Unhandled error. Please help us by opening a"," ",r.createElement("a",{href:"https://github.com/smartcontractkit/chainlink/issues/new"},"bug report"))};let g=m;function v(e){return"string"==typeof e?e:e.component?e.component(e.props):r.createElement(g,null)}function y(e,t){var n;return n="string"==typeof e?e:e.component?e.component(e.props):r.createElement(g,null),r.createElement("p",{key:t},n)}var w=function(e){var t=e.notifications;return r.createElement(b,{error:!0},t.map(y))},_=function(e){var t=e.notifications;return r.createElement(b,{success:!0},t.map(y))},E=function(e){var t=e.errors,n=e.successes;return r.createElement("div",null,(null==t?void 0:t.length)>0&&r.createElement(w,{notifications:t}),n.length>0&&r.createElement(_,{notifications:n}))},S=function(e){return{errors:e.notifications.errors,successes:e.notifications.successes}},k=(0,i.$j)(S)(E);let x=k},9409(e,t,n){"use strict";n.d(t,{ZP:()=>j});var r=n(67294),i=n(55977),a=n(47886),o=n(32316),s=n(1398),u=n(82204),c=n(30060),l=n(71426),f=n(60520),d=n(97779),h=n(57209),p=n(26842),b=n(3950),m=n(5536),g=n(45697),v=n.n(g);let y=n.p+"9f6d832ef97e8493764e.svg";function w(){return(w=Object.assign||function(e){for(var t=1;te.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&_.map(function(e,t){return r.createElement(d.Z,{item:!0,xs:12,key:t},r.createElement(u.Z,{raised:!1,className:v.error},r.createElement(c.Z,null,r.createElement(l.default,{variant:"body1",className:v.errorText},(0,b.jK)(e)))))}),r.createElement(d.Z,{item:!0,xs:12},r.createElement(f.Z,{id:"email",label:"Email",margin:"normal",value:n,onChange:m("email"),error:_.length>0,variant:"outlined",fullWidth:!0})),r.createElement(d.Z,{item:!0,xs:12},r.createElement(f.Z,{id:"password",label:"Password",type:"password",autoComplete:"password",margin:"normal",value:h,onChange:m("password"),error:_.length>0,variant:"outlined",fullWidth:!0})),r.createElement(d.Z,{item:!0,xs:12},r.createElement(d.Z,{container:!0,spacing:0,justify:"center"},r.createElement(d.Z,{item:!0},r.createElement(s.Z,{type:"submit",variant:"primary"},"Access Account")))),y&&r.createElement(l.default,{variant:"body1",color:"textSecondary"},"Signing in...")))))))},P=function(e){return{fetching:e.authentication.fetching,authenticated:e.authentication.allowed,errors:e.notifications.errors}},R=(0,i.$j)(P,x({submitSignIn:p.L7}))(N);let j=(0,h.wU)(e)((0,o.withStyles)(D)(R))},16353(e,t,n){"use strict";n.d(t,{ZP:()=>H,rH:()=>U});var r,i=n(55977),a=n(15857),o=n(9541),s=n(19084);function u(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function c(e){for(var t=1;t0&&void 0!==arguments[0]?arguments[0]:h,t=arguments.length>1?arguments[1]:void 0;switch(t.type){case s.Mk.RECEIVE_SIGNOUT_SUCCESS:case s.Mk.RECEIVE_SIGNIN_SUCCESS:var n={allowed:t.authenticated};return o.Ks(n),f(c({},e,n),{errors:[]});case s.Mk.RECEIVE_SIGNIN_FAIL:var r={allowed:!1};return o.Ks(r),f(c({},e,r),{errors:[]});case s.Mk.RECEIVE_SIGNIN_ERROR:case s.Mk.RECEIVE_SIGNOUT_ERROR:var i={allowed:!1};return o.Ks(i),f(c({},e,i),{errors:t.errors||[]});default:return e}};let b=p;function m(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function g(e){for(var t=1;t0&&void 0!==arguments[0]?arguments[0]:_,t=arguments.length>1?arguments[1]:void 0;return t.type?t.type.startsWith(r.REQUEST)?y(g({},e),{count:e.count+1}):t.type.startsWith(r.RECEIVE)?y(g({},e),{count:Math.max(e.count-1,0)}):t.type.startsWith(r.RESPONSE)?y(g({},e),{count:Math.max(e.count-1,0)}):t.type===s.di.REDIRECT?y(g({},e),{count:0}):e:e};let S=E;function k(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function x(e){for(var t=1;t0&&void 0!==arguments[0]?arguments[0]:O,t=arguments.length>1?arguments[1]:void 0;switch(t.type){case s.di.MATCH_ROUTE:return M(x({},O),{currentUrl:t.pathname});case s.Ih.NOTIFY_SUCCESS:var n={component:t.component,props:t.props};return M(x({},e),{successes:[n],errors:[]});case s.Ih.NOTIFY_SUCCESS_MSG:return M(x({},e),{successes:[t.msg],errors:[]});case s.Ih.NOTIFY_ERROR:var r=t.error.errors,i=null==r?void 0:r.map(function(e){return L(t,e)});return M(x({},e),{successes:[],errors:i});case s.Ih.NOTIFY_ERROR_MSG:return M(x({},e),{successes:[],errors:[t.msg]});case s.Mk.RECEIVE_SIGNIN_FAIL:return M(x({},e),{successes:[],errors:["Your email or password is incorrect. Please try again"]});default:return e}};function L(e,t){return{component:e.component,props:{msg:t.detail}}}let C=A;function I(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function D(e){for(var t=1;t0&&void 0!==arguments[0]?arguments[0]:R,t=arguments.length>1?arguments[1]:void 0;switch(t.type){case s.di.REDIRECT:return P(D({},e),{to:t.to});case s.di.MATCH_ROUTE:return P(D({},e),{to:void 0});default:return e}};let F=j;var Y=n(87013),B=(0,a.UY)({authentication:b,fetching:S,notifications:C,redirect:F,buildInfo:Y.Z});B(void 0,{type:"INITIAL_STATE"});var U=i.v9;let H=B},19084(e,t,n){"use strict";var r,i,a,o,s,u,c,l,f,d;n.d(t,{Ih:()=>i,Mk:()=>a,Y0:()=>s,di:()=>r,jp:()=>o}),n(67294),(u=r||(r={})).REDIRECT="REDIRECT",u.MATCH_ROUTE="MATCH_ROUTE",(c=i||(i={})).NOTIFY_SUCCESS="NOTIFY_SUCCESS",c.NOTIFY_SUCCESS_MSG="NOTIFY_SUCCESS_MSG",c.NOTIFY_ERROR="NOTIFY_ERROR",c.NOTIFY_ERROR_MSG="NOTIFY_ERROR_MSG",(l=a||(a={})).REQUEST_SIGNIN="REQUEST_SIGNIN",l.RECEIVE_SIGNIN_SUCCESS="RECEIVE_SIGNIN_SUCCESS",l.RECEIVE_SIGNIN_FAIL="RECEIVE_SIGNIN_FAIL",l.RECEIVE_SIGNIN_ERROR="RECEIVE_SIGNIN_ERROR",l.RECEIVE_SIGNOUT_SUCCESS="RECEIVE_SIGNOUT_SUCCESS",l.RECEIVE_SIGNOUT_ERROR="RECEIVE_SIGNOUT_ERROR",(f=o||(o={})).RECEIVE_CREATE_ERROR="RECEIVE_CREATE_ERROR",f.RECEIVE_CREATE_SUCCESS="RECEIVE_CREATE_SUCCESS",f.RECEIVE_DELETE_ERROR="RECEIVE_DELETE_ERROR",f.RECEIVE_DELETE_SUCCESS="RECEIVE_DELETE_SUCCESS",f.RECEIVE_UPDATE_ERROR="RECEIVE_UPDATE_ERROR",f.RECEIVE_UPDATE_SUCCESS="RECEIVE_UPDATE_SUCCESS",f.REQUEST_CREATE="REQUEST_CREATE",f.REQUEST_DELETE="REQUEST_DELETE",f.REQUEST_UPDATE="REQUEST_UPDATE",f.UPSERT_CONFIGURATION="UPSERT_CONFIGURATION",f.UPSERT_JOB_RUN="UPSERT_JOB_RUN",f.UPSERT_JOB_RUNS="UPSERT_JOB_RUNS",f.UPSERT_TRANSACTION="UPSERT_TRANSACTION",f.UPSERT_TRANSACTIONS="UPSERT_TRANSACTIONS",f.UPSERT_BUILD_INFO="UPSERT_BUILD_INFO",(d=s||(s={})).FETCH_BUILD_INFO_REQUESTED="FETCH_BUILD_INFO_REQUESTED",d.FETCH_BUILD_INFO_SUCCEEDED="FETCH_BUILD_INFO_SUCCEEDED",d.FETCH_BUILD_INFO_FAILED="FETCH_BUILD_INFO_FAILED"},87013(e,t,n){"use strict";n.d(t,{Y:()=>o,Z:()=>u});var r=n(19084);function i(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function a(e){for(var t=1;t0&&void 0!==arguments[0]?arguments[0]:o,t=arguments.length>1?arguments[1]:void 0;return t.type===r.Y0.FETCH_BUILD_INFO_SUCCEEDED?a({},t.buildInfo):e};let u=s},34823(e,t,n){"use strict";n.d(t,{N:()=>r});var r=function(e){return e.buildInfo}},73343(e,t,n){"use strict";n.d(t,{r:()=>u});var r=n(19350),i=n(32316),a=n(59114),o=n(5324),s={props:{MuiGrid:{spacing:3*o.default.unit},MuiCardHeader:{titleTypographyProps:{color:"secondary"}}},palette:{action:{hoverOpacity:.3},primary:{light:"#E5F1FF",main:"#3c40c6",contrastText:"#fff"},secondary:{main:"#3d5170"},success:{light:"#e8faf1",main:r.ek.A700,dark:r.ek[700],contrastText:r.y0.white},warning:{light:"#FFFBF1",main:"#fff6b6",contrastText:"#fad27a"},error:{light:"#ffdada",main:"#f44336",dark:"#d32f2f",contrastText:"#fff"},background:{default:"#f5f6f8",appBar:"#3c40c6"},text:{primary:(0,a.darken)(r.BA.A700,.7),secondary:"#818ea3"},listPendingStatus:{background:"#fef7e5",color:"#fecb4c"},listCompletedStatus:{background:"#e9faf2",color:"#4ed495"}},shape:{borderRadius:o.default.unit},overrides:{MuiButton:{root:{borderRadius:o.default.unit/2,textTransform:"none"},sizeLarge:{padding:void 0,fontSize:void 0,paddingTop:o.default.unit,paddingBottom:o.default.unit,paddingLeft:5*o.default.unit,paddingRight:5*o.default.unit}},MuiTableCell:{body:{fontSize:"1rem"},head:{fontSize:"1rem",fontWeight:400}},MuiCardHeader:{root:{borderBottom:"1px solid rgba(0, 0, 0, 0.12)"},action:{marginTop:-2,marginRight:0,"& >*":{marginLeft:2*o.default.unit}},subheader:{marginTop:.5*o.default.unit}}},typography:{useNextVariants:!0,fontFamily:"-apple-system,BlinkMacSystemFont,Roboto,Helvetica,Arial,sans-serif",button:{textTransform:"none",fontSize:"1.2em"},body1:{fontSize:"1.0rem",fontWeight:400,lineHeight:"1.46429em",color:"rgba(0, 0, 0, 0.87)",letterSpacing:-.4},body2:{fontSize:"1.0rem",fontWeight:500,lineHeight:"1.71429em",color:"rgba(0, 0, 0, 0.87)",letterSpacing:-.4},body1Next:{color:"rgb(29, 29, 29)",fontWeight:400,fontSize:"1rem",lineHeight:1.5,letterSpacing:-.4},body2Next:{color:"rgb(29, 29, 29)",fontWeight:400,fontSize:"0.875rem",lineHeight:1.5,letterSpacing:-.4},display1:{color:"#818ea3",fontSize:"2.125rem",fontWeight:400,lineHeight:"1.20588em",letterSpacing:-.4},display2:{color:"#818ea3",fontSize:"2.8125rem",fontWeight:400,lineHeight:"1.13333em",marginLeft:"-.02em",letterSpacing:-.4},display3:{color:"#818ea3",fontSize:"3.5rem",fontWeight:400,lineHeight:"1.30357em",marginLeft:"-.02em",letterSpacing:-.4},display4:{fontSize:14,fontWeightLight:300,fontWeightMedium:500,fontWeightRegular:400,letterSpacing:-.4},h1:{color:"rgb(29, 29, 29)",fontSize:"6rem",fontWeight:300,lineHeight:1},h2:{color:"rgb(29, 29, 29)",fontSize:"3.75rem",fontWeight:300,lineHeight:1},h3:{color:"rgb(29, 29, 29)",fontSize:"3rem",fontWeight:400,lineHeight:1.04},h4:{color:"rgb(29, 29, 29)",fontSize:"2.125rem",fontWeight:400,lineHeight:1.17},h5:{color:"rgb(29, 29, 29)",fontSize:"1.5rem",fontWeight:400,lineHeight:1.33,letterSpacing:-.4},h6:{fontSize:"0.8rem",fontWeight:450,lineHeight:"1.71429em",color:"rgba(0, 0, 0, 0.87)",letterSpacing:-.4},subheading:{color:"rgb(29, 29, 29)",fontSize:"1rem",fontWeight:400,lineHeight:"1.5em",letterSpacing:-.4},subtitle1:{color:"rgb(29, 29, 29)",fontSize:"1rem",fontWeight:400,lineHeight:1.75,letterSpacing:-.4},subtitle2:{color:"rgb(29, 29, 29)",fontSize:"0.875rem",fontWeight:500,lineHeight:1.57,letterSpacing:-.4}},shadows:["none","0px 1px 3px 0px rgba(0, 0, 0, 0.1),0px 1px 1px 0px rgba(0, 0, 0, 0.04),0px 2px 1px -1px rgba(0, 0, 0, 0.02)","0px 1px 5px 0px rgba(0, 0, 0, 0.1),0px 2px 2px 0px rgba(0, 0, 0, 0.04),0px 3px 1px -2px rgba(0, 0, 0, 0.02)","0px 1px 8px 0px rgba(0, 0, 0, 0.1),0px 3px 4px 0px rgba(0, 0, 0, 0.04),0px 3px 3px -2px rgba(0, 0, 0, 0.02)","0px 2px 4px -1px rgba(0, 0, 0, 0.1),0px 4px 5px 0px rgba(0, 0, 0, 0.04),0px 1px 10px 0px rgba(0, 0, 0, 0.02)","0px 3px 5px -1px rgba(0, 0, 0, 0.1),0px 5px 8px 0px rgba(0, 0, 0, 0.04),0px 1px 14px 0px rgba(0, 0, 0, 0.02)","0px 3px 5px -1px rgba(0, 0, 0, 0.1),0px 6px 10px 0px rgba(0, 0, 0, 0.04),0px 1px 18px 0px rgba(0, 0, 0, 0.02)","0px 4px 5px -2px rgba(0, 0, 0, 0.1),0px 7px 10px 1px rgba(0, 0, 0, 0.04),0px 2px 16px 1px rgba(0, 0, 0, 0.02)","0px 5px 5px -3px rgba(0, 0, 0, 0.1),0px 8px 10px 1px rgba(0, 0, 0, 0.04),0px 3px 14px 2px rgba(0, 0, 0, 0.02)","0px 5px 6px -3px rgba(0, 0, 0, 0.1),0px 9px 12px 1px rgba(0, 0, 0, 0.04),0px 3px 16px 2px rgba(0, 0, 0, 0.02)","0px 6px 6px -3px rgba(0, 0, 0, 0.1),0px 10px 14px 1px rgba(0, 0, 0, 0.04),0px 4px 18px 3px rgba(0, 0, 0, 0.02)","0px 6px 7px -4px rgba(0, 0, 0, 0.1),0px 11px 15px 1px rgba(0, 0, 0, 0.04),0px 4px 20px 3px rgba(0, 0, 0, 0.02)","0px 7px 8px -4px rgba(0, 0, 0, 0.1),0px 12px 17px 2px rgba(0, 0, 0, 0.04),0px 5px 22px 4px rgba(0, 0, 0, 0.02)","0px 7px 8px -4px rgba(0, 0, 0, 0.1),0px 13px 19px 2px rgba(0, 0, 0, 0.04),0px 5px 24px 4px rgba(0, 0, 0, 0.02)","0px 7px 9px -4px rgba(0, 0, 0, 0.1),0px 14px 21px 2px rgba(0, 0, 0, 0.04),0px 5px 26px 4px rgba(0, 0, 0, 0.02)","0px 8px 9px -5px rgba(0, 0, 0, 0.1),0px 15px 22px 2px rgba(0, 0, 0, 0.04),0px 6px 28px 5px rgba(0, 0, 0, 0.02)","0px 8px 10px -5px rgba(0, 0, 0, 0.1),0px 16px 24px 2px rgba(0, 0, 0, 0.04),0px 6px 30px 5px rgba(0, 0, 0, 0.02)","0px 8px 11px -5px rgba(0, 0, 0, 0.1),0px 17px 26px 2px rgba(0, 0, 0, 0.04),0px 6px 32px 5px rgba(0, 0, 0, 0.02)","0px 9px 11px -5px rgba(0, 0, 0, 0.1),0px 18px 28px 2px rgba(0, 0, 0, 0.04),0px 7px 34px 6px rgba(0, 0, 0, 0.02)","0px 9px 12px -6px rgba(0, 0, 0, 0.1),0px 19px 29px 2px rgba(0, 0, 0, 0.04),0px 7px 36px 6px rgba(0, 0, 0, 0.02)","0px 10px 13px -6px rgba(0, 0, 0, 0.1),0px 20px 31px 3px rgba(0, 0, 0, 0.04),0px 8px 38px 7px rgba(0, 0, 0, 0.02)","0px 10px 13px -6px rgba(0, 0, 0, 0.1),0px 21px 33px 3px rgba(0, 0, 0, 0.04),0px 8px 40px 7px rgba(0, 0, 0, 0.02)","0px 10px 14px -6px rgba(0, 0, 0, 0.1),0px 22px 35px 3px rgba(0, 0, 0, 0.04),0px 8px 42px 7px rgba(0, 0, 0, 0.02)","0px 11px 14px -7px rgba(0, 0, 0, 0.1),0px 23px 36px 3px rgba(0, 0, 0, 0.04),0px 9px 44px 8px rgba(0, 0, 0, 0.02)","0px 11px 15px -7px rgba(0, 0, 0, 0.1),0px 24px 38px 3px rgba(0, 0, 0, 0.04),0px 9px 46px 8px rgba(0, 0, 0, 0.02)",]},u=(0,i.createMuiTheme)(s)},66289(e,t,n){"use strict";function r(e){if(void 0===e)throw ReferenceError("this hasn't been initialised - super() hasn't been called");return e}function i(e,t){if(!(e instanceof t))throw TypeError("Cannot call a class as a function")}function a(){if("undefined"==typeof Reflect||!Reflect.construct||Reflect.construct.sham)return!1;if("function"==typeof Proxy)return!0;try{return Date.prototype.toString.call(Reflect.construct(Date,[],function(){})),!0}catch(e){return!1}}function o(e,t,n){return(o=a()?Reflect.construct:function(e,t,n){var r=[null];r.push.apply(r,t);var i=new(Function.bind.apply(e,r));return n&&f(i,n.prototype),i}).apply(null,arguments)}function s(e){return(s=Object.setPrototypeOf?Object.getPrototypeOf:function(e){return e.__proto__||Object.getPrototypeOf(e)})(e)}function u(e,t){if("function"!=typeof t&&null!==t)throw TypeError("Super expression must either be null or a function");e.prototype=Object.create(t&&t.prototype,{constructor:{value:e,writable:!0,configurable:!0}}),t&&f(e,t)}function c(e){return -1!==Function.toString.call(e).indexOf("[native code]")}function l(e,t){return t&&("object"===p(t)||"function"==typeof t)?t:r(e)}function f(e,t){return(f=Object.setPrototypeOf||function(e,t){return e.__proto__=t,e})(e,t)}n.d(t,{V0:()=>B,_7:()=>v});var d,h,p=function(e){return e&&"undefined"!=typeof Symbol&&e.constructor===Symbol?"symbol":typeof e};function b(e){var t="function"==typeof Map?new Map:void 0;return(b=function(e){if(null===e||!c(e))return e;if("function"!=typeof e)throw TypeError("Super expression must either be null or a function");if(void 0!==t){if(t.has(e))return t.get(e);t.set(e,n)}function n(){return o(e,arguments,s(this).constructor)}return n.prototype=Object.create(e.prototype,{constructor:{value:n,enumerable:!1,writable:!0,configurable:!0}}),f(n,e)})(e)}function m(){if("undefined"==typeof Reflect||!Reflect.construct||Reflect.construct.sham)return!1;if("function"==typeof Proxy)return!0;try{return Boolean.prototype.valueOf.call(Reflect.construct(Boolean,[],function(){})),!0}catch(e){return!1}}function g(e){var t=m();return function(){var n,r=s(e);if(t){var i=s(this).constructor;n=Reflect.construct(r,arguments,i)}else n=r.apply(this,arguments);return l(this,n)}}var v=function(e){u(n,e);var t=g(n);function n(e){var r;return i(this,n),(r=t.call(this,"AuthenticationError(".concat(e.statusText,")"))).errors=[{status:e.status,detail:e},],r}return n}(b(Error)),y=function(e){u(n,e);var t=g(n);function n(e){var r,a=e.errors;return i(this,n),(r=t.call(this,"BadRequestError")).errors=a,r}return n}(b(Error)),w=function(e){u(n,e);var t=g(n);function n(e){var r;return i(this,n),(r=t.call(this,"UnprocessableEntityError")).errors=e,r}return n}(b(Error)),_=function(e){u(n,e);var t=g(n);function n(e){var r;return i(this,n),(r=t.call(this,"ServerError")).errors=e,r}return n}(b(Error)),E=function(e){u(n,e);var t=g(n);function n(e){var r,a=e.errors;return i(this,n),(r=t.call(this,"ConflictError")).errors=a,r}return n}(b(Error)),S=function(e){u(n,e);var t=g(n);function n(e){var r;return i(this,n),(r=t.call(this,"UnknownResponseError(".concat(e.statusText,")"))).errors=[{status:e.status,detail:e.statusText},],r}return n}(b(Error));function k(e,t){var n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:2e4;return Promise.race([fetch(e,t),new Promise(function(e,t){return setTimeout(function(){return t(Error("timeout"))},n)}),])}function x(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&i[i.length-1])&&(6===a[0]||2===a[0])){o=0;continue}if(3===a[0]&&(!i||a[1]>i[0]&&a[1]=200&&e.status<300))return[3,2];return[2,e.json()];case 2:if(400!==e.status)return[3,3];return[2,e.json().then(function(e){throw new y(e)})];case 3:if(401!==e.status)return[3,4];throw new v(e);case 4:if(422!==e.status)return[3,6];return[4,$(e)];case 5:throw n=i.sent(),new w(n);case 6:if(409!==e.status)return[3,7];return[2,e.json().then(function(e){throw new E(e)})];case 7:if(!(e.status>=500))return[3,9];return[4,$(e)];case 8:throw r=i.sent(),new _(r);case 9:throw new S(e);case 10:return[2]}})})).apply(this,arguments)}function $(e){return z.apply(this,arguments)}function z(){return(z=j(function(e){return Y(this,function(t){return[2,e.json().then(function(t){return t.errors?t.errors.map(function(t){return{status:e.status,detail:t.detail}}):G(e)}).catch(function(){return G(e)})]})})).apply(this,arguments)}function G(e){return[{status:e.status,detail:e.statusText},]}},50109(e,t,n){"use strict";n.d(t,{LK:()=>o,U2:()=>i,eT:()=>s,t8:()=>a});var r=n(12795);function i(e){return r.ZP.getItem("chainlink.".concat(e))}function a(e,t){r.ZP.setItem("chainlink.".concat(e),t)}function o(e){var t=i(e),n={};if(t)try{return JSON.parse(t)}catch(r){}return n}function s(e,t){a(e,JSON.stringify(t))}},9541(e,t,n){"use strict";n.d(t,{Ks:()=>u,Tp:()=>a,iR:()=>o,pm:()=>s});var r=n(50109),i="persistURL";function a(){return r.U2(i)||""}function o(e){r.t8(i,e)}function s(){return r.LK("authentication")}function u(e){r.eT("authentication",e)}},67121(e,t,n){"use strict";function r(e){var t,n=e.Symbol;return"function"==typeof n?n.observable?t=n.observable:(t=n("observable"),n.observable=t):t="@@observable",t}n.r(t),n.d(t,{default:()=>o}),e=n.hmd(e),i="undefined"!=typeof self?self:"undefined"!=typeof window?window:void 0!==n.g?n.g:e;var i,a=r(i);let o=a},2177(e,t,n){"use strict";n.d(t,{Z:()=>o});var r=!0,i="Invariant failed";function a(e,t){if(!e){if(r)throw Error(i);throw Error(i+": "+(t||""))}}let o=a},11742(e){e.exports=function(){var e=document.getSelection();if(!e.rangeCount)return function(){};for(var t=document.activeElement,n=[],r=0;ri,pi:()=>a});var r=function(e,t){return(r=Object.setPrototypeOf||({__proto__:[]})instanceof Array&&function(e,t){e.__proto__=t}||function(e,t){for(var n in t)Object.prototype.hasOwnProperty.call(t,n)&&(e[n]=t[n])})(e,t)};function i(e,t){if("function"!=typeof t&&null!==t)throw TypeError("Class extends value "+String(t)+" is not a constructor or null");function n(){this.constructor=e}r(e,t),e.prototype=null===t?Object.create(t):(n.prototype=t.prototype,new n)}var a=function(){return(a=Object.assign||function(e){for(var t,n=1,r=arguments.length;nr})},94927(e,t,n){function r(e,t){if(i("noDeprecation"))return e;var n=!1;function r(){if(!n){if(i("throwDeprecation"))throw Error(t);i("traceDeprecation")?console.trace(t):console.warn(t),n=!0}return e.apply(this,arguments)}return r}function i(e){try{if(!n.g.localStorage)return!1}catch(t){return!1}var r=n.g.localStorage[e];return null!=r&&"true"===String(r).toLowerCase()}e.exports=r},42473(e){"use strict";var t=function(){};e.exports=t},84763(e){e.exports=Worker},47529(e){e.exports=n;var t=Object.prototype.hasOwnProperty;function n(){for(var e={},n=0;nr,O:()=>a}),(i=r||(r={}))[i.loading=1]="loading",i[i.setVariables=2]="setVariables",i[i.fetchMore=3]="fetchMore",i[i.refetch=4]="refetch",i[i.poll=6]="poll",i[i.ready=7]="ready",i[i.error=8]="error"},30990(e,t,n){"use strict";n.d(t,{MS:()=>s,YG:()=>a,cA:()=>c,ls:()=>o});var r=n(23564);n(83952);var i=n(13154),a=Symbol();function o(e){return!!e.extensions&&Array.isArray(e.extensions[a])}function s(e){return e.hasOwnProperty("graphQLErrors")}var u=function(e){var t=(0,r.ev)((0,r.ev)((0,r.ev)([],e.graphQLErrors,!0),e.clientErrors,!0),e.protocolErrors,!0);return e.networkError&&t.push(e.networkError),t.map(function(e){return(0,i.s)(e)&&e.message||"Error message not found."}).join("\n")},c=function(e){function t(n){var r=n.graphQLErrors,i=n.protocolErrors,a=n.clientErrors,o=n.networkError,s=n.errorMessage,c=n.extraInfo,l=e.call(this,s)||this;return l.name="ApolloError",l.graphQLErrors=r||[],l.protocolErrors=i||[],l.clientErrors=a||[],l.networkError=o||null,l.message=s||u(l),l.extraInfo=c,l.__proto__=t.prototype,l}return(0,r.ZT)(t,e),t}(Error)},85317(e,t,n){"use strict";n.d(t,{K:()=>a});var r=n(67294),i=n(30320).aS?Symbol.for("__APOLLO_CONTEXT__"):"__APOLLO_CONTEXT__";function a(){var e=r.createContext[i];return e||(Object.defineProperty(r.createContext,i,{value:e=r.createContext({}),enumerable:!1,writable:!1,configurable:!0}),e.displayName="ApolloContext"),e}},21436(e,t,n){"use strict";n.d(t,{O:()=>i,k:()=>r});var r=Array.isArray;function i(e){return Array.isArray(e)&&e.length>0}},30320(e,t,n){"use strict";n.d(t,{DN:()=>s,JC:()=>l,aS:()=>o,mr:()=>i,sy:()=>a});var r=n(83952),i="function"==typeof WeakMap&&"ReactNative"!==(0,r.wY)(function(){return navigator.product}),a="function"==typeof WeakSet,o="function"==typeof Symbol&&"function"==typeof Symbol.for,s=o&&Symbol.asyncIterator,u="function"==typeof(0,r.wY)(function(){return window.document.createElement}),c=(0,r.wY)(function(){return navigator.userAgent.indexOf("jsdom")>=0})||!1,l=u&&!c},53712(e,t,n){"use strict";function r(){for(var e=[],t=0;tr})},10542(e,t,n){"use strict";n.d(t,{J:()=>o}),n(83952);var r=n(13154);function i(e){var t=new Set([e]);return t.forEach(function(e){(0,r.s)(e)&&a(e)===e&&Object.getOwnPropertyNames(e).forEach(function(n){(0,r.s)(e[n])&&t.add(e[n])})}),e}function a(e){if(__DEV__&&!Object.isFrozen(e))try{Object.freeze(e)}catch(t){if(t instanceof TypeError)return null;throw t}return e}function o(e){return __DEV__&&i(e),e}},14012(e,t,n){"use strict";n.d(t,{J:()=>a});var r=n(23564),i=n(53712);function a(e,t){return(0,i.o)(e,t,t.variables&&{variables:(0,r.pi)((0,r.pi)({},e&&e.variables),t.variables)})}},13154(e,t,n){"use strict";function r(e){return null!==e&&"object"==typeof e}n.d(t,{s:()=>r})},83952(e,t,n){"use strict";n.d(t,{ej:()=>u,kG:()=>c,wY:()=>h});var r,i=n(70655),a="Invariant Violation",o=Object.setPrototypeOf,s=void 0===o?function(e,t){return e.__proto__=t,e}:o,u=function(e){function t(n){void 0===n&&(n=a);var r=e.call(this,"number"==typeof n?a+": "+n+" (see https://github.com/apollographql/invariant-packages)":n)||this;return r.framesToPop=1,r.name=a,s(r,t.prototype),r}return(0,i.ZT)(t,e),t}(Error);function c(e,t){if(!e)throw new u(t)}var l=["debug","log","warn","error","silent"],f=l.indexOf("log");function d(e){return function(){if(l.indexOf(e)>=f)return(console[e]||console.log).apply(console,arguments)}}function h(e){try{return e()}catch(t){}}(r=c||(c={})).debug=d("debug"),r.log=d("log"),r.warn=d("warn"),r.error=d("error");let p=h(function(){return globalThis})||h(function(){return window})||h(function(){return self})||h(function(){return global})||h(function(){return h.constructor("return this")()});var b="__",m=[b,b].join("DEV");function g(){try{return Boolean(__DEV__)}catch(e){return Object.defineProperty(p,m,{value:"production"!==h(function(){return"production"}),enumerable:!1,configurable:!0,writable:!0}),p[m]}}let v=g();function y(e){try{return e()}catch(t){}}var w=y(function(){return globalThis})||y(function(){return window})||y(function(){return self})||y(function(){return global})||y(function(){return y.constructor("return this")()}),_=!1;function E(){!w||y(function(){return"production"})||y(function(){return process})||(Object.defineProperty(w,"process",{value:{env:{NODE_ENV:"production"}},configurable:!0,enumerable:!1,writable:!0}),_=!0)}function S(){_&&(delete w.process,_=!1)}E();var k=n(10143);function x(){return k.H,S()}function T(){__DEV__?c("boolean"==typeof v,v):c("boolean"==typeof v,39)}x(),T()},87462(e,t,n){"use strict";function r(){return(r=Object.assign||function(e){for(var t=1;tr})},25821(e,t,n){"use strict";n.d(t,{Z:()=>s});var r=n(45695);function i(e){return(i="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e})(e)}var a=10,o=2;function s(e){return u(e,[])}function u(e,t){switch(i(e)){case"string":return JSON.stringify(e);case"function":return e.name?"[function ".concat(e.name,"]"):"[function]";case"object":if(null===e)return"null";return c(e,t);default:return String(e)}}function c(e,t){if(-1!==t.indexOf(e))return"[Circular]";var n=[].concat(t,[e]),r=d(e);if(void 0!==r){var i=r.call(e);if(i!==e)return"string"==typeof i?i:u(i,n)}else if(Array.isArray(e))return f(e,n);return l(e,n)}function l(e,t){var n=Object.keys(e);return 0===n.length?"{}":t.length>o?"["+h(e)+"]":"{ "+n.map(function(n){var r=u(e[n],t);return n+": "+r}).join(", ")+" }"}function f(e,t){if(0===e.length)return"[]";if(t.length>o)return"[Array]";for(var n=Math.min(a,e.length),r=e.length-n,i=[],s=0;s1&&i.push("... ".concat(r," more items")),"["+i.join(", ")+"]"}function d(e){var t=e[String(r.Z)];return"function"==typeof t?t:"function"==typeof e.inspect?e.inspect:void 0}function h(e){var t=Object.prototype.toString.call(e).replace(/^\[object /,"").replace(/]$/,"");if("Object"===t&&"function"==typeof e.constructor){var n=e.constructor.name;if("string"==typeof n&&""!==n)return n}return t}},45695(e,t,n){"use strict";n.d(t,{Z:()=>i});var r="function"==typeof Symbol&&"function"==typeof Symbol.for?Symbol.for("nodejs.util.inspect.custom"):void 0;let i=r},25217(e,t,n){"use strict";function r(e,t){if(!Boolean(e))throw Error(null!=t?t:"Unexpected invariant triggered.")}n.d(t,{Ye:()=>o,WU:()=>s,UG:()=>u});var i=n(45695);function a(e){var t=e.prototype.toJSON;"function"==typeof t||r(0),e.prototype.inspect=t,i.Z&&(e.prototype[i.Z]=t)}var o=function(){function e(e,t,n){this.start=e.start,this.end=t.end,this.startToken=e,this.endToken=t,this.source=n}return e.prototype.toJSON=function(){return{start:this.start,end:this.end}},e}();a(o);var s=function(){function e(e,t,n,r,i,a,o){this.kind=e,this.start=t,this.end=n,this.line=r,this.column=i,this.value=o,this.prev=a,this.next=null}return e.prototype.toJSON=function(){return{kind:this.kind,value:this.value,line:this.line,column:this.column}},e}();function u(e){return null!=e&&"string"==typeof e.kind}a(s)},87392(e,t,n){"use strict";function r(e){var t=e.split(/\r\n|[\n\r]/g),n=a(e);if(0!==n)for(var r=1;ro&&i(t[s-1]);)--s;return t.slice(o,s).join("\n")}function i(e){for(var t=0;t1&&void 0!==arguments[1]?arguments[1]:"",n=arguments.length>2&&void 0!==arguments[2]&&arguments[2],r=-1===e.indexOf("\n"),i=" "===e[0]||" "===e[0],a='"'===e[e.length-1],o="\\"===e[e.length-1],s=!r||a||o||n,u="";return s&&!(r&&i)&&(u+="\n"+t),u+=t?e.replace(/\n/g,"\n"+t):e,s&&(u+="\n"),'"""'+u.replace(/"""/g,'\\"""')+'"""'}n.d(t,{LZ:()=>o,W7:()=>r})},97359(e,t,n){"use strict";n.d(t,{h:()=>r});var r=Object.freeze({NAME:"Name",DOCUMENT:"Document",OPERATION_DEFINITION:"OperationDefinition",VARIABLE_DEFINITION:"VariableDefinition",SELECTION_SET:"SelectionSet",FIELD:"Field",ARGUMENT:"Argument",FRAGMENT_SPREAD:"FragmentSpread",INLINE_FRAGMENT:"InlineFragment",FRAGMENT_DEFINITION:"FragmentDefinition",VARIABLE:"Variable",INT:"IntValue",FLOAT:"FloatValue",STRING:"StringValue",BOOLEAN:"BooleanValue",NULL:"NullValue",ENUM:"EnumValue",LIST:"ListValue",OBJECT:"ObjectValue",OBJECT_FIELD:"ObjectField",DIRECTIVE:"Directive",NAMED_TYPE:"NamedType",LIST_TYPE:"ListType",NON_NULL_TYPE:"NonNullType",SCHEMA_DEFINITION:"SchemaDefinition",OPERATION_TYPE_DEFINITION:"OperationTypeDefinition",SCALAR_TYPE_DEFINITION:"ScalarTypeDefinition",OBJECT_TYPE_DEFINITION:"ObjectTypeDefinition",FIELD_DEFINITION:"FieldDefinition",INPUT_VALUE_DEFINITION:"InputValueDefinition",INTERFACE_TYPE_DEFINITION:"InterfaceTypeDefinition",UNION_TYPE_DEFINITION:"UnionTypeDefinition",ENUM_TYPE_DEFINITION:"EnumTypeDefinition",ENUM_VALUE_DEFINITION:"EnumValueDefinition",INPUT_OBJECT_TYPE_DEFINITION:"InputObjectTypeDefinition",DIRECTIVE_DEFINITION:"DirectiveDefinition",SCHEMA_EXTENSION:"SchemaExtension",SCALAR_TYPE_EXTENSION:"ScalarTypeExtension",OBJECT_TYPE_EXTENSION:"ObjectTypeExtension",INTERFACE_TYPE_EXTENSION:"InterfaceTypeExtension",UNION_TYPE_EXTENSION:"UnionTypeExtension",ENUM_TYPE_EXTENSION:"EnumTypeExtension",INPUT_OBJECT_TYPE_EXTENSION:"InputObjectTypeExtension"})},10143(e,t,n){"use strict";n.d(t,{H:()=>c,T:()=>l});var r=n(99763),i=n(25821);function a(e,t){if(!Boolean(e))throw Error(t)}let o=function(e,t){return e instanceof t};function s(e,t){for(var n=0;n1&&void 0!==arguments[1]?arguments[1]:"GraphQL request",n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:{line:1,column:1};"string"==typeof e||a(0,"Body must be a string. Received: ".concat((0,i.Z)(e),".")),this.body=e,this.name=t,this.locationOffset=n,this.locationOffset.line>0||a(0,"line in locationOffset is 1-indexed and must be positive."),this.locationOffset.column>0||a(0,"column in locationOffset is 1-indexed and must be positive.")}return u(e,[{key:r.YF,get:function(){return"Source"}}]),e}();function l(e){return o(e,c)}},99763(e,t,n){"use strict";n.d(t,{YF:()=>r});var r="function"==typeof Symbol&&null!=Symbol.toStringTag?Symbol.toStringTag:"@@toStringTag"},37452(e){"use strict";e.exports=JSON.parse('{"AElig":"\xc6","AMP":"&","Aacute":"\xc1","Acirc":"\xc2","Agrave":"\xc0","Aring":"\xc5","Atilde":"\xc3","Auml":"\xc4","COPY":"\xa9","Ccedil":"\xc7","ETH":"\xd0","Eacute":"\xc9","Ecirc":"\xca","Egrave":"\xc8","Euml":"\xcb","GT":">","Iacute":"\xcd","Icirc":"\xce","Igrave":"\xcc","Iuml":"\xcf","LT":"<","Ntilde":"\xd1","Oacute":"\xd3","Ocirc":"\xd4","Ograve":"\xd2","Oslash":"\xd8","Otilde":"\xd5","Ouml":"\xd6","QUOT":"\\"","REG":"\xae","THORN":"\xde","Uacute":"\xda","Ucirc":"\xdb","Ugrave":"\xd9","Uuml":"\xdc","Yacute":"\xdd","aacute":"\xe1","acirc":"\xe2","acute":"\xb4","aelig":"\xe6","agrave":"\xe0","amp":"&","aring":"\xe5","atilde":"\xe3","auml":"\xe4","brvbar":"\xa6","ccedil":"\xe7","cedil":"\xb8","cent":"\xa2","copy":"\xa9","curren":"\xa4","deg":"\xb0","divide":"\xf7","eacute":"\xe9","ecirc":"\xea","egrave":"\xe8","eth":"\xf0","euml":"\xeb","frac12":"\xbd","frac14":"\xbc","frac34":"\xbe","gt":">","iacute":"\xed","icirc":"\xee","iexcl":"\xa1","igrave":"\xec","iquest":"\xbf","iuml":"\xef","laquo":"\xab","lt":"<","macr":"\xaf","micro":"\xb5","middot":"\xb7","nbsp":"\xa0","not":"\xac","ntilde":"\xf1","oacute":"\xf3","ocirc":"\xf4","ograve":"\xf2","ordf":"\xaa","ordm":"\xba","oslash":"\xf8","otilde":"\xf5","ouml":"\xf6","para":"\xb6","plusmn":"\xb1","pound":"\xa3","quot":"\\"","raquo":"\xbb","reg":"\xae","sect":"\xa7","shy":"\xad","sup1":"\xb9","sup2":"\xb2","sup3":"\xb3","szlig":"\xdf","thorn":"\xfe","times":"\xd7","uacute":"\xfa","ucirc":"\xfb","ugrave":"\xf9","uml":"\xa8","uuml":"\xfc","yacute":"\xfd","yen":"\xa5","yuml":"\xff"}')},93580(e){"use strict";e.exports=JSON.parse('{"0":"�","128":"€","130":"‚","131":"ƒ","132":"„","133":"…","134":"†","135":"‡","136":"ˆ","137":"‰","138":"Š","139":"‹","140":"Œ","142":"Ž","145":"‘","146":"’","147":"“","148":"”","149":"•","150":"–","151":"—","152":"˜","153":"™","154":"š","155":"›","156":"œ","158":"ž","159":"Ÿ"}')},67946(e){"use strict";e.exports=JSON.parse('{"locale":"en","long":{"year":{"previous":"last year","current":"this year","next":"next year","past":{"one":"{0} year ago","other":"{0} years ago"},"future":{"one":"in {0} year","other":"in {0} years"}},"quarter":{"previous":"last quarter","current":"this quarter","next":"next quarter","past":{"one":"{0} quarter ago","other":"{0} quarters ago"},"future":{"one":"in {0} quarter","other":"in {0} quarters"}},"month":{"previous":"last month","current":"this month","next":"next month","past":{"one":"{0} month ago","other":"{0} months ago"},"future":{"one":"in {0} month","other":"in {0} months"}},"week":{"previous":"last week","current":"this week","next":"next week","past":{"one":"{0} week ago","other":"{0} weeks ago"},"future":{"one":"in {0} week","other":"in {0} weeks"}},"day":{"previous":"yesterday","current":"today","next":"tomorrow","past":{"one":"{0} day ago","other":"{0} days ago"},"future":{"one":"in {0} day","other":"in {0} days"}},"hour":{"current":"this hour","past":{"one":"{0} hour ago","other":"{0} hours ago"},"future":{"one":"in {0} hour","other":"in {0} hours"}},"minute":{"current":"this minute","past":{"one":"{0} minute ago","other":"{0} minutes ago"},"future":{"one":"in {0} minute","other":"in {0} minutes"}},"second":{"current":"now","past":{"one":"{0} second ago","other":"{0} seconds ago"},"future":{"one":"in {0} second","other":"in {0} seconds"}}},"short":{"year":{"previous":"last yr.","current":"this yr.","next":"next yr.","past":"{0} yr. ago","future":"in {0} yr."},"quarter":{"previous":"last qtr.","current":"this qtr.","next":"next qtr.","past":{"one":"{0} qtr. ago","other":"{0} qtrs. ago"},"future":{"one":"in {0} qtr.","other":"in {0} qtrs."}},"month":{"previous":"last mo.","current":"this mo.","next":"next mo.","past":"{0} mo. ago","future":"in {0} mo."},"week":{"previous":"last wk.","current":"this wk.","next":"next wk.","past":"{0} wk. ago","future":"in {0} wk."},"day":{"previous":"yesterday","current":"today","next":"tomorrow","past":{"one":"{0} day ago","other":"{0} days ago"},"future":{"one":"in {0} day","other":"in {0} days"}},"hour":{"current":"this hour","past":"{0} hr. ago","future":"in {0} hr."},"minute":{"current":"this minute","past":"{0} min. ago","future":"in {0} min."},"second":{"current":"now","past":"{0} sec. ago","future":"in {0} sec."}},"narrow":{"year":{"previous":"last yr.","current":"this yr.","next":"next yr.","past":"{0} yr. ago","future":"in {0} yr."},"quarter":{"previous":"last qtr.","current":"this qtr.","next":"next qtr.","past":{"one":"{0} qtr. ago","other":"{0} qtrs. ago"},"future":{"one":"in {0} qtr.","other":"in {0} qtrs."}},"month":{"previous":"last mo.","current":"this mo.","next":"next mo.","past":"{0} mo. ago","future":"in {0} mo."},"week":{"previous":"last wk.","current":"this wk.","next":"next wk.","past":"{0} wk. ago","future":"in {0} wk."},"day":{"previous":"yesterday","current":"today","next":"tomorrow","past":{"one":"{0} day ago","other":"{0} days ago"},"future":{"one":"in {0} day","other":"in {0} days"}},"hour":{"current":"this hour","past":"{0} hr. ago","future":"in {0} hr."},"minute":{"current":"this minute","past":"{0} min. ago","future":"in {0} min."},"second":{"current":"now","past":"{0} sec. ago","future":"in {0} sec."}},"now":{"now":{"current":"now","future":"in a moment","past":"just now"}},"mini":{"year":"{0}yr","month":"{0}mo","week":"{0}wk","day":"{0}d","hour":"{0}h","minute":"{0}m","second":"{0}s","now":"now"},"short-time":{"year":"{0} yr.","month":"{0} mo.","week":"{0} wk.","day":{"one":"{0} day","other":"{0} days"},"hour":"{0} hr.","minute":"{0} min.","second":"{0} sec."},"long-time":{"year":{"one":"{0} year","other":"{0} years"},"month":{"one":"{0} month","other":"{0} months"},"week":{"one":"{0} week","other":"{0} weeks"},"day":{"one":"{0} day","other":"{0} days"},"hour":{"one":"{0} hour","other":"{0} hours"},"minute":{"one":"{0} minute","other":"{0} minutes"},"second":{"one":"{0} second","other":"{0} seconds"}}}')}},__webpack_module_cache__={};function __webpack_require__(e){var t=__webpack_module_cache__[e];if(void 0!==t)return t.exports;var n=__webpack_module_cache__[e]={id:e,loaded:!1,exports:{}};return __webpack_modules__[e].call(n.exports,n,n.exports,__webpack_require__),n.loaded=!0,n.exports}__webpack_require__.n=e=>{var t=e&&e.__esModule?()=>e.default:()=>e;return __webpack_require__.d(t,{a:t}),t},(()=>{var e,t=Object.getPrototypeOf?e=>Object.getPrototypeOf(e):e=>e.__proto__;__webpack_require__.t=function(n,r){if(1&r&&(n=this(n)),8&r||"object"==typeof n&&n&&(4&r&&n.__esModule||16&r&&"function"==typeof n.then))return n;var i=Object.create(null);__webpack_require__.r(i);var a={};e=e||[null,t({}),t([]),t(t)];for(var o=2&r&&n;"object"==typeof o&&!~e.indexOf(o);o=t(o))Object.getOwnPropertyNames(o).forEach(e=>a[e]=()=>n[e]);return a.default=()=>n,__webpack_require__.d(i,a),i}})(),__webpack_require__.d=(e,t)=>{for(var n in t)__webpack_require__.o(t,n)&&!__webpack_require__.o(e,n)&&Object.defineProperty(e,n,{enumerable:!0,get:t[n]})},__webpack_require__.g=function(){if("object"==typeof globalThis)return globalThis;try{return this||Function("return this")()}catch(e){if("object"==typeof window)return window}}(),__webpack_require__.hmd=e=>((e=Object.create(e)).children||(e.children=[]),Object.defineProperty(e,"exports",{enumerable:!0,set(){throw Error("ES Modules may not assign module.exports or exports.*, Use ESM export syntax, instead: "+e.id)}}),e),__webpack_require__.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t),__webpack_require__.r=e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},__webpack_require__.nmd=e=>(e.paths=[],e.children||(e.children=[]),e),__webpack_require__.p="/assets/",__webpack_require__.nc=void 0;var __webpack_exports__={};(()=>{"use strict";var e,t,n,r,i=__webpack_require__(32316),a=__webpack_require__(8126),o=__webpack_require__(5690),s=__webpack_require__(30381),u=__webpack_require__.n(s),c=__webpack_require__(67294),l=__webpack_require__(73935),f=__webpack_require__.n(l),d=__webpack_require__(57209),h=__webpack_require__(55977),p=__webpack_require__(15857),b=__webpack_require__(28500);function m(e){return function(t){var n=t.dispatch,r=t.getState;return function(t){return function(i){return"function"==typeof i?i(n,r,e):t(i)}}}}var g=m();g.withExtraArgument=m;let v=g;var y=__webpack_require__(76489);function w(e){return function(t){return function(n){return function(r){n(r);var i=e||document&&document.cookie||"",a=t.getState();if("MATCH_ROUTE"===r.type&&"/signin"!==a.notifications.currentUrl){var o=(0,y.Q)(i);if(o.explorer)try{var s=JSON.parse(o.explorer);if("error"===s.status){var u=_(s.url);n({type:"NOTIFY_ERROR_MSG",msg:u})}}catch(c){n({type:"NOTIFY_ERROR_MSG",msg:"Invalid explorer status"})}}}}}}function _(e){var t="Can't connect to explorer: ".concat(e);return e.match(/^wss?:.+/)?t:"".concat(t,". You must use a websocket.")}var E=__webpack_require__(16353);function S(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=Array(t);n=e.length?{done:!0}:{done:!1,value:e[r++]}}}throw TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}function ei(e,t){if(e){if("string"==typeof e)return ea(e,t);var n=Object.prototype.toString.call(e).slice(8,-1);if("Object"===n&&e.constructor&&(n=e.constructor.name),"Map"===n||"Set"===n)return Array.from(e);if("Arguments"===n||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n))return ea(e,t)}}function ea(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=Array(t);n1,i=!1,a=arguments[1],o=a;return new n(function(n){return t.subscribe({next:function(t){var a=!i;if(i=!0,!a||r)try{o=e(o,t)}catch(s){return n.error(s)}else o=t},error:function(e){n.error(e)},complete:function(){if(!i&&!r)return n.error(TypeError("Cannot reduce an empty sequence"));n.next(o),n.complete()}})})},t.concat=function(){for(var e=this,t=arguments.length,n=Array(t),r=0;r=0&&i.splice(e,1),o()}});i.push(s)},error:function(e){r.error(e)},complete:function(){o()}});function o(){a.closed&&0===i.length&&r.complete()}return function(){i.forEach(function(e){return e.unsubscribe()}),a.unsubscribe()}})},t[ed]=function(){return this},e.from=function(t){var n="function"==typeof this?this:e;if(null==t)throw TypeError(t+" is not an object");var r=ep(t,ed);if(r){var i=r.call(t);if(Object(i)!==i)throw TypeError(i+" is not an object");return em(i)&&i.constructor===n?i:new n(function(e){return i.subscribe(e)})}if(ec("iterator")&&(r=ep(t,ef)))return new n(function(e){ev(function(){if(!e.closed){for(var n,i=er(r.call(t));!(n=i()).done;){var a=n.value;if(e.next(a),e.closed)return}e.complete()}})});if(Array.isArray(t))return new n(function(e){ev(function(){if(!e.closed){for(var n=0;n0))return n.connection.key;var r=n.connection.filter?n.connection.filter:[];r.sort();var i={};return r.forEach(function(e){i[e]=t[e]}),"".concat(n.connection.key,"(").concat(eV(i),")")}var a=e;if(t){var o=eV(t);a+="(".concat(o,")")}return n&&Object.keys(n).forEach(function(e){-1===eW.indexOf(e)&&(n[e]&&Object.keys(n[e]).length?a+="@".concat(e,"(").concat(eV(n[e]),")"):a+="@".concat(e))}),a},{setStringify:function(e){var t=eV;return eV=e,t}}),eV=function(e){return JSON.stringify(e,eq)};function eq(e,t){return(0,eO.s)(t)&&!Array.isArray(t)&&(t=Object.keys(t).sort().reduce(function(e,n){return e[n]=t[n],e},{})),t}function eZ(e,t){if(e.arguments&&e.arguments.length){var n={};return e.arguments.forEach(function(e){var r;return ez(n,e.name,e.value,t)}),n}return null}function eX(e){return e.alias?e.alias.value:e.name.value}function eJ(e,t,n){for(var r,i=0,a=t.selections;it.indexOf(i))throw __DEV__?new Q.ej("illegal argument: ".concat(i)):new Q.ej(27)}return e}function tt(e,t){return t?t(e):eT.of()}function tn(e){return"function"==typeof e?new ta(e):e}function tr(e){return e.request.length<=1}var ti=function(e){function t(t,n){var r=e.call(this,t)||this;return r.link=n,r}return(0,en.ZT)(t,e),t}(Error),ta=function(){function e(e){e&&(this.request=e)}return e.empty=function(){return new e(function(){return eT.of()})},e.from=function(t){return 0===t.length?e.empty():t.map(tn).reduce(function(e,t){return e.concat(t)})},e.split=function(t,n,r){var i=tn(n),a=tn(r||new e(tt));return new e(tr(i)&&tr(a)?function(e){return t(e)?i.request(e)||eT.of():a.request(e)||eT.of()}:function(e,n){return t(e)?i.request(e,n)||eT.of():a.request(e,n)||eT.of()})},e.execute=function(e,t){return e.request(eM(t.context,e7(te(t))))||eT.of()},e.concat=function(t,n){var r=tn(t);if(tr(r))return __DEV__&&Q.kG.warn(new ti("You are calling concat on a terminating link, which will have no effect",r)),r;var i=tn(n);return new e(tr(i)?function(e){return r.request(e,function(e){return i.request(e)||eT.of()})||eT.of()}:function(e,t){return r.request(e,function(e){return i.request(e,t)||eT.of()})||eT.of()})},e.prototype.split=function(t,n,r){return this.concat(e.split(t,n,r||new e(tt)))},e.prototype.concat=function(t){return e.concat(this,t)},e.prototype.request=function(e,t){throw __DEV__?new Q.ej("request is not implemented"):new Q.ej(22)},e.prototype.onError=function(e,t){if(t&&t.error)return t.error(e),!1;throw e},e.prototype.setOnError=function(e){return this.onError=e,this},e}(),to=__webpack_require__(25821),ts=__webpack_require__(25217),tu={Name:[],Document:["definitions"],OperationDefinition:["name","variableDefinitions","directives","selectionSet"],VariableDefinition:["variable","type","defaultValue","directives"],Variable:["name"],SelectionSet:["selections"],Field:["alias","name","arguments","directives","selectionSet"],Argument:["name","value"],FragmentSpread:["name","directives"],InlineFragment:["typeCondition","directives","selectionSet"],FragmentDefinition:["name","variableDefinitions","typeCondition","directives","selectionSet"],IntValue:[],FloatValue:[],StringValue:[],BooleanValue:[],NullValue:[],EnumValue:[],ListValue:["values"],ObjectValue:["fields"],ObjectField:["name","value"],Directive:["name","arguments"],NamedType:["name"],ListType:["type"],NonNullType:["type"],SchemaDefinition:["description","directives","operationTypes"],OperationTypeDefinition:["type"],ScalarTypeDefinition:["description","name","directives"],ObjectTypeDefinition:["description","name","interfaces","directives","fields"],FieldDefinition:["description","name","arguments","type","directives"],InputValueDefinition:["description","name","type","defaultValue","directives"],InterfaceTypeDefinition:["description","name","interfaces","directives","fields"],UnionTypeDefinition:["description","name","directives","types"],EnumTypeDefinition:["description","name","directives","values"],EnumValueDefinition:["description","name","directives"],InputObjectTypeDefinition:["description","name","directives","fields"],DirectiveDefinition:["description","name","arguments","locations"],SchemaExtension:["directives","operationTypes"],ScalarTypeExtension:["name","directives"],ObjectTypeExtension:["name","interfaces","directives","fields"],InterfaceTypeExtension:["name","interfaces","directives","fields"],UnionTypeExtension:["name","directives","types"],EnumTypeExtension:["name","directives","values"],InputObjectTypeExtension:["name","directives","fields"]},tc=Object.freeze({});function tl(e,t){var n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:tu,r=void 0,i=Array.isArray(e),a=[e],o=-1,s=[],u=void 0,c=void 0,l=void 0,f=[],d=[],h=e;do{var p,b=++o===a.length,m=b&&0!==s.length;if(b){if(c=0===d.length?void 0:f[f.length-1],u=l,l=d.pop(),m){if(i)u=u.slice();else{for(var g={},v=0,y=Object.keys(u);v1)for(var r=new tB,i=1;i=0;--a){var o=i[a],s=isNaN(+o)?{}:[];s[o]=t,t=s}n=r.merge(n,t)}),n}var tW=Object.prototype.hasOwnProperty;function tK(e,t){var n,r,i,a,o;return(0,en.mG)(this,void 0,void 0,function(){var s,u,c,l,f,d,h,p,b,m,g,v,y,w,_,E,S,k,x,T,M,O,A;return(0,en.Jh)(this,function(L){switch(L.label){case 0:if(void 0===TextDecoder)throw Error("TextDecoder must be defined in the environment: please import a polyfill.");s=new TextDecoder("utf-8"),u=null===(n=e.headers)||void 0===n?void 0:n.get("content-type"),c="boundary=",l=(null==u?void 0:u.includes(c))?null==u?void 0:u.substring((null==u?void 0:u.indexOf(c))+c.length).replace(/['"]/g,"").replace(/\;(.*)/gm,"").trim():"-",f="\r\n--".concat(l),d="",h=tI(e),p=!0,L.label=1;case 1:if(!p)return[3,3];return[4,h.next()];case 2:for(m=(b=L.sent()).value,g=b.done,v="string"==typeof m?m:s.decode(m),y=d.length-f.length+1,p=!g,d+=v,w=d.indexOf(f,y);w>-1;){if(_=void 0,_=(O=[d.slice(0,w),d.slice(w+f.length),])[0],d=O[1],E=_.indexOf("\r\n\r\n"),(k=(S=tV(_.slice(0,E)))["content-type"])&&-1===k.toLowerCase().indexOf("application/json"))throw Error("Unsupported patch content type: application/json is required.");if(x=_.slice(E))try{T=tq(e,x),Object.keys(T).length>1||"data"in T||"incremental"in T||"errors"in T||"payload"in T?tz(T)?(M={},"payload"in T&&(M=(0,en.pi)({},T.payload)),"errors"in T&&(M=(0,en.pi)((0,en.pi)({},M),{extensions:(0,en.pi)((0,en.pi)({},"extensions"in M?M.extensions:null),((A={})[tN.YG]=T.errors,A))})),null===(r=t.next)||void 0===r||r.call(t,M)):null===(i=t.next)||void 0===i||i.call(t,T):1===Object.keys(T).length&&"hasNext"in T&&!T.hasNext&&(null===(a=t.complete)||void 0===a||a.call(t))}catch(C){tZ(C,t)}w=d.indexOf(f)}return[3,1];case 3:return null===(o=t.complete)||void 0===o||o.call(t),[2]}})})}function tV(e){var t={};return e.split("\n").forEach(function(e){var n=e.indexOf(":");if(n>-1){var r=e.slice(0,n).trim().toLowerCase(),i=e.slice(n+1).trim();t[r]=i}}),t}function tq(e,t){e.status>=300&&tD(e,function(){try{return JSON.parse(t)}catch(e){return t}}(),"Response not successful: Received status code ".concat(e.status));try{return JSON.parse(t)}catch(n){var r=n;throw r.name="ServerParseError",r.response=e,r.statusCode=e.status,r.bodyText=t,r}}function tZ(e,t){var n,r;"AbortError"!==e.name&&(e.result&&e.result.errors&&e.result.data&&(null===(n=t.next)||void 0===n||n.call(t,e.result)),null===(r=t.error)||void 0===r||r.call(t,e))}function tX(e,t,n){tJ(t)(e).then(function(e){var t,r;null===(t=n.next)||void 0===t||t.call(n,e),null===(r=n.complete)||void 0===r||r.call(n)}).catch(function(e){return tZ(e,n)})}function tJ(e){return function(t){return t.text().then(function(e){return tq(t,e)}).then(function(n){return t.status>=300&&tD(t,n,"Response not successful: Received status code ".concat(t.status)),Array.isArray(n)||tW.call(n,"data")||tW.call(n,"errors")||tD(t,n,"Server response was missing for query '".concat(Array.isArray(e)?e.map(function(e){return e.operationName}):e.operationName,"'.")),n})}}var tQ=function(e){if(!e&&"undefined"==typeof fetch)throw __DEV__?new Q.ej("\n\"fetch\" has not been found globally and no fetcher has been configured. To fix this, install a fetch package (like https://www.npmjs.com/package/cross-fetch), instantiate the fetcher, and pass it into your HttpLink constructor. For example:\n\nimport fetch from 'cross-fetch';\nimport { ApolloClient, HttpLink } from '@apollo/client';\nconst client = new ApolloClient({\n link: new HttpLink({ uri: '/graphql', fetch })\n});\n "):new Q.ej(23)},t1=__webpack_require__(87392);function t0(e){return tl(e,{leave:t3})}var t2=80,t3={Name:function(e){return e.value},Variable:function(e){return"$"+e.name},Document:function(e){return t5(e.definitions,"\n\n")+"\n"},OperationDefinition:function(e){var t=e.operation,n=e.name,r=t9("(",t5(e.variableDefinitions,", "),")"),i=t5(e.directives," "),a=e.selectionSet;return n||i||r||"query"!==t?t5([t,t5([n,r]),i,a]," "):a},VariableDefinition:function(e){var t=e.variable,n=e.type,r=e.defaultValue,i=e.directives;return t+": "+n+t9(" = ",r)+t9(" ",t5(i," "))},SelectionSet:function(e){return t6(e.selections)},Field:function(e){var t=e.alias,n=e.name,r=e.arguments,i=e.directives,a=e.selectionSet,o=t9("",t,": ")+n,s=o+t9("(",t5(r,", "),")");return s.length>t2&&(s=o+t9("(\n",t8(t5(r,"\n")),"\n)")),t5([s,t5(i," "),a]," ")},Argument:function(e){var t;return e.name+": "+e.value},FragmentSpread:function(e){var t;return"..."+e.name+t9(" ",t5(e.directives," "))},InlineFragment:function(e){var t=e.typeCondition,n=e.directives,r=e.selectionSet;return t5(["...",t9("on ",t),t5(n," "),r]," ")},FragmentDefinition:function(e){var t=e.name,n=e.typeCondition,r=e.variableDefinitions,i=e.directives,a=e.selectionSet;return"fragment ".concat(t).concat(t9("(",t5(r,", "),")")," ")+"on ".concat(n," ").concat(t9("",t5(i," ")," "))+a},IntValue:function(e){return e.value},FloatValue:function(e){return e.value},StringValue:function(e,t){var n=e.value;return e.block?(0,t1.LZ)(n,"description"===t?"":" "):JSON.stringify(n)},BooleanValue:function(e){return e.value?"true":"false"},NullValue:function(){return"null"},EnumValue:function(e){return e.value},ListValue:function(e){return"["+t5(e.values,", ")+"]"},ObjectValue:function(e){return"{"+t5(e.fields,", ")+"}"},ObjectField:function(e){var t;return e.name+": "+e.value},Directive:function(e){var t;return"@"+e.name+t9("(",t5(e.arguments,", "),")")},NamedType:function(e){return e.name},ListType:function(e){return"["+e.type+"]"},NonNullType:function(e){return e.type+"!"},SchemaDefinition:t4(function(e){var t=e.directives,n=e.operationTypes;return t5(["schema",t5(t," "),t6(n)]," ")}),OperationTypeDefinition:function(e){var t;return e.operation+": "+e.type},ScalarTypeDefinition:t4(function(e){var t;return t5(["scalar",e.name,t5(e.directives," ")]," ")}),ObjectTypeDefinition:t4(function(e){var t=e.name,n=e.interfaces,r=e.directives,i=e.fields;return t5(["type",t,t9("implements ",t5(n," & ")),t5(r," "),t6(i)]," ")}),FieldDefinition:t4(function(e){var t=e.name,n=e.arguments,r=e.type,i=e.directives;return t+(ne(n)?t9("(\n",t8(t5(n,"\n")),"\n)"):t9("(",t5(n,", "),")"))+": "+r+t9(" ",t5(i," "))}),InputValueDefinition:t4(function(e){var t=e.name,n=e.type,r=e.defaultValue,i=e.directives;return t5([t+": "+n,t9("= ",r),t5(i," ")]," ")}),InterfaceTypeDefinition:t4(function(e){var t=e.name,n=e.interfaces,r=e.directives,i=e.fields;return t5(["interface",t,t9("implements ",t5(n," & ")),t5(r," "),t6(i)]," ")}),UnionTypeDefinition:t4(function(e){var t=e.name,n=e.directives,r=e.types;return t5(["union",t,t5(n," "),r&&0!==r.length?"= "+t5(r," | "):""]," ")}),EnumTypeDefinition:t4(function(e){var t=e.name,n=e.directives,r=e.values;return t5(["enum",t,t5(n," "),t6(r)]," ")}),EnumValueDefinition:t4(function(e){var t;return t5([e.name,t5(e.directives," ")]," ")}),InputObjectTypeDefinition:t4(function(e){var t=e.name,n=e.directives,r=e.fields;return t5(["input",t,t5(n," "),t6(r)]," ")}),DirectiveDefinition:t4(function(e){var t=e.name,n=e.arguments,r=e.repeatable,i=e.locations;return"directive @"+t+(ne(n)?t9("(\n",t8(t5(n,"\n")),"\n)"):t9("(",t5(n,", "),")"))+(r?" repeatable":"")+" on "+t5(i," | ")}),SchemaExtension:function(e){var t=e.directives,n=e.operationTypes;return t5(["extend schema",t5(t," "),t6(n)]," ")},ScalarTypeExtension:function(e){var t;return t5(["extend scalar",e.name,t5(e.directives," ")]," ")},ObjectTypeExtension:function(e){var t=e.name,n=e.interfaces,r=e.directives,i=e.fields;return t5(["extend type",t,t9("implements ",t5(n," & ")),t5(r," "),t6(i)]," ")},InterfaceTypeExtension:function(e){var t=e.name,n=e.interfaces,r=e.directives,i=e.fields;return t5(["extend interface",t,t9("implements ",t5(n," & ")),t5(r," "),t6(i)]," ")},UnionTypeExtension:function(e){var t=e.name,n=e.directives,r=e.types;return t5(["extend union",t,t5(n," "),r&&0!==r.length?"= "+t5(r," | "):""]," ")},EnumTypeExtension:function(e){var t=e.name,n=e.directives,r=e.values;return t5(["extend enum",t,t5(n," "),t6(r)]," ")},InputObjectTypeExtension:function(e){var t=e.name,n=e.directives,r=e.fields;return t5(["extend input",t,t5(n," "),t6(r)]," ")}};function t4(e){return function(t){return t5([t.description,e(t)],"\n")}}function t5(e){var t,n=arguments.length>1&&void 0!==arguments[1]?arguments[1]:"";return null!==(t=null==e?void 0:e.filter(function(e){return e}).join(n))&&void 0!==t?t:""}function t6(e){return t9("{\n",t8(t5(e,"\n")),"\n}")}function t9(e,t){var n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:"";return null!=t&&""!==t?e+t+n:""}function t8(e){return t9(" ",e.replace(/\n/g,"\n "))}function t7(e){return -1!==e.indexOf("\n")}function ne(e){return null!=e&&e.some(t7)}var nt,nn,nr,ni={http:{includeQuery:!0,includeExtensions:!1,preserveHeaderCase:!1},headers:{accept:"*/*","content-type":"application/json"},options:{method:"POST"}},na=function(e,t){return t(e)};function no(e,t){for(var n=[],r=2;rObject.create(null),{forEach:nv,slice:ny}=Array.prototype,{hasOwnProperty:nw}=Object.prototype;class n_{constructor(e=!0,t=ng){this.weakness=e,this.makeData=t}lookup(...e){return this.lookupArray(e)}lookupArray(e){let t=this;return nv.call(e,e=>t=t.getChildTrie(e)),nw.call(t,"data")?t.data:t.data=this.makeData(ny.call(e))}peek(...e){return this.peekArray(e)}peekArray(e){let t=this;for(let n=0,r=e.length;t&&n=0;--o)t.definitions[o].kind===nL.h.OPERATION_DEFINITION&&++a;var s=nN(e),u=e.some(function(e){return e.remove}),c=function(e){return u&&e&&e.some(s)},l=new Map,f=!1,d={enter:function(e){if(c(e.directives))return f=!0,null}},h=tl(t,{Field:d,InlineFragment:d,VariableDefinition:{enter:function(){return!1}},Variable:{enter:function(e,t,n,r,a){var o=i(a);o&&o.variables.add(e.name.value)}},FragmentSpread:{enter:function(e,t,n,r,a){if(c(e.directives))return f=!0,null;var o=i(a);o&&o.fragmentSpreads.add(e.name.value)}},FragmentDefinition:{enter:function(e,t,n,r){l.set(JSON.stringify(r),e)},leave:function(e,t,n,i){return e===l.get(JSON.stringify(i))?e:a>0&&e.selectionSet.selections.every(function(e){return e.kind===nL.h.FIELD&&"__typename"===e.name.value})?(r(e.name.value).removed=!0,f=!0,null):void 0}},Directive:{leave:function(e){if(s(e))return f=!0,null}}});if(!f)return t;var p=function(e){return e.transitiveVars||(e.transitiveVars=new Set(e.variables),e.removed||e.fragmentSpreads.forEach(function(t){p(r(t)).transitiveVars.forEach(function(t){e.transitiveVars.add(t)})})),e},b=new Set;h.definitions.forEach(function(e){e.kind===nL.h.OPERATION_DEFINITION?p(n(e.name&&e.name.value)).fragmentSpreads.forEach(function(e){b.add(e)}):e.kind!==nL.h.FRAGMENT_DEFINITION||0!==a||r(e.name.value).removed||b.add(e.name.value)}),b.forEach(function(e){p(r(e)).fragmentSpreads.forEach(function(e){b.add(e)})});var m=function(e){return!!(!b.has(e)||r(e).removed)},g={enter:function(e){if(m(e.name.value))return null}};return nD(tl(h,{FragmentSpread:g,FragmentDefinition:g,OperationDefinition:{leave:function(e){if(e.variableDefinitions){var t=p(n(e.name&&e.name.value)).transitiveVars;if(t.size0},t.prototype.tearDownQuery=function(){this.isTornDown||(this.concast&&this.observer&&(this.concast.removeObserver(this.observer),delete this.concast,delete this.observer),this.stopPolling(),this.subscriptions.forEach(function(e){return e.unsubscribe()}),this.subscriptions.clear(),this.queryManager.stopQuery(this.queryId),this.observers.clear(),this.isTornDown=!0)},t}(eT);function n4(e){var t=e.options,n=t.fetchPolicy,r=t.nextFetchPolicy;return"cache-and-network"===n||"network-only"===n?e.reobserve({fetchPolicy:"cache-first",nextFetchPolicy:function(){return(this.nextFetchPolicy=r,"function"==typeof r)?r.apply(this,arguments):n}}):e.reobserve()}function n5(e){__DEV__&&Q.kG.error("Unhandled error",e.message,e.stack)}function n6(e){__DEV__&&e&&__DEV__&&Q.kG.debug("Missing cache result fields: ".concat(JSON.stringify(e)),e)}function n9(e){return"network-only"===e||"no-cache"===e||"standby"===e}nK(n3);function n8(e){return e.kind===nL.h.FIELD||e.kind===nL.h.FRAGMENT_SPREAD||e.kind===nL.h.INLINE_FRAGMENT}function n7(e){return e.kind===Kind.SCALAR_TYPE_DEFINITION||e.kind===Kind.OBJECT_TYPE_DEFINITION||e.kind===Kind.INTERFACE_TYPE_DEFINITION||e.kind===Kind.UNION_TYPE_DEFINITION||e.kind===Kind.ENUM_TYPE_DEFINITION||e.kind===Kind.INPUT_OBJECT_TYPE_DEFINITION}function re(e){return e.kind===Kind.SCALAR_TYPE_EXTENSION||e.kind===Kind.OBJECT_TYPE_EXTENSION||e.kind===Kind.INTERFACE_TYPE_EXTENSION||e.kind===Kind.UNION_TYPE_EXTENSION||e.kind===Kind.ENUM_TYPE_EXTENSION||e.kind===Kind.INPUT_OBJECT_TYPE_EXTENSION}var rt=function(){return Object.create(null)},rn=Array.prototype,rr=rn.forEach,ri=rn.slice,ra=function(){function e(e,t){void 0===e&&(e=!0),void 0===t&&(t=rt),this.weakness=e,this.makeData=t}return e.prototype.lookup=function(){for(var e=[],t=0;tclass{constructor(){this.id=["slot",rc++,Date.now(),Math.random().toString(36).slice(2),].join(":")}hasValue(){for(let e=rs;e;e=e.parent)if(this.id in e.slots){let t=e.slots[this.id];if(t===ru)break;return e!==rs&&(rs.slots[this.id]=t),!0}return rs&&(rs.slots[this.id]=ru),!1}getValue(){if(this.hasValue())return rs.slots[this.id]}withValue(e,t,n,r){let i={__proto__:null,[this.id]:e},a=rs;rs={parent:a,slots:i};try{return t.apply(r,n)}finally{rs=a}}static bind(e){let t=rs;return function(){let n=rs;try{return rs=t,e.apply(this,arguments)}finally{rs=n}}}static noContext(e,t,n){if(!rs)return e.apply(n,t);{let r=rs;try{return rs=null,e.apply(n,t)}finally{rs=r}}}};function rf(e){try{return e()}catch(t){}}let rd="@wry/context:Slot",rh=rf(()=>globalThis)||rf(()=>global)||Object.create(null),rp=rh,rb=rp[rd]||Array[rd]||function(e){try{Object.defineProperty(rp,rd,{value:e,enumerable:!1,writable:!1,configurable:!0})}finally{return e}}(rl()),{bind:rm,noContext:rg}=rb;function rv(){}var ry=function(){function e(e,t){void 0===e&&(e=1/0),void 0===t&&(t=rv),this.max=e,this.dispose=t,this.map=new Map,this.newest=null,this.oldest=null}return e.prototype.has=function(e){return this.map.has(e)},e.prototype.get=function(e){var t=this.getNode(e);return t&&t.value},e.prototype.getNode=function(e){var t=this.map.get(e);if(t&&t!==this.newest){var n=t.older,r=t.newer;r&&(r.older=n),n&&(n.newer=r),t.older=this.newest,t.older.newer=t,t.newer=null,this.newest=t,t===this.oldest&&(this.oldest=r)}return t},e.prototype.set=function(e,t){var n=this.getNode(e);return n?n.value=t:(n={key:e,value:t,newer:null,older:this.newest},this.newest&&(this.newest.newer=n),this.newest=n,this.oldest=this.oldest||n,this.map.set(e,n),n.value)},e.prototype.clean=function(){for(;this.oldest&&this.map.size>this.max;)this.delete(this.oldest.key)},e.prototype.delete=function(e){var t=this.map.get(e);return!!t&&(t===this.newest&&(this.newest=t.older),t===this.oldest&&(this.oldest=t.newer),t.newer&&(t.newer.older=t.older),t.older&&(t.older.newer=t.newer),this.map.delete(e),this.dispose(t.value,e),!0)},e}(),rw=new rb,r_=Object.prototype.hasOwnProperty,rE=void 0===(n=Array.from)?function(e){var t=[];return e.forEach(function(e){return t.push(e)}),t}:n;function rS(e){var t=e.unsubscribe;"function"==typeof t&&(e.unsubscribe=void 0,t())}var rk=[],rx=100;function rT(e,t){if(!e)throw Error(t||"assertion failure")}function rM(e,t){var n=e.length;return n>0&&n===t.length&&e[n-1]===t[n-1]}function rO(e){switch(e.length){case 0:throw Error("unknown value");case 1:return e[0];case 2:throw e[1]}}function rA(e){return e.slice(0)}var rL=function(){function e(t){this.fn=t,this.parents=new Set,this.childValues=new Map,this.dirtyChildren=null,this.dirty=!0,this.recomputing=!1,this.value=[],this.deps=null,++e.count}return e.prototype.peek=function(){if(1===this.value.length&&!rN(this))return rC(this),this.value[0]},e.prototype.recompute=function(e){return rT(!this.recomputing,"already recomputing"),rC(this),rN(this)?rI(this,e):rO(this.value)},e.prototype.setDirty=function(){this.dirty||(this.dirty=!0,this.value.length=0,rR(this),rS(this))},e.prototype.dispose=function(){var e=this;this.setDirty(),rH(this),rF(this,function(t,n){t.setDirty(),r$(t,e)})},e.prototype.forget=function(){this.dispose()},e.prototype.dependOn=function(e){e.add(this),this.deps||(this.deps=rk.pop()||new Set),this.deps.add(e)},e.prototype.forgetDeps=function(){var e=this;this.deps&&(rE(this.deps).forEach(function(t){return t.delete(e)}),this.deps.clear(),rk.push(this.deps),this.deps=null)},e.count=0,e}();function rC(e){var t=rw.getValue();if(t)return e.parents.add(t),t.childValues.has(e)||t.childValues.set(e,[]),rN(e)?rY(t,e):rB(t,e),t}function rI(e,t){return rH(e),rw.withValue(e,rD,[e,t]),rz(e,t)&&rP(e),rO(e.value)}function rD(e,t){e.recomputing=!0,e.value.length=0;try{e.value[0]=e.fn.apply(null,t)}catch(n){e.value[1]=n}e.recomputing=!1}function rN(e){return e.dirty||!!(e.dirtyChildren&&e.dirtyChildren.size)}function rP(e){e.dirty=!1,!rN(e)&&rj(e)}function rR(e){rF(e,rY)}function rj(e){rF(e,rB)}function rF(e,t){var n=e.parents.size;if(n)for(var r=rE(e.parents),i=0;i0&&e.childValues.forEach(function(t,n){r$(e,n)}),e.forgetDeps(),rT(null===e.dirtyChildren)}function r$(e,t){t.parents.delete(e),e.childValues.delete(t),rU(e,t)}function rz(e,t){if("function"==typeof e.subscribe)try{rS(e),e.unsubscribe=e.subscribe.apply(null,t)}catch(n){return e.setDirty(),!1}return!0}var rG={setDirty:!0,dispose:!0,forget:!0};function rW(e){var t=new Map,n=e&&e.subscribe;function r(e){var r=rw.getValue();if(r){var i=t.get(e);i||t.set(e,i=new Set),r.dependOn(i),"function"==typeof n&&(rS(i),i.unsubscribe=n(e))}}return r.dirty=function(e,n){var r=t.get(e);if(r){var i=n&&r_.call(rG,n)?n:"setDirty";rE(r).forEach(function(e){return e[i]()}),t.delete(e),rS(r)}},r}function rK(){var e=new ra("function"==typeof WeakMap);return function(){return e.lookupArray(arguments)}}var rV=rK(),rq=new Set;function rZ(e,t){void 0===t&&(t=Object.create(null));var n=new ry(t.max||65536,function(e){return e.dispose()}),r=t.keyArgs,i=t.makeCacheKey||rK(),a=function(){var a=i.apply(null,r?r.apply(null,arguments):arguments);if(void 0===a)return e.apply(null,arguments);var o=n.get(a);o||(n.set(a,o=new rL(e)),o.subscribe=t.subscribe,o.forget=function(){return n.delete(a)});var s=o.recompute(Array.prototype.slice.call(arguments));return n.set(a,o),rq.add(n),rw.hasValue()||(rq.forEach(function(e){return e.clean()}),rq.clear()),s};function o(e){var t=n.get(e);t&&t.setDirty()}function s(e){var t=n.get(e);if(t)return t.peek()}function u(e){return n.delete(e)}return Object.defineProperty(a,"size",{get:function(){return n.map.size},configurable:!1,enumerable:!1}),a.dirtyKey=o,a.dirty=function(){o(i.apply(null,arguments))},a.peekKey=s,a.peek=function(){return s(i.apply(null,arguments))},a.forgetKey=u,a.forget=function(){return u(i.apply(null,arguments))},a.makeCacheKey=i,a.getKey=r?function(){return i.apply(null,r.apply(null,arguments))}:i,Object.freeze(a)}var rX=new rb,rJ=new WeakMap;function rQ(e){var t=rJ.get(e);return t||rJ.set(e,t={vars:new Set,dep:rW()}),t}function r1(e){rQ(e).vars.forEach(function(t){return t.forgetCache(e)})}function r0(e){rQ(e).vars.forEach(function(t){return t.attachCache(e)})}function r2(e){var t=new Set,n=new Set,r=function(a){if(arguments.length>0){if(e!==a){e=a,t.forEach(function(e){rQ(e).dep.dirty(r),r3(e)});var o=Array.from(n);n.clear(),o.forEach(function(t){return t(e)})}}else{var s=rX.getValue();s&&(i(s),rQ(s).dep(r))}return e};r.onNextChange=function(e){return n.add(e),function(){n.delete(e)}};var i=r.attachCache=function(e){return t.add(e),rQ(e).vars.add(r),r};return r.forgetCache=function(e){return t.delete(e)},r}function r3(e){e.broadcastWatches&&e.broadcastWatches()}var r4=function(){function e(e){var t=e.cache,n=e.client,r=e.resolvers,i=e.fragmentMatcher;this.selectionsToResolveCache=new WeakMap,this.cache=t,n&&(this.client=n),r&&this.addResolvers(r),i&&this.setFragmentMatcher(i)}return e.prototype.addResolvers=function(e){var t=this;this.resolvers=this.resolvers||{},Array.isArray(e)?e.forEach(function(e){t.resolvers=tj(t.resolvers,e)}):this.resolvers=tj(this.resolvers,e)},e.prototype.setResolvers=function(e){this.resolvers={},this.addResolvers(e)},e.prototype.getResolvers=function(){return this.resolvers||{}},e.prototype.runResolvers=function(e){var t=e.document,n=e.remoteResult,r=e.context,i=e.variables,a=e.onlyRunForcedResolvers,o=void 0!==a&&a;return(0,en.mG)(this,void 0,void 0,function(){return(0,en.Jh)(this,function(e){return t?[2,this.resolveDocument(t,n.data,r,i,this.fragmentMatcher,o).then(function(e){return(0,en.pi)((0,en.pi)({},n),{data:e.result})})]:[2,n]})})},e.prototype.setFragmentMatcher=function(e){this.fragmentMatcher=e},e.prototype.getFragmentMatcher=function(){return this.fragmentMatcher},e.prototype.clientQuery=function(e){return tb(["client"],e)&&this.resolvers?e:null},e.prototype.serverQuery=function(e){return n$(e)},e.prototype.prepareContext=function(e){var t=this.cache;return(0,en.pi)((0,en.pi)({},e),{cache:t,getCacheKey:function(e){return t.identify(e)}})},e.prototype.addExportedVariables=function(e,t,n){return void 0===t&&(t={}),void 0===n&&(n={}),(0,en.mG)(this,void 0,void 0,function(){return(0,en.Jh)(this,function(r){return e?[2,this.resolveDocument(e,this.buildRootValueFromCache(e,t)||{},this.prepareContext(n),t).then(function(e){return(0,en.pi)((0,en.pi)({},t),e.exportedVariables)})]:[2,(0,en.pi)({},t)]})})},e.prototype.shouldForceResolvers=function(e){var t=!1;return tl(e,{Directive:{enter:function(e){if("client"===e.name.value&&e.arguments&&(t=e.arguments.some(function(e){return"always"===e.name.value&&"BooleanValue"===e.value.kind&&!0===e.value.value})))return tc}}}),t},e.prototype.buildRootValueFromCache=function(e,t){return this.cache.diff({query:nH(e),variables:t,returnPartialData:!0,optimistic:!1}).result},e.prototype.resolveDocument=function(e,t,n,r,i,a){return void 0===n&&(n={}),void 0===r&&(r={}),void 0===i&&(i=function(){return!0}),void 0===a&&(a=!1),(0,en.mG)(this,void 0,void 0,function(){var o,s,u,c,l,f,d,h,p,b,m;return(0,en.Jh)(this,function(g){return o=e9(e),s=e4(e),u=eL(s),c=this.collectSelectionsToResolve(o,u),f=(l=o.operation)?l.charAt(0).toUpperCase()+l.slice(1):"Query",d=this,h=d.cache,p=d.client,b={fragmentMap:u,context:(0,en.pi)((0,en.pi)({},n),{cache:h,client:p}),variables:r,fragmentMatcher:i,defaultOperationType:f,exportedVariables:{},selectionsToResolve:c,onlyRunForcedResolvers:a},m=!1,[2,this.resolveSelectionSet(o.selectionSet,m,t,b).then(function(e){return{result:e,exportedVariables:b.exportedVariables}})]})})},e.prototype.resolveSelectionSet=function(e,t,n,r){return(0,en.mG)(this,void 0,void 0,function(){var i,a,o,s,u,c=this;return(0,en.Jh)(this,function(l){return i=r.fragmentMap,a=r.context,o=r.variables,s=[n],u=function(e){return(0,en.mG)(c,void 0,void 0,function(){var u,c;return(0,en.Jh)(this,function(l){return(t||r.selectionsToResolve.has(e))&&td(e,o)?eQ(e)?[2,this.resolveField(e,t,n,r).then(function(t){var n;void 0!==t&&s.push(((n={})[eX(e)]=t,n))})]:(e1(e)?u=e:(u=i[e.name.value],__DEV__?(0,Q.kG)(u,"No fragment named ".concat(e.name.value)):(0,Q.kG)(u,11)),u&&u.typeCondition&&(c=u.typeCondition.name.value,r.fragmentMatcher(n,c,a)))?[2,this.resolveSelectionSet(u.selectionSet,t,n,r).then(function(e){s.push(e)})]:[2]:[2]})})},[2,Promise.all(e.selections.map(u)).then(function(){return tF(s)})]})})},e.prototype.resolveField=function(e,t,n,r){return(0,en.mG)(this,void 0,void 0,function(){var i,a,o,s,u,c,l,f,d,h=this;return(0,en.Jh)(this,function(p){return n?(i=r.variables,a=e.name.value,o=eX(e),s=a!==o,c=Promise.resolve(u=n[o]||n[a]),(!r.onlyRunForcedResolvers||this.shouldForceResolvers(e))&&(l=n.__typename||r.defaultOperationType,(f=this.resolvers&&this.resolvers[l])&&(d=f[s?a:o])&&(c=Promise.resolve(rX.withValue(this.cache,d,[n,eZ(e,i),r.context,{field:e,fragmentMap:r.fragmentMap},])))),[2,c.then(function(n){if(void 0===n&&(n=u),e.directives&&e.directives.forEach(function(e){"export"===e.name.value&&e.arguments&&e.arguments.forEach(function(e){"as"===e.name.value&&"StringValue"===e.value.kind&&(r.exportedVariables[e.value.value]=n)})}),!e.selectionSet||null==n)return n;var i,a,o=null!==(a=null===(i=e.directives)||void 0===i?void 0:i.some(function(e){return"client"===e.name.value}))&&void 0!==a&&a;return Array.isArray(n)?h.resolveSubSelectedArray(e,t||o,n,r):e.selectionSet?h.resolveSelectionSet(e.selectionSet,t||o,n,r):void 0})]):[2,null]})})},e.prototype.resolveSubSelectedArray=function(e,t,n,r){var i=this;return Promise.all(n.map(function(n){return null===n?null:Array.isArray(n)?i.resolveSubSelectedArray(e,t,n,r):e.selectionSet?i.resolveSelectionSet(e.selectionSet,t,n,r):void 0}))},e.prototype.collectSelectionsToResolve=function(e,t){var n=function(e){return!Array.isArray(e)},r=this.selectionsToResolveCache;function i(e){if(!r.has(e)){var a=new Set;r.set(e,a),tl(e,{Directive:function(e,t,r,i,o){"client"===e.name.value&&o.forEach(function(e){n(e)&&n8(e)&&a.add(e)})},FragmentSpread:function(e,r,o,s,u){var c=t[e.name.value];__DEV__?(0,Q.kG)(c,"No fragment named ".concat(e.name.value)):(0,Q.kG)(c,12);var l=i(c);l.size>0&&(u.forEach(function(e){n(e)&&n8(e)&&a.add(e)}),a.add(e),l.forEach(function(e){a.add(e)}))}})}return r.get(e)}return i(e)},e}(),r5=new(t_.mr?WeakMap:Map);function r6(e,t){var n=e[t];"function"==typeof n&&(e[t]=function(){return r5.set(e,(r5.get(e)+1)%1e15),n.apply(this,arguments)})}function r9(e){e.notifyTimeout&&(clearTimeout(e.notifyTimeout),e.notifyTimeout=void 0)}var r8=function(){function e(e,t){void 0===t&&(t=e.generateQueryId()),this.queryId=t,this.listeners=new Set,this.document=null,this.lastRequestId=1,this.subscriptions=new Set,this.stopped=!1,this.dirty=!1,this.observableQuery=null;var n=this.cache=e.cache;r5.has(n)||(r5.set(n,0),r6(n,"evict"),r6(n,"modify"),r6(n,"reset"))}return e.prototype.init=function(e){var t=e.networkStatus||nZ.I.loading;return this.variables&&this.networkStatus!==nZ.I.loading&&!(0,nm.D)(this.variables,e.variables)&&(t=nZ.I.setVariables),(0,nm.D)(e.variables,this.variables)||(this.lastDiff=void 0),Object.assign(this,{document:e.document,variables:e.variables,networkError:null,graphQLErrors:this.graphQLErrors||[],networkStatus:t}),e.observableQuery&&this.setObservableQuery(e.observableQuery),e.lastRequestId&&(this.lastRequestId=e.lastRequestId),this},e.prototype.reset=function(){r9(this),this.dirty=!1},e.prototype.getDiff=function(e){void 0===e&&(e=this.variables);var t=this.getDiffOptions(e);if(this.lastDiff&&(0,nm.D)(t,this.lastDiff.options))return this.lastDiff.diff;this.updateWatch(this.variables=e);var n=this.observableQuery;if(n&&"no-cache"===n.options.fetchPolicy)return{complete:!1};var r=this.cache.diff(t);return this.updateLastDiff(r,t),r},e.prototype.updateLastDiff=function(e,t){this.lastDiff=e?{diff:e,options:t||this.getDiffOptions()}:void 0},e.prototype.getDiffOptions=function(e){var t;return void 0===e&&(e=this.variables),{query:this.document,variables:e,returnPartialData:!0,optimistic:!0,canonizeResults:null===(t=this.observableQuery)||void 0===t?void 0:t.options.canonizeResults}},e.prototype.setDiff=function(e){var t=this,n=this.lastDiff&&this.lastDiff.diff;this.updateLastDiff(e),this.dirty||(0,nm.D)(n&&n.result,e&&e.result)||(this.dirty=!0,this.notifyTimeout||(this.notifyTimeout=setTimeout(function(){return t.notify()},0)))},e.prototype.setObservableQuery=function(e){var t=this;e!==this.observableQuery&&(this.oqListener&&this.listeners.delete(this.oqListener),this.observableQuery=e,e?(e.queryInfo=this,this.listeners.add(this.oqListener=function(){t.getDiff().fromOptimisticTransaction?e.observe():n4(e)})):delete this.oqListener)},e.prototype.notify=function(){var e=this;r9(this),this.shouldNotify()&&this.listeners.forEach(function(t){return t(e)}),this.dirty=!1},e.prototype.shouldNotify=function(){if(!this.dirty||!this.listeners.size)return!1;if((0,nZ.O)(this.networkStatus)&&this.observableQuery){var e=this.observableQuery.options.fetchPolicy;if("cache-only"!==e&&"cache-and-network"!==e)return!1}return!0},e.prototype.stop=function(){if(!this.stopped){this.stopped=!0,this.reset(),this.cancel(),this.cancel=e.prototype.cancel,this.subscriptions.forEach(function(e){return e.unsubscribe()});var t=this.observableQuery;t&&t.stopPolling()}},e.prototype.cancel=function(){},e.prototype.updateWatch=function(e){var t=this;void 0===e&&(e=this.variables);var n=this.observableQuery;if(!n||"no-cache"!==n.options.fetchPolicy){var r=(0,en.pi)((0,en.pi)({},this.getDiffOptions(e)),{watcher:this,callback:function(e){return t.setDiff(e)}});this.lastWatch&&(0,nm.D)(r,this.lastWatch)||(this.cancel(),this.cancel=this.cache.watch(this.lastWatch=r))}},e.prototype.resetLastWrite=function(){this.lastWrite=void 0},e.prototype.shouldWrite=function(e,t){var n=this.lastWrite;return!(n&&n.dmCount===r5.get(this.cache)&&(0,nm.D)(t,n.variables)&&(0,nm.D)(e.data,n.result.data))},e.prototype.markResult=function(e,t,n,r){var i=this,a=new tB,o=(0,tP.O)(e.errors)?e.errors.slice(0):[];if(this.reset(),"incremental"in e&&(0,tP.O)(e.incremental)){var s=tG(this.getDiff().result,e);e.data=s}else if("hasNext"in e&&e.hasNext){var u=this.getDiff();e.data=a.merge(u.result,e.data)}this.graphQLErrors=o,"no-cache"===n.fetchPolicy?this.updateLastDiff({result:e.data,complete:!0},this.getDiffOptions(n.variables)):0!==r&&(r7(e,n.errorPolicy)?this.cache.performTransaction(function(a){if(i.shouldWrite(e,n.variables))a.writeQuery({query:t,data:e.data,variables:n.variables,overwrite:1===r}),i.lastWrite={result:e,variables:n.variables,dmCount:r5.get(i.cache)};else if(i.lastDiff&&i.lastDiff.diff.complete){e.data=i.lastDiff.diff.result;return}var o=i.getDiffOptions(n.variables),s=a.diff(o);i.stopped||i.updateWatch(n.variables),i.updateLastDiff(s,o),s.complete&&(e.data=s.result)}):this.lastWrite=void 0)},e.prototype.markReady=function(){return this.networkError=null,this.networkStatus=nZ.I.ready},e.prototype.markError=function(e){return this.networkStatus=nZ.I.error,this.lastWrite=void 0,this.reset(),e.graphQLErrors&&(this.graphQLErrors=e.graphQLErrors),e.networkError&&(this.networkError=e.networkError),e},e}();function r7(e,t){void 0===t&&(t="none");var n="ignore"===t||"all"===t,r=!nO(e);return!r&&n&&e.data&&(r=!0),r}var ie=Object.prototype.hasOwnProperty,it=function(){function e(e){var t=e.cache,n=e.link,r=e.defaultOptions,i=e.queryDeduplication,a=void 0!==i&&i,o=e.onBroadcast,s=e.ssrMode,u=void 0!==s&&s,c=e.clientAwareness,l=void 0===c?{}:c,f=e.localState,d=e.assumeImmutableResults;this.clientAwareness={},this.queries=new Map,this.fetchCancelFns=new Map,this.transformCache=new(t_.mr?WeakMap:Map),this.queryIdCounter=1,this.requestIdCounter=1,this.mutationIdCounter=1,this.inFlightLinkObservables=new Map,this.cache=t,this.link=n,this.defaultOptions=r||Object.create(null),this.queryDeduplication=a,this.clientAwareness=l,this.localState=f||new r4({cache:t}),this.ssrMode=u,this.assumeImmutableResults=!!d,(this.onBroadcast=o)&&(this.mutationStore=Object.create(null))}return e.prototype.stop=function(){var e=this;this.queries.forEach(function(t,n){e.stopQueryNoBroadcast(n)}),this.cancelPendingFetches(__DEV__?new Q.ej("QueryManager stopped while query was in flight"):new Q.ej(14))},e.prototype.cancelPendingFetches=function(e){this.fetchCancelFns.forEach(function(t){return t(e)}),this.fetchCancelFns.clear()},e.prototype.mutate=function(e){var t,n,r=e.mutation,i=e.variables,a=e.optimisticResponse,o=e.updateQueries,s=e.refetchQueries,u=void 0===s?[]:s,c=e.awaitRefetchQueries,l=void 0!==c&&c,f=e.update,d=e.onQueryUpdated,h=e.fetchPolicy,p=void 0===h?(null===(t=this.defaultOptions.mutate)||void 0===t?void 0:t.fetchPolicy)||"network-only":h,b=e.errorPolicy,m=void 0===b?(null===(n=this.defaultOptions.mutate)||void 0===n?void 0:n.errorPolicy)||"none":b,g=e.keepRootFields,v=e.context;return(0,en.mG)(this,void 0,void 0,function(){var e,t,n,s,c,h;return(0,en.Jh)(this,function(b){switch(b.label){case 0:if(__DEV__?(0,Q.kG)(r,"mutation option is required. You must specify your GraphQL document in the mutation option."):(0,Q.kG)(r,15),__DEV__?(0,Q.kG)("network-only"===p||"no-cache"===p,"Mutations support only 'network-only' or 'no-cache' fetchPolicy strings. The default `network-only` behavior automatically writes mutation results to the cache. Passing `no-cache` skips the cache write."):(0,Q.kG)("network-only"===p||"no-cache"===p,16),e=this.generateMutationId(),n=(t=this.transform(r)).document,s=t.hasClientExports,r=this.cache.transformForLink(n),i=this.getVariables(r,i),!s)return[3,2];return[4,this.localState.addExportedVariables(r,i,v)];case 1:i=b.sent(),b.label=2;case 2:return c=this.mutationStore&&(this.mutationStore[e]={mutation:r,variables:i,loading:!0,error:null}),a&&this.markMutationOptimistic(a,{mutationId:e,document:r,variables:i,fetchPolicy:p,errorPolicy:m,context:v,updateQueries:o,update:f,keepRootFields:g}),this.broadcastQueries(),h=this,[2,new Promise(function(t,n){return nM(h.getObservableFromLink(r,(0,en.pi)((0,en.pi)({},v),{optimisticResponse:a}),i,!1),function(t){if(nO(t)&&"none"===m)throw new tN.cA({graphQLErrors:nA(t)});c&&(c.loading=!1,c.error=null);var n=(0,en.pi)({},t);return"function"==typeof u&&(u=u(n)),"ignore"===m&&nO(n)&&delete n.errors,h.markMutationResult({mutationId:e,result:n,document:r,variables:i,fetchPolicy:p,errorPolicy:m,context:v,update:f,updateQueries:o,awaitRefetchQueries:l,refetchQueries:u,removeOptimistic:a?e:void 0,onQueryUpdated:d,keepRootFields:g})}).subscribe({next:function(e){h.broadcastQueries(),"hasNext"in e&&!1!==e.hasNext||t(e)},error:function(t){c&&(c.loading=!1,c.error=t),a&&h.cache.removeOptimistic(e),h.broadcastQueries(),n(t instanceof tN.cA?t:new tN.cA({networkError:t}))}})})]}})})},e.prototype.markMutationResult=function(e,t){var n=this;void 0===t&&(t=this.cache);var r=e.result,i=[],a="no-cache"===e.fetchPolicy;if(!a&&r7(r,e.errorPolicy)){if(tU(r)||i.push({result:r.data,dataId:"ROOT_MUTATION",query:e.document,variables:e.variables}),tU(r)&&(0,tP.O)(r.incremental)){var o=t.diff({id:"ROOT_MUTATION",query:this.transform(e.document).asQuery,variables:e.variables,optimistic:!1,returnPartialData:!0}),s=void 0;o.result&&(s=tG(o.result,r)),void 0!==s&&(r.data=s,i.push({result:s,dataId:"ROOT_MUTATION",query:e.document,variables:e.variables}))}var u=e.updateQueries;u&&this.queries.forEach(function(e,a){var o=e.observableQuery,s=o&&o.queryName;if(s&&ie.call(u,s)){var c,l=u[s],f=n.queries.get(a),d=f.document,h=f.variables,p=t.diff({query:d,variables:h,returnPartialData:!0,optimistic:!1}),b=p.result;if(p.complete&&b){var m=l(b,{mutationResult:r,queryName:d&&e3(d)||void 0,queryVariables:h});m&&i.push({result:m,dataId:"ROOT_QUERY",query:d,variables:h})}}})}if(i.length>0||e.refetchQueries||e.update||e.onQueryUpdated||e.removeOptimistic){var c=[];if(this.refetchQueries({updateCache:function(t){a||i.forEach(function(e){return t.write(e)});var o=e.update,s=!t$(r)||tU(r)&&!r.hasNext;if(o){if(!a){var u=t.diff({id:"ROOT_MUTATION",query:n.transform(e.document).asQuery,variables:e.variables,optimistic:!1,returnPartialData:!0});u.complete&&("incremental"in(r=(0,en.pi)((0,en.pi)({},r),{data:u.result}))&&delete r.incremental,"hasNext"in r&&delete r.hasNext)}s&&o(t,r,{context:e.context,variables:e.variables})}a||e.keepRootFields||!s||t.modify({id:"ROOT_MUTATION",fields:function(e,t){var n=t.fieldName,r=t.DELETE;return"__typename"===n?e:r}})},include:e.refetchQueries,optimistic:!1,removeOptimistic:e.removeOptimistic,onQueryUpdated:e.onQueryUpdated||null}).forEach(function(e){return c.push(e)}),e.awaitRefetchQueries||e.onQueryUpdated)return Promise.all(c).then(function(){return r})}return Promise.resolve(r)},e.prototype.markMutationOptimistic=function(e,t){var n=this,r="function"==typeof e?e(t.variables):e;return this.cache.recordOptimisticTransaction(function(e){try{n.markMutationResult((0,en.pi)((0,en.pi)({},t),{result:{data:r}}),e)}catch(i){__DEV__&&Q.kG.error(i)}},t.mutationId)},e.prototype.fetchQuery=function(e,t,n){return this.fetchQueryObservable(e,t,n).promise},e.prototype.getQueryStore=function(){var e=Object.create(null);return this.queries.forEach(function(t,n){e[n]={variables:t.variables,networkStatus:t.networkStatus,networkError:t.networkError,graphQLErrors:t.graphQLErrors}}),e},e.prototype.resetErrors=function(e){var t=this.queries.get(e);t&&(t.networkError=void 0,t.graphQLErrors=[])},e.prototype.transform=function(e){var t=this.transformCache;if(!t.has(e)){var n=this.cache.transformDocument(e),r=nY(n),i=this.localState.clientQuery(n),a=r&&this.localState.serverQuery(r),o={document:n,hasClientExports:tm(n),hasForcedResolvers:this.localState.shouldForceResolvers(n),clientQuery:i,serverQuery:a,defaultVars:e8(e2(n)),asQuery:(0,en.pi)((0,en.pi)({},n),{definitions:n.definitions.map(function(e){return"OperationDefinition"===e.kind&&"query"!==e.operation?(0,en.pi)((0,en.pi)({},e),{operation:"query"}):e})})},s=function(e){e&&!t.has(e)&&t.set(e,o)};s(e),s(n),s(i),s(a)}return t.get(e)},e.prototype.getVariables=function(e,t){return(0,en.pi)((0,en.pi)({},this.transform(e).defaultVars),t)},e.prototype.watchQuery=function(e){void 0===(e=(0,en.pi)((0,en.pi)({},e),{variables:this.getVariables(e.query,e.variables)})).notifyOnNetworkStatusChange&&(e.notifyOnNetworkStatusChange=!1);var t=new r8(this),n=new n3({queryManager:this,queryInfo:t,options:e});return this.queries.set(n.queryId,t),t.init({document:n.query,observableQuery:n,variables:n.variables}),n},e.prototype.query=function(e,t){var n=this;return void 0===t&&(t=this.generateQueryId()),__DEV__?(0,Q.kG)(e.query,"query option is required. You must specify your GraphQL document in the query option."):(0,Q.kG)(e.query,17),__DEV__?(0,Q.kG)("Document"===e.query.kind,'You must wrap the query string in a "gql" tag.'):(0,Q.kG)("Document"===e.query.kind,18),__DEV__?(0,Q.kG)(!e.returnPartialData,"returnPartialData option only supported on watchQuery."):(0,Q.kG)(!e.returnPartialData,19),__DEV__?(0,Q.kG)(!e.pollInterval,"pollInterval option only supported on watchQuery."):(0,Q.kG)(!e.pollInterval,20),this.fetchQuery(t,e).finally(function(){return n.stopQuery(t)})},e.prototype.generateQueryId=function(){return String(this.queryIdCounter++)},e.prototype.generateRequestId=function(){return this.requestIdCounter++},e.prototype.generateMutationId=function(){return String(this.mutationIdCounter++)},e.prototype.stopQueryInStore=function(e){this.stopQueryInStoreNoBroadcast(e),this.broadcastQueries()},e.prototype.stopQueryInStoreNoBroadcast=function(e){var t=this.queries.get(e);t&&t.stop()},e.prototype.clearStore=function(e){return void 0===e&&(e={discardWatches:!0}),this.cancelPendingFetches(__DEV__?new Q.ej("Store reset while query was in flight (not completed in link chain)"):new Q.ej(21)),this.queries.forEach(function(e){e.observableQuery?e.networkStatus=nZ.I.loading:e.stop()}),this.mutationStore&&(this.mutationStore=Object.create(null)),this.cache.reset(e)},e.prototype.getObservableQueries=function(e){var t=this;void 0===e&&(e="active");var n=new Map,r=new Map,i=new Set;return Array.isArray(e)&&e.forEach(function(e){"string"==typeof e?r.set(e,!1):eN(e)?r.set(t.transform(e).document,!1):(0,eO.s)(e)&&e.query&&i.add(e)}),this.queries.forEach(function(t,i){var a=t.observableQuery,o=t.document;if(a){if("all"===e){n.set(i,a);return}var s=a.queryName;if("standby"===a.options.fetchPolicy||"active"===e&&!a.hasObservers())return;("active"===e||s&&r.has(s)||o&&r.has(o))&&(n.set(i,a),s&&r.set(s,!0),o&&r.set(o,!0))}}),i.size&&i.forEach(function(e){var r=nG("legacyOneTimeQuery"),i=t.getQuery(r).init({document:e.query,variables:e.variables}),a=new n3({queryManager:t,queryInfo:i,options:(0,en.pi)((0,en.pi)({},e),{fetchPolicy:"network-only"})});(0,Q.kG)(a.queryId===r),i.setObservableQuery(a),n.set(r,a)}),__DEV__&&r.size&&r.forEach(function(e,t){!e&&__DEV__&&Q.kG.warn("Unknown query ".concat("string"==typeof t?"named ":"").concat(JSON.stringify(t,null,2)," requested in refetchQueries options.include array"))}),n},e.prototype.reFetchObservableQueries=function(e){var t=this;void 0===e&&(e=!1);var n=[];return this.getObservableQueries(e?"all":"active").forEach(function(r,i){var a=r.options.fetchPolicy;r.resetLastResults(),(e||"standby"!==a&&"cache-only"!==a)&&n.push(r.refetch()),t.getQuery(i).setDiff(null)}),this.broadcastQueries(),Promise.all(n)},e.prototype.setObservableQuery=function(e){this.getQuery(e.queryId).setObservableQuery(e)},e.prototype.startGraphQLSubscription=function(e){var t=this,n=e.query,r=e.fetchPolicy,i=e.errorPolicy,a=e.variables,o=e.context,s=void 0===o?{}:o;n=this.transform(n).document,a=this.getVariables(n,a);var u=function(e){return t.getObservableFromLink(n,s,e).map(function(a){"no-cache"!==r&&(r7(a,i)&&t.cache.write({query:n,result:a.data,dataId:"ROOT_SUBSCRIPTION",variables:e}),t.broadcastQueries());var o=nO(a),s=(0,tN.ls)(a);if(o||s){var u={};throw o&&(u.graphQLErrors=a.errors),s&&(u.protocolErrors=a.extensions[tN.YG]),new tN.cA(u)}return a})};if(this.transform(n).hasClientExports){var c=this.localState.addExportedVariables(n,a,s).then(u);return new eT(function(e){var t=null;return c.then(function(n){return t=n.subscribe(e)},e.error),function(){return t&&t.unsubscribe()}})}return u(a)},e.prototype.stopQuery=function(e){this.stopQueryNoBroadcast(e),this.broadcastQueries()},e.prototype.stopQueryNoBroadcast=function(e){this.stopQueryInStoreNoBroadcast(e),this.removeQuery(e)},e.prototype.removeQuery=function(e){this.fetchCancelFns.delete(e),this.queries.has(e)&&(this.getQuery(e).stop(),this.queries.delete(e))},e.prototype.broadcastQueries=function(){this.onBroadcast&&this.onBroadcast(),this.queries.forEach(function(e){return e.notify()})},e.prototype.getLocalState=function(){return this.localState},e.prototype.getObservableFromLink=function(e,t,n,r){var i,a,o=this;void 0===r&&(r=null!==(i=null==t?void 0:t.queryDeduplication)&&void 0!==i?i:this.queryDeduplication);var s=this.transform(e).serverQuery;if(s){var u=this,c=u.inFlightLinkObservables,l=u.link,f={query:s,variables:n,operationName:e3(s)||void 0,context:this.prepareContext((0,en.pi)((0,en.pi)({},t),{forceFetch:!r}))};if(t=f.context,r){var d=c.get(s)||new Map;c.set(s,d);var h=nx(n);if(!(a=d.get(h))){var p=new nq([np(l,f)]);d.set(h,a=p),p.beforeNext(function(){d.delete(h)&&d.size<1&&c.delete(s)})}}else a=new nq([np(l,f)])}else a=new nq([eT.of({data:{}})]),t=this.prepareContext(t);var b=this.transform(e).clientQuery;return b&&(a=nM(a,function(e){return o.localState.runResolvers({document:b,remoteResult:e,context:t,variables:n})})),a},e.prototype.getResultsFromLink=function(e,t,n){var r=e.lastRequestId=this.generateRequestId(),i=this.cache.transformForLink(this.transform(e.document).document);return nM(this.getObservableFromLink(i,n.context,n.variables),function(a){var o=nA(a),s=o.length>0;if(r>=e.lastRequestId){if(s&&"none"===n.errorPolicy)throw e.markError(new tN.cA({graphQLErrors:o}));e.markResult(a,i,n,t),e.markReady()}var u={data:a.data,loading:!1,networkStatus:nZ.I.ready};return s&&"ignore"!==n.errorPolicy&&(u.errors=o,u.networkStatus=nZ.I.error),u},function(t){var n=(0,tN.MS)(t)?t:new tN.cA({networkError:t});throw r>=e.lastRequestId&&e.markError(n),n})},e.prototype.fetchQueryObservable=function(e,t,n){return this.fetchConcastWithInfo(e,t,n).concast},e.prototype.fetchConcastWithInfo=function(e,t,n){var r,i,a=this;void 0===n&&(n=nZ.I.loading);var o=this.transform(t.query).document,s=this.getVariables(o,t.variables),u=this.getQuery(e),c=this.defaultOptions.watchQuery,l=t.fetchPolicy,f=void 0===l?c&&c.fetchPolicy||"cache-first":l,d=t.errorPolicy,h=void 0===d?c&&c.errorPolicy||"none":d,p=t.returnPartialData,b=void 0!==p&&p,m=t.notifyOnNetworkStatusChange,g=void 0!==m&&m,v=t.context,y=void 0===v?{}:v,w=Object.assign({},t,{query:o,variables:s,fetchPolicy:f,errorPolicy:h,returnPartialData:b,notifyOnNetworkStatusChange:g,context:y}),_=function(e){w.variables=e;var r=a.fetchQueryByPolicy(u,w,n);return"standby"!==w.fetchPolicy&&r.sources.length>0&&u.observableQuery&&u.observableQuery.applyNextFetchPolicy("after-fetch",t),r},E=function(){return a.fetchCancelFns.delete(e)};if(this.fetchCancelFns.set(e,function(e){E(),setTimeout(function(){return r.cancel(e)})}),this.transform(w.query).hasClientExports)r=new nq(this.localState.addExportedVariables(w.query,w.variables,w.context).then(_).then(function(e){return e.sources})),i=!0;else{var S=_(w.variables);i=S.fromLink,r=new nq(S.sources)}return r.promise.then(E,E),{concast:r,fromLink:i}},e.prototype.refetchQueries=function(e){var t=this,n=e.updateCache,r=e.include,i=e.optimistic,a=void 0!==i&&i,o=e.removeOptimistic,s=void 0===o?a?nG("refetchQueries"):void 0:o,u=e.onQueryUpdated,c=new Map;r&&this.getObservableQueries(r).forEach(function(e,n){c.set(n,{oq:e,lastDiff:t.getQuery(n).getDiff()})});var l=new Map;return n&&this.cache.batch({update:n,optimistic:a&&s||!1,removeOptimistic:s,onWatchUpdated:function(e,t,n){var r=e.watcher instanceof r8&&e.watcher.observableQuery;if(r){if(u){c.delete(r.queryId);var i=u(r,t,n);return!0===i&&(i=r.refetch()),!1!==i&&l.set(r,i),i}null!==u&&c.set(r.queryId,{oq:r,lastDiff:n,diff:t})}}}),c.size&&c.forEach(function(e,n){var r,i=e.oq,a=e.lastDiff,o=e.diff;if(u){if(!o){var s=i.queryInfo;s.reset(),o=s.getDiff()}r=u(i,o,a)}u&&!0!==r||(r=i.refetch()),!1!==r&&l.set(i,r),n.indexOf("legacyOneTimeQuery")>=0&&t.stopQueryNoBroadcast(n)}),s&&this.cache.removeOptimistic(s),l},e.prototype.fetchQueryByPolicy=function(e,t,n){var r=this,i=t.query,a=t.variables,o=t.fetchPolicy,s=t.refetchWritePolicy,u=t.errorPolicy,c=t.returnPartialData,l=t.context,f=t.notifyOnNetworkStatusChange,d=e.networkStatus;e.init({document:this.transform(i).document,variables:a,networkStatus:n});var h=function(){return e.getDiff(a)},p=function(t,n){void 0===n&&(n=e.networkStatus||nZ.I.loading);var o=t.result;!__DEV__||c||(0,nm.D)(o,{})||n6(t.missing);var s=function(e){return eT.of((0,en.pi)({data:e,loading:(0,nZ.O)(n),networkStatus:n},t.complete?null:{partial:!0}))};return o&&r.transform(i).hasForcedResolvers?r.localState.runResolvers({document:i,remoteResult:{data:o},context:l,variables:a,onlyRunForcedResolvers:!0}).then(function(e){return s(e.data||void 0)}):"none"===u&&n===nZ.I.refetch&&Array.isArray(t.missing)?s(void 0):s(o)},b="no-cache"===o?0:n===nZ.I.refetch&&"merge"!==s?1:2,m=function(){return r.getResultsFromLink(e,b,{variables:a,context:l,fetchPolicy:o,errorPolicy:u})},g=f&&"number"==typeof d&&d!==n&&(0,nZ.O)(n);switch(o){default:case"cache-first":var v=h();if(v.complete)return{fromLink:!1,sources:[p(v,e.markReady())]};if(c||g)return{fromLink:!0,sources:[p(v),m()]};return{fromLink:!0,sources:[m()]};case"cache-and-network":var v=h();if(v.complete||c||g)return{fromLink:!0,sources:[p(v),m()]};return{fromLink:!0,sources:[m()]};case"cache-only":return{fromLink:!1,sources:[p(h(),e.markReady())]};case"network-only":if(g)return{fromLink:!0,sources:[p(h()),m()]};return{fromLink:!0,sources:[m()]};case"no-cache":if(g)return{fromLink:!0,sources:[p(e.getDiff()),m(),]};return{fromLink:!0,sources:[m()]};case"standby":return{fromLink:!1,sources:[]}}},e.prototype.getQuery=function(e){return e&&!this.queries.has(e)&&this.queries.set(e,new r8(this,e)),this.queries.get(e)},e.prototype.prepareContext=function(e){void 0===e&&(e={});var t=this.localState.prepareContext(e);return(0,en.pi)((0,en.pi)({},t),{clientAwareness:this.clientAwareness})},e}(),ir=__webpack_require__(14012),ii=!1,ia=function(){function e(e){var t=this;this.resetStoreCallbacks=[],this.clearStoreCallbacks=[];var n=e.uri,r=e.credentials,i=e.headers,a=e.cache,o=e.ssrMode,s=void 0!==o&&o,u=e.ssrForceFetchDelay,c=void 0===u?0:u,l=e.connectToDevTools,f=void 0===l?"object"==typeof window&&!window.__APOLLO_CLIENT__&&__DEV__:l,d=e.queryDeduplication,h=void 0===d||d,p=e.defaultOptions,b=e.assumeImmutableResults,m=void 0!==b&&b,g=e.resolvers,v=e.typeDefs,y=e.fragmentMatcher,w=e.name,_=e.version,E=e.link;if(E||(E=n?new nh({uri:n,credentials:r,headers:i}):ta.empty()),!a)throw __DEV__?new Q.ej("To initialize Apollo Client, you must specify a 'cache' property in the options object. \nFor more information, please visit: https://go.apollo.dev/c/docs"):new Q.ej(9);if(this.link=E,this.cache=a,this.disableNetworkFetches=s||c>0,this.queryDeduplication=h,this.defaultOptions=p||Object.create(null),this.typeDefs=v,c&&setTimeout(function(){return t.disableNetworkFetches=!1},c),this.watchQuery=this.watchQuery.bind(this),this.query=this.query.bind(this),this.mutate=this.mutate.bind(this),this.resetStore=this.resetStore.bind(this),this.reFetchObservableQueries=this.reFetchObservableQueries.bind(this),f&&"object"==typeof window&&(window.__APOLLO_CLIENT__=this),!ii&&f&&__DEV__&&(ii=!0,"undefined"!=typeof window&&window.document&&window.top===window.self&&!window.__APOLLO_DEVTOOLS_GLOBAL_HOOK__)){var S=window.navigator,k=S&&S.userAgent,x=void 0;"string"==typeof k&&(k.indexOf("Chrome/")>-1?x="https://chrome.google.com/webstore/detail/apollo-client-developer-t/jdkknkkbebbapilgoeccciglkfbmbnfm":k.indexOf("Firefox/")>-1&&(x="https://addons.mozilla.org/en-US/firefox/addon/apollo-developer-tools/")),x&&__DEV__&&Q.kG.log("Download the Apollo DevTools for a better development experience: "+x)}this.version=nb,this.localState=new r4({cache:a,client:this,resolvers:g,fragmentMatcher:y}),this.queryManager=new it({cache:this.cache,link:this.link,defaultOptions:this.defaultOptions,queryDeduplication:h,ssrMode:s,clientAwareness:{name:w,version:_},localState:this.localState,assumeImmutableResults:m,onBroadcast:f?function(){t.devToolsHookCb&&t.devToolsHookCb({action:{},state:{queries:t.queryManager.getQueryStore(),mutations:t.queryManager.mutationStore||{}},dataWithOptimisticResults:t.cache.extract(!0)})}:void 0})}return e.prototype.stop=function(){this.queryManager.stop()},e.prototype.watchQuery=function(e){return this.defaultOptions.watchQuery&&(e=(0,ir.J)(this.defaultOptions.watchQuery,e)),this.disableNetworkFetches&&("network-only"===e.fetchPolicy||"cache-and-network"===e.fetchPolicy)&&(e=(0,en.pi)((0,en.pi)({},e),{fetchPolicy:"cache-first"})),this.queryManager.watchQuery(e)},e.prototype.query=function(e){return this.defaultOptions.query&&(e=(0,ir.J)(this.defaultOptions.query,e)),__DEV__?(0,Q.kG)("cache-and-network"!==e.fetchPolicy,"The cache-and-network fetchPolicy does not work with client.query, because client.query can only return a single result. Please use client.watchQuery to receive multiple results from the cache and the network, or consider using a different fetchPolicy, such as cache-first or network-only."):(0,Q.kG)("cache-and-network"!==e.fetchPolicy,10),this.disableNetworkFetches&&"network-only"===e.fetchPolicy&&(e=(0,en.pi)((0,en.pi)({},e),{fetchPolicy:"cache-first"})),this.queryManager.query(e)},e.prototype.mutate=function(e){return this.defaultOptions.mutate&&(e=(0,ir.J)(this.defaultOptions.mutate,e)),this.queryManager.mutate(e)},e.prototype.subscribe=function(e){return this.queryManager.startGraphQLSubscription(e)},e.prototype.readQuery=function(e,t){return void 0===t&&(t=!1),this.cache.readQuery(e,t)},e.prototype.readFragment=function(e,t){return void 0===t&&(t=!1),this.cache.readFragment(e,t)},e.prototype.writeQuery=function(e){var t=this.cache.writeQuery(e);return!1!==e.broadcast&&this.queryManager.broadcastQueries(),t},e.prototype.writeFragment=function(e){var t=this.cache.writeFragment(e);return!1!==e.broadcast&&this.queryManager.broadcastQueries(),t},e.prototype.__actionHookForDevTools=function(e){this.devToolsHookCb=e},e.prototype.__requestRaw=function(e){return np(this.link,e)},e.prototype.resetStore=function(){var e=this;return Promise.resolve().then(function(){return e.queryManager.clearStore({discardWatches:!1})}).then(function(){return Promise.all(e.resetStoreCallbacks.map(function(e){return e()}))}).then(function(){return e.reFetchObservableQueries()})},e.prototype.clearStore=function(){var e=this;return Promise.resolve().then(function(){return e.queryManager.clearStore({discardWatches:!0})}).then(function(){return Promise.all(e.clearStoreCallbacks.map(function(e){return e()}))})},e.prototype.onResetStore=function(e){var t=this;return this.resetStoreCallbacks.push(e),function(){t.resetStoreCallbacks=t.resetStoreCallbacks.filter(function(t){return t!==e})}},e.prototype.onClearStore=function(e){var t=this;return this.clearStoreCallbacks.push(e),function(){t.clearStoreCallbacks=t.clearStoreCallbacks.filter(function(t){return t!==e})}},e.prototype.reFetchObservableQueries=function(e){return this.queryManager.reFetchObservableQueries(e)},e.prototype.refetchQueries=function(e){var t=this.queryManager.refetchQueries(e),n=[],r=[];t.forEach(function(e,t){n.push(t),r.push(e)});var i=Promise.all(r);return i.queries=n,i.results=r,i.catch(function(e){__DEV__&&Q.kG.debug("In client.refetchQueries, Promise.all promise rejected with error ".concat(e))}),i},e.prototype.getObservableQueries=function(e){return void 0===e&&(e="active"),this.queryManager.getObservableQueries(e)},e.prototype.extract=function(e){return this.cache.extract(e)},e.prototype.restore=function(e){return this.cache.restore(e)},e.prototype.addResolvers=function(e){this.localState.addResolvers(e)},e.prototype.setResolvers=function(e){this.localState.setResolvers(e)},e.prototype.getResolvers=function(){return this.localState.getResolvers()},e.prototype.setLocalStateFragmentMatcher=function(e){this.localState.setFragmentMatcher(e)},e.prototype.setLink=function(e){this.link=this.queryManager.link=e},e}(),io=function(){function e(){this.getFragmentDoc=rZ(eA)}return e.prototype.batch=function(e){var t,n=this,r="string"==typeof e.optimistic?e.optimistic:!1===e.optimistic?null:void 0;return this.performTransaction(function(){return t=e.update(n)},r),t},e.prototype.recordOptimisticTransaction=function(e,t){this.performTransaction(e,t)},e.prototype.transformDocument=function(e){return e},e.prototype.transformForLink=function(e){return e},e.prototype.identify=function(e){},e.prototype.gc=function(){return[]},e.prototype.modify=function(e){return!1},e.prototype.readQuery=function(e,t){return void 0===t&&(t=!!e.optimistic),this.read((0,en.pi)((0,en.pi)({},e),{rootId:e.id||"ROOT_QUERY",optimistic:t}))},e.prototype.readFragment=function(e,t){return void 0===t&&(t=!!e.optimistic),this.read((0,en.pi)((0,en.pi)({},e),{query:this.getFragmentDoc(e.fragment,e.fragmentName),rootId:e.id,optimistic:t}))},e.prototype.writeQuery=function(e){var t=e.id,n=e.data,r=(0,en._T)(e,["id","data"]);return this.write(Object.assign(r,{dataId:t||"ROOT_QUERY",result:n}))},e.prototype.writeFragment=function(e){var t=e.id,n=e.data,r=e.fragment,i=e.fragmentName,a=(0,en._T)(e,["id","data","fragment","fragmentName"]);return this.write(Object.assign(a,{query:this.getFragmentDoc(r,i),dataId:t,result:n}))},e.prototype.updateQuery=function(e,t){return this.batch({update:function(n){var r=n.readQuery(e),i=t(r);return null==i?r:(n.writeQuery((0,en.pi)((0,en.pi)({},e),{data:i})),i)}})},e.prototype.updateFragment=function(e,t){return this.batch({update:function(n){var r=n.readFragment(e),i=t(r);return null==i?r:(n.writeFragment((0,en.pi)((0,en.pi)({},e),{data:i})),i)}})},e}(),is=function(e){function t(n,r,i,a){var o,s=e.call(this,n)||this;if(s.message=n,s.path=r,s.query=i,s.variables=a,Array.isArray(s.path)){s.missing=s.message;for(var u=s.path.length-1;u>=0;--u)s.missing=((o={})[s.path[u]]=s.missing,o)}else s.missing=s.path;return s.__proto__=t.prototype,s}return(0,en.ZT)(t,e),t}(Error),iu=__webpack_require__(10542),ic=Object.prototype.hasOwnProperty;function il(e){return null==e}function id(e,t){var n=e.__typename,r=e.id,i=e._id;if("string"==typeof n&&(t&&(t.keyObject=il(r)?il(i)?void 0:{_id:i}:{id:r}),il(r)&&!il(i)&&(r=i),!il(r)))return"".concat(n,":").concat("number"==typeof r||"string"==typeof r?r:JSON.stringify(r))}var ih={dataIdFromObject:id,addTypename:!0,resultCaching:!0,canonizeResults:!1};function ip(e){return(0,n1.o)(ih,e)}function ib(e){var t=e.canonizeResults;return void 0===t?ih.canonizeResults:t}function im(e,t){return eD(t)?e.get(t.__ref,"__typename"):t&&t.__typename}var ig=/^[_a-z][_0-9a-z]*/i;function iv(e){var t=e.match(ig);return t?t[0]:e}function iy(e,t,n){return!!(0,eO.s)(t)&&((0,tP.k)(t)?t.every(function(t){return iy(e,t,n)}):e.selections.every(function(e){if(eQ(e)&&td(e,n)){var r=eX(e);return ic.call(t,r)&&(!e.selectionSet||iy(e.selectionSet,t[r],n))}return!0}))}function iw(e){return(0,eO.s)(e)&&!eD(e)&&!(0,tP.k)(e)}function i_(){return new tB}function iE(e,t){var n=eL(e4(e));return{fragmentMap:n,lookupFragment:function(e){var r=n[e];return!r&&t&&(r=t.lookup(e)),r||null}}}var iS=Object.create(null),ik=function(){return iS},ix=Object.create(null),iT=function(){function e(e,t){var n=this;this.policies=e,this.group=t,this.data=Object.create(null),this.rootIds=Object.create(null),this.refs=Object.create(null),this.getFieldValue=function(e,t){return(0,iu.J)(eD(e)?n.get(e.__ref,t):e&&e[t])},this.canRead=function(e){return eD(e)?n.has(e.__ref):"object"==typeof e},this.toReference=function(e,t){if("string"==typeof e)return eI(e);if(eD(e))return e;var r=n.policies.identify(e)[0];if(r){var i=eI(r);return t&&n.merge(r,e),i}}}return e.prototype.toObject=function(){return(0,en.pi)({},this.data)},e.prototype.has=function(e){return void 0!==this.lookup(e,!0)},e.prototype.get=function(e,t){if(this.group.depend(e,t),ic.call(this.data,e)){var n=this.data[e];if(n&&ic.call(n,t))return n[t]}return"__typename"===t&&ic.call(this.policies.rootTypenamesById,e)?this.policies.rootTypenamesById[e]:this instanceof iL?this.parent.get(e,t):void 0},e.prototype.lookup=function(e,t){return(t&&this.group.depend(e,"__exists"),ic.call(this.data,e))?this.data[e]:this instanceof iL?this.parent.lookup(e,t):this.policies.rootTypenamesById[e]?Object.create(null):void 0},e.prototype.merge=function(e,t){var n,r=this;eD(e)&&(e=e.__ref),eD(t)&&(t=t.__ref);var i="string"==typeof e?this.lookup(n=e):e,a="string"==typeof t?this.lookup(n=t):t;if(a){__DEV__?(0,Q.kG)("string"==typeof n,"store.merge expects a string ID"):(0,Q.kG)("string"==typeof n,1);var o=new tB(iI).merge(i,a);if(this.data[n]=o,o!==i&&(delete this.refs[n],this.group.caching)){var s=Object.create(null);i||(s.__exists=1),Object.keys(a).forEach(function(e){if(!i||i[e]!==o[e]){s[e]=1;var t=iv(e);t===e||r.policies.hasKeyArgs(o.__typename,t)||(s[t]=1),void 0!==o[e]||r instanceof iL||delete o[e]}}),s.__typename&&!(i&&i.__typename)&&this.policies.rootTypenamesById[n]===o.__typename&&delete s.__typename,Object.keys(s).forEach(function(e){return r.group.dirty(n,e)})}}},e.prototype.modify=function(e,t){var n=this,r=this.lookup(e);if(r){var i=Object.create(null),a=!1,o=!0,s={DELETE:iS,INVALIDATE:ix,isReference:eD,toReference:this.toReference,canRead:this.canRead,readField:function(t,r){return n.policies.readField("string"==typeof t?{fieldName:t,from:r||eI(e)}:t,{store:n})}};if(Object.keys(r).forEach(function(u){var c=iv(u),l=r[u];if(void 0!==l){var f="function"==typeof t?t:t[u]||t[c];if(f){var d=f===ik?iS:f((0,iu.J)(l),(0,en.pi)((0,en.pi)({},s),{fieldName:c,storeFieldName:u,storage:n.getStorage(e,u)}));d===ix?n.group.dirty(e,u):(d===iS&&(d=void 0),d!==l&&(i[u]=d,a=!0,l=d))}void 0!==l&&(o=!1)}}),a)return this.merge(e,i),o&&(this instanceof iL?this.data[e]=void 0:delete this.data[e],this.group.dirty(e,"__exists")),!0}return!1},e.prototype.delete=function(e,t,n){var r,i=this.lookup(e);if(i){var a=this.getFieldValue(i,"__typename"),o=t&&n?this.policies.getStoreFieldName({typename:a,fieldName:t,args:n}):t;return this.modify(e,o?((r={})[o]=ik,r):ik)}return!1},e.prototype.evict=function(e,t){var n=!1;return e.id&&(ic.call(this.data,e.id)&&(n=this.delete(e.id,e.fieldName,e.args)),this instanceof iL&&this!==t&&(n=this.parent.evict(e,t)||n),(e.fieldName||n)&&this.group.dirty(e.id,e.fieldName||"__exists")),n},e.prototype.clear=function(){this.replace(null)},e.prototype.extract=function(){var e=this,t=this.toObject(),n=[];return this.getRootIdSet().forEach(function(t){ic.call(e.policies.rootTypenamesById,t)||n.push(t)}),n.length&&(t.__META={extraRootIds:n.sort()}),t},e.prototype.replace=function(e){var t=this;if(Object.keys(this.data).forEach(function(n){e&&ic.call(e,n)||t.delete(n)}),e){var n=e.__META,r=(0,en._T)(e,["__META"]);Object.keys(r).forEach(function(e){t.merge(e,r[e])}),n&&n.extraRootIds.forEach(this.retain,this)}},e.prototype.retain=function(e){return this.rootIds[e]=(this.rootIds[e]||0)+1},e.prototype.release=function(e){if(this.rootIds[e]>0){var t=--this.rootIds[e];return t||delete this.rootIds[e],t}return 0},e.prototype.getRootIdSet=function(e){return void 0===e&&(e=new Set),Object.keys(this.rootIds).forEach(e.add,e),this instanceof iL?this.parent.getRootIdSet(e):Object.keys(this.policies.rootTypenamesById).forEach(e.add,e),e},e.prototype.gc=function(){var e=this,t=this.getRootIdSet(),n=this.toObject();t.forEach(function(r){ic.call(n,r)&&(Object.keys(e.findChildRefIds(r)).forEach(t.add,t),delete n[r])});var r=Object.keys(n);if(r.length){for(var i=this;i instanceof iL;)i=i.parent;r.forEach(function(e){return i.delete(e)})}return r},e.prototype.findChildRefIds=function(e){if(!ic.call(this.refs,e)){var t=this.refs[e]=Object.create(null),n=this.data[e];if(!n)return t;var r=new Set([n]);r.forEach(function(e){eD(e)&&(t[e.__ref]=!0),(0,eO.s)(e)&&Object.keys(e).forEach(function(t){var n=e[t];(0,eO.s)(n)&&r.add(n)})})}return this.refs[e]},e.prototype.makeCacheKey=function(){return this.group.keyMaker.lookupArray(arguments)},e}(),iM=function(){function e(e,t){void 0===t&&(t=null),this.caching=e,this.parent=t,this.d=null,this.resetCaching()}return e.prototype.resetCaching=function(){this.d=this.caching?rW():null,this.keyMaker=new n_(t_.mr)},e.prototype.depend=function(e,t){if(this.d){this.d(iO(e,t));var n=iv(t);n!==t&&this.d(iO(e,n)),this.parent&&this.parent.depend(e,t)}},e.prototype.dirty=function(e,t){this.d&&this.d.dirty(iO(e,t),"__exists"===t?"forget":"setDirty")},e}();function iO(e,t){return t+"#"+e}function iA(e,t){iD(e)&&e.group.depend(t,"__exists")}!function(e){var t=function(e){function t(t){var n=t.policies,r=t.resultCaching,i=void 0===r||r,a=t.seed,o=e.call(this,n,new iM(i))||this;return o.stump=new iC(o),o.storageTrie=new n_(t_.mr),a&&o.replace(a),o}return(0,en.ZT)(t,e),t.prototype.addLayer=function(e,t){return this.stump.addLayer(e,t)},t.prototype.removeLayer=function(){return this},t.prototype.getStorage=function(){return this.storageTrie.lookupArray(arguments)},t}(e);e.Root=t}(iT||(iT={}));var iL=function(e){function t(t,n,r,i){var a=e.call(this,n.policies,i)||this;return a.id=t,a.parent=n,a.replay=r,a.group=i,r(a),a}return(0,en.ZT)(t,e),t.prototype.addLayer=function(e,n){return new t(e,this,n,this.group)},t.prototype.removeLayer=function(e){var t=this,n=this.parent.removeLayer(e);return e===this.id?(this.group.caching&&Object.keys(this.data).forEach(function(e){var r=t.data[e],i=n.lookup(e);i?r?r!==i&&Object.keys(r).forEach(function(n){(0,nm.D)(r[n],i[n])||t.group.dirty(e,n)}):(t.group.dirty(e,"__exists"),Object.keys(i).forEach(function(n){t.group.dirty(e,n)})):t.delete(e)}),n):n===this.parent?this:n.addLayer(this.id,this.replay)},t.prototype.toObject=function(){return(0,en.pi)((0,en.pi)({},this.parent.toObject()),this.data)},t.prototype.findChildRefIds=function(t){var n=this.parent.findChildRefIds(t);return ic.call(this.data,t)?(0,en.pi)((0,en.pi)({},n),e.prototype.findChildRefIds.call(this,t)):n},t.prototype.getStorage=function(){for(var e=this.parent;e.parent;)e=e.parent;return e.getStorage.apply(e,arguments)},t}(iT),iC=function(e){function t(t){return e.call(this,"EntityStore.Stump",t,function(){},new iM(t.group.caching,t.group))||this}return(0,en.ZT)(t,e),t.prototype.removeLayer=function(){return this},t.prototype.merge=function(){return this.parent.merge.apply(this.parent,arguments)},t}(iL);function iI(e,t,n){var r=e[n],i=t[n];return(0,nm.D)(r,i)?r:i}function iD(e){return!!(e instanceof iT&&e.group.caching)}function iN(e){return[e.selectionSet,e.objectOrReference,e.context,e.context.canonizeResults,]}var iP=function(){function e(e){var t=this;this.knownResults=new(t_.mr?WeakMap:Map),this.config=(0,n1.o)(e,{addTypename:!1!==e.addTypename,canonizeResults:ib(e)}),this.canon=e.canon||new nk,this.executeSelectionSet=rZ(function(e){var n,r=e.context.canonizeResults,i=iN(e);i[3]=!r;var a=(n=t.executeSelectionSet).peek.apply(n,i);return a?r?(0,en.pi)((0,en.pi)({},a),{result:t.canon.admit(a.result)}):a:(iA(e.context.store,e.enclosingRef.__ref),t.execSelectionSetImpl(e))},{max:this.config.resultCacheMaxSize,keyArgs:iN,makeCacheKey:function(e,t,n,r){if(iD(n.store))return n.store.makeCacheKey(e,eD(t)?t.__ref:t,n.varString,r)}}),this.executeSubSelectedArray=rZ(function(e){return iA(e.context.store,e.enclosingRef.__ref),t.execSubSelectedArrayImpl(e)},{max:this.config.resultCacheMaxSize,makeCacheKey:function(e){var t=e.field,n=e.array,r=e.context;if(iD(r.store))return r.store.makeCacheKey(t,n,r.varString)}})}return e.prototype.resetCanon=function(){this.canon=new nk},e.prototype.diffQueryAgainstStore=function(e){var t,n=e.store,r=e.query,i=e.rootId,a=void 0===i?"ROOT_QUERY":i,o=e.variables,s=e.returnPartialData,u=void 0===s||s,c=e.canonizeResults,l=void 0===c?this.config.canonizeResults:c,f=this.config.cache.policies;o=(0,en.pi)((0,en.pi)({},e8(e5(r))),o);var d=eI(a),h=this.executeSelectionSet({selectionSet:e9(r).selectionSet,objectOrReference:d,enclosingRef:d,context:(0,en.pi)({store:n,query:r,policies:f,variables:o,varString:nx(o),canonizeResults:l},iE(r,this.config.fragments))});if(h.missing&&(t=[new is(iR(h.missing),h.missing,r,o)],!u))throw t[0];return{result:h.result,complete:!t,missing:t}},e.prototype.isFresh=function(e,t,n,r){if(iD(r.store)&&this.knownResults.get(e)===n){var i=this.executeSelectionSet.peek(n,t,r,this.canon.isKnown(e));if(i&&e===i.result)return!0}return!1},e.prototype.execSelectionSetImpl=function(e){var t,n=this,r=e.selectionSet,i=e.objectOrReference,a=e.enclosingRef,o=e.context;if(eD(i)&&!o.policies.rootTypenamesById[i.__ref]&&!o.store.has(i.__ref))return{result:this.canon.empty,missing:"Dangling reference to missing ".concat(i.__ref," object")};var s=o.variables,u=o.policies,c=o.store.getFieldValue(i,"__typename"),l=[],f=new tB;function d(e,n){var r;return e.missing&&(t=f.merge(t,((r={})[n]=e.missing,r))),e.result}this.config.addTypename&&"string"==typeof c&&!u.rootIdsByTypename[c]&&l.push({__typename:c});var h=new Set(r.selections);h.forEach(function(e){var r,p;if(td(e,s)){if(eQ(e)){var b=u.readField({fieldName:e.name.value,field:e,variables:o.variables,from:i},o),m=eX(e);void 0===b?nj.added(e)||(t=f.merge(t,((r={})[m]="Can't find field '".concat(e.name.value,"' on ").concat(eD(i)?i.__ref+" object":"object "+JSON.stringify(i,null,2)),r))):(0,tP.k)(b)?b=d(n.executeSubSelectedArray({field:e,array:b,enclosingRef:a,context:o}),m):e.selectionSet?null!=b&&(b=d(n.executeSelectionSet({selectionSet:e.selectionSet,objectOrReference:b,enclosingRef:eD(b)?b:a,context:o}),m)):o.canonizeResults&&(b=n.canon.pass(b)),void 0!==b&&l.push(((p={})[m]=b,p))}else{var g=eC(e,o.lookupFragment);if(!g&&e.kind===nL.h.FRAGMENT_SPREAD)throw __DEV__?new Q.ej("No fragment named ".concat(e.name.value)):new Q.ej(5);g&&u.fragmentMatches(g,c)&&g.selectionSet.selections.forEach(h.add,h)}}});var p={result:tF(l),missing:t},b=o.canonizeResults?this.canon.admit(p):(0,iu.J)(p);return b.result&&this.knownResults.set(b.result,r),b},e.prototype.execSubSelectedArrayImpl=function(e){var t,n=this,r=e.field,i=e.array,a=e.enclosingRef,o=e.context,s=new tB;function u(e,n){var r;return e.missing&&(t=s.merge(t,((r={})[n]=e.missing,r))),e.result}return r.selectionSet&&(i=i.filter(o.store.canRead)),i=i.map(function(e,t){return null===e?null:(0,tP.k)(e)?u(n.executeSubSelectedArray({field:r,array:e,enclosingRef:a,context:o}),t):r.selectionSet?u(n.executeSelectionSet({selectionSet:r.selectionSet,objectOrReference:e,enclosingRef:eD(e)?e:a,context:o}),t):(__DEV__&&ij(o.store,r,e),e)}),{result:o.canonizeResults?this.canon.admit(i):i,missing:t}},e}();function iR(e){try{JSON.stringify(e,function(e,t){if("string"==typeof t)throw t;return t})}catch(t){return t}}function ij(e,t,n){if(!t.selectionSet){var r=new Set([n]);r.forEach(function(n){(0,eO.s)(n)&&(__DEV__?(0,Q.kG)(!eD(n),"Missing selection set for object of type ".concat(im(e,n)," returned for query field ").concat(t.name.value)):(0,Q.kG)(!eD(n),6),Object.values(n).forEach(r.add,r))})}}function iF(e){var t=nG("stringifyForDisplay");return JSON.stringify(e,function(e,n){return void 0===n?t:n}).split(JSON.stringify(t)).join("")}var iY=Object.create(null);function iB(e){var t=JSON.stringify(e);return iY[t]||(iY[t]=Object.create(null))}function iU(e){var t=iB(e);return t.keyFieldsFn||(t.keyFieldsFn=function(t,n){var r=function(e,t){return n.readField(t,e)},i=n.keyObject=i$(e,function(e){var i=iW(n.storeObject,e,r);return void 0===i&&t!==n.storeObject&&ic.call(t,e[0])&&(i=iW(t,e,iG)),__DEV__?(0,Q.kG)(void 0!==i,"Missing field '".concat(e.join("."),"' while extracting keyFields from ").concat(JSON.stringify(t))):(0,Q.kG)(void 0!==i,2),i});return"".concat(n.typename,":").concat(JSON.stringify(i))})}function iH(e){var t=iB(e);return t.keyArgsFn||(t.keyArgsFn=function(t,n){var r=n.field,i=n.variables,a=n.fieldName,o=JSON.stringify(i$(e,function(e){var n=e[0],a=n.charAt(0);if("@"===a){if(r&&(0,tP.O)(r.directives)){var o=n.slice(1),s=r.directives.find(function(e){return e.name.value===o}),u=s&&eZ(s,i);return u&&iW(u,e.slice(1))}return}if("$"===a){var c=n.slice(1);if(i&&ic.call(i,c)){var l=e.slice(0);return l[0]=c,iW(i,l)}return}if(t)return iW(t,e)}));return(t||"{}"!==o)&&(a+=":"+o),a})}function i$(e,t){var n=new tB;return iz(e).reduce(function(e,r){var i,a=t(r);if(void 0!==a){for(var o=r.length-1;o>=0;--o)a=((i={})[r[o]]=a,i);e=n.merge(e,a)}return e},Object.create(null))}function iz(e){var t=iB(e);if(!t.paths){var n=t.paths=[],r=[];e.forEach(function(t,i){(0,tP.k)(t)?(iz(t).forEach(function(e){return n.push(r.concat(e))}),r.length=0):(r.push(t),(0,tP.k)(e[i+1])||(n.push(r.slice(0)),r.length=0))})}return t.paths}function iG(e,t){return e[t]}function iW(e,t,n){return n=n||iG,iK(t.reduce(function e(t,r){return(0,tP.k)(t)?t.map(function(t){return e(t,r)}):t&&n(t,r)},e))}function iK(e){return(0,eO.s)(e)?(0,tP.k)(e)?e.map(iK):i$(Object.keys(e).sort(),function(t){return iW(e,t)}):e}function iV(e){return void 0!==e.args?e.args:e.field?eZ(e.field,e.variables):null}eK.setStringify(nx);var iq=function(){},iZ=function(e,t){return t.fieldName},iX=function(e,t,n){return(0,n.mergeObjects)(e,t)},iJ=function(e,t){return t},iQ=function(){function e(e){this.config=e,this.typePolicies=Object.create(null),this.toBeAdded=Object.create(null),this.supertypeMap=new Map,this.fuzzySubtypes=new Map,this.rootIdsByTypename=Object.create(null),this.rootTypenamesById=Object.create(null),this.usingPossibleTypes=!1,this.config=(0,en.pi)({dataIdFromObject:id},e),this.cache=this.config.cache,this.setRootTypename("Query"),this.setRootTypename("Mutation"),this.setRootTypename("Subscription"),e.possibleTypes&&this.addPossibleTypes(e.possibleTypes),e.typePolicies&&this.addTypePolicies(e.typePolicies)}return e.prototype.identify=function(e,t){var n,r,i=this,a=t&&(t.typename||(null===(n=t.storeObject)||void 0===n?void 0:n.__typename))||e.__typename;if(a===this.rootTypenamesById.ROOT_QUERY)return["ROOT_QUERY"];for(var o=t&&t.storeObject||e,s=(0,en.pi)((0,en.pi)({},t),{typename:a,storeObject:o,readField:t&&t.readField||function(){var e=i0(arguments,o);return i.readField(e,{store:i.cache.data,variables:e.variables})}}),u=a&&this.getTypePolicy(a),c=u&&u.keyFn||this.config.dataIdFromObject;c;){var l=c((0,en.pi)((0,en.pi)({},e),o),s);if((0,tP.k)(l))c=iU(l);else{r=l;break}}return r=r?String(r):void 0,s.keyObject?[r,s.keyObject]:[r]},e.prototype.addTypePolicies=function(e){var t=this;Object.keys(e).forEach(function(n){var r=e[n],i=r.queryType,a=r.mutationType,o=r.subscriptionType,s=(0,en._T)(r,["queryType","mutationType","subscriptionType"]);i&&t.setRootTypename("Query",n),a&&t.setRootTypename("Mutation",n),o&&t.setRootTypename("Subscription",n),ic.call(t.toBeAdded,n)?t.toBeAdded[n].push(s):t.toBeAdded[n]=[s]})},e.prototype.updateTypePolicy=function(e,t){var n=this,r=this.getTypePolicy(e),i=t.keyFields,a=t.fields;function o(e,t){e.merge="function"==typeof t?t:!0===t?iX:!1===t?iJ:e.merge}o(r,t.merge),r.keyFn=!1===i?iq:(0,tP.k)(i)?iU(i):"function"==typeof i?i:r.keyFn,a&&Object.keys(a).forEach(function(t){var r=n.getFieldPolicy(e,t,!0),i=a[t];if("function"==typeof i)r.read=i;else{var s=i.keyArgs,u=i.read,c=i.merge;r.keyFn=!1===s?iZ:(0,tP.k)(s)?iH(s):"function"==typeof s?s:r.keyFn,"function"==typeof u&&(r.read=u),o(r,c)}r.read&&r.merge&&(r.keyFn=r.keyFn||iZ)})},e.prototype.setRootTypename=function(e,t){void 0===t&&(t=e);var n="ROOT_"+e.toUpperCase(),r=this.rootTypenamesById[n];t!==r&&(__DEV__?(0,Q.kG)(!r||r===e,"Cannot change root ".concat(e," __typename more than once")):(0,Q.kG)(!r||r===e,3),r&&delete this.rootIdsByTypename[r],this.rootIdsByTypename[t]=n,this.rootTypenamesById[n]=t)},e.prototype.addPossibleTypes=function(e){var t=this;this.usingPossibleTypes=!0,Object.keys(e).forEach(function(n){t.getSupertypeSet(n,!0),e[n].forEach(function(e){t.getSupertypeSet(e,!0).add(n);var r=e.match(ig);r&&r[0]===e||t.fuzzySubtypes.set(e,RegExp(e))})})},e.prototype.getTypePolicy=function(e){var t=this;if(!ic.call(this.typePolicies,e)){var n=this.typePolicies[e]=Object.create(null);n.fields=Object.create(null);var r=this.supertypeMap.get(e);r&&r.size&&r.forEach(function(e){var r=t.getTypePolicy(e),i=r.fields;Object.assign(n,(0,en._T)(r,["fields"])),Object.assign(n.fields,i)})}var i=this.toBeAdded[e];return i&&i.length&&i.splice(0).forEach(function(n){t.updateTypePolicy(e,n)}),this.typePolicies[e]},e.prototype.getFieldPolicy=function(e,t,n){if(e){var r=this.getTypePolicy(e).fields;return r[t]||n&&(r[t]=Object.create(null))}},e.prototype.getSupertypeSet=function(e,t){var n=this.supertypeMap.get(e);return!n&&t&&this.supertypeMap.set(e,n=new Set),n},e.prototype.fragmentMatches=function(e,t,n,r){var i=this;if(!e.typeCondition)return!0;if(!t)return!1;var a=e.typeCondition.name.value;if(t===a)return!0;if(this.usingPossibleTypes&&this.supertypeMap.has(a))for(var o=this.getSupertypeSet(t,!0),s=[o],u=function(e){var t=i.getSupertypeSet(e,!1);t&&t.size&&0>s.indexOf(t)&&s.push(t)},c=!!(n&&this.fuzzySubtypes.size),l=!1,f=0;f1?a:t}:(r=(0,en.pi)({},i),ic.call(r,"from")||(r.from=t)),__DEV__&&void 0===r.from&&__DEV__&&Q.kG.warn("Undefined 'from' passed to readField with arguments ".concat(iF(Array.from(e)))),void 0===r.variables&&(r.variables=n),r}function i2(e){return function(t,n){if((0,tP.k)(t)||(0,tP.k)(n))throw __DEV__?new Q.ej("Cannot automatically merge arrays"):new Q.ej(4);if((0,eO.s)(t)&&(0,eO.s)(n)){var r=e.getFieldValue(t,"__typename"),i=e.getFieldValue(n,"__typename");if(r&&i&&r!==i)return n;if(eD(t)&&iw(n))return e.merge(t.__ref,n),t;if(iw(t)&&eD(n))return e.merge(t,n.__ref),n;if(iw(t)&&iw(n))return(0,en.pi)((0,en.pi)({},t),n)}return n}}function i3(e,t,n){var r="".concat(t).concat(n),i=e.flavors.get(r);return i||e.flavors.set(r,i=e.clientOnly===t&&e.deferred===n?e:(0,en.pi)((0,en.pi)({},e),{clientOnly:t,deferred:n})),i}var i4=function(){function e(e,t,n){this.cache=e,this.reader=t,this.fragments=n}return e.prototype.writeToStore=function(e,t){var n=this,r=t.query,i=t.result,a=t.dataId,o=t.variables,s=t.overwrite,u=e2(r),c=i_();o=(0,en.pi)((0,en.pi)({},e8(u)),o);var l=(0,en.pi)((0,en.pi)({store:e,written:Object.create(null),merge:function(e,t){return c.merge(e,t)},variables:o,varString:nx(o)},iE(r,this.fragments)),{overwrite:!!s,incomingById:new Map,clientOnly:!1,deferred:!1,flavors:new Map}),f=this.processSelectionSet({result:i||Object.create(null),dataId:a,selectionSet:u.selectionSet,mergeTree:{map:new Map},context:l});if(!eD(f))throw __DEV__?new Q.ej("Could not identify object ".concat(JSON.stringify(i))):new Q.ej(7);return l.incomingById.forEach(function(t,r){var i=t.storeObject,a=t.mergeTree,o=t.fieldNodeSet,s=eI(r);if(a&&a.map.size){var u=n.applyMerges(a,s,i,l);if(eD(u))return;i=u}if(__DEV__&&!l.overwrite){var c=Object.create(null);o.forEach(function(e){e.selectionSet&&(c[e.name.value]=!0)});var f=function(e){return!0===c[iv(e)]},d=function(e){var t=a&&a.map.get(e);return Boolean(t&&t.info&&t.info.merge)};Object.keys(i).forEach(function(e){f(e)&&!d(e)&&at(s,i,e,l.store)})}e.merge(r,i)}),e.retain(f.__ref),f},e.prototype.processSelectionSet=function(e){var t=this,n=e.dataId,r=e.result,i=e.selectionSet,a=e.context,o=e.mergeTree,s=this.cache.policies,u=Object.create(null),c=n&&s.rootTypenamesById[n]||eJ(r,i,a.fragmentMap)||n&&a.store.get(n,"__typename");"string"==typeof c&&(u.__typename=c);var l=function(){var e=i0(arguments,u,a.variables);if(eD(e.from)){var t=a.incomingById.get(e.from.__ref);if(t){var n=s.readField((0,en.pi)((0,en.pi)({},e),{from:t.storeObject}),a);if(void 0!==n)return n}}return s.readField(e,a)},f=new Set;this.flattenFields(i,r,a,c).forEach(function(e,n){var i,a=r[eX(n)];if(f.add(n),void 0!==a){var d=s.getStoreFieldName({typename:c,fieldName:n.name.value,field:n,variables:e.variables}),h=i6(o,d),p=t.processFieldValue(a,n,n.selectionSet?i3(e,!1,!1):e,h),b=void 0;n.selectionSet&&(eD(p)||iw(p))&&(b=l("__typename",p));var m=s.getMergeFunction(c,n.name.value,b);m?h.info={field:n,typename:c,merge:m}:i7(o,d),u=e.merge(u,((i={})[d]=p,i))}else __DEV__&&!e.clientOnly&&!e.deferred&&!nj.added(n)&&!s.getReadFunction(c,n.name.value)&&__DEV__&&Q.kG.error("Missing field '".concat(eX(n),"' while writing result ").concat(JSON.stringify(r,null,2)).substring(0,1e3))});try{var d=s.identify(r,{typename:c,selectionSet:i,fragmentMap:a.fragmentMap,storeObject:u,readField:l}),h=d[0],p=d[1];n=n||h,p&&(u=a.merge(u,p))}catch(b){if(!n)throw b}if("string"==typeof n){var m=eI(n),g=a.written[n]||(a.written[n]=[]);if(g.indexOf(i)>=0||(g.push(i),this.reader&&this.reader.isFresh(r,m,i,a)))return m;var v=a.incomingById.get(n);return v?(v.storeObject=a.merge(v.storeObject,u),v.mergeTree=i9(v.mergeTree,o),f.forEach(function(e){return v.fieldNodeSet.add(e)})):a.incomingById.set(n,{storeObject:u,mergeTree:i8(o)?void 0:o,fieldNodeSet:f}),m}return u},e.prototype.processFieldValue=function(e,t,n,r){var i=this;return t.selectionSet&&null!==e?(0,tP.k)(e)?e.map(function(e,a){var o=i.processFieldValue(e,t,n,i6(r,a));return i7(r,a),o}):this.processSelectionSet({result:e,selectionSet:t.selectionSet,context:n,mergeTree:r}):__DEV__?nJ(e):e},e.prototype.flattenFields=function(e,t,n,r){void 0===r&&(r=eJ(t,e,n.fragmentMap));var i=new Map,a=this.cache.policies,o=new n_(!1);return function e(s,u){var c=o.lookup(s,u.clientOnly,u.deferred);c.visited||(c.visited=!0,s.selections.forEach(function(o){if(td(o,n.variables)){var s=u.clientOnly,c=u.deferred;if(!(s&&c)&&(0,tP.O)(o.directives)&&o.directives.forEach(function(e){var t=e.name.value;if("client"===t&&(s=!0),"defer"===t){var r=eZ(e,n.variables);r&&!1===r.if||(c=!0)}}),eQ(o)){var l=i.get(o);l&&(s=s&&l.clientOnly,c=c&&l.deferred),i.set(o,i3(n,s,c))}else{var f=eC(o,n.lookupFragment);if(!f&&o.kind===nL.h.FRAGMENT_SPREAD)throw __DEV__?new Q.ej("No fragment named ".concat(o.name.value)):new Q.ej(8);f&&a.fragmentMatches(f,r,t,n.variables)&&e(f.selectionSet,i3(n,s,c))}}}))}(e,n),i},e.prototype.applyMerges=function(e,t,n,r,i){var a=this;if(e.map.size&&!eD(n)){var o,s,u=!(0,tP.k)(n)&&(eD(t)||iw(t))?t:void 0,c=n;u&&!i&&(i=[eD(u)?u.__ref:u]);var l=function(e,t){return(0,tP.k)(e)?"number"==typeof t?e[t]:void 0:r.store.getFieldValue(e,String(t))};e.map.forEach(function(e,t){var n=l(u,t),o=l(c,t);if(void 0!==o){i&&i.push(t);var f=a.applyMerges(e,n,o,r,i);f!==o&&(s=s||new Map).set(t,f),i&&(0,Q.kG)(i.pop()===t)}}),s&&(n=(0,tP.k)(c)?c.slice(0):(0,en.pi)({},c),s.forEach(function(e,t){n[t]=e}))}return e.info?this.cache.policies.runMergeFunction(t,n,e.info,r,i&&(o=r.store).getStorage.apply(o,i)):n},e}(),i5=[];function i6(e,t){var n=e.map;return n.has(t)||n.set(t,i5.pop()||{map:new Map}),n.get(t)}function i9(e,t){if(e===t||!t||i8(t))return e;if(!e||i8(e))return t;var n=e.info&&t.info?(0,en.pi)((0,en.pi)({},e.info),t.info):e.info||t.info,r=e.map.size&&t.map.size,i=r?new Map:e.map.size?e.map:t.map,a={info:n,map:i};if(r){var o=new Set(t.map.keys());e.map.forEach(function(e,n){a.map.set(n,i9(e,t.map.get(n))),o.delete(n)}),o.forEach(function(n){a.map.set(n,i9(t.map.get(n),e.map.get(n)))})}return a}function i8(e){return!e||!(e.info||e.map.size)}function i7(e,t){var n=e.map,r=n.get(t);r&&i8(r)&&(i5.push(r),n.delete(t))}var ae=new Set;function at(e,t,n,r){var i=function(e){var t=r.getFieldValue(e,n);return"object"==typeof t&&t},a=i(e);if(a){var o=i(t);if(!(!o||eD(a)||(0,nm.D)(a,o)||Object.keys(a).every(function(e){return void 0!==r.getFieldValue(o,e)}))){var s=r.getFieldValue(e,"__typename")||r.getFieldValue(t,"__typename"),u=iv(n),c="".concat(s,".").concat(u);if(!ae.has(c)){ae.add(c);var l=[];(0,tP.k)(a)||(0,tP.k)(o)||[a,o].forEach(function(e){var t=r.getFieldValue(e,"__typename");"string"!=typeof t||l.includes(t)||l.push(t)}),__DEV__&&Q.kG.warn("Cache data may be lost when replacing the ".concat(u," field of a ").concat(s," object.\n\nThis could cause additional (usually avoidable) network requests to fetch data that were otherwise cached.\n\nTo address this problem (which is not a bug in Apollo Client), ").concat(l.length?"either ensure all objects of type "+l.join(" and ")+" have an ID or a custom merge function, or ":"","define a custom merge function for the ").concat(c," field, so InMemoryCache can safely merge these objects:\n\n existing: ").concat(JSON.stringify(a).slice(0,1e3),"\n incoming: ").concat(JSON.stringify(o).slice(0,1e3),"\n\nFor more information about these options, please refer to the documentation:\n\n * Ensuring entity objects have IDs: https://go.apollo.dev/c/generating-unique-identifiers\n * Defining custom merge functions: https://go.apollo.dev/c/merging-non-normalized-objects\n"))}}}}var an=function(e){function t(t){void 0===t&&(t={});var n=e.call(this)||this;return n.watches=new Set,n.typenameDocumentCache=new Map,n.makeVar=r2,n.txCount=0,n.config=ip(t),n.addTypename=!!n.config.addTypename,n.policies=new iQ({cache:n,dataIdFromObject:n.config.dataIdFromObject,possibleTypes:n.config.possibleTypes,typePolicies:n.config.typePolicies}),n.init(),n}return(0,en.ZT)(t,e),t.prototype.init=function(){var e=this.data=new iT.Root({policies:this.policies,resultCaching:this.config.resultCaching});this.optimisticData=e.stump,this.resetResultCache()},t.prototype.resetResultCache=function(e){var t=this,n=this.storeReader,r=this.config.fragments;this.storeWriter=new i4(this,this.storeReader=new iP({cache:this,addTypename:this.addTypename,resultCacheMaxSize:this.config.resultCacheMaxSize,canonizeResults:ib(this.config),canon:e?void 0:n&&n.canon,fragments:r}),r),this.maybeBroadcastWatch=rZ(function(e,n){return t.broadcastWatch(e,n)},{max:this.config.resultCacheMaxSize,makeCacheKey:function(e){var n=e.optimistic?t.optimisticData:t.data;if(iD(n)){var r=e.optimistic,i=e.id,a=e.variables;return n.makeCacheKey(e.query,e.callback,nx({optimistic:r,id:i,variables:a}))}}}),new Set([this.data.group,this.optimisticData.group,]).forEach(function(e){return e.resetCaching()})},t.prototype.restore=function(e){return this.init(),e&&this.data.replace(e),this},t.prototype.extract=function(e){return void 0===e&&(e=!1),(e?this.optimisticData:this.data).extract()},t.prototype.read=function(e){var t=e.returnPartialData,n=void 0!==t&&t;try{return this.storeReader.diffQueryAgainstStore((0,en.pi)((0,en.pi)({},e),{store:e.optimistic?this.optimisticData:this.data,config:this.config,returnPartialData:n})).result||null}catch(r){if(r instanceof is)return null;throw r}},t.prototype.write=function(e){try{return++this.txCount,this.storeWriter.writeToStore(this.data,e)}finally{--this.txCount||!1===e.broadcast||this.broadcastWatches()}},t.prototype.modify=function(e){if(ic.call(e,"id")&&!e.id)return!1;var t=e.optimistic?this.optimisticData:this.data;try{return++this.txCount,t.modify(e.id||"ROOT_QUERY",e.fields)}finally{--this.txCount||!1===e.broadcast||this.broadcastWatches()}},t.prototype.diff=function(e){return this.storeReader.diffQueryAgainstStore((0,en.pi)((0,en.pi)({},e),{store:e.optimistic?this.optimisticData:this.data,rootId:e.id||"ROOT_QUERY",config:this.config}))},t.prototype.watch=function(e){var t=this;return this.watches.size||r0(this),this.watches.add(e),e.immediate&&this.maybeBroadcastWatch(e),function(){t.watches.delete(e)&&!t.watches.size&&r1(t),t.maybeBroadcastWatch.forget(e)}},t.prototype.gc=function(e){nx.reset();var t=this.optimisticData.gc();return e&&!this.txCount&&(e.resetResultCache?this.resetResultCache(e.resetResultIdentities):e.resetResultIdentities&&this.storeReader.resetCanon()),t},t.prototype.retain=function(e,t){return(t?this.optimisticData:this.data).retain(e)},t.prototype.release=function(e,t){return(t?this.optimisticData:this.data).release(e)},t.prototype.identify=function(e){if(eD(e))return e.__ref;try{return this.policies.identify(e)[0]}catch(t){__DEV__&&Q.kG.warn(t)}},t.prototype.evict=function(e){if(!e.id){if(ic.call(e,"id"))return!1;e=(0,en.pi)((0,en.pi)({},e),{id:"ROOT_QUERY"})}try{return++this.txCount,this.optimisticData.evict(e,this.data)}finally{--this.txCount||!1===e.broadcast||this.broadcastWatches()}},t.prototype.reset=function(e){var t=this;return this.init(),nx.reset(),e&&e.discardWatches?(this.watches.forEach(function(e){return t.maybeBroadcastWatch.forget(e)}),this.watches.clear(),r1(this)):this.broadcastWatches(),Promise.resolve()},t.prototype.removeOptimistic=function(e){var t=this.optimisticData.removeLayer(e);t!==this.optimisticData&&(this.optimisticData=t,this.broadcastWatches())},t.prototype.batch=function(e){var t,n=this,r=e.update,i=e.optimistic,a=void 0===i||i,o=e.removeOptimistic,s=e.onWatchUpdated,u=function(e){var i=n,a=i.data,o=i.optimisticData;++n.txCount,e&&(n.data=n.optimisticData=e);try{return t=r(n)}finally{--n.txCount,n.data=a,n.optimisticData=o}},c=new Set;return s&&!this.txCount&&this.broadcastWatches((0,en.pi)((0,en.pi)({},e),{onWatchUpdated:function(e){return c.add(e),!1}})),"string"==typeof a?this.optimisticData=this.optimisticData.addLayer(a,u):!1===a?u(this.data):u(),"string"==typeof o&&(this.optimisticData=this.optimisticData.removeLayer(o)),s&&c.size?(this.broadcastWatches((0,en.pi)((0,en.pi)({},e),{onWatchUpdated:function(e,t){var n=s.call(this,e,t);return!1!==n&&c.delete(e),n}})),c.size&&c.forEach(function(e){return n.maybeBroadcastWatch.dirty(e)})):this.broadcastWatches(e),t},t.prototype.performTransaction=function(e,t){return this.batch({update:e,optimistic:t||null!==t})},t.prototype.transformDocument=function(e){if(this.addTypename){var t=this.typenameDocumentCache.get(e);return t||(t=nj(e),this.typenameDocumentCache.set(e,t),this.typenameDocumentCache.set(t,t)),t}return e},t.prototype.transformForLink=function(e){var t=this.config.fragments;return t?t.transform(e):e},t.prototype.broadcastWatches=function(e){var t=this;this.txCount||this.watches.forEach(function(n){return t.maybeBroadcastWatch(n,e)})},t.prototype.broadcastWatch=function(e,t){var n=e.lastDiff,r=this.diff(e);(!t||(e.optimistic&&"string"==typeof t.optimistic&&(r.fromOptimisticTransaction=!0),!t.onWatchUpdated||!1!==t.onWatchUpdated.call(this,e,r,n)))&&(n&&(0,nm.D)(n.result,r.result)||e.callback(e.lastDiff=r,n))},t}(io),ar={possibleTypes:{ApproveJobProposalSpecPayload:["ApproveJobProposalSpecSuccess","JobAlreadyExistsError","NotFoundError"],BridgePayload:["Bridge","NotFoundError"],CancelJobProposalSpecPayload:["CancelJobProposalSpecSuccess","NotFoundError"],ChainPayload:["Chain","NotFoundError"],CreateAPITokenPayload:["CreateAPITokenSuccess","InputErrors"],CreateBridgePayload:["CreateBridgeSuccess"],CreateCSAKeyPayload:["CSAKeyExistsError","CreateCSAKeySuccess"],CreateFeedsManagerChainConfigPayload:["CreateFeedsManagerChainConfigSuccess","InputErrors","NotFoundError"],CreateFeedsManagerPayload:["CreateFeedsManagerSuccess","InputErrors","NotFoundError","SingleFeedsManagerError"],CreateJobPayload:["CreateJobSuccess","InputErrors"],CreateOCR2KeyBundlePayload:["CreateOCR2KeyBundleSuccess"],CreateOCRKeyBundlePayload:["CreateOCRKeyBundleSuccess"],CreateP2PKeyPayload:["CreateP2PKeySuccess"],DeleteAPITokenPayload:["DeleteAPITokenSuccess","InputErrors"],DeleteBridgePayload:["DeleteBridgeConflictError","DeleteBridgeInvalidNameError","DeleteBridgeSuccess","NotFoundError"],DeleteCSAKeyPayload:["DeleteCSAKeySuccess","NotFoundError"],DeleteFeedsManagerChainConfigPayload:["DeleteFeedsManagerChainConfigSuccess","NotFoundError"],DeleteJobPayload:["DeleteJobSuccess","NotFoundError"],DeleteOCR2KeyBundlePayload:["DeleteOCR2KeyBundleSuccess","NotFoundError"],DeleteOCRKeyBundlePayload:["DeleteOCRKeyBundleSuccess","NotFoundError"],DeleteP2PKeyPayload:["DeleteP2PKeySuccess","NotFoundError"],DeleteVRFKeyPayload:["DeleteVRFKeySuccess","NotFoundError"],DismissJobErrorPayload:["DismissJobErrorSuccess","NotFoundError"],Error:["CSAKeyExistsError","DeleteBridgeConflictError","DeleteBridgeInvalidNameError","InputError","JobAlreadyExistsError","NotFoundError","RunJobCannotRunError","SingleFeedsManagerError"],EthTransactionPayload:["EthTransaction","NotFoundError"],FeaturesPayload:["Features"],FeedsManagerPayload:["FeedsManager","NotFoundError"],GetSQLLoggingPayload:["SQLLogging"],GlobalLogLevelPayload:["GlobalLogLevel"],JobPayload:["Job","NotFoundError"],JobProposalPayload:["JobProposal","NotFoundError"],JobRunPayload:["JobRun","NotFoundError"],JobSpec:["BlockHeaderFeederSpec","BlockhashStoreSpec","BootstrapSpec","CronSpec","DirectRequestSpec","FluxMonitorSpec","GatewaySpec","KeeperSpec","OCR2Spec","OCRSpec","VRFSpec","WebhookSpec"],NodePayload:["Node","NotFoundError"],PaginatedPayload:["BridgesPayload","ChainsPayload","EthTransactionAttemptsPayload","EthTransactionsPayload","JobRunsPayload","JobsPayload","NodesPayload"],RejectJobProposalSpecPayload:["NotFoundError","RejectJobProposalSpecSuccess"],RunJobPayload:["NotFoundError","RunJobCannotRunError","RunJobSuccess"],SetGlobalLogLevelPayload:["InputErrors","SetGlobalLogLevelSuccess"],SetSQLLoggingPayload:["SetSQLLoggingSuccess"],SetServicesLogLevelsPayload:["InputErrors","SetServicesLogLevelsSuccess"],UpdateBridgePayload:["NotFoundError","UpdateBridgeSuccess"],UpdateFeedsManagerChainConfigPayload:["InputErrors","NotFoundError","UpdateFeedsManagerChainConfigSuccess"],UpdateFeedsManagerPayload:["InputErrors","NotFoundError","UpdateFeedsManagerSuccess"],UpdateJobProposalSpecDefinitionPayload:["NotFoundError","UpdateJobProposalSpecDefinitionSuccess"],UpdatePasswordPayload:["InputErrors","UpdatePasswordSuccess"],VRFKeyPayload:["NotFoundError","VRFKeySuccess"]}};let ai=ar;var aa=(r=void 0,location.origin),ao=new nh({uri:"".concat(aa,"/query"),credentials:"include"}),as=new ia({cache:new an({possibleTypes:ai.possibleTypes}),link:ao});if(a.Z.locale(o),u().defaultFormat="YYYY-MM-DD h:mm:ss A","undefined"!=typeof document){var au,ac,al=f().hydrate;ac=X,al(c.createElement(et,{client:as},c.createElement(d.zj,null,c.createElement(i.MuiThemeProvider,{theme:J.r},c.createElement(ac,null)))),document.getElementById("root"))}})()})(); \ No newline at end of file +`+(a!==i?`result of cast: ${a}`:""))}return r}_cast(e,t){let n=void 0===e?e:this.transforms.reduce((t,n)=>n.call(this,t,e,this),e);return void 0===n&&(n=this.getDefault()),n}_validate(e,t={},n){let{sync:r,path:i,from:a=[],originalValue:o=e,strict:s=this.spec.strict,abortEarly:u=this.spec.abortEarly}=t,c=e;s||(c=this._cast(c,pU({assert:!1},t)));let l={value:c,path:i,options:t,originalValue:o,schema:this,label:this.spec.label,sync:r,from:a},f=[];this._typeError&&f.push(this._typeError),this._whitelistError&&f.push(this._whitelistError),this._blacklistError&&f.push(this._blacklistError),pA({args:l,value:c,path:i,sync:r,tests:f,endEarly:u},e=>{if(e)return void n(e,c);pA({tests:this.tests,args:l,path:i,sync:r,value:c,endEarly:u},n)})}validate(e,t,n){let r=this.resolve(pU({},t,{value:e}));return"function"==typeof n?r._validate(e,t,n):new Promise((n,i)=>r._validate(e,t,(e,t)=>{e?i(e):n(t)}))}validateSync(e,t){let n;return this.resolve(pU({},t,{value:e}))._validate(e,pU({},t,{sync:!0}),(e,t)=>{if(e)throw e;n=t}),n}isValid(e,t){return this.validate(e,t).then(()=>!0,e=>{if(pM.isError(e))return!1;throw e})}isValidSync(e,t){try{return this.validateSync(e,t),!0}catch(n){if(pM.isError(n))return!1;throw n}}_getDefault(){let e=this.spec.default;return null==e?e:"function"==typeof e?e.call(this):pr(e)}getDefault(e){return this.resolve(e||{})._getDefault()}default(e){return 0===arguments.length?this._getDefault():this.clone({default:e})}strict(e=!0){var t=this.clone();return t.spec.strict=e,t}_isPresent(e){return null!=e}defined(e=pd.defined){return this.test({message:e,name:"defined",exclusive:!0,test:e=>void 0!==e})}required(e=pd.required){return this.clone({presence:"required"}).withMutation(t=>t.test({message:e,name:"required",exclusive:!0,test(e){return this.schema._isPresent(e)}}))}notRequired(){var e=this.clone({presence:"optional"});return e.tests=e.tests.filter(e=>"required"!==e.OPTIONS.name),e}nullable(e=!0){return this.clone({nullable:!1!==e})}transform(e){var t=this.clone();return t.transforms.push(e),t}test(...e){let t;if(void 0===(t=1===e.length?"function"==typeof e[0]?{test:e[0]}:e[0]:2===e.length?{name:e[0],test:e[1]}:{name:e[0],message:e[1],test:e[2]}).message&&(t.message=pd.default),"function"!=typeof t.test)throw TypeError("`test` is a required parameters");let n=this.clone(),r=pj(t),i=t.exclusive||t.name&&!0===n.exclusiveTests[t.name];if(t.exclusive&&!t.name)throw TypeError("Exclusive tests must provide a unique `name` identifying the test");return t.name&&(n.exclusiveTests[t.name]=!!t.exclusive),n.tests=n.tests.filter(e=>e.OPTIONS.name!==t.name||!i&&e.OPTIONS.test!==r.OPTIONS.test),n.tests.push(r),n}when(e,t){Array.isArray(e)||"string"==typeof e||(t=e,e=".");let n=this.clone(),r=pk(e).map(e=>new pN(e));return r.forEach(e=>{e.isSibling&&n.deps.push(e.key)}),n.conditions.push(new pS(r,t)),n}typeError(e){var t=this.clone();return t._typeError=pj({message:e,name:"typeError",test(e){return!!(void 0===e||this.schema.isType(e))||this.createError({params:{type:this.schema._type}})}}),t}oneOf(e,t=pd.oneOf){var n=this.clone();return e.forEach(e=>{n._whitelist.add(e),n._blacklist.delete(e)}),n._whitelistError=pj({message:t,name:"oneOf",test(e){if(void 0===e)return!0;let t=this.schema._whitelist;return!!t.has(e,this.resolve)||this.createError({params:{values:t.toArray().join(", ")}})}}),n}notOneOf(e,t=pd.notOneOf){var n=this.clone();return e.forEach(e=>{n._blacklist.add(e),n._whitelist.delete(e)}),n._blacklistError=pj({message:t,name:"notOneOf",test(e){let t=this.schema._blacklist;return!t.has(e,this.resolve)||this.createError({params:{values:t.toArray().join(", ")}})}}),n}strip(e=!0){let t=this.clone();return t.spec.strip=e,t}describe(){let e=this.clone(),{label:t,meta:n}=e.spec,r={meta:n,label:t,type:e.type,oneOf:e._whitelist.describe(),notOneOf:e._blacklist.describe(),tests:e.tests.map(e=>({name:e.OPTIONS.name,params:e.OPTIONS.params})).filter((e,t,n)=>n.findIndex(t=>t.name===e.name)===t)};return r}}for(let p$ of(pH.prototype.__isYupSchema__=!0,["validate","validateSync"]))pH.prototype[`${p$}At`]=function(e,t,n={}){let{parent:r,parentPath:i,schema:a}=pY(this,e,t,n.context);return a[p$](r&&r[i],pU({},n,{parent:r,path:e}))};for(let pz of["equals","is"])pH.prototype[pz]=pH.prototype.oneOf;for(let pG of["not","nope"])pH.prototype[pG]=pH.prototype.notOneOf;pH.prototype.optional=pH.prototype.notRequired;let pW=pH;function pK(){return new pW}pK.prototype=pW.prototype;let pV=e=>null==e;function pq(){return new pZ}class pZ extends pH{constructor(){super({type:"boolean"}),this.withMutation(()=>{this.transform(function(e){if(!this.isType(e)){if(/^(true|1)$/i.test(String(e)))return!0;if(/^(false|0)$/i.test(String(e)))return!1}return e})})}_typeCheck(e){return e instanceof Boolean&&(e=e.valueOf()),"boolean"==typeof e}isTrue(e=pm.isValue){return this.test({message:e,name:"is-value",exclusive:!0,params:{value:"true"},test:e=>pV(e)||!0===e})}isFalse(e=pm.isValue){return this.test({message:e,name:"is-value",exclusive:!0,params:{value:"false"},test:e=>pV(e)||!1===e})}}pq.prototype=pZ.prototype;let pX=/^((([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+(\.([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+)*)|((\x22)((((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(([\x01-\x08\x0b\x0c\x0e-\x1f\x7f]|\x21|[\x23-\x5b]|[\x5d-\x7e]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(\\([\x01-\x09\x0b\x0c\x0d-\x7f]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]))))*(((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(\x22)))@((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))$/i,pJ=/^((https?|ftp):)?\/\/(((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:)*@)?(((\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5]))|((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.?)(:\d*)?)(\/((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)+(\/(([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)*)*)?)?(\?((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|[\uE000-\uF8FF]|\/|\?)*)?(\#((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|\/|\?)*)?$/i,pQ=/^(?:[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}|00000000-0000-0000-0000-000000000000)$/i,p1=e=>pV(e)||e===e.trim(),p0=({}).toString();function p2(){return new p3}class p3 extends pH{constructor(){super({type:"string"}),this.withMutation(()=>{this.transform(function(e){if(this.isType(e)||Array.isArray(e))return e;let t=null!=e&&e.toString?e.toString():e;return t===p0?e:t})})}_typeCheck(e){return e instanceof String&&(e=e.valueOf()),"string"==typeof e}_isPresent(e){return super._isPresent(e)&&!!e.length}length(e,t=ph.length){return this.test({message:t,name:"length",exclusive:!0,params:{length:e},test(t){return pV(t)||t.length===this.resolve(e)}})}min(e,t=ph.min){return this.test({message:t,name:"min",exclusive:!0,params:{min:e},test(t){return pV(t)||t.length>=this.resolve(e)}})}max(e,t=ph.max){return this.test({name:"max",exclusive:!0,message:t,params:{max:e},test(t){return pV(t)||t.length<=this.resolve(e)}})}matches(e,t){let n=!1,r,i;return t&&("object"==typeof t?{excludeEmptyString:n=!1,message:r,name:i}=t:r=t),this.test({name:i||"matches",message:r||ph.matches,params:{regex:e},test:t=>pV(t)||""===t&&n||-1!==t.search(e)})}email(e=ph.email){return this.matches(pX,{name:"email",message:e,excludeEmptyString:!0})}url(e=ph.url){return this.matches(pJ,{name:"url",message:e,excludeEmptyString:!0})}uuid(e=ph.uuid){return this.matches(pQ,{name:"uuid",message:e,excludeEmptyString:!1})}ensure(){return this.default("").transform(e=>null===e?"":e)}trim(e=ph.trim){return this.transform(e=>null!=e?e.trim():e).test({message:e,name:"trim",test:p1})}lowercase(e=ph.lowercase){return this.transform(e=>pV(e)?e:e.toLowerCase()).test({message:e,name:"string_case",exclusive:!0,test:e=>pV(e)||e===e.toLowerCase()})}uppercase(e=ph.uppercase){return this.transform(e=>pV(e)?e:e.toUpperCase()).test({message:e,name:"string_case",exclusive:!0,test:e=>pV(e)||e===e.toUpperCase()})}}p2.prototype=p3.prototype;let p4=e=>e!=+e;function p5(){return new p6}class p6 extends pH{constructor(){super({type:"number"}),this.withMutation(()=>{this.transform(function(e){let t=e;if("string"==typeof t){if(""===(t=t.replace(/\s/g,"")))return NaN;t=+t}return this.isType(t)?t:parseFloat(t)})})}_typeCheck(e){return e instanceof Number&&(e=e.valueOf()),"number"==typeof e&&!p4(e)}min(e,t=pp.min){return this.test({message:t,name:"min",exclusive:!0,params:{min:e},test(t){return pV(t)||t>=this.resolve(e)}})}max(e,t=pp.max){return this.test({message:t,name:"max",exclusive:!0,params:{max:e},test(t){return pV(t)||t<=this.resolve(e)}})}lessThan(e,t=pp.lessThan){return this.test({message:t,name:"max",exclusive:!0,params:{less:e},test(t){return pV(t)||tthis.resolve(e)}})}positive(e=pp.positive){return this.moreThan(0,e)}negative(e=pp.negative){return this.lessThan(0,e)}integer(e=pp.integer){return this.test({name:"integer",message:e,test:e=>pV(e)||Number.isInteger(e)})}truncate(){return this.transform(e=>pV(e)?e:0|e)}round(e){var t,n=["ceil","floor","round","trunc"];if("trunc"===(e=(null==(t=e)?void 0:t.toLowerCase())||"round"))return this.truncate();if(-1===n.indexOf(e.toLowerCase()))throw TypeError("Only valid options for round() are: "+n.join(", "));return this.transform(t=>pV(t)?t:Math[e](t))}}p5.prototype=p6.prototype;var p9=/^(\d{4}|[+\-]\d{6})(?:-?(\d{2})(?:-?(\d{2}))?)?(?:[ T]?(\d{2}):?(\d{2})(?::?(\d{2})(?:[,\.](\d{1,}))?)?(?:(Z)|([+\-])(\d{2})(?::?(\d{2}))?)?)?$/;function p8(e){var t,n,r=[1,4,5,6,7,10,11],i=0;if(n=p9.exec(e)){for(var a,o=0;a=r[o];++o)n[a]=+n[a]||0;n[2]=(+n[2]||1)-1,n[3]=+n[3]||1,n[7]=n[7]?String(n[7]).substr(0,3):0,(void 0===n[8]||""===n[8])&&(void 0===n[9]||""===n[9])?t=+new Date(n[1],n[2],n[3],n[4],n[5],n[6],n[7]):("Z"!==n[8]&&void 0!==n[9]&&(i=60*n[10]+n[11],"+"===n[9]&&(i=0-i)),t=Date.UTC(n[1],n[2],n[3],n[4],n[5]+i,n[6],n[7]))}else t=Date.parse?Date.parse(e):NaN;return t}let p7=new Date(""),be=e=>"[object Date]"===Object.prototype.toString.call(e);function bt(){return new bn}class bn extends pH{constructor(){super({type:"date"}),this.withMutation(()=>{this.transform(function(e){return this.isType(e)?e:(e=p8(e),isNaN(e)?p7:new Date(e))})})}_typeCheck(e){return be(e)&&!isNaN(e.getTime())}prepareParam(e,t){let n;if(pN.isRef(e))n=e;else{let r=this.cast(e);if(!this._typeCheck(r))throw TypeError(`\`${t}\` must be a Date or a value that can be \`cast()\` to a Date`);n=r}return n}min(e,t=pb.min){let n=this.prepareParam(e,"min");return this.test({message:t,name:"min",exclusive:!0,params:{min:e},test(e){return pV(e)||e>=this.resolve(n)}})}max(e,t=pb.max){var n=this.prepareParam(e,"max");return this.test({message:t,name:"max",exclusive:!0,params:{max:e},test(e){return pV(e)||e<=this.resolve(n)}})}}bn.INVALID_DATE=p7,bt.prototype=bn.prototype,bt.INVALID_DATE=p7;var br=n(11865),bi=n.n(br),ba=n(68929),bo=n.n(ba),bs=n(67523),bu=n.n(bs),bc=n(94633),bl=n.n(bc);function bf(e,t=[]){let n=[],r=[];function i(e,i){var a=(0,pI.split)(e)[0];~r.indexOf(a)||r.push(a),~t.indexOf(`${i}-${a}`)||n.push([i,a])}for(let a in e)if(pw()(e,a)){let o=e[a];~r.indexOf(a)||r.push(a),pN.isRef(o)&&o.isSibling?i(o.path,a):p_(o)&&"deps"in o&&o.deps.forEach(e=>i(e,a))}return bl().array(r,n).reverse()}function bd(e,t){let n=1/0;return e.some((e,r)=>{var i;if((null==(i=t.path)?void 0:i.indexOf(e))!==-1)return n=r,!0}),n}function bh(e){return(t,n)=>bd(e,t)-bd(e,n)}function bp(){return(bp=Object.assign||function(e){for(var t=1;t"[object Object]"===Object.prototype.toString.call(e);function bm(e,t){let n=Object.keys(e.fields);return Object.keys(t).filter(e=>-1===n.indexOf(e))}let bg=bh([]);class bv extends pH{constructor(e){super({type:"object"}),this.fields=Object.create(null),this._sortErrors=bg,this._nodes=[],this._excludedEdges=[],this.withMutation(()=>{this.transform(function(e){if("string"==typeof e)try{e=JSON.parse(e)}catch(t){e=null}return this.isType(e)?e:null}),e&&this.shape(e)})}_typeCheck(e){return bb(e)||"function"==typeof e}_cast(e,t={}){var n;let r=super._cast(e,t);if(void 0===r)return this.getDefault();if(!this._typeCheck(r))return r;let i=this.fields,a=null!=(n=t.stripUnknown)?n:this.spec.noUnknown,o=this._nodes.concat(Object.keys(r).filter(e=>-1===this._nodes.indexOf(e))),s={},u=bp({},t,{parent:s,__validating:t.__validating||!1}),c=!1;for(let l of o){let f=i[l],d=pw()(r,l);if(f){let h,p=r[l];u.path=(t.path?`${t.path}.`:"")+l;let b="spec"in(f=f.resolve({value:p,context:t.context,parent:s}))?f.spec:void 0,m=null==b?void 0:b.strict;if(null==b?void 0:b.strip){c=c||l in r;continue}void 0!==(h=t.__validating&&m?r[l]:f.cast(r[l],u))&&(s[l]=h)}else d&&!a&&(s[l]=r[l]);s[l]!==r[l]&&(c=!0)}return c?s:r}_validate(e,t={},n){let r=[],{sync:i,from:a=[],originalValue:o=e,abortEarly:s=this.spec.abortEarly,recursive:u=this.spec.recursive}=t;a=[{schema:this,value:o},...a],t.__validating=!0,t.originalValue=o,t.from=a,super._validate(e,t,(e,c)=>{if(e){if(!pM.isError(e)||s)return void n(e,c);r.push(e)}if(!u||!bb(c)){n(r[0]||null,c);return}o=o||c;let l=this._nodes.map(e=>(n,r)=>{let i=-1===e.indexOf(".")?(t.path?`${t.path}.`:"")+e:`${t.path||""}["${e}"]`,s=this.fields[e];if(s&&"validate"in s){s.validate(c[e],bp({},t,{path:i,from:a,strict:!0,parent:c,originalValue:o[e]}),r);return}r(null)});pA({sync:i,tests:l,value:c,errors:r,endEarly:s,sort:this._sortErrors,path:t.path},n)})}clone(e){let t=super.clone(e);return t.fields=bp({},this.fields),t._nodes=this._nodes,t._excludedEdges=this._excludedEdges,t._sortErrors=this._sortErrors,t}concat(e){let t=super.concat(e),n=t.fields;for(let[r,i]of Object.entries(this.fields)){let a=n[r];void 0===a?n[r]=i:a instanceof pH&&i instanceof pH&&(n[r]=i.concat(a))}return t.withMutation(()=>t.shape(n))}getDefaultFromShape(){let e={};return this._nodes.forEach(t=>{let n=this.fields[t];e[t]="default"in n?n.getDefault():void 0}),e}_getDefault(){return"default"in this.spec?super._getDefault():this._nodes.length?this.getDefaultFromShape():void 0}shape(e,t=[]){let n=this.clone(),r=Object.assign(n.fields,e);if(n.fields=r,n._sortErrors=bh(Object.keys(r)),t.length){Array.isArray(t[0])||(t=[t]);let i=t.map(([e,t])=>`${e}-${t}`);n._excludedEdges=n._excludedEdges.concat(i)}return n._nodes=bf(r,n._excludedEdges),n}pick(e){let t={};for(let n of e)this.fields[n]&&(t[n]=this.fields[n]);return this.clone().withMutation(e=>(e.fields={},e.shape(t)))}omit(e){let t=this.clone(),n=t.fields;for(let r of(t.fields={},e))delete n[r];return t.withMutation(()=>t.shape(n))}from(e,t,n){let r=(0,pI.getter)(e,!0);return this.transform(i=>{if(null==i)return i;let a=i;return pw()(i,e)&&(a=bp({},i),n||delete a[e],a[t]=r(i)),a})}noUnknown(e=!0,t=pg.noUnknown){"string"==typeof e&&(t=e,e=!0);let n=this.test({name:"noUnknown",exclusive:!0,message:t,test(t){if(null==t)return!0;let n=bm(this.schema,t);return!e||0===n.length||this.createError({params:{unknown:n.join(", ")}})}});return n.spec.noUnknown=e,n}unknown(e=!0,t=pg.noUnknown){return this.noUnknown(!e,t)}transformKeys(e){return this.transform(t=>t&&bu()(t,(t,n)=>e(n)))}camelCase(){return this.transformKeys(bo())}snakeCase(){return this.transformKeys(bi())}constantCase(){return this.transformKeys(e=>bi()(e).toUpperCase())}describe(){let e=super.describe();return e.fields=pC()(this.fields,e=>e.describe()),e}}function by(e){return new bv(e)}function bw(){return(bw=Object.assign||function(e){for(var t=1;t{this.transform(function(e){if("string"==typeof e)try{e=JSON.parse(e)}catch(t){e=null}return this.isType(e)?e:null})})}_typeCheck(e){return Array.isArray(e)}get _subType(){return this.innerType}_cast(e,t){let n=super._cast(e,t);if(!this._typeCheck(n)||!this.innerType)return n;let r=!1,i=n.map((e,n)=>{let i=this.innerType.cast(e,bw({},t,{path:`${t.path||""}[${n}]`}));return i!==e&&(r=!0),i});return r?i:n}_validate(e,t={},n){var r,i;let a=[],o=t.sync,s=t.path,u=this.innerType,c=null!=(r=t.abortEarly)?r:this.spec.abortEarly,l=null!=(i=t.recursive)?i:this.spec.recursive,f=null!=t.originalValue?t.originalValue:e;super._validate(e,t,(e,r)=>{if(e){if(!pM.isError(e)||c)return void n(e,r);a.push(e)}if(!l||!u||!this._typeCheck(r)){n(a[0]||null,r);return}f=f||r;let i=Array(r.length);for(let d=0;du.validate(h,b,t)}pA({sync:o,path:s,value:r,errors:a,endEarly:c,tests:i},n)})}clone(e){let t=super.clone(e);return t.innerType=this.innerType,t}concat(e){let t=super.concat(e);return t.innerType=this.innerType,e.innerType&&(t.innerType=t.innerType?t.innerType.concat(e.innerType):e.innerType),t}of(e){let t=this.clone();if(!p_(e))throw TypeError("`array.of()` sub-schema must be a valid yup schema not: "+pf(e));return t.innerType=e,t}length(e,t=pv.length){return this.test({message:t,name:"length",exclusive:!0,params:{length:e},test(t){return pV(t)||t.length===this.resolve(e)}})}min(e,t){return t=t||pv.min,this.test({message:t,name:"min",exclusive:!0,params:{min:e},test(t){return pV(t)||t.length>=this.resolve(e)}})}max(e,t){return t=t||pv.max,this.test({message:t,name:"max",exclusive:!0,params:{max:e},test(t){return pV(t)||t.length<=this.resolve(e)}})}ensure(){return this.default(()=>[]).transform((e,t)=>this._typeCheck(e)?e:null==t?[]:[].concat(t))}compact(e){let t=e?(t,n,r)=>!e(t,n,r):e=>!!e;return this.transform(e=>null!=e?e.filter(t):e)}describe(){let e=super.describe();return this.innerType&&(e.innerType=this.innerType.describe()),e}nullable(e=!0){return super.nullable(e)}defined(){return super.defined()}required(e){return super.required(e)}}b_.prototype=bE.prototype;var bS=by().shape({name:p2().required("Required"),url:p2().required("Required")}),bk=function(e){var t=e.initialValues,n=e.onSubmit,r=e.submitButtonText,i=e.nameDisabled,a=void 0!==i&&i;return l.createElement(hM,{initialValues:t,validationSchema:bS,onSubmit:n},function(e){var t=e.isSubmitting;return l.createElement(l.Fragment,null,l.createElement(hj,{"data-testid":"bridge-form",noValidate:!0},l.createElement(d.Z,{container:!0,spacing:16},l.createElement(d.Z,{item:!0,xs:12,md:7},l.createElement(hR,{component:hJ,id:"name",name:"name",label:"Name",disabled:a,required:!0,fullWidth:!0,FormHelperTextProps:{"data-testid":"name-helper-text"}})),l.createElement(d.Z,{item:!0,xs:12,md:7},l.createElement(hR,{component:hJ,id:"url",name:"url",label:"Bridge URL",placeholder:"https://",required:!0,fullWidth:!0,FormHelperTextProps:{"data-testid":"url-helper-text"}})),l.createElement(d.Z,{item:!0,xs:12,md:7},l.createElement(d.Z,{container:!0,spacing:16},l.createElement(d.Z,{item:!0,xs:7},l.createElement(hR,{component:hJ,id:"minimumContractPayment",name:"minimumContractPayment",label:"Minimum Contract Payment",placeholder:"0",fullWidth:!0,inputProps:{min:0},FormHelperTextProps:{"data-testid":"minimumContractPayment-helper-text"}})),l.createElement(d.Z,{item:!0,xs:7},l.createElement(hR,{component:hJ,id:"confirmations",name:"confirmations",label:"Confirmations",placeholder:"0",type:"number",fullWidth:!0,inputProps:{min:0},FormHelperTextProps:{"data-testid":"confirmations-helper-text"}})))),l.createElement(d.Z,{item:!0,xs:12,md:7},l.createElement(ox.default,{variant:"contained",color:"primary",type:"submit",disabled:t,size:"large"},r)))))})},bx=function(e){var t=e.bridge,n=e.onSubmit,r={name:t.name,url:t.url,minimumContractPayment:t.minimumContractPayment,confirmations:t.confirmations};return l.createElement(iv,null,l.createElement(d.Z,{container:!0,spacing:40},l.createElement(d.Z,{item:!0,xs:12,md:11,lg:9},l.createElement(r9.Z,null,l.createElement(sf.Z,{title:"Edit Bridge",action:l.createElement(aL.Z,{component:tz,href:"/bridges/".concat(t.id)},"Cancel")}),l.createElement(aK.Z,null,l.createElement(bk,{nameDisabled:!0,initialValues:r,onSubmit:n,submitButtonText:"Save Bridge"}))))))};function bT(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&i[i.length-1])&&(6===a[0]||2===a[0])){o=0;continue}if(3===a[0]&&(!i||a[1]>i[0]&&a[1]e.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&i[i.length-1])&&(6===a[0]||2===a[0])){o=0;continue}if(3===a[0]&&(!i||a[1]>i[0]&&a[1]e.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&void 0!==arguments[0]&&arguments[0],t=e?function(){return l.createElement(x.default,{variant:"body1"},"Loading...")}:function(){return null};return{isLoading:e,LoadingPlaceholder:t}},ml=n(76023);function mf(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&i[i.length-1])&&(6===a[0]||2===a[0])){o=0;continue}if(3===a[0]&&(!i||a[1]>i[0]&&a[1]e.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&i[i.length-1])&&(6===a[0]||2===a[0])){o=0;continue}if(3===a[0]&&(!i||a[1]>i[0]&&a[1]=0||(i[n]=e[n]);return i}function mB(e,t){if(null==e)return{};var n,r,i=mY(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(r=0;r=0)&&Object.prototype.propertyIsEnumerable.call(e,n)&&(i[n]=e[n])}return i}function mU(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=Array(t);n=4?[e[0],e[1],e[2],e[3],"".concat(e[0],".").concat(e[1]),"".concat(e[0],".").concat(e[2]),"".concat(e[0],".").concat(e[3]),"".concat(e[1],".").concat(e[0]),"".concat(e[1],".").concat(e[2]),"".concat(e[1],".").concat(e[3]),"".concat(e[2],".").concat(e[0]),"".concat(e[2],".").concat(e[1]),"".concat(e[2],".").concat(e[3]),"".concat(e[3],".").concat(e[0]),"".concat(e[3],".").concat(e[1]),"".concat(e[3],".").concat(e[2]),"".concat(e[0],".").concat(e[1],".").concat(e[2]),"".concat(e[0],".").concat(e[1],".").concat(e[3]),"".concat(e[0],".").concat(e[2],".").concat(e[1]),"".concat(e[0],".").concat(e[2],".").concat(e[3]),"".concat(e[0],".").concat(e[3],".").concat(e[1]),"".concat(e[0],".").concat(e[3],".").concat(e[2]),"".concat(e[1],".").concat(e[0],".").concat(e[2]),"".concat(e[1],".").concat(e[0],".").concat(e[3]),"".concat(e[1],".").concat(e[2],".").concat(e[0]),"".concat(e[1],".").concat(e[2],".").concat(e[3]),"".concat(e[1],".").concat(e[3],".").concat(e[0]),"".concat(e[1],".").concat(e[3],".").concat(e[2]),"".concat(e[2],".").concat(e[0],".").concat(e[1]),"".concat(e[2],".").concat(e[0],".").concat(e[3]),"".concat(e[2],".").concat(e[1],".").concat(e[0]),"".concat(e[2],".").concat(e[1],".").concat(e[3]),"".concat(e[2],".").concat(e[3],".").concat(e[0]),"".concat(e[2],".").concat(e[3],".").concat(e[1]),"".concat(e[3],".").concat(e[0],".").concat(e[1]),"".concat(e[3],".").concat(e[0],".").concat(e[2]),"".concat(e[3],".").concat(e[1],".").concat(e[0]),"".concat(e[3],".").concat(e[1],".").concat(e[2]),"".concat(e[3],".").concat(e[2],".").concat(e[0]),"".concat(e[3],".").concat(e[2],".").concat(e[1]),"".concat(e[0],".").concat(e[1],".").concat(e[2],".").concat(e[3]),"".concat(e[0],".").concat(e[1],".").concat(e[3],".").concat(e[2]),"".concat(e[0],".").concat(e[2],".").concat(e[1],".").concat(e[3]),"".concat(e[0],".").concat(e[2],".").concat(e[3],".").concat(e[1]),"".concat(e[0],".").concat(e[3],".").concat(e[1],".").concat(e[2]),"".concat(e[0],".").concat(e[3],".").concat(e[2],".").concat(e[1]),"".concat(e[1],".").concat(e[0],".").concat(e[2],".").concat(e[3]),"".concat(e[1],".").concat(e[0],".").concat(e[3],".").concat(e[2]),"".concat(e[1],".").concat(e[2],".").concat(e[0],".").concat(e[3]),"".concat(e[1],".").concat(e[2],".").concat(e[3],".").concat(e[0]),"".concat(e[1],".").concat(e[3],".").concat(e[0],".").concat(e[2]),"".concat(e[1],".").concat(e[3],".").concat(e[2],".").concat(e[0]),"".concat(e[2],".").concat(e[0],".").concat(e[1],".").concat(e[3]),"".concat(e[2],".").concat(e[0],".").concat(e[3],".").concat(e[1]),"".concat(e[2],".").concat(e[1],".").concat(e[0],".").concat(e[3]),"".concat(e[2],".").concat(e[1],".").concat(e[3],".").concat(e[0]),"".concat(e[2],".").concat(e[3],".").concat(e[0],".").concat(e[1]),"".concat(e[2],".").concat(e[3],".").concat(e[1],".").concat(e[0]),"".concat(e[3],".").concat(e[0],".").concat(e[1],".").concat(e[2]),"".concat(e[3],".").concat(e[0],".").concat(e[2],".").concat(e[1]),"".concat(e[3],".").concat(e[1],".").concat(e[0],".").concat(e[2]),"".concat(e[3],".").concat(e[1],".").concat(e[2],".").concat(e[0]),"".concat(e[3],".").concat(e[2],".").concat(e[0],".").concat(e[1]),"".concat(e[3],".").concat(e[2],".").concat(e[1],".").concat(e[0])]:void 0}var mX={};function mJ(e){if(0===e.length||1===e.length)return e;var t=e.join(".");return mX[t]||(mX[t]=mZ(e)),mX[t]}function mQ(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{},n=arguments.length>2?arguments[2]:void 0;return mJ(e.filter(function(e){return"token"!==e})).reduce(function(e,t){return mV({},e,n[t])},t)}function m1(e){return e.join(" ")}function m0(e,t){var n=0;return function(r){return n+=1,r.map(function(r,i){return m2({node:r,stylesheet:e,useInlineStyles:t,key:"code-segment-".concat(n,"-").concat(i)})})}}function m2(e){var t=e.node,n=e.stylesheet,r=e.style,i=void 0===r?{}:r,a=e.useInlineStyles,o=e.key,s=t.properties,u=t.type,c=t.tagName,f=t.value;if("text"===u)return f;if(c){var d,h=m0(n,a);if(a){var p=Object.keys(n).reduce(function(e,t){return t.split(".").forEach(function(t){e.includes(t)||e.push(t)}),e},[]),b=s.className&&s.className.includes("token")?["token"]:[],m=s.className&&b.concat(s.className.filter(function(e){return!p.includes(e)}));d=mV({},s,{className:m1(m)||void 0,style:mQ(s.className,Object.assign({},s.style,i),n)})}else d=mV({},s,{className:m1(s.className)});var g=h(t.children);return l.createElement(c,mq({key:o},d),g)}}let m3=function(e,t){return -1!==e.listLanguages().indexOf(t)};var m4=/\n/g;function m5(e){return e.match(m4)}function m6(e){var t=e.lines,n=e.startingLineNumber,r=e.style;return t.map(function(e,t){var i=t+n;return l.createElement("span",{key:"line-".concat(t),className:"react-syntax-highlighter-line-number",style:"function"==typeof r?r(i):r},"".concat(i,"\n"))})}function m9(e){var t=e.codeString,n=e.codeStyle,r=e.containerStyle,i=void 0===r?{float:"left",paddingRight:"10px"}:r,a=e.numberStyle,o=void 0===a?{}:a,s=e.startingLineNumber;return l.createElement("code",{style:Object.assign({},n,i)},m6({lines:t.replace(/\n$/,"").split("\n"),style:o,startingLineNumber:s}))}function m8(e){return"".concat(e.toString().length,".25em")}function m7(e,t){return{type:"element",tagName:"span",properties:{key:"line-number--".concat(e),className:["comment","linenumber","react-syntax-highlighter-line-number"],style:t},children:[{type:"text",value:e}]}}function ge(e,t,n){var r,i={display:"inline-block",minWidth:m8(n),paddingRight:"1em",textAlign:"right",userSelect:"none"};return mV({},i,"function"==typeof e?e(t):e)}function gt(e){var t=e.children,n=e.lineNumber,r=e.lineNumberStyle,i=e.largestLineNumber,a=e.showInlineLineNumbers,o=e.lineProps,s=void 0===o?{}:o,u=e.className,c=void 0===u?[]:u,l=e.showLineNumbers,f=e.wrapLongLines,d="function"==typeof s?s(n):s;if(d.className=c,n&&a){var h=ge(r,n,i);t.unshift(m7(n,h))}return f&l&&(d.style=mV({},d.style,{display:"flex"})),{type:"element",tagName:"span",properties:d,children:t}}function gn(e){for(var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:[],n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:[],r=0;r2&&void 0!==arguments[2]?arguments[2]:[];return gt({children:e,lineNumber:t,lineNumberStyle:s,largestLineNumber:o,showInlineLineNumbers:i,lineProps:n,className:a,showLineNumbers:r,wrapLongLines:u})}function b(e,t){if(r&&t&&i){var n=ge(s,t,o);e.unshift(m7(t,n))}return e}function m(e,n){var r=arguments.length>2&&void 0!==arguments[2]?arguments[2]:[];return t||r.length>0?p(e,n,r):b(e,n)}for(var g=function(){var e=l[h],t=e.children[0].value;if(m5(t)){var n=t.split("\n");n.forEach(function(t,i){var o=r&&f.length+a,s={type:"text",value:"".concat(t,"\n")};if(0===i){var u=l.slice(d+1,h).concat(gt({children:[s],className:e.properties.className})),c=m(u,o);f.push(c)}else if(i===n.length-1){if(l[h+1]&&l[h+1].children&&l[h+1].children[0]){var p={type:"text",value:"".concat(t)},b=gt({children:[p],className:e.properties.className});l.splice(h+1,0,b)}else{var g=[s],v=m(g,o,e.properties.className);f.push(v)}}else{var y=[s],w=m(y,o,e.properties.className);f.push(w)}}),d=h}h++};h code[class*="language-"]':{background:"#f5f2f0",padding:".1em",borderRadius:".3em",whiteSpace:"normal"},comment:{color:"slategray"},prolog:{color:"slategray"},doctype:{color:"slategray"},cdata:{color:"slategray"},punctuation:{color:"#999"},namespace:{Opacity:".7"},property:{color:"#905"},tag:{color:"#905"},boolean:{color:"#905"},number:{color:"#905"},constant:{color:"#905"},symbol:{color:"#905"},deleted:{color:"#905"},selector:{color:"#690"},"attr-name":{color:"#690"},string:{color:"#690"},char:{color:"#690"},builtin:{color:"#690"},inserted:{color:"#690"},operator:{color:"#9a6e3a",background:"hsla(0, 0%, 100%, .5)"},entity:{color:"#9a6e3a",background:"hsla(0, 0%, 100%, .5)",cursor:"help"},url:{color:"#9a6e3a",background:"hsla(0, 0%, 100%, .5)"},".language-css .token.string":{color:"#9a6e3a",background:"hsla(0, 0%, 100%, .5)"},".style .token.string":{color:"#9a6e3a",background:"hsla(0, 0%, 100%, .5)"},atrule:{color:"#07a"},"attr-value":{color:"#07a"},keyword:{color:"#07a"},function:{color:"#DD4A68"},"class-name":{color:"#DD4A68"},regex:{color:"#e90"},important:{color:"#e90",fontWeight:"bold"},variable:{color:"#e90"},bold:{fontWeight:"bold"},italic:{fontStyle:"italic"}};var gc=n(98695),gl=n.n(gc);let gf=["abap","abnf","actionscript","ada","agda","al","antlr4","apacheconf","apl","applescript","aql","arduino","arff","asciidoc","asm6502","aspnet","autohotkey","autoit","bash","basic","batch","bbcode","birb","bison","bnf","brainfuck","brightscript","bro","bsl","c","cil","clike","clojure","cmake","coffeescript","concurnas","cpp","crystal","csharp","csp","css-extras","css","cypher","d","dart","dax","dhall","diff","django","dns-zone-file","docker","ebnf","editorconfig","eiffel","ejs","elixir","elm","erb","erlang","etlua","excel-formula","factor","firestore-security-rules","flow","fortran","fsharp","ftl","gcode","gdscript","gedcom","gherkin","git","glsl","gml","go","graphql","groovy","haml","handlebars","haskell","haxe","hcl","hlsl","hpkp","hsts","http","ichigojam","icon","iecst","ignore","inform7","ini","io","j","java","javadoc","javadoclike","javascript","javastacktrace","jolie","jq","js-extras","js-templates","jsdoc","json","json5","jsonp","jsstacktrace","jsx","julia","keyman","kotlin","latex","latte","less","lilypond","liquid","lisp","livescript","llvm","lolcode","lua","makefile","markdown","markup-templating","markup","matlab","mel","mizar","mongodb","monkey","moonscript","n1ql","n4js","nand2tetris-hdl","naniscript","nasm","neon","nginx","nim","nix","nsis","objectivec","ocaml","opencl","oz","parigp","parser","pascal","pascaligo","pcaxis","peoplecode","perl","php-extras","php","phpdoc","plsql","powerquery","powershell","processing","prolog","properties","protobuf","pug","puppet","pure","purebasic","purescript","python","q","qml","qore","r","racket","reason","regex","renpy","rest","rip","roboconf","robotframework","ruby","rust","sas","sass","scala","scheme","scss","shell-session","smali","smalltalk","smarty","sml","solidity","solution-file","soy","sparql","splunk-spl","sqf","sql","stan","stylus","swift","t4-cs","t4-templating","t4-vb","tap","tcl","textile","toml","tsx","tt2","turtle","twig","typescript","typoscript","unrealscript","vala","vbnet","velocity","verilog","vhdl","vim","visual-basic","warpscript","wasm","wiki","xeora","xml-doc","xojo","xquery","yaml","yang","zig"];var gd=gs(gl(),gu);gd.supportedLanguages=gf;let gh=gd;var gp=n(64566);function gb(e,t){return t||(t=e.slice(0)),Object.freeze(Object.defineProperties(e,{raw:{value:Object.freeze(t)}}))}function gm(){var e=gb(["\n query FetchConfigV2 {\n configv2 {\n user\n effective\n }\n }\n"]);return gm=function(){return e},e}var gg=n0(gm()),gv=function(e){var t=e.children;return l.createElement(ii.Z,null,l.createElement(ie.default,{component:"th",scope:"row",colSpan:3},t))},gy=function(){return l.createElement(gv,null,"...")},gw=function(e){var t=e.children;return l.createElement(gv,null,t)},g_=function(e){var t=e.loading,n=e.toml,r=e.error,i=void 0===r?"":r,a=e.title,o=e.expanded;if(i)return l.createElement(gw,null,i);if(t)return l.createElement(gy,null);a||(a="TOML");var s={display:"block"};return l.createElement(x.default,null,l.createElement(mR.Z,{defaultExpanded:o},l.createElement(mj.Z,{expandIcon:l.createElement(gp.Z,null)},a),l.createElement(mF.Z,{style:s},l.createElement(gh,{language:"toml",style:gu},n))))},gE=function(){var e=ry(gg,{fetchPolicy:"cache-and-network"}),t=e.data,n=e.loading,r=e.error;return(null==t?void 0:t.configv2.effective)=="N/A"?l.createElement(l.Fragment,null,l.createElement(d.Z,{item:!0,xs:12},l.createElement(r9.Z,null,l.createElement(sf.Z,{title:"TOML Configuration"}),l.createElement(g_,{title:"V2 config dump:",error:null==r?void 0:r.message,loading:n,toml:null==t?void 0:t.configv2.user,showHead:!0})))):l.createElement(l.Fragment,null,l.createElement(d.Z,{container:!0},l.createElement(d.Z,{item:!0,xs:12},l.createElement(r9.Z,null,l.createElement(sf.Z,{title:"TOML Configuration"}),l.createElement(g_,{title:"User specified:",error:null==r?void 0:r.message,loading:n,toml:null==t?void 0:t.configv2.user,showHead:!0,expanded:!0}),l.createElement(g_,{title:"Effective (with defaults):",error:null==r?void 0:r.message,loading:n,toml:null==t?void 0:t.configv2.effective,showHead:!0})))))},gS=n(34823),gk=function(e){return(0,b.createStyles)({cell:{paddingTop:1.5*e.spacing.unit,paddingBottom:1.5*e.spacing.unit}})},gx=(0,b.withStyles)(gk)(function(e){var t=e.classes,n=(0,A.I0)();(0,l.useEffect)(function(){n((0,ty.DQ)())});var r=(0,A.v9)(gS.N,A.wU);return l.createElement(r9.Z,null,l.createElement(sf.Z,{title:"Node"}),l.createElement(r8.Z,null,l.createElement(r7.Z,null,l.createElement(ii.Z,null,l.createElement(ie.default,{className:t.cell},l.createElement(x.default,null,"Version"),l.createElement(x.default,{variant:"subtitle1",color:"textSecondary"},r.version))),l.createElement(ii.Z,null,l.createElement(ie.default,{className:t.cell},l.createElement(x.default,null,"SHA"),l.createElement(x.default,{variant:"subtitle1",color:"textSecondary"},r.commitSHA))))))}),gT=function(){return l.createElement(iv,null,l.createElement(d.Z,{container:!0},l.createElement(d.Z,{item:!0,sm:12,md:8},l.createElement(d.Z,{container:!0},l.createElement(gE,null))),l.createElement(d.Z,{item:!0,sm:12,md:4},l.createElement(d.Z,{container:!0},l.createElement(d.Z,{item:!0,xs:12},l.createElement(gx,null)),l.createElement(d.Z,{item:!0,xs:12},l.createElement(mP,null)),l.createElement(d.Z,{item:!0,xs:12},l.createElement(mS,null))))))},gM=function(){return l.createElement(gT,null)},gO=function(){return l.createElement(gM,null)},gA=n(44431),gL=1e18,gC=function(e){return new gA.BigNumber(e).dividedBy(gL).toFixed(8)},gI=function(e){var t=e.keys,n=e.chainID,r=e.hideHeaderTitle;return l.createElement(l.Fragment,null,l.createElement(sf.Z,{title:!r&&"Account Balances",subheader:"Chain ID "+n}),l.createElement(aK.Z,null,l.createElement(w.default,{dense:!1,disablePadding:!0},t&&t.map(function(e,r){return l.createElement(l.Fragment,null,l.createElement(_.default,{disableGutters:!0,key:["acc-balance",n.toString(),r.toString()].join("-")},l.createElement(E.Z,{primary:l.createElement(l.Fragment,null,l.createElement(d.Z,{container:!0,spacing:16},l.createElement(d.Z,{item:!0,xs:12},l.createElement(ob,{title:"Address"}),l.createElement(om,{value:e.address})),l.createElement(d.Z,{item:!0,xs:6},l.createElement(ob,{title:"Native Token Balance"}),l.createElement(om,{value:e.ethBalance||"--"})),l.createElement(d.Z,{item:!0,xs:6},l.createElement(ob,{title:"LINK Balance"}),l.createElement(om,{value:e.linkBalance?gC(e.linkBalance):"--"}))))})),r+1s&&l.createElement(gU.Z,null,l.createElement(ii.Z,null,l.createElement(ie.default,{className:r.footer},l.createElement(aL.Z,{href:"/runs",component:tz},"View More"))))))});function vn(e,t){return t||(t=e.slice(0)),Object.freeze(Object.defineProperties(e,{raw:{value:Object.freeze(t)}}))}function vr(){var e=vn(["\n ","\n query FetchRecentJobRuns($offset: Int, $limit: Int) {\n jobRuns(offset: $offset, limit: $limit) {\n results {\n ...RecentJobRunsPayload_ResultsFields\n }\n metadata {\n total\n }\n }\n }\n"]);return vr=function(){return e},e}var vi=5,va=n0(vr(),g7),vo=function(){var e=ry(va,{variables:{offset:0,limit:vi},fetchPolicy:"cache-and-network"}),t=e.data,n=e.loading,r=e.error;return l.createElement(vt,{data:t,errorMsg:null==r?void 0:r.message,loading:n,maxRunsSize:vi})},vs=function(e){return(0,b.createStyles)({style:{textAlign:"center",padding:2.5*e.spacing.unit,position:"fixed",left:"0",bottom:"0",width:"100%",borderRadius:0},bareAnchor:{color:e.palette.common.black,textDecoration:"none"}})},vu=(0,b.withStyles)(vs)(function(e){var t=e.classes,n=(0,A.v9)(gS.N,A.wU),r=(0,A.I0)();return(0,l.useEffect)(function(){r((0,ty.DQ)())}),l.createElement(ia.default,{className:t.style},l.createElement(x.default,null,"Chainlink Node ",n.version," at commit"," ",l.createElement("a",{target:"_blank",rel:"noopener noreferrer",href:"https://github.com/smartcontractkit/chainlink/commit/".concat(n.commitSHA),className:t.bareAnchor},n.commitSHA)))}),vc=function(e){return(0,b.createStyles)({cell:{borderColor:e.palette.divider,borderTop:"1px solid",borderBottom:"none",paddingTop:2*e.spacing.unit,paddingBottom:2*e.spacing.unit,paddingLeft:2*e.spacing.unit},block:{display:"block"},overflowEllipsis:{textOverflow:"ellipsis",overflow:"hidden"}})},vl=(0,b.withStyles)(vc)(function(e){var t=e.classes,n=e.job;return l.createElement(ii.Z,null,l.createElement(ie.default,{scope:"row",className:t.cell},l.createElement(d.Z,{container:!0,spacing:0},l.createElement(d.Z,{item:!0,xs:12},l.createElement(ip,{href:"/jobs/".concat(n.id),classes:{linkContent:t.block}},l.createElement(x.default,{className:t.overflowEllipsis,variant:"body1",component:"span",color:"primary"},n.name||n.id))),l.createElement(d.Z,{item:!0,xs:12},l.createElement(x.default,{variant:"body1",color:"textSecondary"},"Created ",l.createElement(aA,{tooltip:!0},n.createdAt))))))});function vf(e,t){return t||(t=e.slice(0)),Object.freeze(Object.defineProperties(e,{raw:{value:Object.freeze(t)}}))}function vd(){var e=vf(["\n fragment RecentJobsPayload_ResultsFields on Job {\n id\n name\n createdAt\n }\n"]);return vd=function(){return e},e}var vh=n0(vd()),vp=function(){return(0,b.createStyles)({cardHeader:{borderBottom:0},table:{tableLayout:"fixed"}})},vb=(0,b.withStyles)(vp)(function(e){var t,n,r=e.classes,i=e.data,a=e.errorMsg,o=e.loading;return l.createElement(r9.Z,null,l.createElement(sf.Z,{title:"Recent Jobs",className:r.cardHeader}),l.createElement(r8.Z,{className:r.table},l.createElement(r7.Z,null,l.createElement(gz,{visible:o}),l.createElement(gG,{visible:(null===(t=null==i?void 0:i.jobs.results)||void 0===t?void 0:t.length)===0},"No recently created jobs"),l.createElement(gH,{msg:a}),null===(n=null==i?void 0:i.jobs.results)||void 0===n?void 0:n.map(function(e,t){return l.createElement(vl,{job:e,key:t})}))))});function vm(e,t){return t||(t=e.slice(0)),Object.freeze(Object.defineProperties(e,{raw:{value:Object.freeze(t)}}))}function vg(){var e=vm(["\n ","\n query FetchRecentJobs($offset: Int, $limit: Int) {\n jobs(offset: $offset, limit: $limit) {\n results {\n ...RecentJobsPayload_ResultsFields\n }\n }\n }\n"]);return vg=function(){return e},e}var vv=5,vy=n0(vg(),vh),vw=function(){var e=ry(vy,{variables:{offset:0,limit:vv},fetchPolicy:"cache-and-network"}),t=e.data,n=e.loading,r=e.error;return l.createElement(vb,{data:t,errorMsg:null==r?void 0:r.message,loading:n})},v_=function(){return l.createElement(iv,null,l.createElement(d.Z,{container:!0},l.createElement(d.Z,{item:!0,xs:8},l.createElement(vo,null)),l.createElement(d.Z,{item:!0,xs:4},l.createElement(d.Z,{container:!0},l.createElement(d.Z,{item:!0,xs:12},l.createElement(gB,null)),l.createElement(d.Z,{item:!0,xs:12},l.createElement(vw,null))))),l.createElement(vu,null))},vE=function(){return l.createElement(v_,null)},vS=function(){return l.createElement(vE,null)},vk=n(87239),vx=function(e){switch(e){case"DirectRequestSpec":return"Direct Request";case"FluxMonitorSpec":return"Flux Monitor";default:return e.replace(/Spec$/,"")}},vT=n(5022),vM=n(78718),vO=n.n(vM);function vA(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=Array(t);n1?t-1:0),r=1;r1?t-1:0),r=1;re.length)&&(t=e.length);for(var n=0,r=Array(t);ne.length)&&(t=e.length);for(var n=0,r=Array(t);ne.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&n.map(function(e){return l.createElement(ii.Z,{key:e.id,style:{cursor:"pointer"},onClick:function(){return r.push("/runs/".concat(e.id))}},l.createElement(ie.default,{className:t.idCell,scope:"row"},l.createElement("div",{className:t.runDetails},l.createElement(x.default,{variant:"h5",color:"primary",component:"span"},e.id))),l.createElement(ie.default,{className:t.stampCell},l.createElement(x.default,{variant:"body1",color:"textSecondary",className:t.stamp},"Created ",l.createElement(aA,{tooltip:!0},e.createdAt))),l.createElement(ie.default,{className:t.statusCell,scope:"row"},l.createElement(x.default,{variant:"body1",className:O()(t.status,yp(t,e.status))},e.status.toLowerCase())))})))}),ym=n(16839),yg=n.n(ym);function yv(e){var t=e.replace(/\w+\s*=\s*<([^>]|[\r\n])*>/g,""),n=yg().read(t),r=n.edges();return n.nodes().map(function(e){var t={id:e,parentIds:r.filter(function(t){return t.w===e}).map(function(e){return e.v})};return Object.keys(n.node(e)).length>0&&(t.attributes=n.node(e)),t})}var yy=n(94164),yw=function(e){var t=e.data,n=[];return(null==t?void 0:t.attributes)&&Object.keys(t.attributes).forEach(function(e){var r;n.push(l.createElement("div",{key:e},l.createElement(x.default,{variant:"body1",color:"textSecondary",component:"div"},l.createElement("b",null,e,":")," ",null===(r=t.attributes)||void 0===r?void 0:r[e])))}),l.createElement("div",null,t&&l.createElement(x.default,{variant:"body1",color:"textPrimary"},l.createElement("b",null,t.id)),n)},y_=n(73343),yE=n(3379),yS=n.n(yE);function yk(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=Array(t);nwindow.innerWidth?u-r.getBoundingClientRect().width-a:u+a,n=c+r.getBoundingClientRect().height+i>window.innerHeight?c-r.getBoundingClientRect().height-a:c+a,r.style.opacity=String(1),r.style.top="".concat(n,"px"),r.style.left="".concat(t,"px"),r.style.zIndex=String(1)}},h=function(e){var t=document.getElementById("tooltip-d3-chart-".concat(e));t&&(t.style.opacity=String(0),t.style.zIndex=String(-1))};return l.createElement("div",{style:{fontFamily:"sans-serif",fontWeight:"normal"}},l.createElement(yy.kJ,{id:"task-list-graph-d3",data:i,config:s,onMouseOverNode:d,onMouseOutNode:h},"D3 chart"),n.map(function(e){return l.createElement("div",{key:"d3-tooltip-key-".concat(e.id),id:"tooltip-d3-chart-".concat(e.id),style:{position:"absolute",opacity:"0",border:"1px solid rgba(0, 0, 0, 0.1)",padding:y_.r.spacing.unit,background:"white",borderRadius:5,zIndex:-1,inlineSize:"min-content"}},l.createElement(yw,{data:e}))}))};function yC(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=Array(t);nyB&&l.createElement("div",{className:t.runDetails},l.createElement(aL.Z,{href:"/jobs/".concat(n.id,"/runs"),component:tz},"View more")))),l.createElement(d.Z,{item:!0,xs:12,sm:6},l.createElement(yY,{observationSource:n.observationSource})))});function y$(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=Array(t);ne.length)&&(t=e.length);for(var n=0,r=Array(t);ne.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&i[i.length-1])&&(6===a[0]||2===a[0])){o=0;continue}if(3===a[0]&&(!i||a[1]>i[0]&&a[1]e.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&void 0!==arguments[0]?arguments[0]:"";try{return vT.parse(e),!0}catch(t){return!1}})}),wK=function(e){var t=e.initialValues,n=e.onSubmit,r=e.onTOMLChange;return l.createElement(hM,{initialValues:t,validationSchema:wW,onSubmit:n},function(e){var t=e.isSubmitting,n=e.values;return r&&r(n.toml),l.createElement(hj,{"data-testid":"job-form",noValidate:!0},l.createElement(d.Z,{container:!0,spacing:16},l.createElement(d.Z,{item:!0,xs:12},l.createElement(hR,{component:hJ,id:"toml",name:"toml",label:"Job Spec (TOML)",required:!0,fullWidth:!0,multiline:!0,rows:10,rowsMax:25,variant:"outlined",autoComplete:"off",FormHelperTextProps:{"data-testid":"toml-helper-text"}})),l.createElement(d.Z,{item:!0,xs:12,md:7},l.createElement(ox.default,{variant:"contained",color:"primary",type:"submit",disabled:t,size:"large"},"Create Job"))))})},wV=n(50109),wq="persistSpec";function wZ(e){var t=e.query,n=new URLSearchParams(t).get("definition");return n?(wV.t8(wq,n),{toml:n}):{toml:wV.U2(wq)||""}}var wX=function(e){var t=e.onSubmit,n=e.onTOMLChange,r=wZ({query:(0,h.TH)().search}),i=function(e){var t=e.replace(/[\u200B-\u200D\uFEFF]/g,"");wV.t8("".concat(wq),t),n&&n(t)};return l.createElement(r9.Z,null,l.createElement(sf.Z,{title:"New Job"}),l.createElement(aK.Z,null,l.createElement(wK,{initialValues:r,onSubmit:t,onTOMLChange:i})))};function wJ(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=Array(t);ne.length)&&(t=e.length);for(var n=0,r=Array(t);ne.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&i[i.length-1])&&(6===a[0]||2===a[0])){o=0;continue}if(3===a[0]&&(!i||a[1]>i[0]&&a[1]e.length)&&(t=e.length);for(var n=0,r=Array(t);n1&&void 0!==arguments[1]?arguments[1]:{},n=t.start,r=void 0===n?6:n,i=t.end,a=void 0===i?4:i;return e.substring(0,r)+"..."+e.substring(e.length-a)}function _O(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&i[i.length-1])&&(6===a[0]||2===a[0])){o=0;continue}if(3===a[0]&&(!i||a[1]>i[0]&&a[1]0&&void 0!==arguments[0]?arguments[0]:{};return ry(_K,e)},_q=function(){var e=_V({fetchPolicy:"cache-and-network"}),t=e.data,n=e.loading,r=e.error,i=e.refetch;return l.createElement(_H,{loading:n,data:t,errorMsg:null==r?void 0:r.message,refetch:i})},_Z=function(e){var t=e.csaKey;return l.createElement(ii.Z,{hover:!0},l.createElement(ie.default,null,l.createElement(x.default,{variant:"body1"},t.publicKey," ",l.createElement(_T,{data:t.publicKey}))))};function _X(e,t){return t||(t=e.slice(0)),Object.freeze(Object.defineProperties(e,{raw:{value:Object.freeze(t)}}))}function _J(){var e=_X(["\n fragment CSAKeysPayload_ResultsFields on CSAKey {\n id\n publicKey\n }\n"]);return _J=function(){return e},e}var _Q=n0(_J()),_1=function(e){var t,n,r,i=e.data,a=e.errorMsg,o=e.loading,s=e.onCreate;return l.createElement(r9.Z,null,l.createElement(sf.Z,{action:(null===(t=null==i?void 0:i.csaKeys.results)||void 0===t?void 0:t.length)===0&&l.createElement(ox.default,{variant:"outlined",color:"primary",onClick:s},"New CSA Key"),title:"CSA Key",subheader:"Manage your CSA Key"}),l.createElement(r8.Z,null,l.createElement(it.Z,null,l.createElement(ii.Z,null,l.createElement(ie.default,null,"Public Key"))),l.createElement(r7.Z,null,l.createElement(gz,{visible:o}),l.createElement(gG,{visible:(null===(n=null==i?void 0:i.csaKeys.results)||void 0===n?void 0:n.length)===0}),l.createElement(gH,{msg:a}),null===(r=null==i?void 0:i.csaKeys.results)||void 0===r?void 0:r.map(function(e,t){return l.createElement(_Z,{csaKey:e,key:t})}))))};function _0(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&i[i.length-1])&&(6===a[0]||2===a[0])){o=0;continue}if(3===a[0]&&(!i||a[1]>i[0]&&a[1]e.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&i[i.length-1])&&(6===a[0]||2===a[0])){o=0;continue}if(3===a[0]&&(!i||a[1]>i[0]&&a[1]0&&void 0!==arguments[0]?arguments[0]:{};return ry(EO,e)};function EL(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&i[i.length-1])&&(6===a[0]||2===a[0])){o=0;continue}if(3===a[0]&&(!i||a[1]>i[0]&&a[1]0&&void 0!==arguments[0]?arguments[0]:{};return ry(EQ,e)},E4=function(){return os(E1)},E5=function(){return os(E0)},E6=function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};return ry(E2,e)};function E9(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=Array(t);ne.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&i[i.length-1])&&(6===a[0]||2===a[0])){o=0;continue}if(3===a[0]&&(!i||a[1]>i[0]&&a[1]e.length)&&(t=e.length);for(var n=0,r=Array(t);ne.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&i[i.length-1])&&(6===a[0]||2===a[0])){o=0;continue}if(3===a[0]&&(!i||a[1]>i[0]&&a[1]e.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&i[i.length-1])&&(6===a[0]||2===a[0])){o=0;continue}if(3===a[0]&&(!i||a[1]>i[0]&&a[1]0&&void 0!==arguments[0]?arguments[0]:{};return ry(SV,e)};function SZ(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&i[i.length-1])&&(6===a[0]||2===a[0])){o=0;continue}if(3===a[0]&&(!i||a[1]>i[0]&&a[1]e.length)&&(t=e.length);for(var n=0,r=Array(t);n=0)&&Object.prototype.propertyIsEnumerable.call(e,n)&&(i[n]=e[n])}return i}function kq(e,t){if(null==e)return{};var n,r,i={},a=Object.keys(e);for(r=0;r=0||(i[n]=e[n]);return i}var kZ=function(e){var t=e.run,n=l.useMemo(function(){var e=t.inputs,n=t.outputs,r=t.taskRuns,i=kV(t,["inputs","outputs","taskRuns"]),a={};try{a=JSON.parse(e)}catch(o){a={}}return kK(kG({},i),{inputs:a,outputs:n,taskRuns:r})},[t]);return l.createElement(r9.Z,null,l.createElement(aK.Z,null,l.createElement(k$,{object:n})))};function kX(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function kJ(e){for(var t=1;t0&&l.createElement(ki,{errors:t.allErrors})),l.createElement(d.Z,{item:!0,xs:12},l.createElement(h.rs,null,l.createElement(h.AW,{path:"".concat(n,"/json")},l.createElement(kZ,{run:t})),l.createElement(h.AW,{path:n},t.taskRuns.length>0&&l.createElement(kP,{taskRuns:t.taskRuns,observationSource:t.job.observationSource}))))))))};function k9(e,t){return t||(t=e.slice(0)),Object.freeze(Object.defineProperties(e,{raw:{value:Object.freeze(t)}}))}function k8(){var e=k9(["\n ","\n query FetchJobRun($id: ID!) {\n jobRun(id: $id) {\n __typename\n ... on JobRun {\n ...JobRunPayload_Fields\n }\n ... on NotFoundError {\n message\n }\n }\n }\n"]);return k8=function(){return e},e}var k7=n0(k8(),k5),xe=function(){var e=ry(k7,{variables:{id:(0,h.UO)().id}}),t=e.data,n=e.loading,r=e.error;if(n)return l.createElement(ij,null);if(r)return l.createElement(iN,{error:r});var i=null==t?void 0:t.jobRun;switch(null==i?void 0:i.__typename){case"JobRun":return l.createElement(k6,{run:i});case"NotFoundError":return l.createElement(oo,null);default:return null}};function xt(e,t){return t||(t=e.slice(0)),Object.freeze(Object.defineProperties(e,{raw:{value:Object.freeze(t)}}))}function xn(){var e=xt(["\n fragment JobRunsPayload_ResultsFields on JobRun {\n id\n allErrors\n createdAt\n finishedAt\n status\n job {\n id\n }\n }\n"]);return xn=function(){return e},e}var xr=n0(xn()),xi=function(e){var t=e.loading,n=e.data,r=e.page,i=e.pageSize,a=(0,h.k6)(),o=l.useMemo(function(){return null==n?void 0:n.jobRuns.results.map(function(e){var t,n=e.allErrors,r=e.id,i=e.createdAt;return{id:r,createdAt:i,errors:n,finishedAt:e.finishedAt,status:e.status}})},[n]);return l.createElement(iv,null,l.createElement(d.Z,{container:!0,spacing:32},l.createElement(d.Z,{item:!0,xs:12},l.createElement(iw,null,"Job Runs")),t&&l.createElement(ij,null),n&&o&&l.createElement(d.Z,{item:!0,xs:12},l.createElement(r9.Z,null,l.createElement(yb,{runs:o}),l.createElement(ir.Z,{component:"div",count:n.jobRuns.metadata.total,rowsPerPage:i,rowsPerPageOptions:[i],page:r-1,onChangePage:function(e,t){a.push("/runs?page=".concat(t+1,"&per=").concat(i))},onChangeRowsPerPage:function(){},backIconButtonProps:{"aria-label":"prev-page"},nextIconButtonProps:{"aria-label":"next-page"}})))))};function xa(e,t){return t||(t=e.slice(0)),Object.freeze(Object.defineProperties(e,{raw:{value:Object.freeze(t)}}))}function xo(){var e=xa(["\n ","\n query FetchJobRuns($offset: Int, $limit: Int) {\n jobRuns(offset: $offset, limit: $limit) {\n results {\n ...JobRunsPayload_ResultsFields\n }\n metadata {\n total\n }\n }\n }\n"]);return xo=function(){return e},e}var xs=n0(xo(),xr),xu=function(){var e=iF(),t=parseInt(e.get("page")||"1",10),n=parseInt(e.get("per")||"25",10),r=ry(xs,{variables:{offset:(t-1)*n,limit:n},fetchPolicy:"cache-and-network"}),i=r.data,a=r.loading,o=r.error;return o?l.createElement(iN,{error:o}):l.createElement(xi,{loading:a,data:i,page:t,pageSize:n})},xc=function(){var e=(0,h.$B)().path;return l.createElement(h.rs,null,l.createElement(h.AW,{exact:!0,path:e},l.createElement(xu,null)),l.createElement(h.AW,{path:"".concat(e,"/:id")},l.createElement(xe,null)))},xl=by().shape({name:p2().required("Required"),uri:p2().required("Required"),publicKey:p2().required("Required")}),xf=function(e){var t=e.initialValues,n=e.onSubmit;return l.createElement(hM,{initialValues:t,validationSchema:xl,onSubmit:n},function(e){var t=e.isSubmitting,n=e.submitForm;return l.createElement(hj,{"data-testid":"feeds-manager-form"},l.createElement(d.Z,{container:!0,spacing:16},l.createElement(d.Z,{item:!0,xs:12,md:6},l.createElement(hR,{component:hJ,id:"name",name:"name",label:"Name",required:!0,fullWidth:!0,FormHelperTextProps:{"data-testid":"name-helper-text"}})),l.createElement(d.Z,{item:!0,xs:!1,md:6}),l.createElement(d.Z,{item:!0,xs:12,md:6},l.createElement(hR,{component:hJ,id:"uri",name:"uri",label:"URI",required:!0,fullWidth:!0,helperText:"Provided by the Feeds Manager operator",FormHelperTextProps:{"data-testid":"uri-helper-text"}})),l.createElement(d.Z,{item:!0,xs:12,md:6},l.createElement(hR,{component:hJ,id:"publicKey",name:"publicKey",label:"Public Key",required:!0,fullWidth:!0,helperText:"Provided by the Feeds Manager operator",FormHelperTextProps:{"data-testid":"publicKey-helper-text"}})),l.createElement(d.Z,{item:!0,xs:12},l.createElement(ox.default,{variant:"contained",color:"primary",disabled:t,onClick:n},"Submit"))))})},xd=function(e){var t=e.data,n=e.onSubmit,r={name:t.name,uri:t.uri,publicKey:t.publicKey};return l.createElement(d.Z,{container:!0},l.createElement(d.Z,{item:!0,xs:12,md:11,lg:9},l.createElement(r9.Z,null,l.createElement(sf.Z,{title:"Edit Feeds Manager"}),l.createElement(aK.Z,null,l.createElement(xf,{initialValues:r,onSubmit:n})))))};function xh(e,t){return t||(t=e.slice(0)),Object.freeze(Object.defineProperties(e,{raw:{value:Object.freeze(t)}}))}function xp(){var e=xh(["\n query FetchFeedsManagers {\n feedsManagers {\n results {\n __typename\n id\n name\n uri\n publicKey\n isConnectionActive\n createdAt\n }\n }\n }\n"]);return xp=function(){return e},e}var xb=n0(xp()),xm=function(){return ry(xb)};function xg(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&i[i.length-1])&&(6===a[0]||2===a[0])){o=0;continue}if(3===a[0]&&(!i||a[1]>i[0]&&a[1]0&&void 0!==arguments[0]?arguments[0]:{};return ry(xZ,e)};function xJ(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&i[i.length-1])&&(6===a[0]||2===a[0])){o=0;continue}if(3===a[0]&&(!i||a[1]>i[0]&&a[1]e.length)&&(t=e.length);for(var n=0,r=Array(t);ne.length)&&(t=e.length);for(var n=0,r=Array(t);n0?n.feedsManagers.results[0]:void 0;return n&&a?l.createElement(TH,{manager:a}):l.createElement(h.l_,{to:{pathname:"/feeds_manager/new",state:{from:e}}})},Tz={name:"Chainlink Feeds Manager",uri:"",publicKey:""},TG=function(e){var t=e.onSubmit;return l.createElement(d.Z,{container:!0},l.createElement(d.Z,{item:!0,xs:12,md:11,lg:9},l.createElement(r9.Z,null,l.createElement(sf.Z,{title:"Register Feeds Manager"}),l.createElement(aK.Z,null,l.createElement(xf,{initialValues:Tz,onSubmit:t})))))};function TW(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&i[i.length-1])&&(6===a[0]||2===a[0])){o=0;continue}if(3===a[0]&&(!i||a[1]>i[0]&&a[1]0&&i[i.length-1])&&(6===a[0]||2===a[0])){o=0;continue}if(3===a[0]&&(!i||a[1]>i[0]&&a[1]e.length)&&(t=e.length);for(var n=0,r=Array(t);nt.version?e:t})},[o]),g=l.useMemo(function(){return Mp(o).sort(function(e,t){return t.version-e.version})},[o]),v=function(e,t,n){switch(e){case"PENDING":return l.createElement(l.Fragment,null,l.createElement(ox.default,{variant:"text",color:"secondary",onClick:function(){return b("reject",t)}},"Reject"),m.id===t&&"DELETED"!==n.status&&"REVOKED"!==n.status&&l.createElement(ox.default,{variant:"contained",color:"primary",onClick:function(){return b("approve",t)}},"Approve"),m.id===t&&"DELETED"===n.status&&n.pendingUpdate&&l.createElement(l.Fragment,null,l.createElement(ox.default,{variant:"contained",color:"primary",onClick:function(){return b("cancel",t)}},"Cancel"),l.createElement(x.default,{color:"error"},"This proposal was deleted. Cancel the spec to delete any running jobs")));case"APPROVED":return l.createElement(l.Fragment,null,l.createElement(ox.default,{variant:"contained",onClick:function(){return b("cancel",t)}},"Cancel"),"DELETED"===n.status&&n.pendingUpdate&&l.createElement(x.default,{color:"error"},"This proposal was deleted. Cancel the spec to delete any running jobs"));case"CANCELLED":if(m.id===t&&"DELETED"!==n.status&&"REVOKED"!==n.status)return l.createElement(ox.default,{variant:"contained",color:"primary",onClick:function(){return b("approve",t)}},"Approve");return null;default:return null}};return l.createElement("div",null,g.map(function(e,n){return l.createElement(mR.Z,{defaultExpanded:0===n,key:n},l.createElement(mj.Z,{expandIcon:l.createElement(gp.Z,null)},l.createElement(x.default,{className:t.versionText},"Version ",e.version),l.createElement(Eu.Z,{label:e.status,color:"APPROVED"===e.status?"primary":"default",variant:"REJECTED"===e.status||"CANCELLED"===e.status?"outlined":"default"}),l.createElement("div",{className:t.proposedAtContainer},l.createElement(x.default,null,"Proposed ",l.createElement(aA,{tooltip:!0},e.createdAt)))),l.createElement(mF.Z,{className:t.expansionPanelDetails},l.createElement("div",{className:t.actions},l.createElement("div",{className:t.editContainer},0===n&&("PENDING"===e.status||"CANCELLED"===e.status)&&"DELETED"!==s.status&&"REVOKED"!==s.status&&l.createElement(ox.default,{variant:"contained",onClick:function(){return p(!0)}},"Edit")),l.createElement("div",{className:t.actionsContainer},v(e.status,e.id,s))),l.createElement(gh,{language:"toml",style:gu,"data-testid":"codeblock"},e.definition)))}),l.createElement(oI,{open:null!=c,title:c?My[c.action].title:"",body:c?My[c.action].body:"",onConfirm:function(){if(c){switch(c.action){case"approve":n(c.id);break;case"cancel":r(c.id);break;case"reject":i(c.id)}f(null)}},cancelButtonText:"Cancel",onCancel:function(){return f(null)}}),l.createElement(Mi,{open:h,onClose:function(){return p(!1)},initialValues:{definition:m.definition,id:m.id},onSubmit:a}))});function M_(e,t){return t||(t=e.slice(0)),Object.freeze(Object.defineProperties(e,{raw:{value:Object.freeze(t)}}))}function ME(){var e=M_(["\n ","\n fragment JobProposalPayloadFields on JobProposal {\n id\n externalJobID\n remoteUUID\n jobID\n specs {\n ...JobProposal_SpecsFields\n }\n status\n pendingUpdate\n }\n"]);return ME=function(){return e},e}var MS=n0(ME(),Mg),Mk=function(e){var t=e.onApprove,n=e.onCancel,r=e.onReject,i=e.onUpdateSpec,a=e.proposal;return l.createElement(iv,null,l.createElement(d.Z,{container:!0,spacing:32},l.createElement(d.Z,{item:!0,xs:9},l.createElement(iw,null,"Job Proposal #",a.id))),l.createElement(T8,{proposal:a}),l.createElement(d.Z,{container:!0,spacing:32},l.createElement(d.Z,{item:!0,xs:9},l.createElement(TU,null,"Specs"))),l.createElement(d.Z,{container:!0,spacing:32},l.createElement(d.Z,{item:!0,xs:12},l.createElement(Mw,{proposal:a,specs:a.specs,onReject:r,onApprove:t,onCancel:n,onUpdateSpec:i}))))};function Mx(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&i[i.length-1])&&(6===a[0]||2===a[0])){o=0;continue}if(3===a[0]&&(!i||a[1]>i[0]&&a[1]e.length)&&(t=e.length);for(var n=0,r=Array(t);ne.length)&&(t=e.length);for(var n=0,r=Array(t);nU,tA:()=>$,KL:()=>H,Iw:()=>V,DQ:()=>W,cB:()=>T,LO:()=>M,t5:()=>k,qt:()=>x,Jc:()=>C,L7:()=>Y,EO:()=>B});var r,i,a=n(66289),o=n(41800),s=n.n(o),u=n(67932);(i=r||(r={})).IN_PROGRESS="in_progress",i.PENDING_INCOMING_CONFIRMATIONS="pending_incoming_confirmations",i.PENDING_CONNECTION="pending_connection",i.PENDING_BRIDGE="pending_bridge",i.PENDING_SLEEP="pending_sleep",i.ERRORED="errored",i.COMPLETED="completed";var c=n(87013),l=n(19084),f=n(34823);function d(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&i[i.length-1])&&(6===a[0]||2===a[0])){o=0;continue}if(3===a[0]&&(!i||a[1]>i[0]&&a[1]j,v2:()=>F});var r=n(66289);function i(e,t){if(!(e instanceof t))throw TypeError("Cannot call a class as a function")}var a="/sessions",o="/sessions",s=function e(t){var n=this;i(this,e),this.api=t,this.createSession=function(e){return n.create(e)},this.destroySession=function(){return n.destroy()},this.create=this.api.createResource(a),this.destroy=this.api.deleteResource(o)};function u(e,t){if(!(e instanceof t))throw TypeError("Cannot call a class as a function")}var c="/v2/bulk_delete_runs",l=function e(t){var n=this;u(this,e),this.api=t,this.bulkDeleteJobRuns=function(e){return n.destroy(e)},this.destroy=this.api.deleteResource(c)};function f(e,t){if(!(e instanceof t))throw TypeError("Cannot call a class as a function")}var d="/v2/chains/evm",h="".concat(d,"/:id"),p=function e(t){var n=this;f(this,e),this.api=t,this.getChains=function(){return n.index()},this.createChain=function(e){return n.create(e)},this.destroyChain=function(e){return n.destroy(void 0,{id:e})},this.updateChain=function(e,t){return n.update(t,{id:e})},this.index=this.api.fetchResource(d),this.create=this.api.createResource(d),this.destroy=this.api.deleteResource(h),this.update=this.api.updateResource(h)};function b(e,t){if(!(e instanceof t))throw TypeError("Cannot call a class as a function")}var m="/v2/keys/evm/chain",g=function e(t){var n=this;b(this,e),this.api=t,this.chain=function(e){var t=new URLSearchParams;t.append("address",e.address),t.append("evmChainID",e.evmChainID),null!==e.nextNonce&&t.append("nextNonce",e.nextNonce),null!==e.abandon&&t.append("abandon",String(e.abandon)),null!==e.enabled&&t.append("enabled",String(e.enabled));var r=m+"?"+t.toString();return n.api.createResource(r)()}};function v(e,t){if(!(e instanceof t))throw TypeError("Cannot call a class as a function")}var y="/v2/jobs",w="".concat(y,"/:specId/runs"),_=function e(t){var n=this;v(this,e),this.api=t,this.createJobRunV2=function(e,t){return n.post(t,{specId:e})},this.post=this.api.createResource(w,!0)};function E(e,t){if(!(e instanceof t))throw TypeError("Cannot call a class as a function")}var S="/v2/log",k=function e(t){var n=this;E(this,e),this.api=t,this.getLogConfig=function(){return n.show()},this.updateLogConfig=function(e){return n.update(e)},this.show=this.api.fetchResource(S),this.update=this.api.updateResource(S)};function x(e,t){if(!(e instanceof t))throw TypeError("Cannot call a class as a function")}var T="/v2/nodes",M=function e(t){var n=this;x(this,e),this.api=t,this.getNodes=function(){return n.index()},this.createNode=function(e){return n.create(e)},this.index=this.api.fetchResource(T),this.create=this.api.createResource(T)};function O(e,t){if(!(e instanceof t))throw TypeError("Cannot call a class as a function")}var A="/v2/enroll_webauthn",L=function e(t){var n=this;O(this,e),this.api=t,this.beginKeyRegistration=function(e){return n.create(e)},this.finishKeyRegistration=function(e){return n.put(e)},this.create=this.api.fetchResource(A),this.put=this.api.createResource(A)};function C(e,t){if(!(e instanceof t))throw TypeError("Cannot call a class as a function")}var I="/v2/build_info",D=function e(t){var n=this;C(this,e),this.api=t,this.show=function(){return n.api.GET(I)()}};function N(e,t){if(!(e instanceof t))throw TypeError("Cannot call a class as a function")}var P=function e(t){N(this,e),this.api=t,this.buildInfo=new D(this.api),this.bulkDeleteRuns=new l(this.api),this.chains=new p(this.api),this.logConfig=new k(this.api),this.nodes=new M(this.api),this.jobs=new _(this.api),this.webauthn=new L(this.api),this.evmKeys=new g(this.api)},R=new r.V0({base:void 0}),j=new s(R),F=new P(R)},1398(e,t,n){"use strict";n.d(t,{Z:()=>d});var r=n(67294),i=n(32316),a=n(83638),o=n(94184),s=n.n(o);function u(){return(u=Object.assign||function(e){for(var t=1;tc});var r=n(67294),i=n(32316);function a(){return(a=Object.assign||function(e){for(var t=1;tx,jK:()=>v});var r=n(67294),i=n(55977),a=n(45697),o=n.n(a),s=n(82204),u=n(71426),c=n(94184),l=n.n(c),f=n(32316),d=function(e){var t=e.palette.success||{},n=e.palette.warning||{};return{base:{paddingLeft:5*e.spacing.unit,paddingRight:5*e.spacing.unit},success:{backgroundColor:t.main,color:t.contrastText},error:{backgroundColor:e.palette.error.dark,color:e.palette.error.contrastText},warning:{backgroundColor:n.contrastText,color:n.main}}},h=function(e){var t,n=e.success,r=e.error,i=e.warning,a=e.classes,o=e.className;return n?t=a.success:r?t=a.error:i&&(t=a.warning),l()(a.base,o,t)},p=function(e){return r.createElement(s.Z,{className:h(e),square:!0},r.createElement(u.default,{variant:"body2",color:"inherit",component:"div"},e.children))};p.defaultProps={success:!1,error:!1,warning:!1},p.propTypes={success:o().bool,error:o().bool,warning:o().bool};let b=(0,f.withStyles)(d)(p);var m=function(){return r.createElement(r.Fragment,null,"Unhandled error. Please help us by opening a"," ",r.createElement("a",{href:"https://github.com/smartcontractkit/chainlink/issues/new"},"bug report"))};let g=m;function v(e){return"string"==typeof e?e:e.component?e.component(e.props):r.createElement(g,null)}function y(e,t){var n;return n="string"==typeof e?e:e.component?e.component(e.props):r.createElement(g,null),r.createElement("p",{key:t},n)}var w=function(e){var t=e.notifications;return r.createElement(b,{error:!0},t.map(y))},_=function(e){var t=e.notifications;return r.createElement(b,{success:!0},t.map(y))},E=function(e){var t=e.errors,n=e.successes;return r.createElement("div",null,(null==t?void 0:t.length)>0&&r.createElement(w,{notifications:t}),n.length>0&&r.createElement(_,{notifications:n}))},S=function(e){return{errors:e.notifications.errors,successes:e.notifications.successes}},k=(0,i.$j)(S)(E);let x=k},9409(e,t,n){"use strict";n.d(t,{ZP:()=>j});var r=n(67294),i=n(55977),a=n(47886),o=n(32316),s=n(1398),u=n(82204),c=n(30060),l=n(71426),f=n(60520),d=n(97779),h=n(57209),p=n(26842),b=n(3950),m=n(5536),g=n(45697),v=n.n(g);let y=n.p+"9f6d832ef97e8493764e.svg";function w(){return(w=Object.assign||function(e){for(var t=1;te.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&_.map(function(e,t){return r.createElement(d.Z,{item:!0,xs:12,key:t},r.createElement(u.Z,{raised:!1,className:v.error},r.createElement(c.Z,null,r.createElement(l.default,{variant:"body1",className:v.errorText},(0,b.jK)(e)))))}),r.createElement(d.Z,{item:!0,xs:12},r.createElement(f.Z,{id:"email",label:"Email",margin:"normal",value:n,onChange:m("email"),error:_.length>0,variant:"outlined",fullWidth:!0})),r.createElement(d.Z,{item:!0,xs:12},r.createElement(f.Z,{id:"password",label:"Password",type:"password",autoComplete:"password",margin:"normal",value:h,onChange:m("password"),error:_.length>0,variant:"outlined",fullWidth:!0})),r.createElement(d.Z,{item:!0,xs:12},r.createElement(d.Z,{container:!0,spacing:0,justify:"center"},r.createElement(d.Z,{item:!0},r.createElement(s.Z,{type:"submit",variant:"primary"},"Access Account")))),y&&r.createElement(l.default,{variant:"body1",color:"textSecondary"},"Signing in...")))))))},P=function(e){return{fetching:e.authentication.fetching,authenticated:e.authentication.allowed,errors:e.notifications.errors}},R=(0,i.$j)(P,x({submitSignIn:p.L7}))(N);let j=(0,h.wU)(e)((0,o.withStyles)(D)(R))},16353(e,t,n){"use strict";n.d(t,{ZP:()=>H,rH:()=>U});var r,i=n(55977),a=n(15857),o=n(9541),s=n(19084);function u(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function c(e){for(var t=1;t0&&void 0!==arguments[0]?arguments[0]:h,t=arguments.length>1?arguments[1]:void 0;switch(t.type){case s.Mk.RECEIVE_SIGNOUT_SUCCESS:case s.Mk.RECEIVE_SIGNIN_SUCCESS:var n={allowed:t.authenticated};return o.Ks(n),f(c({},e,n),{errors:[]});case s.Mk.RECEIVE_SIGNIN_FAIL:var r={allowed:!1};return o.Ks(r),f(c({},e,r),{errors:[]});case s.Mk.RECEIVE_SIGNIN_ERROR:case s.Mk.RECEIVE_SIGNOUT_ERROR:var i={allowed:!1};return o.Ks(i),f(c({},e,i),{errors:t.errors||[]});default:return e}};let b=p;function m(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function g(e){for(var t=1;t0&&void 0!==arguments[0]?arguments[0]:_,t=arguments.length>1?arguments[1]:void 0;return t.type?t.type.startsWith(r.REQUEST)?y(g({},e),{count:e.count+1}):t.type.startsWith(r.RECEIVE)?y(g({},e),{count:Math.max(e.count-1,0)}):t.type.startsWith(r.RESPONSE)?y(g({},e),{count:Math.max(e.count-1,0)}):t.type===s.di.REDIRECT?y(g({},e),{count:0}):e:e};let S=E;function k(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function x(e){for(var t=1;t0&&void 0!==arguments[0]?arguments[0]:O,t=arguments.length>1?arguments[1]:void 0;switch(t.type){case s.di.MATCH_ROUTE:return M(x({},O),{currentUrl:t.pathname});case s.Ih.NOTIFY_SUCCESS:var n={component:t.component,props:t.props};return M(x({},e),{successes:[n],errors:[]});case s.Ih.NOTIFY_SUCCESS_MSG:return M(x({},e),{successes:[t.msg],errors:[]});case s.Ih.NOTIFY_ERROR:var r=t.error.errors,i=null==r?void 0:r.map(function(e){return L(t,e)});return M(x({},e),{successes:[],errors:i});case s.Ih.NOTIFY_ERROR_MSG:return M(x({},e),{successes:[],errors:[t.msg]});case s.Mk.RECEIVE_SIGNIN_FAIL:return M(x({},e),{successes:[],errors:["Your email or password is incorrect. Please try again"]});default:return e}};function L(e,t){return{component:e.component,props:{msg:t.detail}}}let C=A;function I(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function D(e){for(var t=1;t0&&void 0!==arguments[0]?arguments[0]:R,t=arguments.length>1?arguments[1]:void 0;switch(t.type){case s.di.REDIRECT:return P(D({},e),{to:t.to});case s.di.MATCH_ROUTE:return P(D({},e),{to:void 0});default:return e}};let F=j;var Y=n(87013),B=(0,a.UY)({authentication:b,fetching:S,notifications:C,redirect:F,buildInfo:Y.Z});B(void 0,{type:"INITIAL_STATE"});var U=i.v9;let H=B},19084(e,t,n){"use strict";var r,i,a,o,s,u,c,l,f,d;n.d(t,{Ih:()=>i,Mk:()=>a,Y0:()=>s,di:()=>r,jp:()=>o}),n(67294),(u=r||(r={})).REDIRECT="REDIRECT",u.MATCH_ROUTE="MATCH_ROUTE",(c=i||(i={})).NOTIFY_SUCCESS="NOTIFY_SUCCESS",c.NOTIFY_SUCCESS_MSG="NOTIFY_SUCCESS_MSG",c.NOTIFY_ERROR="NOTIFY_ERROR",c.NOTIFY_ERROR_MSG="NOTIFY_ERROR_MSG",(l=a||(a={})).REQUEST_SIGNIN="REQUEST_SIGNIN",l.RECEIVE_SIGNIN_SUCCESS="RECEIVE_SIGNIN_SUCCESS",l.RECEIVE_SIGNIN_FAIL="RECEIVE_SIGNIN_FAIL",l.RECEIVE_SIGNIN_ERROR="RECEIVE_SIGNIN_ERROR",l.RECEIVE_SIGNOUT_SUCCESS="RECEIVE_SIGNOUT_SUCCESS",l.RECEIVE_SIGNOUT_ERROR="RECEIVE_SIGNOUT_ERROR",(f=o||(o={})).RECEIVE_CREATE_ERROR="RECEIVE_CREATE_ERROR",f.RECEIVE_CREATE_SUCCESS="RECEIVE_CREATE_SUCCESS",f.RECEIVE_DELETE_ERROR="RECEIVE_DELETE_ERROR",f.RECEIVE_DELETE_SUCCESS="RECEIVE_DELETE_SUCCESS",f.RECEIVE_UPDATE_ERROR="RECEIVE_UPDATE_ERROR",f.RECEIVE_UPDATE_SUCCESS="RECEIVE_UPDATE_SUCCESS",f.REQUEST_CREATE="REQUEST_CREATE",f.REQUEST_DELETE="REQUEST_DELETE",f.REQUEST_UPDATE="REQUEST_UPDATE",f.UPSERT_CONFIGURATION="UPSERT_CONFIGURATION",f.UPSERT_JOB_RUN="UPSERT_JOB_RUN",f.UPSERT_JOB_RUNS="UPSERT_JOB_RUNS",f.UPSERT_TRANSACTION="UPSERT_TRANSACTION",f.UPSERT_TRANSACTIONS="UPSERT_TRANSACTIONS",f.UPSERT_BUILD_INFO="UPSERT_BUILD_INFO",(d=s||(s={})).FETCH_BUILD_INFO_REQUESTED="FETCH_BUILD_INFO_REQUESTED",d.FETCH_BUILD_INFO_SUCCEEDED="FETCH_BUILD_INFO_SUCCEEDED",d.FETCH_BUILD_INFO_FAILED="FETCH_BUILD_INFO_FAILED"},87013(e,t,n){"use strict";n.d(t,{Y:()=>o,Z:()=>u});var r=n(19084);function i(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function a(e){for(var t=1;t0&&void 0!==arguments[0]?arguments[0]:o,t=arguments.length>1?arguments[1]:void 0;return t.type===r.Y0.FETCH_BUILD_INFO_SUCCEEDED?a({},t.buildInfo):e};let u=s},34823(e,t,n){"use strict";n.d(t,{N:()=>r});var r=function(e){return e.buildInfo}},73343(e,t,n){"use strict";n.d(t,{r:()=>u});var r=n(19350),i=n(32316),a=n(59114),o=n(5324),s={props:{MuiGrid:{spacing:3*o.default.unit},MuiCardHeader:{titleTypographyProps:{color:"secondary"}}},palette:{action:{hoverOpacity:.3},primary:{light:"#E5F1FF",main:"#3c40c6",contrastText:"#fff"},secondary:{main:"#3d5170"},success:{light:"#e8faf1",main:r.ek.A700,dark:r.ek[700],contrastText:r.y0.white},warning:{light:"#FFFBF1",main:"#fff6b6",contrastText:"#fad27a"},error:{light:"#ffdada",main:"#f44336",dark:"#d32f2f",contrastText:"#fff"},background:{default:"#f5f6f8",appBar:"#3c40c6"},text:{primary:(0,a.darken)(r.BA.A700,.7),secondary:"#818ea3"},listPendingStatus:{background:"#fef7e5",color:"#fecb4c"},listCompletedStatus:{background:"#e9faf2",color:"#4ed495"}},shape:{borderRadius:o.default.unit},overrides:{MuiButton:{root:{borderRadius:o.default.unit/2,textTransform:"none"},sizeLarge:{padding:void 0,fontSize:void 0,paddingTop:o.default.unit,paddingBottom:o.default.unit,paddingLeft:5*o.default.unit,paddingRight:5*o.default.unit}},MuiTableCell:{body:{fontSize:"1rem"},head:{fontSize:"1rem",fontWeight:400}},MuiCardHeader:{root:{borderBottom:"1px solid rgba(0, 0, 0, 0.12)"},action:{marginTop:-2,marginRight:0,"& >*":{marginLeft:2*o.default.unit}},subheader:{marginTop:.5*o.default.unit}}},typography:{useNextVariants:!0,fontFamily:"-apple-system,BlinkMacSystemFont,Roboto,Helvetica,Arial,sans-serif",button:{textTransform:"none",fontSize:"1.2em"},body1:{fontSize:"1.0rem",fontWeight:400,lineHeight:"1.46429em",color:"rgba(0, 0, 0, 0.87)",letterSpacing:-.4},body2:{fontSize:"1.0rem",fontWeight:500,lineHeight:"1.71429em",color:"rgba(0, 0, 0, 0.87)",letterSpacing:-.4},body1Next:{color:"rgb(29, 29, 29)",fontWeight:400,fontSize:"1rem",lineHeight:1.5,letterSpacing:-.4},body2Next:{color:"rgb(29, 29, 29)",fontWeight:400,fontSize:"0.875rem",lineHeight:1.5,letterSpacing:-.4},display1:{color:"#818ea3",fontSize:"2.125rem",fontWeight:400,lineHeight:"1.20588em",letterSpacing:-.4},display2:{color:"#818ea3",fontSize:"2.8125rem",fontWeight:400,lineHeight:"1.13333em",marginLeft:"-.02em",letterSpacing:-.4},display3:{color:"#818ea3",fontSize:"3.5rem",fontWeight:400,lineHeight:"1.30357em",marginLeft:"-.02em",letterSpacing:-.4},display4:{fontSize:14,fontWeightLight:300,fontWeightMedium:500,fontWeightRegular:400,letterSpacing:-.4},h1:{color:"rgb(29, 29, 29)",fontSize:"6rem",fontWeight:300,lineHeight:1},h2:{color:"rgb(29, 29, 29)",fontSize:"3.75rem",fontWeight:300,lineHeight:1},h3:{color:"rgb(29, 29, 29)",fontSize:"3rem",fontWeight:400,lineHeight:1.04},h4:{color:"rgb(29, 29, 29)",fontSize:"2.125rem",fontWeight:400,lineHeight:1.17},h5:{color:"rgb(29, 29, 29)",fontSize:"1.5rem",fontWeight:400,lineHeight:1.33,letterSpacing:-.4},h6:{fontSize:"0.8rem",fontWeight:450,lineHeight:"1.71429em",color:"rgba(0, 0, 0, 0.87)",letterSpacing:-.4},subheading:{color:"rgb(29, 29, 29)",fontSize:"1rem",fontWeight:400,lineHeight:"1.5em",letterSpacing:-.4},subtitle1:{color:"rgb(29, 29, 29)",fontSize:"1rem",fontWeight:400,lineHeight:1.75,letterSpacing:-.4},subtitle2:{color:"rgb(29, 29, 29)",fontSize:"0.875rem",fontWeight:500,lineHeight:1.57,letterSpacing:-.4}},shadows:["none","0px 1px 3px 0px rgba(0, 0, 0, 0.1),0px 1px 1px 0px rgba(0, 0, 0, 0.04),0px 2px 1px -1px rgba(0, 0, 0, 0.02)","0px 1px 5px 0px rgba(0, 0, 0, 0.1),0px 2px 2px 0px rgba(0, 0, 0, 0.04),0px 3px 1px -2px rgba(0, 0, 0, 0.02)","0px 1px 8px 0px rgba(0, 0, 0, 0.1),0px 3px 4px 0px rgba(0, 0, 0, 0.04),0px 3px 3px -2px rgba(0, 0, 0, 0.02)","0px 2px 4px -1px rgba(0, 0, 0, 0.1),0px 4px 5px 0px rgba(0, 0, 0, 0.04),0px 1px 10px 0px rgba(0, 0, 0, 0.02)","0px 3px 5px -1px rgba(0, 0, 0, 0.1),0px 5px 8px 0px rgba(0, 0, 0, 0.04),0px 1px 14px 0px rgba(0, 0, 0, 0.02)","0px 3px 5px -1px rgba(0, 0, 0, 0.1),0px 6px 10px 0px rgba(0, 0, 0, 0.04),0px 1px 18px 0px rgba(0, 0, 0, 0.02)","0px 4px 5px -2px rgba(0, 0, 0, 0.1),0px 7px 10px 1px rgba(0, 0, 0, 0.04),0px 2px 16px 1px rgba(0, 0, 0, 0.02)","0px 5px 5px -3px rgba(0, 0, 0, 0.1),0px 8px 10px 1px rgba(0, 0, 0, 0.04),0px 3px 14px 2px rgba(0, 0, 0, 0.02)","0px 5px 6px -3px rgba(0, 0, 0, 0.1),0px 9px 12px 1px rgba(0, 0, 0, 0.04),0px 3px 16px 2px rgba(0, 0, 0, 0.02)","0px 6px 6px -3px rgba(0, 0, 0, 0.1),0px 10px 14px 1px rgba(0, 0, 0, 0.04),0px 4px 18px 3px rgba(0, 0, 0, 0.02)","0px 6px 7px -4px rgba(0, 0, 0, 0.1),0px 11px 15px 1px rgba(0, 0, 0, 0.04),0px 4px 20px 3px rgba(0, 0, 0, 0.02)","0px 7px 8px -4px rgba(0, 0, 0, 0.1),0px 12px 17px 2px rgba(0, 0, 0, 0.04),0px 5px 22px 4px rgba(0, 0, 0, 0.02)","0px 7px 8px -4px rgba(0, 0, 0, 0.1),0px 13px 19px 2px rgba(0, 0, 0, 0.04),0px 5px 24px 4px rgba(0, 0, 0, 0.02)","0px 7px 9px -4px rgba(0, 0, 0, 0.1),0px 14px 21px 2px rgba(0, 0, 0, 0.04),0px 5px 26px 4px rgba(0, 0, 0, 0.02)","0px 8px 9px -5px rgba(0, 0, 0, 0.1),0px 15px 22px 2px rgba(0, 0, 0, 0.04),0px 6px 28px 5px rgba(0, 0, 0, 0.02)","0px 8px 10px -5px rgba(0, 0, 0, 0.1),0px 16px 24px 2px rgba(0, 0, 0, 0.04),0px 6px 30px 5px rgba(0, 0, 0, 0.02)","0px 8px 11px -5px rgba(0, 0, 0, 0.1),0px 17px 26px 2px rgba(0, 0, 0, 0.04),0px 6px 32px 5px rgba(0, 0, 0, 0.02)","0px 9px 11px -5px rgba(0, 0, 0, 0.1),0px 18px 28px 2px rgba(0, 0, 0, 0.04),0px 7px 34px 6px rgba(0, 0, 0, 0.02)","0px 9px 12px -6px rgba(0, 0, 0, 0.1),0px 19px 29px 2px rgba(0, 0, 0, 0.04),0px 7px 36px 6px rgba(0, 0, 0, 0.02)","0px 10px 13px -6px rgba(0, 0, 0, 0.1),0px 20px 31px 3px rgba(0, 0, 0, 0.04),0px 8px 38px 7px rgba(0, 0, 0, 0.02)","0px 10px 13px -6px rgba(0, 0, 0, 0.1),0px 21px 33px 3px rgba(0, 0, 0, 0.04),0px 8px 40px 7px rgba(0, 0, 0, 0.02)","0px 10px 14px -6px rgba(0, 0, 0, 0.1),0px 22px 35px 3px rgba(0, 0, 0, 0.04),0px 8px 42px 7px rgba(0, 0, 0, 0.02)","0px 11px 14px -7px rgba(0, 0, 0, 0.1),0px 23px 36px 3px rgba(0, 0, 0, 0.04),0px 9px 44px 8px rgba(0, 0, 0, 0.02)","0px 11px 15px -7px rgba(0, 0, 0, 0.1),0px 24px 38px 3px rgba(0, 0, 0, 0.04),0px 9px 46px 8px rgba(0, 0, 0, 0.02)",]},u=(0,i.createMuiTheme)(s)},66289(e,t,n){"use strict";function r(e){if(void 0===e)throw ReferenceError("this hasn't been initialised - super() hasn't been called");return e}function i(e,t){if(!(e instanceof t))throw TypeError("Cannot call a class as a function")}function a(){if("undefined"==typeof Reflect||!Reflect.construct||Reflect.construct.sham)return!1;if("function"==typeof Proxy)return!0;try{return Date.prototype.toString.call(Reflect.construct(Date,[],function(){})),!0}catch(e){return!1}}function o(e,t,n){return(o=a()?Reflect.construct:function(e,t,n){var r=[null];r.push.apply(r,t);var i=new(Function.bind.apply(e,r));return n&&f(i,n.prototype),i}).apply(null,arguments)}function s(e){return(s=Object.setPrototypeOf?Object.getPrototypeOf:function(e){return e.__proto__||Object.getPrototypeOf(e)})(e)}function u(e,t){if("function"!=typeof t&&null!==t)throw TypeError("Super expression must either be null or a function");e.prototype=Object.create(t&&t.prototype,{constructor:{value:e,writable:!0,configurable:!0}}),t&&f(e,t)}function c(e){return -1!==Function.toString.call(e).indexOf("[native code]")}function l(e,t){return t&&("object"===p(t)||"function"==typeof t)?t:r(e)}function f(e,t){return(f=Object.setPrototypeOf||function(e,t){return e.__proto__=t,e})(e,t)}n.d(t,{V0:()=>B,_7:()=>v});var d,h,p=function(e){return e&&"undefined"!=typeof Symbol&&e.constructor===Symbol?"symbol":typeof e};function b(e){var t="function"==typeof Map?new Map:void 0;return(b=function(e){if(null===e||!c(e))return e;if("function"!=typeof e)throw TypeError("Super expression must either be null or a function");if(void 0!==t){if(t.has(e))return t.get(e);t.set(e,n)}function n(){return o(e,arguments,s(this).constructor)}return n.prototype=Object.create(e.prototype,{constructor:{value:n,enumerable:!1,writable:!0,configurable:!0}}),f(n,e)})(e)}function m(){if("undefined"==typeof Reflect||!Reflect.construct||Reflect.construct.sham)return!1;if("function"==typeof Proxy)return!0;try{return Boolean.prototype.valueOf.call(Reflect.construct(Boolean,[],function(){})),!0}catch(e){return!1}}function g(e){var t=m();return function(){var n,r=s(e);if(t){var i=s(this).constructor;n=Reflect.construct(r,arguments,i)}else n=r.apply(this,arguments);return l(this,n)}}var v=function(e){u(n,e);var t=g(n);function n(e){var r;return i(this,n),(r=t.call(this,"AuthenticationError(".concat(e.statusText,")"))).errors=[{status:e.status,detail:e},],r}return n}(b(Error)),y=function(e){u(n,e);var t=g(n);function n(e){var r,a=e.errors;return i(this,n),(r=t.call(this,"BadRequestError")).errors=a,r}return n}(b(Error)),w=function(e){u(n,e);var t=g(n);function n(e){var r;return i(this,n),(r=t.call(this,"UnprocessableEntityError")).errors=e,r}return n}(b(Error)),_=function(e){u(n,e);var t=g(n);function n(e){var r;return i(this,n),(r=t.call(this,"ServerError")).errors=e,r}return n}(b(Error)),E=function(e){u(n,e);var t=g(n);function n(e){var r,a=e.errors;return i(this,n),(r=t.call(this,"ConflictError")).errors=a,r}return n}(b(Error)),S=function(e){u(n,e);var t=g(n);function n(e){var r;return i(this,n),(r=t.call(this,"UnknownResponseError(".concat(e.statusText,")"))).errors=[{status:e.status,detail:e.statusText},],r}return n}(b(Error));function k(e,t){var n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:2e4;return Promise.race([fetch(e,t),new Promise(function(e,t){return setTimeout(function(){return t(Error("timeout"))},n)}),])}function x(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&i[i.length-1])&&(6===a[0]||2===a[0])){o=0;continue}if(3===a[0]&&(!i||a[1]>i[0]&&a[1]=200&&e.status<300))return[3,2];return[2,e.json()];case 2:if(400!==e.status)return[3,3];return[2,e.json().then(function(e){throw new y(e)})];case 3:if(401!==e.status)return[3,4];throw new v(e);case 4:if(422!==e.status)return[3,6];return[4,$(e)];case 5:throw n=i.sent(),new w(n);case 6:if(409!==e.status)return[3,7];return[2,e.json().then(function(e){throw new E(e)})];case 7:if(!(e.status>=500))return[3,9];return[4,$(e)];case 8:throw r=i.sent(),new _(r);case 9:throw new S(e);case 10:return[2]}})})).apply(this,arguments)}function $(e){return z.apply(this,arguments)}function z(){return(z=j(function(e){return Y(this,function(t){return[2,e.json().then(function(t){return t.errors?t.errors.map(function(t){return{status:e.status,detail:t.detail}}):G(e)}).catch(function(){return G(e)})]})})).apply(this,arguments)}function G(e){return[{status:e.status,detail:e.statusText},]}},50109(e,t,n){"use strict";n.d(t,{LK:()=>o,U2:()=>i,eT:()=>s,t8:()=>a});var r=n(12795);function i(e){return r.ZP.getItem("chainlink.".concat(e))}function a(e,t){r.ZP.setItem("chainlink.".concat(e),t)}function o(e){var t=i(e),n={};if(t)try{return JSON.parse(t)}catch(r){}return n}function s(e,t){a(e,JSON.stringify(t))}},9541(e,t,n){"use strict";n.d(t,{Ks:()=>u,Tp:()=>a,iR:()=>o,pm:()=>s});var r=n(50109),i="persistURL";function a(){return r.U2(i)||""}function o(e){r.t8(i,e)}function s(){return r.LK("authentication")}function u(e){r.eT("authentication",e)}},67121(e,t,n){"use strict";function r(e){var t,n=e.Symbol;return"function"==typeof n?n.observable?t=n.observable:(t=n("observable"),n.observable=t):t="@@observable",t}n.r(t),n.d(t,{default:()=>o}),e=n.hmd(e),i="undefined"!=typeof self?self:"undefined"!=typeof window?window:void 0!==n.g?n.g:e;var i,a=r(i);let o=a},2177(e,t,n){"use strict";n.d(t,{Z:()=>o});var r=!0,i="Invariant failed";function a(e,t){if(!e){if(r)throw Error(i);throw Error(i+": "+(t||""))}}let o=a},11742(e){e.exports=function(){var e=document.getSelection();if(!e.rangeCount)return function(){};for(var t=document.activeElement,n=[],r=0;ri,pi:()=>a});var r=function(e,t){return(r=Object.setPrototypeOf||({__proto__:[]})instanceof Array&&function(e,t){e.__proto__=t}||function(e,t){for(var n in t)Object.prototype.hasOwnProperty.call(t,n)&&(e[n]=t[n])})(e,t)};function i(e,t){if("function"!=typeof t&&null!==t)throw TypeError("Class extends value "+String(t)+" is not a constructor or null");function n(){this.constructor=e}r(e,t),e.prototype=null===t?Object.create(t):(n.prototype=t.prototype,new n)}var a=function(){return(a=Object.assign||function(e){for(var t,n=1,r=arguments.length;nr})},94927(e,t,n){function r(e,t){if(i("noDeprecation"))return e;var n=!1;function r(){if(!n){if(i("throwDeprecation"))throw Error(t);i("traceDeprecation")?console.trace(t):console.warn(t),n=!0}return e.apply(this,arguments)}return r}function i(e){try{if(!n.g.localStorage)return!1}catch(t){return!1}var r=n.g.localStorage[e];return null!=r&&"true"===String(r).toLowerCase()}e.exports=r},42473(e){"use strict";var t=function(){};e.exports=t},84763(e){e.exports=Worker},47529(e){e.exports=n;var t=Object.prototype.hasOwnProperty;function n(){for(var e={},n=0;nr,O:()=>a}),(i=r||(r={}))[i.loading=1]="loading",i[i.setVariables=2]="setVariables",i[i.fetchMore=3]="fetchMore",i[i.refetch=4]="refetch",i[i.poll=6]="poll",i[i.ready=7]="ready",i[i.error=8]="error"},30990(e,t,n){"use strict";n.d(t,{MS:()=>s,YG:()=>a,cA:()=>c,ls:()=>o});var r=n(23564);n(83952);var i=n(13154),a=Symbol();function o(e){return!!e.extensions&&Array.isArray(e.extensions[a])}function s(e){return e.hasOwnProperty("graphQLErrors")}var u=function(e){var t=(0,r.ev)((0,r.ev)((0,r.ev)([],e.graphQLErrors,!0),e.clientErrors,!0),e.protocolErrors,!0);return e.networkError&&t.push(e.networkError),t.map(function(e){return(0,i.s)(e)&&e.message||"Error message not found."}).join("\n")},c=function(e){function t(n){var r=n.graphQLErrors,i=n.protocolErrors,a=n.clientErrors,o=n.networkError,s=n.errorMessage,c=n.extraInfo,l=e.call(this,s)||this;return l.name="ApolloError",l.graphQLErrors=r||[],l.protocolErrors=i||[],l.clientErrors=a||[],l.networkError=o||null,l.message=s||u(l),l.extraInfo=c,l.__proto__=t.prototype,l}return(0,r.ZT)(t,e),t}(Error)},85317(e,t,n){"use strict";n.d(t,{K:()=>a});var r=n(67294),i=n(30320).aS?Symbol.for("__APOLLO_CONTEXT__"):"__APOLLO_CONTEXT__";function a(){var e=r.createContext[i];return e||(Object.defineProperty(r.createContext,i,{value:e=r.createContext({}),enumerable:!1,writable:!1,configurable:!0}),e.displayName="ApolloContext"),e}},21436(e,t,n){"use strict";n.d(t,{O:()=>i,k:()=>r});var r=Array.isArray;function i(e){return Array.isArray(e)&&e.length>0}},30320(e,t,n){"use strict";n.d(t,{DN:()=>s,JC:()=>l,aS:()=>o,mr:()=>i,sy:()=>a});var r=n(83952),i="function"==typeof WeakMap&&"ReactNative"!==(0,r.wY)(function(){return navigator.product}),a="function"==typeof WeakSet,o="function"==typeof Symbol&&"function"==typeof Symbol.for,s=o&&Symbol.asyncIterator,u="function"==typeof(0,r.wY)(function(){return window.document.createElement}),c=(0,r.wY)(function(){return navigator.userAgent.indexOf("jsdom")>=0})||!1,l=u&&!c},53712(e,t,n){"use strict";function r(){for(var e=[],t=0;tr})},10542(e,t,n){"use strict";n.d(t,{J:()=>o}),n(83952);var r=n(13154);function i(e){var t=new Set([e]);return t.forEach(function(e){(0,r.s)(e)&&a(e)===e&&Object.getOwnPropertyNames(e).forEach(function(n){(0,r.s)(e[n])&&t.add(e[n])})}),e}function a(e){if(__DEV__&&!Object.isFrozen(e))try{Object.freeze(e)}catch(t){if(t instanceof TypeError)return null;throw t}return e}function o(e){return __DEV__&&i(e),e}},14012(e,t,n){"use strict";n.d(t,{J:()=>a});var r=n(23564),i=n(53712);function a(e,t){return(0,i.o)(e,t,t.variables&&{variables:(0,r.pi)((0,r.pi)({},e&&e.variables),t.variables)})}},13154(e,t,n){"use strict";function r(e){return null!==e&&"object"==typeof e}n.d(t,{s:()=>r})},83952(e,t,n){"use strict";n.d(t,{ej:()=>u,kG:()=>c,wY:()=>h});var r,i=n(70655),a="Invariant Violation",o=Object.setPrototypeOf,s=void 0===o?function(e,t){return e.__proto__=t,e}:o,u=function(e){function t(n){void 0===n&&(n=a);var r=e.call(this,"number"==typeof n?a+": "+n+" (see https://github.com/apollographql/invariant-packages)":n)||this;return r.framesToPop=1,r.name=a,s(r,t.prototype),r}return(0,i.ZT)(t,e),t}(Error);function c(e,t){if(!e)throw new u(t)}var l=["debug","log","warn","error","silent"],f=l.indexOf("log");function d(e){return function(){if(l.indexOf(e)>=f)return(console[e]||console.log).apply(console,arguments)}}function h(e){try{return e()}catch(t){}}(r=c||(c={})).debug=d("debug"),r.log=d("log"),r.warn=d("warn"),r.error=d("error");let p=h(function(){return globalThis})||h(function(){return window})||h(function(){return self})||h(function(){return global})||h(function(){return h.constructor("return this")()});var b="__",m=[b,b].join("DEV");function g(){try{return Boolean(__DEV__)}catch(e){return Object.defineProperty(p,m,{value:"production"!==h(function(){return"production"}),enumerable:!1,configurable:!0,writable:!0}),p[m]}}let v=g();function y(e){try{return e()}catch(t){}}var w=y(function(){return globalThis})||y(function(){return window})||y(function(){return self})||y(function(){return global})||y(function(){return y.constructor("return this")()}),_=!1;function E(){!w||y(function(){return"production"})||y(function(){return process})||(Object.defineProperty(w,"process",{value:{env:{NODE_ENV:"production"}},configurable:!0,enumerable:!1,writable:!0}),_=!0)}function S(){_&&(delete w.process,_=!1)}E();var k=n(10143);function x(){return k.H,S()}function T(){__DEV__?c("boolean"==typeof v,v):c("boolean"==typeof v,39)}x(),T()},87462(e,t,n){"use strict";function r(){return(r=Object.assign||function(e){for(var t=1;tr})},25821(e,t,n){"use strict";n.d(t,{Z:()=>s});var r=n(45695);function i(e){return(i="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e})(e)}var a=10,o=2;function s(e){return u(e,[])}function u(e,t){switch(i(e)){case"string":return JSON.stringify(e);case"function":return e.name?"[function ".concat(e.name,"]"):"[function]";case"object":if(null===e)return"null";return c(e,t);default:return String(e)}}function c(e,t){if(-1!==t.indexOf(e))return"[Circular]";var n=[].concat(t,[e]),r=d(e);if(void 0!==r){var i=r.call(e);if(i!==e)return"string"==typeof i?i:u(i,n)}else if(Array.isArray(e))return f(e,n);return l(e,n)}function l(e,t){var n=Object.keys(e);return 0===n.length?"{}":t.length>o?"["+h(e)+"]":"{ "+n.map(function(n){var r=u(e[n],t);return n+": "+r}).join(", ")+" }"}function f(e,t){if(0===e.length)return"[]";if(t.length>o)return"[Array]";for(var n=Math.min(a,e.length),r=e.length-n,i=[],s=0;s1&&i.push("... ".concat(r," more items")),"["+i.join(", ")+"]"}function d(e){var t=e[String(r.Z)];return"function"==typeof t?t:"function"==typeof e.inspect?e.inspect:void 0}function h(e){var t=Object.prototype.toString.call(e).replace(/^\[object /,"").replace(/]$/,"");if("Object"===t&&"function"==typeof e.constructor){var n=e.constructor.name;if("string"==typeof n&&""!==n)return n}return t}},45695(e,t,n){"use strict";n.d(t,{Z:()=>i});var r="function"==typeof Symbol&&"function"==typeof Symbol.for?Symbol.for("nodejs.util.inspect.custom"):void 0;let i=r},25217(e,t,n){"use strict";function r(e,t){if(!Boolean(e))throw Error(null!=t?t:"Unexpected invariant triggered.")}n.d(t,{Ye:()=>o,WU:()=>s,UG:()=>u});var i=n(45695);function a(e){var t=e.prototype.toJSON;"function"==typeof t||r(0),e.prototype.inspect=t,i.Z&&(e.prototype[i.Z]=t)}var o=function(){function e(e,t,n){this.start=e.start,this.end=t.end,this.startToken=e,this.endToken=t,this.source=n}return e.prototype.toJSON=function(){return{start:this.start,end:this.end}},e}();a(o);var s=function(){function e(e,t,n,r,i,a,o){this.kind=e,this.start=t,this.end=n,this.line=r,this.column=i,this.value=o,this.prev=a,this.next=null}return e.prototype.toJSON=function(){return{kind:this.kind,value:this.value,line:this.line,column:this.column}},e}();function u(e){return null!=e&&"string"==typeof e.kind}a(s)},87392(e,t,n){"use strict";function r(e){var t=e.split(/\r\n|[\n\r]/g),n=a(e);if(0!==n)for(var r=1;ro&&i(t[s-1]);)--s;return t.slice(o,s).join("\n")}function i(e){for(var t=0;t1&&void 0!==arguments[1]?arguments[1]:"",n=arguments.length>2&&void 0!==arguments[2]&&arguments[2],r=-1===e.indexOf("\n"),i=" "===e[0]||" "===e[0],a='"'===e[e.length-1],o="\\"===e[e.length-1],s=!r||a||o||n,u="";return s&&!(r&&i)&&(u+="\n"+t),u+=t?e.replace(/\n/g,"\n"+t):e,s&&(u+="\n"),'"""'+u.replace(/"""/g,'\\"""')+'"""'}n.d(t,{LZ:()=>o,W7:()=>r})},97359(e,t,n){"use strict";n.d(t,{h:()=>r});var r=Object.freeze({NAME:"Name",DOCUMENT:"Document",OPERATION_DEFINITION:"OperationDefinition",VARIABLE_DEFINITION:"VariableDefinition",SELECTION_SET:"SelectionSet",FIELD:"Field",ARGUMENT:"Argument",FRAGMENT_SPREAD:"FragmentSpread",INLINE_FRAGMENT:"InlineFragment",FRAGMENT_DEFINITION:"FragmentDefinition",VARIABLE:"Variable",INT:"IntValue",FLOAT:"FloatValue",STRING:"StringValue",BOOLEAN:"BooleanValue",NULL:"NullValue",ENUM:"EnumValue",LIST:"ListValue",OBJECT:"ObjectValue",OBJECT_FIELD:"ObjectField",DIRECTIVE:"Directive",NAMED_TYPE:"NamedType",LIST_TYPE:"ListType",NON_NULL_TYPE:"NonNullType",SCHEMA_DEFINITION:"SchemaDefinition",OPERATION_TYPE_DEFINITION:"OperationTypeDefinition",SCALAR_TYPE_DEFINITION:"ScalarTypeDefinition",OBJECT_TYPE_DEFINITION:"ObjectTypeDefinition",FIELD_DEFINITION:"FieldDefinition",INPUT_VALUE_DEFINITION:"InputValueDefinition",INTERFACE_TYPE_DEFINITION:"InterfaceTypeDefinition",UNION_TYPE_DEFINITION:"UnionTypeDefinition",ENUM_TYPE_DEFINITION:"EnumTypeDefinition",ENUM_VALUE_DEFINITION:"EnumValueDefinition",INPUT_OBJECT_TYPE_DEFINITION:"InputObjectTypeDefinition",DIRECTIVE_DEFINITION:"DirectiveDefinition",SCHEMA_EXTENSION:"SchemaExtension",SCALAR_TYPE_EXTENSION:"ScalarTypeExtension",OBJECT_TYPE_EXTENSION:"ObjectTypeExtension",INTERFACE_TYPE_EXTENSION:"InterfaceTypeExtension",UNION_TYPE_EXTENSION:"UnionTypeExtension",ENUM_TYPE_EXTENSION:"EnumTypeExtension",INPUT_OBJECT_TYPE_EXTENSION:"InputObjectTypeExtension"})},10143(e,t,n){"use strict";n.d(t,{H:()=>c,T:()=>l});var r=n(99763),i=n(25821);function a(e,t){if(!Boolean(e))throw Error(t)}let o=function(e,t){return e instanceof t};function s(e,t){for(var n=0;n1&&void 0!==arguments[1]?arguments[1]:"GraphQL request",n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:{line:1,column:1};"string"==typeof e||a(0,"Body must be a string. Received: ".concat((0,i.Z)(e),".")),this.body=e,this.name=t,this.locationOffset=n,this.locationOffset.line>0||a(0,"line in locationOffset is 1-indexed and must be positive."),this.locationOffset.column>0||a(0,"column in locationOffset is 1-indexed and must be positive.")}return u(e,[{key:r.YF,get:function(){return"Source"}}]),e}();function l(e){return o(e,c)}},99763(e,t,n){"use strict";n.d(t,{YF:()=>r});var r="function"==typeof Symbol&&null!=Symbol.toStringTag?Symbol.toStringTag:"@@toStringTag"},37452(e){"use strict";e.exports=JSON.parse('{"AElig":"\xc6","AMP":"&","Aacute":"\xc1","Acirc":"\xc2","Agrave":"\xc0","Aring":"\xc5","Atilde":"\xc3","Auml":"\xc4","COPY":"\xa9","Ccedil":"\xc7","ETH":"\xd0","Eacute":"\xc9","Ecirc":"\xca","Egrave":"\xc8","Euml":"\xcb","GT":">","Iacute":"\xcd","Icirc":"\xce","Igrave":"\xcc","Iuml":"\xcf","LT":"<","Ntilde":"\xd1","Oacute":"\xd3","Ocirc":"\xd4","Ograve":"\xd2","Oslash":"\xd8","Otilde":"\xd5","Ouml":"\xd6","QUOT":"\\"","REG":"\xae","THORN":"\xde","Uacute":"\xda","Ucirc":"\xdb","Ugrave":"\xd9","Uuml":"\xdc","Yacute":"\xdd","aacute":"\xe1","acirc":"\xe2","acute":"\xb4","aelig":"\xe6","agrave":"\xe0","amp":"&","aring":"\xe5","atilde":"\xe3","auml":"\xe4","brvbar":"\xa6","ccedil":"\xe7","cedil":"\xb8","cent":"\xa2","copy":"\xa9","curren":"\xa4","deg":"\xb0","divide":"\xf7","eacute":"\xe9","ecirc":"\xea","egrave":"\xe8","eth":"\xf0","euml":"\xeb","frac12":"\xbd","frac14":"\xbc","frac34":"\xbe","gt":">","iacute":"\xed","icirc":"\xee","iexcl":"\xa1","igrave":"\xec","iquest":"\xbf","iuml":"\xef","laquo":"\xab","lt":"<","macr":"\xaf","micro":"\xb5","middot":"\xb7","nbsp":"\xa0","not":"\xac","ntilde":"\xf1","oacute":"\xf3","ocirc":"\xf4","ograve":"\xf2","ordf":"\xaa","ordm":"\xba","oslash":"\xf8","otilde":"\xf5","ouml":"\xf6","para":"\xb6","plusmn":"\xb1","pound":"\xa3","quot":"\\"","raquo":"\xbb","reg":"\xae","sect":"\xa7","shy":"\xad","sup1":"\xb9","sup2":"\xb2","sup3":"\xb3","szlig":"\xdf","thorn":"\xfe","times":"\xd7","uacute":"\xfa","ucirc":"\xfb","ugrave":"\xf9","uml":"\xa8","uuml":"\xfc","yacute":"\xfd","yen":"\xa5","yuml":"\xff"}')},93580(e){"use strict";e.exports=JSON.parse('{"0":"�","128":"€","130":"‚","131":"ƒ","132":"„","133":"…","134":"†","135":"‡","136":"ˆ","137":"‰","138":"Š","139":"‹","140":"Œ","142":"Ž","145":"‘","146":"’","147":"“","148":"”","149":"•","150":"–","151":"—","152":"˜","153":"™","154":"š","155":"›","156":"œ","158":"ž","159":"Ÿ"}')},67946(e){"use strict";e.exports=JSON.parse('{"locale":"en","long":{"year":{"previous":"last year","current":"this year","next":"next year","past":{"one":"{0} year ago","other":"{0} years ago"},"future":{"one":"in {0} year","other":"in {0} years"}},"quarter":{"previous":"last quarter","current":"this quarter","next":"next quarter","past":{"one":"{0} quarter ago","other":"{0} quarters ago"},"future":{"one":"in {0} quarter","other":"in {0} quarters"}},"month":{"previous":"last month","current":"this month","next":"next month","past":{"one":"{0} month ago","other":"{0} months ago"},"future":{"one":"in {0} month","other":"in {0} months"}},"week":{"previous":"last week","current":"this week","next":"next week","past":{"one":"{0} week ago","other":"{0} weeks ago"},"future":{"one":"in {0} week","other":"in {0} weeks"}},"day":{"previous":"yesterday","current":"today","next":"tomorrow","past":{"one":"{0} day ago","other":"{0} days ago"},"future":{"one":"in {0} day","other":"in {0} days"}},"hour":{"current":"this hour","past":{"one":"{0} hour ago","other":"{0} hours ago"},"future":{"one":"in {0} hour","other":"in {0} hours"}},"minute":{"current":"this minute","past":{"one":"{0} minute ago","other":"{0} minutes ago"},"future":{"one":"in {0} minute","other":"in {0} minutes"}},"second":{"current":"now","past":{"one":"{0} second ago","other":"{0} seconds ago"},"future":{"one":"in {0} second","other":"in {0} seconds"}}},"short":{"year":{"previous":"last yr.","current":"this yr.","next":"next yr.","past":"{0} yr. ago","future":"in {0} yr."},"quarter":{"previous":"last qtr.","current":"this qtr.","next":"next qtr.","past":{"one":"{0} qtr. ago","other":"{0} qtrs. ago"},"future":{"one":"in {0} qtr.","other":"in {0} qtrs."}},"month":{"previous":"last mo.","current":"this mo.","next":"next mo.","past":"{0} mo. ago","future":"in {0} mo."},"week":{"previous":"last wk.","current":"this wk.","next":"next wk.","past":"{0} wk. ago","future":"in {0} wk."},"day":{"previous":"yesterday","current":"today","next":"tomorrow","past":{"one":"{0} day ago","other":"{0} days ago"},"future":{"one":"in {0} day","other":"in {0} days"}},"hour":{"current":"this hour","past":"{0} hr. ago","future":"in {0} hr."},"minute":{"current":"this minute","past":"{0} min. ago","future":"in {0} min."},"second":{"current":"now","past":"{0} sec. ago","future":"in {0} sec."}},"narrow":{"year":{"previous":"last yr.","current":"this yr.","next":"next yr.","past":"{0} yr. ago","future":"in {0} yr."},"quarter":{"previous":"last qtr.","current":"this qtr.","next":"next qtr.","past":{"one":"{0} qtr. ago","other":"{0} qtrs. ago"},"future":{"one":"in {0} qtr.","other":"in {0} qtrs."}},"month":{"previous":"last mo.","current":"this mo.","next":"next mo.","past":"{0} mo. ago","future":"in {0} mo."},"week":{"previous":"last wk.","current":"this wk.","next":"next wk.","past":"{0} wk. ago","future":"in {0} wk."},"day":{"previous":"yesterday","current":"today","next":"tomorrow","past":{"one":"{0} day ago","other":"{0} days ago"},"future":{"one":"in {0} day","other":"in {0} days"}},"hour":{"current":"this hour","past":"{0} hr. ago","future":"in {0} hr."},"minute":{"current":"this minute","past":"{0} min. ago","future":"in {0} min."},"second":{"current":"now","past":"{0} sec. ago","future":"in {0} sec."}},"now":{"now":{"current":"now","future":"in a moment","past":"just now"}},"mini":{"year":"{0}yr","month":"{0}mo","week":"{0}wk","day":"{0}d","hour":"{0}h","minute":"{0}m","second":"{0}s","now":"now"},"short-time":{"year":"{0} yr.","month":"{0} mo.","week":"{0} wk.","day":{"one":"{0} day","other":"{0} days"},"hour":"{0} hr.","minute":"{0} min.","second":"{0} sec."},"long-time":{"year":{"one":"{0} year","other":"{0} years"},"month":{"one":"{0} month","other":"{0} months"},"week":{"one":"{0} week","other":"{0} weeks"},"day":{"one":"{0} day","other":"{0} days"},"hour":{"one":"{0} hour","other":"{0} hours"},"minute":{"one":"{0} minute","other":"{0} minutes"},"second":{"one":"{0} second","other":"{0} seconds"}}}')}},__webpack_module_cache__={};function __webpack_require__(e){var t=__webpack_module_cache__[e];if(void 0!==t)return t.exports;var n=__webpack_module_cache__[e]={id:e,loaded:!1,exports:{}};return __webpack_modules__[e].call(n.exports,n,n.exports,__webpack_require__),n.loaded=!0,n.exports}__webpack_require__.n=e=>{var t=e&&e.__esModule?()=>e.default:()=>e;return __webpack_require__.d(t,{a:t}),t},(()=>{var e,t=Object.getPrototypeOf?e=>Object.getPrototypeOf(e):e=>e.__proto__;__webpack_require__.t=function(n,r){if(1&r&&(n=this(n)),8&r||"object"==typeof n&&n&&(4&r&&n.__esModule||16&r&&"function"==typeof n.then))return n;var i=Object.create(null);__webpack_require__.r(i);var a={};e=e||[null,t({}),t([]),t(t)];for(var o=2&r&&n;"object"==typeof o&&!~e.indexOf(o);o=t(o))Object.getOwnPropertyNames(o).forEach(e=>a[e]=()=>n[e]);return a.default=()=>n,__webpack_require__.d(i,a),i}})(),__webpack_require__.d=(e,t)=>{for(var n in t)__webpack_require__.o(t,n)&&!__webpack_require__.o(e,n)&&Object.defineProperty(e,n,{enumerable:!0,get:t[n]})},__webpack_require__.g=function(){if("object"==typeof globalThis)return globalThis;try{return this||Function("return this")()}catch(e){if("object"==typeof window)return window}}(),__webpack_require__.hmd=e=>((e=Object.create(e)).children||(e.children=[]),Object.defineProperty(e,"exports",{enumerable:!0,set(){throw Error("ES Modules may not assign module.exports or exports.*, Use ESM export syntax, instead: "+e.id)}}),e),__webpack_require__.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t),__webpack_require__.r=e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},__webpack_require__.nmd=e=>(e.paths=[],e.children||(e.children=[]),e),__webpack_require__.p="/assets/",__webpack_require__.nc=void 0;var __webpack_exports__={};(()=>{"use strict";var e,t,n,r,i=__webpack_require__(32316),a=__webpack_require__(8126),o=__webpack_require__(5690),s=__webpack_require__(30381),u=__webpack_require__.n(s),c=__webpack_require__(67294),l=__webpack_require__(73935),f=__webpack_require__.n(l),d=__webpack_require__(57209),h=__webpack_require__(55977),p=__webpack_require__(15857),b=__webpack_require__(28500);function m(e){return function(t){var n=t.dispatch,r=t.getState;return function(t){return function(i){return"function"==typeof i?i(n,r,e):t(i)}}}}var g=m();g.withExtraArgument=m;let v=g;var y=__webpack_require__(76489);function w(e){return function(t){return function(n){return function(r){n(r);var i=e||document&&document.cookie||"",a=t.getState();if("MATCH_ROUTE"===r.type&&"/signin"!==a.notifications.currentUrl){var o=(0,y.Q)(i);if(o.explorer)try{var s=JSON.parse(o.explorer);if("error"===s.status){var u=_(s.url);n({type:"NOTIFY_ERROR_MSG",msg:u})}}catch(c){n({type:"NOTIFY_ERROR_MSG",msg:"Invalid explorer status"})}}}}}}function _(e){var t="Can't connect to explorer: ".concat(e);return e.match(/^wss?:.+/)?t:"".concat(t,". You must use a websocket.")}var E=__webpack_require__(16353);function S(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=Array(t);n=e.length?{done:!0}:{done:!1,value:e[r++]}}}throw TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}function ei(e,t){if(e){if("string"==typeof e)return ea(e,t);var n=Object.prototype.toString.call(e).slice(8,-1);if("Object"===n&&e.constructor&&(n=e.constructor.name),"Map"===n||"Set"===n)return Array.from(e);if("Arguments"===n||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n))return ea(e,t)}}function ea(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=Array(t);n1,i=!1,a=arguments[1],o=a;return new n(function(n){return t.subscribe({next:function(t){var a=!i;if(i=!0,!a||r)try{o=e(o,t)}catch(s){return n.error(s)}else o=t},error:function(e){n.error(e)},complete:function(){if(!i&&!r)return n.error(TypeError("Cannot reduce an empty sequence"));n.next(o),n.complete()}})})},t.concat=function(){for(var e=this,t=arguments.length,n=Array(t),r=0;r=0&&i.splice(e,1),o()}});i.push(s)},error:function(e){r.error(e)},complete:function(){o()}});function o(){a.closed&&0===i.length&&r.complete()}return function(){i.forEach(function(e){return e.unsubscribe()}),a.unsubscribe()}})},t[ed]=function(){return this},e.from=function(t){var n="function"==typeof this?this:e;if(null==t)throw TypeError(t+" is not an object");var r=ep(t,ed);if(r){var i=r.call(t);if(Object(i)!==i)throw TypeError(i+" is not an object");return em(i)&&i.constructor===n?i:new n(function(e){return i.subscribe(e)})}if(ec("iterator")&&(r=ep(t,ef)))return new n(function(e){ev(function(){if(!e.closed){for(var n,i=er(r.call(t));!(n=i()).done;){var a=n.value;if(e.next(a),e.closed)return}e.complete()}})});if(Array.isArray(t))return new n(function(e){ev(function(){if(!e.closed){for(var n=0;n0))return n.connection.key;var r=n.connection.filter?n.connection.filter:[];r.sort();var i={};return r.forEach(function(e){i[e]=t[e]}),"".concat(n.connection.key,"(").concat(eV(i),")")}var a=e;if(t){var o=eV(t);a+="(".concat(o,")")}return n&&Object.keys(n).forEach(function(e){-1===eW.indexOf(e)&&(n[e]&&Object.keys(n[e]).length?a+="@".concat(e,"(").concat(eV(n[e]),")"):a+="@".concat(e))}),a},{setStringify:function(e){var t=eV;return eV=e,t}}),eV=function(e){return JSON.stringify(e,eq)};function eq(e,t){return(0,eO.s)(t)&&!Array.isArray(t)&&(t=Object.keys(t).sort().reduce(function(e,n){return e[n]=t[n],e},{})),t}function eZ(e,t){if(e.arguments&&e.arguments.length){var n={};return e.arguments.forEach(function(e){var r;return ez(n,e.name,e.value,t)}),n}return null}function eX(e){return e.alias?e.alias.value:e.name.value}function eJ(e,t,n){for(var r,i=0,a=t.selections;it.indexOf(i))throw __DEV__?new Q.ej("illegal argument: ".concat(i)):new Q.ej(27)}return e}function tt(e,t){return t?t(e):eT.of()}function tn(e){return"function"==typeof e?new ta(e):e}function tr(e){return e.request.length<=1}var ti=function(e){function t(t,n){var r=e.call(this,t)||this;return r.link=n,r}return(0,en.ZT)(t,e),t}(Error),ta=function(){function e(e){e&&(this.request=e)}return e.empty=function(){return new e(function(){return eT.of()})},e.from=function(t){return 0===t.length?e.empty():t.map(tn).reduce(function(e,t){return e.concat(t)})},e.split=function(t,n,r){var i=tn(n),a=tn(r||new e(tt));return new e(tr(i)&&tr(a)?function(e){return t(e)?i.request(e)||eT.of():a.request(e)||eT.of()}:function(e,n){return t(e)?i.request(e,n)||eT.of():a.request(e,n)||eT.of()})},e.execute=function(e,t){return e.request(eM(t.context,e7(te(t))))||eT.of()},e.concat=function(t,n){var r=tn(t);if(tr(r))return __DEV__&&Q.kG.warn(new ti("You are calling concat on a terminating link, which will have no effect",r)),r;var i=tn(n);return new e(tr(i)?function(e){return r.request(e,function(e){return i.request(e)||eT.of()})||eT.of()}:function(e,t){return r.request(e,function(e){return i.request(e,t)||eT.of()})||eT.of()})},e.prototype.split=function(t,n,r){return this.concat(e.split(t,n,r||new e(tt)))},e.prototype.concat=function(t){return e.concat(this,t)},e.prototype.request=function(e,t){throw __DEV__?new Q.ej("request is not implemented"):new Q.ej(22)},e.prototype.onError=function(e,t){if(t&&t.error)return t.error(e),!1;throw e},e.prototype.setOnError=function(e){return this.onError=e,this},e}(),to=__webpack_require__(25821),ts=__webpack_require__(25217),tu={Name:[],Document:["definitions"],OperationDefinition:["name","variableDefinitions","directives","selectionSet"],VariableDefinition:["variable","type","defaultValue","directives"],Variable:["name"],SelectionSet:["selections"],Field:["alias","name","arguments","directives","selectionSet"],Argument:["name","value"],FragmentSpread:["name","directives"],InlineFragment:["typeCondition","directives","selectionSet"],FragmentDefinition:["name","variableDefinitions","typeCondition","directives","selectionSet"],IntValue:[],FloatValue:[],StringValue:[],BooleanValue:[],NullValue:[],EnumValue:[],ListValue:["values"],ObjectValue:["fields"],ObjectField:["name","value"],Directive:["name","arguments"],NamedType:["name"],ListType:["type"],NonNullType:["type"],SchemaDefinition:["description","directives","operationTypes"],OperationTypeDefinition:["type"],ScalarTypeDefinition:["description","name","directives"],ObjectTypeDefinition:["description","name","interfaces","directives","fields"],FieldDefinition:["description","name","arguments","type","directives"],InputValueDefinition:["description","name","type","defaultValue","directives"],InterfaceTypeDefinition:["description","name","interfaces","directives","fields"],UnionTypeDefinition:["description","name","directives","types"],EnumTypeDefinition:["description","name","directives","values"],EnumValueDefinition:["description","name","directives"],InputObjectTypeDefinition:["description","name","directives","fields"],DirectiveDefinition:["description","name","arguments","locations"],SchemaExtension:["directives","operationTypes"],ScalarTypeExtension:["name","directives"],ObjectTypeExtension:["name","interfaces","directives","fields"],InterfaceTypeExtension:["name","interfaces","directives","fields"],UnionTypeExtension:["name","directives","types"],EnumTypeExtension:["name","directives","values"],InputObjectTypeExtension:["name","directives","fields"]},tc=Object.freeze({});function tl(e,t){var n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:tu,r=void 0,i=Array.isArray(e),a=[e],o=-1,s=[],u=void 0,c=void 0,l=void 0,f=[],d=[],h=e;do{var p,b=++o===a.length,m=b&&0!==s.length;if(b){if(c=0===d.length?void 0:f[f.length-1],u=l,l=d.pop(),m){if(i)u=u.slice();else{for(var g={},v=0,y=Object.keys(u);v1)for(var r=new tB,i=1;i=0;--a){var o=i[a],s=isNaN(+o)?{}:[];s[o]=t,t=s}n=r.merge(n,t)}),n}var tW=Object.prototype.hasOwnProperty;function tK(e,t){var n,r,i,a,o;return(0,en.mG)(this,void 0,void 0,function(){var s,u,c,l,f,d,h,p,b,m,g,v,y,w,_,E,S,k,x,T,M,O,A;return(0,en.Jh)(this,function(L){switch(L.label){case 0:if(void 0===TextDecoder)throw Error("TextDecoder must be defined in the environment: please import a polyfill.");s=new TextDecoder("utf-8"),u=null===(n=e.headers)||void 0===n?void 0:n.get("content-type"),c="boundary=",l=(null==u?void 0:u.includes(c))?null==u?void 0:u.substring((null==u?void 0:u.indexOf(c))+c.length).replace(/['"]/g,"").replace(/\;(.*)/gm,"").trim():"-",f="\r\n--".concat(l),d="",h=tI(e),p=!0,L.label=1;case 1:if(!p)return[3,3];return[4,h.next()];case 2:for(m=(b=L.sent()).value,g=b.done,v="string"==typeof m?m:s.decode(m),y=d.length-f.length+1,p=!g,d+=v,w=d.indexOf(f,y);w>-1;){if(_=void 0,_=(O=[d.slice(0,w),d.slice(w+f.length),])[0],d=O[1],E=_.indexOf("\r\n\r\n"),(k=(S=tV(_.slice(0,E)))["content-type"])&&-1===k.toLowerCase().indexOf("application/json"))throw Error("Unsupported patch content type: application/json is required.");if(x=_.slice(E))try{T=tq(e,x),Object.keys(T).length>1||"data"in T||"incremental"in T||"errors"in T||"payload"in T?tz(T)?(M={},"payload"in T&&(M=(0,en.pi)({},T.payload)),"errors"in T&&(M=(0,en.pi)((0,en.pi)({},M),{extensions:(0,en.pi)((0,en.pi)({},"extensions"in M?M.extensions:null),((A={})[tN.YG]=T.errors,A))})),null===(r=t.next)||void 0===r||r.call(t,M)):null===(i=t.next)||void 0===i||i.call(t,T):1===Object.keys(T).length&&"hasNext"in T&&!T.hasNext&&(null===(a=t.complete)||void 0===a||a.call(t))}catch(C){tZ(C,t)}w=d.indexOf(f)}return[3,1];case 3:return null===(o=t.complete)||void 0===o||o.call(t),[2]}})})}function tV(e){var t={};return e.split("\n").forEach(function(e){var n=e.indexOf(":");if(n>-1){var r=e.slice(0,n).trim().toLowerCase(),i=e.slice(n+1).trim();t[r]=i}}),t}function tq(e,t){e.status>=300&&tD(e,function(){try{return JSON.parse(t)}catch(e){return t}}(),"Response not successful: Received status code ".concat(e.status));try{return JSON.parse(t)}catch(n){var r=n;throw r.name="ServerParseError",r.response=e,r.statusCode=e.status,r.bodyText=t,r}}function tZ(e,t){var n,r;"AbortError"!==e.name&&(e.result&&e.result.errors&&e.result.data&&(null===(n=t.next)||void 0===n||n.call(t,e.result)),null===(r=t.error)||void 0===r||r.call(t,e))}function tX(e,t,n){tJ(t)(e).then(function(e){var t,r;null===(t=n.next)||void 0===t||t.call(n,e),null===(r=n.complete)||void 0===r||r.call(n)}).catch(function(e){return tZ(e,n)})}function tJ(e){return function(t){return t.text().then(function(e){return tq(t,e)}).then(function(n){return t.status>=300&&tD(t,n,"Response not successful: Received status code ".concat(t.status)),Array.isArray(n)||tW.call(n,"data")||tW.call(n,"errors")||tD(t,n,"Server response was missing for query '".concat(Array.isArray(e)?e.map(function(e){return e.operationName}):e.operationName,"'.")),n})}}var tQ=function(e){if(!e&&"undefined"==typeof fetch)throw __DEV__?new Q.ej("\n\"fetch\" has not been found globally and no fetcher has been configured. To fix this, install a fetch package (like https://www.npmjs.com/package/cross-fetch), instantiate the fetcher, and pass it into your HttpLink constructor. For example:\n\nimport fetch from 'cross-fetch';\nimport { ApolloClient, HttpLink } from '@apollo/client';\nconst client = new ApolloClient({\n link: new HttpLink({ uri: '/graphql', fetch })\n});\n "):new Q.ej(23)},t1=__webpack_require__(87392);function t0(e){return tl(e,{leave:t3})}var t2=80,t3={Name:function(e){return e.value},Variable:function(e){return"$"+e.name},Document:function(e){return t5(e.definitions,"\n\n")+"\n"},OperationDefinition:function(e){var t=e.operation,n=e.name,r=t9("(",t5(e.variableDefinitions,", "),")"),i=t5(e.directives," "),a=e.selectionSet;return n||i||r||"query"!==t?t5([t,t5([n,r]),i,a]," "):a},VariableDefinition:function(e){var t=e.variable,n=e.type,r=e.defaultValue,i=e.directives;return t+": "+n+t9(" = ",r)+t9(" ",t5(i," "))},SelectionSet:function(e){return t6(e.selections)},Field:function(e){var t=e.alias,n=e.name,r=e.arguments,i=e.directives,a=e.selectionSet,o=t9("",t,": ")+n,s=o+t9("(",t5(r,", "),")");return s.length>t2&&(s=o+t9("(\n",t8(t5(r,"\n")),"\n)")),t5([s,t5(i," "),a]," ")},Argument:function(e){var t;return e.name+": "+e.value},FragmentSpread:function(e){var t;return"..."+e.name+t9(" ",t5(e.directives," "))},InlineFragment:function(e){var t=e.typeCondition,n=e.directives,r=e.selectionSet;return t5(["...",t9("on ",t),t5(n," "),r]," ")},FragmentDefinition:function(e){var t=e.name,n=e.typeCondition,r=e.variableDefinitions,i=e.directives,a=e.selectionSet;return"fragment ".concat(t).concat(t9("(",t5(r,", "),")")," ")+"on ".concat(n," ").concat(t9("",t5(i," ")," "))+a},IntValue:function(e){return e.value},FloatValue:function(e){return e.value},StringValue:function(e,t){var n=e.value;return e.block?(0,t1.LZ)(n,"description"===t?"":" "):JSON.stringify(n)},BooleanValue:function(e){return e.value?"true":"false"},NullValue:function(){return"null"},EnumValue:function(e){return e.value},ListValue:function(e){return"["+t5(e.values,", ")+"]"},ObjectValue:function(e){return"{"+t5(e.fields,", ")+"}"},ObjectField:function(e){var t;return e.name+": "+e.value},Directive:function(e){var t;return"@"+e.name+t9("(",t5(e.arguments,", "),")")},NamedType:function(e){return e.name},ListType:function(e){return"["+e.type+"]"},NonNullType:function(e){return e.type+"!"},SchemaDefinition:t4(function(e){var t=e.directives,n=e.operationTypes;return t5(["schema",t5(t," "),t6(n)]," ")}),OperationTypeDefinition:function(e){var t;return e.operation+": "+e.type},ScalarTypeDefinition:t4(function(e){var t;return t5(["scalar",e.name,t5(e.directives," ")]," ")}),ObjectTypeDefinition:t4(function(e){var t=e.name,n=e.interfaces,r=e.directives,i=e.fields;return t5(["type",t,t9("implements ",t5(n," & ")),t5(r," "),t6(i)]," ")}),FieldDefinition:t4(function(e){var t=e.name,n=e.arguments,r=e.type,i=e.directives;return t+(ne(n)?t9("(\n",t8(t5(n,"\n")),"\n)"):t9("(",t5(n,", "),")"))+": "+r+t9(" ",t5(i," "))}),InputValueDefinition:t4(function(e){var t=e.name,n=e.type,r=e.defaultValue,i=e.directives;return t5([t+": "+n,t9("= ",r),t5(i," ")]," ")}),InterfaceTypeDefinition:t4(function(e){var t=e.name,n=e.interfaces,r=e.directives,i=e.fields;return t5(["interface",t,t9("implements ",t5(n," & ")),t5(r," "),t6(i)]," ")}),UnionTypeDefinition:t4(function(e){var t=e.name,n=e.directives,r=e.types;return t5(["union",t,t5(n," "),r&&0!==r.length?"= "+t5(r," | "):""]," ")}),EnumTypeDefinition:t4(function(e){var t=e.name,n=e.directives,r=e.values;return t5(["enum",t,t5(n," "),t6(r)]," ")}),EnumValueDefinition:t4(function(e){var t;return t5([e.name,t5(e.directives," ")]," ")}),InputObjectTypeDefinition:t4(function(e){var t=e.name,n=e.directives,r=e.fields;return t5(["input",t,t5(n," "),t6(r)]," ")}),DirectiveDefinition:t4(function(e){var t=e.name,n=e.arguments,r=e.repeatable,i=e.locations;return"directive @"+t+(ne(n)?t9("(\n",t8(t5(n,"\n")),"\n)"):t9("(",t5(n,", "),")"))+(r?" repeatable":"")+" on "+t5(i," | ")}),SchemaExtension:function(e){var t=e.directives,n=e.operationTypes;return t5(["extend schema",t5(t," "),t6(n)]," ")},ScalarTypeExtension:function(e){var t;return t5(["extend scalar",e.name,t5(e.directives," ")]," ")},ObjectTypeExtension:function(e){var t=e.name,n=e.interfaces,r=e.directives,i=e.fields;return t5(["extend type",t,t9("implements ",t5(n," & ")),t5(r," "),t6(i)]," ")},InterfaceTypeExtension:function(e){var t=e.name,n=e.interfaces,r=e.directives,i=e.fields;return t5(["extend interface",t,t9("implements ",t5(n," & ")),t5(r," "),t6(i)]," ")},UnionTypeExtension:function(e){var t=e.name,n=e.directives,r=e.types;return t5(["extend union",t,t5(n," "),r&&0!==r.length?"= "+t5(r," | "):""]," ")},EnumTypeExtension:function(e){var t=e.name,n=e.directives,r=e.values;return t5(["extend enum",t,t5(n," "),t6(r)]," ")},InputObjectTypeExtension:function(e){var t=e.name,n=e.directives,r=e.fields;return t5(["extend input",t,t5(n," "),t6(r)]," ")}};function t4(e){return function(t){return t5([t.description,e(t)],"\n")}}function t5(e){var t,n=arguments.length>1&&void 0!==arguments[1]?arguments[1]:"";return null!==(t=null==e?void 0:e.filter(function(e){return e}).join(n))&&void 0!==t?t:""}function t6(e){return t9("{\n",t8(t5(e,"\n")),"\n}")}function t9(e,t){var n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:"";return null!=t&&""!==t?e+t+n:""}function t8(e){return t9(" ",e.replace(/\n/g,"\n "))}function t7(e){return -1!==e.indexOf("\n")}function ne(e){return null!=e&&e.some(t7)}var nt,nn,nr,ni={http:{includeQuery:!0,includeExtensions:!1,preserveHeaderCase:!1},headers:{accept:"*/*","content-type":"application/json"},options:{method:"POST"}},na=function(e,t){return t(e)};function no(e,t){for(var n=[],r=2;rObject.create(null),{forEach:nv,slice:ny}=Array.prototype,{hasOwnProperty:nw}=Object.prototype;class n_{constructor(e=!0,t=ng){this.weakness=e,this.makeData=t}lookup(...e){return this.lookupArray(e)}lookupArray(e){let t=this;return nv.call(e,e=>t=t.getChildTrie(e)),nw.call(t,"data")?t.data:t.data=this.makeData(ny.call(e))}peek(...e){return this.peekArray(e)}peekArray(e){let t=this;for(let n=0,r=e.length;t&&n=0;--o)t.definitions[o].kind===nL.h.OPERATION_DEFINITION&&++a;var s=nN(e),u=e.some(function(e){return e.remove}),c=function(e){return u&&e&&e.some(s)},l=new Map,f=!1,d={enter:function(e){if(c(e.directives))return f=!0,null}},h=tl(t,{Field:d,InlineFragment:d,VariableDefinition:{enter:function(){return!1}},Variable:{enter:function(e,t,n,r,a){var o=i(a);o&&o.variables.add(e.name.value)}},FragmentSpread:{enter:function(e,t,n,r,a){if(c(e.directives))return f=!0,null;var o=i(a);o&&o.fragmentSpreads.add(e.name.value)}},FragmentDefinition:{enter:function(e,t,n,r){l.set(JSON.stringify(r),e)},leave:function(e,t,n,i){return e===l.get(JSON.stringify(i))?e:a>0&&e.selectionSet.selections.every(function(e){return e.kind===nL.h.FIELD&&"__typename"===e.name.value})?(r(e.name.value).removed=!0,f=!0,null):void 0}},Directive:{leave:function(e){if(s(e))return f=!0,null}}});if(!f)return t;var p=function(e){return e.transitiveVars||(e.transitiveVars=new Set(e.variables),e.removed||e.fragmentSpreads.forEach(function(t){p(r(t)).transitiveVars.forEach(function(t){e.transitiveVars.add(t)})})),e},b=new Set;h.definitions.forEach(function(e){e.kind===nL.h.OPERATION_DEFINITION?p(n(e.name&&e.name.value)).fragmentSpreads.forEach(function(e){b.add(e)}):e.kind!==nL.h.FRAGMENT_DEFINITION||0!==a||r(e.name.value).removed||b.add(e.name.value)}),b.forEach(function(e){p(r(e)).fragmentSpreads.forEach(function(e){b.add(e)})});var m=function(e){return!!(!b.has(e)||r(e).removed)},g={enter:function(e){if(m(e.name.value))return null}};return nD(tl(h,{FragmentSpread:g,FragmentDefinition:g,OperationDefinition:{leave:function(e){if(e.variableDefinitions){var t=p(n(e.name&&e.name.value)).transitiveVars;if(t.size0},t.prototype.tearDownQuery=function(){this.isTornDown||(this.concast&&this.observer&&(this.concast.removeObserver(this.observer),delete this.concast,delete this.observer),this.stopPolling(),this.subscriptions.forEach(function(e){return e.unsubscribe()}),this.subscriptions.clear(),this.queryManager.stopQuery(this.queryId),this.observers.clear(),this.isTornDown=!0)},t}(eT);function n4(e){var t=e.options,n=t.fetchPolicy,r=t.nextFetchPolicy;return"cache-and-network"===n||"network-only"===n?e.reobserve({fetchPolicy:"cache-first",nextFetchPolicy:function(){return(this.nextFetchPolicy=r,"function"==typeof r)?r.apply(this,arguments):n}}):e.reobserve()}function n5(e){__DEV__&&Q.kG.error("Unhandled error",e.message,e.stack)}function n6(e){__DEV__&&e&&__DEV__&&Q.kG.debug("Missing cache result fields: ".concat(JSON.stringify(e)),e)}function n9(e){return"network-only"===e||"no-cache"===e||"standby"===e}nK(n3);function n8(e){return e.kind===nL.h.FIELD||e.kind===nL.h.FRAGMENT_SPREAD||e.kind===nL.h.INLINE_FRAGMENT}function n7(e){return e.kind===Kind.SCALAR_TYPE_DEFINITION||e.kind===Kind.OBJECT_TYPE_DEFINITION||e.kind===Kind.INTERFACE_TYPE_DEFINITION||e.kind===Kind.UNION_TYPE_DEFINITION||e.kind===Kind.ENUM_TYPE_DEFINITION||e.kind===Kind.INPUT_OBJECT_TYPE_DEFINITION}function re(e){return e.kind===Kind.SCALAR_TYPE_EXTENSION||e.kind===Kind.OBJECT_TYPE_EXTENSION||e.kind===Kind.INTERFACE_TYPE_EXTENSION||e.kind===Kind.UNION_TYPE_EXTENSION||e.kind===Kind.ENUM_TYPE_EXTENSION||e.kind===Kind.INPUT_OBJECT_TYPE_EXTENSION}var rt=function(){return Object.create(null)},rn=Array.prototype,rr=rn.forEach,ri=rn.slice,ra=function(){function e(e,t){void 0===e&&(e=!0),void 0===t&&(t=rt),this.weakness=e,this.makeData=t}return e.prototype.lookup=function(){for(var e=[],t=0;tclass{constructor(){this.id=["slot",rc++,Date.now(),Math.random().toString(36).slice(2),].join(":")}hasValue(){for(let e=rs;e;e=e.parent)if(this.id in e.slots){let t=e.slots[this.id];if(t===ru)break;return e!==rs&&(rs.slots[this.id]=t),!0}return rs&&(rs.slots[this.id]=ru),!1}getValue(){if(this.hasValue())return rs.slots[this.id]}withValue(e,t,n,r){let i={__proto__:null,[this.id]:e},a=rs;rs={parent:a,slots:i};try{return t.apply(r,n)}finally{rs=a}}static bind(e){let t=rs;return function(){let n=rs;try{return rs=t,e.apply(this,arguments)}finally{rs=n}}}static noContext(e,t,n){if(!rs)return e.apply(n,t);{let r=rs;try{return rs=null,e.apply(n,t)}finally{rs=r}}}};function rf(e){try{return e()}catch(t){}}let rd="@wry/context:Slot",rh=rf(()=>globalThis)||rf(()=>global)||Object.create(null),rp=rh,rb=rp[rd]||Array[rd]||function(e){try{Object.defineProperty(rp,rd,{value:e,enumerable:!1,writable:!1,configurable:!0})}finally{return e}}(rl()),{bind:rm,noContext:rg}=rb;function rv(){}var ry=function(){function e(e,t){void 0===e&&(e=1/0),void 0===t&&(t=rv),this.max=e,this.dispose=t,this.map=new Map,this.newest=null,this.oldest=null}return e.prototype.has=function(e){return this.map.has(e)},e.prototype.get=function(e){var t=this.getNode(e);return t&&t.value},e.prototype.getNode=function(e){var t=this.map.get(e);if(t&&t!==this.newest){var n=t.older,r=t.newer;r&&(r.older=n),n&&(n.newer=r),t.older=this.newest,t.older.newer=t,t.newer=null,this.newest=t,t===this.oldest&&(this.oldest=r)}return t},e.prototype.set=function(e,t){var n=this.getNode(e);return n?n.value=t:(n={key:e,value:t,newer:null,older:this.newest},this.newest&&(this.newest.newer=n),this.newest=n,this.oldest=this.oldest||n,this.map.set(e,n),n.value)},e.prototype.clean=function(){for(;this.oldest&&this.map.size>this.max;)this.delete(this.oldest.key)},e.prototype.delete=function(e){var t=this.map.get(e);return!!t&&(t===this.newest&&(this.newest=t.older),t===this.oldest&&(this.oldest=t.newer),t.newer&&(t.newer.older=t.older),t.older&&(t.older.newer=t.newer),this.map.delete(e),this.dispose(t.value,e),!0)},e}(),rw=new rb,r_=Object.prototype.hasOwnProperty,rE=void 0===(n=Array.from)?function(e){var t=[];return e.forEach(function(e){return t.push(e)}),t}:n;function rS(e){var t=e.unsubscribe;"function"==typeof t&&(e.unsubscribe=void 0,t())}var rk=[],rx=100;function rT(e,t){if(!e)throw Error(t||"assertion failure")}function rM(e,t){var n=e.length;return n>0&&n===t.length&&e[n-1]===t[n-1]}function rO(e){switch(e.length){case 0:throw Error("unknown value");case 1:return e[0];case 2:throw e[1]}}function rA(e){return e.slice(0)}var rL=function(){function e(t){this.fn=t,this.parents=new Set,this.childValues=new Map,this.dirtyChildren=null,this.dirty=!0,this.recomputing=!1,this.value=[],this.deps=null,++e.count}return e.prototype.peek=function(){if(1===this.value.length&&!rN(this))return rC(this),this.value[0]},e.prototype.recompute=function(e){return rT(!this.recomputing,"already recomputing"),rC(this),rN(this)?rI(this,e):rO(this.value)},e.prototype.setDirty=function(){this.dirty||(this.dirty=!0,this.value.length=0,rR(this),rS(this))},e.prototype.dispose=function(){var e=this;this.setDirty(),rH(this),rF(this,function(t,n){t.setDirty(),r$(t,e)})},e.prototype.forget=function(){this.dispose()},e.prototype.dependOn=function(e){e.add(this),this.deps||(this.deps=rk.pop()||new Set),this.deps.add(e)},e.prototype.forgetDeps=function(){var e=this;this.deps&&(rE(this.deps).forEach(function(t){return t.delete(e)}),this.deps.clear(),rk.push(this.deps),this.deps=null)},e.count=0,e}();function rC(e){var t=rw.getValue();if(t)return e.parents.add(t),t.childValues.has(e)||t.childValues.set(e,[]),rN(e)?rY(t,e):rB(t,e),t}function rI(e,t){return rH(e),rw.withValue(e,rD,[e,t]),rz(e,t)&&rP(e),rO(e.value)}function rD(e,t){e.recomputing=!0,e.value.length=0;try{e.value[0]=e.fn.apply(null,t)}catch(n){e.value[1]=n}e.recomputing=!1}function rN(e){return e.dirty||!!(e.dirtyChildren&&e.dirtyChildren.size)}function rP(e){e.dirty=!1,!rN(e)&&rj(e)}function rR(e){rF(e,rY)}function rj(e){rF(e,rB)}function rF(e,t){var n=e.parents.size;if(n)for(var r=rE(e.parents),i=0;i0&&e.childValues.forEach(function(t,n){r$(e,n)}),e.forgetDeps(),rT(null===e.dirtyChildren)}function r$(e,t){t.parents.delete(e),e.childValues.delete(t),rU(e,t)}function rz(e,t){if("function"==typeof e.subscribe)try{rS(e),e.unsubscribe=e.subscribe.apply(null,t)}catch(n){return e.setDirty(),!1}return!0}var rG={setDirty:!0,dispose:!0,forget:!0};function rW(e){var t=new Map,n=e&&e.subscribe;function r(e){var r=rw.getValue();if(r){var i=t.get(e);i||t.set(e,i=new Set),r.dependOn(i),"function"==typeof n&&(rS(i),i.unsubscribe=n(e))}}return r.dirty=function(e,n){var r=t.get(e);if(r){var i=n&&r_.call(rG,n)?n:"setDirty";rE(r).forEach(function(e){return e[i]()}),t.delete(e),rS(r)}},r}function rK(){var e=new ra("function"==typeof WeakMap);return function(){return e.lookupArray(arguments)}}var rV=rK(),rq=new Set;function rZ(e,t){void 0===t&&(t=Object.create(null));var n=new ry(t.max||65536,function(e){return e.dispose()}),r=t.keyArgs,i=t.makeCacheKey||rK(),a=function(){var a=i.apply(null,r?r.apply(null,arguments):arguments);if(void 0===a)return e.apply(null,arguments);var o=n.get(a);o||(n.set(a,o=new rL(e)),o.subscribe=t.subscribe,o.forget=function(){return n.delete(a)});var s=o.recompute(Array.prototype.slice.call(arguments));return n.set(a,o),rq.add(n),rw.hasValue()||(rq.forEach(function(e){return e.clean()}),rq.clear()),s};function o(e){var t=n.get(e);t&&t.setDirty()}function s(e){var t=n.get(e);if(t)return t.peek()}function u(e){return n.delete(e)}return Object.defineProperty(a,"size",{get:function(){return n.map.size},configurable:!1,enumerable:!1}),a.dirtyKey=o,a.dirty=function(){o(i.apply(null,arguments))},a.peekKey=s,a.peek=function(){return s(i.apply(null,arguments))},a.forgetKey=u,a.forget=function(){return u(i.apply(null,arguments))},a.makeCacheKey=i,a.getKey=r?function(){return i.apply(null,r.apply(null,arguments))}:i,Object.freeze(a)}var rX=new rb,rJ=new WeakMap;function rQ(e){var t=rJ.get(e);return t||rJ.set(e,t={vars:new Set,dep:rW()}),t}function r1(e){rQ(e).vars.forEach(function(t){return t.forgetCache(e)})}function r0(e){rQ(e).vars.forEach(function(t){return t.attachCache(e)})}function r2(e){var t=new Set,n=new Set,r=function(a){if(arguments.length>0){if(e!==a){e=a,t.forEach(function(e){rQ(e).dep.dirty(r),r3(e)});var o=Array.from(n);n.clear(),o.forEach(function(t){return t(e)})}}else{var s=rX.getValue();s&&(i(s),rQ(s).dep(r))}return e};r.onNextChange=function(e){return n.add(e),function(){n.delete(e)}};var i=r.attachCache=function(e){return t.add(e),rQ(e).vars.add(r),r};return r.forgetCache=function(e){return t.delete(e)},r}function r3(e){e.broadcastWatches&&e.broadcastWatches()}var r4=function(){function e(e){var t=e.cache,n=e.client,r=e.resolvers,i=e.fragmentMatcher;this.selectionsToResolveCache=new WeakMap,this.cache=t,n&&(this.client=n),r&&this.addResolvers(r),i&&this.setFragmentMatcher(i)}return e.prototype.addResolvers=function(e){var t=this;this.resolvers=this.resolvers||{},Array.isArray(e)?e.forEach(function(e){t.resolvers=tj(t.resolvers,e)}):this.resolvers=tj(this.resolvers,e)},e.prototype.setResolvers=function(e){this.resolvers={},this.addResolvers(e)},e.prototype.getResolvers=function(){return this.resolvers||{}},e.prototype.runResolvers=function(e){var t=e.document,n=e.remoteResult,r=e.context,i=e.variables,a=e.onlyRunForcedResolvers,o=void 0!==a&&a;return(0,en.mG)(this,void 0,void 0,function(){return(0,en.Jh)(this,function(e){return t?[2,this.resolveDocument(t,n.data,r,i,this.fragmentMatcher,o).then(function(e){return(0,en.pi)((0,en.pi)({},n),{data:e.result})})]:[2,n]})})},e.prototype.setFragmentMatcher=function(e){this.fragmentMatcher=e},e.prototype.getFragmentMatcher=function(){return this.fragmentMatcher},e.prototype.clientQuery=function(e){return tb(["client"],e)&&this.resolvers?e:null},e.prototype.serverQuery=function(e){return n$(e)},e.prototype.prepareContext=function(e){var t=this.cache;return(0,en.pi)((0,en.pi)({},e),{cache:t,getCacheKey:function(e){return t.identify(e)}})},e.prototype.addExportedVariables=function(e,t,n){return void 0===t&&(t={}),void 0===n&&(n={}),(0,en.mG)(this,void 0,void 0,function(){return(0,en.Jh)(this,function(r){return e?[2,this.resolveDocument(e,this.buildRootValueFromCache(e,t)||{},this.prepareContext(n),t).then(function(e){return(0,en.pi)((0,en.pi)({},t),e.exportedVariables)})]:[2,(0,en.pi)({},t)]})})},e.prototype.shouldForceResolvers=function(e){var t=!1;return tl(e,{Directive:{enter:function(e){if("client"===e.name.value&&e.arguments&&(t=e.arguments.some(function(e){return"always"===e.name.value&&"BooleanValue"===e.value.kind&&!0===e.value.value})))return tc}}}),t},e.prototype.buildRootValueFromCache=function(e,t){return this.cache.diff({query:nH(e),variables:t,returnPartialData:!0,optimistic:!1}).result},e.prototype.resolveDocument=function(e,t,n,r,i,a){return void 0===n&&(n={}),void 0===r&&(r={}),void 0===i&&(i=function(){return!0}),void 0===a&&(a=!1),(0,en.mG)(this,void 0,void 0,function(){var o,s,u,c,l,f,d,h,p,b,m;return(0,en.Jh)(this,function(g){return o=e9(e),s=e4(e),u=eL(s),c=this.collectSelectionsToResolve(o,u),f=(l=o.operation)?l.charAt(0).toUpperCase()+l.slice(1):"Query",d=this,h=d.cache,p=d.client,b={fragmentMap:u,context:(0,en.pi)((0,en.pi)({},n),{cache:h,client:p}),variables:r,fragmentMatcher:i,defaultOperationType:f,exportedVariables:{},selectionsToResolve:c,onlyRunForcedResolvers:a},m=!1,[2,this.resolveSelectionSet(o.selectionSet,m,t,b).then(function(e){return{result:e,exportedVariables:b.exportedVariables}})]})})},e.prototype.resolveSelectionSet=function(e,t,n,r){return(0,en.mG)(this,void 0,void 0,function(){var i,a,o,s,u,c=this;return(0,en.Jh)(this,function(l){return i=r.fragmentMap,a=r.context,o=r.variables,s=[n],u=function(e){return(0,en.mG)(c,void 0,void 0,function(){var u,c;return(0,en.Jh)(this,function(l){return(t||r.selectionsToResolve.has(e))&&td(e,o)?eQ(e)?[2,this.resolveField(e,t,n,r).then(function(t){var n;void 0!==t&&s.push(((n={})[eX(e)]=t,n))})]:(e1(e)?u=e:(u=i[e.name.value],__DEV__?(0,Q.kG)(u,"No fragment named ".concat(e.name.value)):(0,Q.kG)(u,11)),u&&u.typeCondition&&(c=u.typeCondition.name.value,r.fragmentMatcher(n,c,a)))?[2,this.resolveSelectionSet(u.selectionSet,t,n,r).then(function(e){s.push(e)})]:[2]:[2]})})},[2,Promise.all(e.selections.map(u)).then(function(){return tF(s)})]})})},e.prototype.resolveField=function(e,t,n,r){return(0,en.mG)(this,void 0,void 0,function(){var i,a,o,s,u,c,l,f,d,h=this;return(0,en.Jh)(this,function(p){return n?(i=r.variables,a=e.name.value,o=eX(e),s=a!==o,c=Promise.resolve(u=n[o]||n[a]),(!r.onlyRunForcedResolvers||this.shouldForceResolvers(e))&&(l=n.__typename||r.defaultOperationType,(f=this.resolvers&&this.resolvers[l])&&(d=f[s?a:o])&&(c=Promise.resolve(rX.withValue(this.cache,d,[n,eZ(e,i),r.context,{field:e,fragmentMap:r.fragmentMap},])))),[2,c.then(function(n){if(void 0===n&&(n=u),e.directives&&e.directives.forEach(function(e){"export"===e.name.value&&e.arguments&&e.arguments.forEach(function(e){"as"===e.name.value&&"StringValue"===e.value.kind&&(r.exportedVariables[e.value.value]=n)})}),!e.selectionSet||null==n)return n;var i,a,o=null!==(a=null===(i=e.directives)||void 0===i?void 0:i.some(function(e){return"client"===e.name.value}))&&void 0!==a&&a;return Array.isArray(n)?h.resolveSubSelectedArray(e,t||o,n,r):e.selectionSet?h.resolveSelectionSet(e.selectionSet,t||o,n,r):void 0})]):[2,null]})})},e.prototype.resolveSubSelectedArray=function(e,t,n,r){var i=this;return Promise.all(n.map(function(n){return null===n?null:Array.isArray(n)?i.resolveSubSelectedArray(e,t,n,r):e.selectionSet?i.resolveSelectionSet(e.selectionSet,t,n,r):void 0}))},e.prototype.collectSelectionsToResolve=function(e,t){var n=function(e){return!Array.isArray(e)},r=this.selectionsToResolveCache;function i(e){if(!r.has(e)){var a=new Set;r.set(e,a),tl(e,{Directive:function(e,t,r,i,o){"client"===e.name.value&&o.forEach(function(e){n(e)&&n8(e)&&a.add(e)})},FragmentSpread:function(e,r,o,s,u){var c=t[e.name.value];__DEV__?(0,Q.kG)(c,"No fragment named ".concat(e.name.value)):(0,Q.kG)(c,12);var l=i(c);l.size>0&&(u.forEach(function(e){n(e)&&n8(e)&&a.add(e)}),a.add(e),l.forEach(function(e){a.add(e)}))}})}return r.get(e)}return i(e)},e}(),r5=new(t_.mr?WeakMap:Map);function r6(e,t){var n=e[t];"function"==typeof n&&(e[t]=function(){return r5.set(e,(r5.get(e)+1)%1e15),n.apply(this,arguments)})}function r9(e){e.notifyTimeout&&(clearTimeout(e.notifyTimeout),e.notifyTimeout=void 0)}var r8=function(){function e(e,t){void 0===t&&(t=e.generateQueryId()),this.queryId=t,this.listeners=new Set,this.document=null,this.lastRequestId=1,this.subscriptions=new Set,this.stopped=!1,this.dirty=!1,this.observableQuery=null;var n=this.cache=e.cache;r5.has(n)||(r5.set(n,0),r6(n,"evict"),r6(n,"modify"),r6(n,"reset"))}return e.prototype.init=function(e){var t=e.networkStatus||nZ.I.loading;return this.variables&&this.networkStatus!==nZ.I.loading&&!(0,nm.D)(this.variables,e.variables)&&(t=nZ.I.setVariables),(0,nm.D)(e.variables,this.variables)||(this.lastDiff=void 0),Object.assign(this,{document:e.document,variables:e.variables,networkError:null,graphQLErrors:this.graphQLErrors||[],networkStatus:t}),e.observableQuery&&this.setObservableQuery(e.observableQuery),e.lastRequestId&&(this.lastRequestId=e.lastRequestId),this},e.prototype.reset=function(){r9(this),this.dirty=!1},e.prototype.getDiff=function(e){void 0===e&&(e=this.variables);var t=this.getDiffOptions(e);if(this.lastDiff&&(0,nm.D)(t,this.lastDiff.options))return this.lastDiff.diff;this.updateWatch(this.variables=e);var n=this.observableQuery;if(n&&"no-cache"===n.options.fetchPolicy)return{complete:!1};var r=this.cache.diff(t);return this.updateLastDiff(r,t),r},e.prototype.updateLastDiff=function(e,t){this.lastDiff=e?{diff:e,options:t||this.getDiffOptions()}:void 0},e.prototype.getDiffOptions=function(e){var t;return void 0===e&&(e=this.variables),{query:this.document,variables:e,returnPartialData:!0,optimistic:!0,canonizeResults:null===(t=this.observableQuery)||void 0===t?void 0:t.options.canonizeResults}},e.prototype.setDiff=function(e){var t=this,n=this.lastDiff&&this.lastDiff.diff;this.updateLastDiff(e),this.dirty||(0,nm.D)(n&&n.result,e&&e.result)||(this.dirty=!0,this.notifyTimeout||(this.notifyTimeout=setTimeout(function(){return t.notify()},0)))},e.prototype.setObservableQuery=function(e){var t=this;e!==this.observableQuery&&(this.oqListener&&this.listeners.delete(this.oqListener),this.observableQuery=e,e?(e.queryInfo=this,this.listeners.add(this.oqListener=function(){t.getDiff().fromOptimisticTransaction?e.observe():n4(e)})):delete this.oqListener)},e.prototype.notify=function(){var e=this;r9(this),this.shouldNotify()&&this.listeners.forEach(function(t){return t(e)}),this.dirty=!1},e.prototype.shouldNotify=function(){if(!this.dirty||!this.listeners.size)return!1;if((0,nZ.O)(this.networkStatus)&&this.observableQuery){var e=this.observableQuery.options.fetchPolicy;if("cache-only"!==e&&"cache-and-network"!==e)return!1}return!0},e.prototype.stop=function(){if(!this.stopped){this.stopped=!0,this.reset(),this.cancel(),this.cancel=e.prototype.cancel,this.subscriptions.forEach(function(e){return e.unsubscribe()});var t=this.observableQuery;t&&t.stopPolling()}},e.prototype.cancel=function(){},e.prototype.updateWatch=function(e){var t=this;void 0===e&&(e=this.variables);var n=this.observableQuery;if(!n||"no-cache"!==n.options.fetchPolicy){var r=(0,en.pi)((0,en.pi)({},this.getDiffOptions(e)),{watcher:this,callback:function(e){return t.setDiff(e)}});this.lastWatch&&(0,nm.D)(r,this.lastWatch)||(this.cancel(),this.cancel=this.cache.watch(this.lastWatch=r))}},e.prototype.resetLastWrite=function(){this.lastWrite=void 0},e.prototype.shouldWrite=function(e,t){var n=this.lastWrite;return!(n&&n.dmCount===r5.get(this.cache)&&(0,nm.D)(t,n.variables)&&(0,nm.D)(e.data,n.result.data))},e.prototype.markResult=function(e,t,n,r){var i=this,a=new tB,o=(0,tP.O)(e.errors)?e.errors.slice(0):[];if(this.reset(),"incremental"in e&&(0,tP.O)(e.incremental)){var s=tG(this.getDiff().result,e);e.data=s}else if("hasNext"in e&&e.hasNext){var u=this.getDiff();e.data=a.merge(u.result,e.data)}this.graphQLErrors=o,"no-cache"===n.fetchPolicy?this.updateLastDiff({result:e.data,complete:!0},this.getDiffOptions(n.variables)):0!==r&&(r7(e,n.errorPolicy)?this.cache.performTransaction(function(a){if(i.shouldWrite(e,n.variables))a.writeQuery({query:t,data:e.data,variables:n.variables,overwrite:1===r}),i.lastWrite={result:e,variables:n.variables,dmCount:r5.get(i.cache)};else if(i.lastDiff&&i.lastDiff.diff.complete){e.data=i.lastDiff.diff.result;return}var o=i.getDiffOptions(n.variables),s=a.diff(o);i.stopped||i.updateWatch(n.variables),i.updateLastDiff(s,o),s.complete&&(e.data=s.result)}):this.lastWrite=void 0)},e.prototype.markReady=function(){return this.networkError=null,this.networkStatus=nZ.I.ready},e.prototype.markError=function(e){return this.networkStatus=nZ.I.error,this.lastWrite=void 0,this.reset(),e.graphQLErrors&&(this.graphQLErrors=e.graphQLErrors),e.networkError&&(this.networkError=e.networkError),e},e}();function r7(e,t){void 0===t&&(t="none");var n="ignore"===t||"all"===t,r=!nO(e);return!r&&n&&e.data&&(r=!0),r}var ie=Object.prototype.hasOwnProperty,it=function(){function e(e){var t=e.cache,n=e.link,r=e.defaultOptions,i=e.queryDeduplication,a=void 0!==i&&i,o=e.onBroadcast,s=e.ssrMode,u=void 0!==s&&s,c=e.clientAwareness,l=void 0===c?{}:c,f=e.localState,d=e.assumeImmutableResults;this.clientAwareness={},this.queries=new Map,this.fetchCancelFns=new Map,this.transformCache=new(t_.mr?WeakMap:Map),this.queryIdCounter=1,this.requestIdCounter=1,this.mutationIdCounter=1,this.inFlightLinkObservables=new Map,this.cache=t,this.link=n,this.defaultOptions=r||Object.create(null),this.queryDeduplication=a,this.clientAwareness=l,this.localState=f||new r4({cache:t}),this.ssrMode=u,this.assumeImmutableResults=!!d,(this.onBroadcast=o)&&(this.mutationStore=Object.create(null))}return e.prototype.stop=function(){var e=this;this.queries.forEach(function(t,n){e.stopQueryNoBroadcast(n)}),this.cancelPendingFetches(__DEV__?new Q.ej("QueryManager stopped while query was in flight"):new Q.ej(14))},e.prototype.cancelPendingFetches=function(e){this.fetchCancelFns.forEach(function(t){return t(e)}),this.fetchCancelFns.clear()},e.prototype.mutate=function(e){var t,n,r=e.mutation,i=e.variables,a=e.optimisticResponse,o=e.updateQueries,s=e.refetchQueries,u=void 0===s?[]:s,c=e.awaitRefetchQueries,l=void 0!==c&&c,f=e.update,d=e.onQueryUpdated,h=e.fetchPolicy,p=void 0===h?(null===(t=this.defaultOptions.mutate)||void 0===t?void 0:t.fetchPolicy)||"network-only":h,b=e.errorPolicy,m=void 0===b?(null===(n=this.defaultOptions.mutate)||void 0===n?void 0:n.errorPolicy)||"none":b,g=e.keepRootFields,v=e.context;return(0,en.mG)(this,void 0,void 0,function(){var e,t,n,s,c,h;return(0,en.Jh)(this,function(b){switch(b.label){case 0:if(__DEV__?(0,Q.kG)(r,"mutation option is required. You must specify your GraphQL document in the mutation option."):(0,Q.kG)(r,15),__DEV__?(0,Q.kG)("network-only"===p||"no-cache"===p,"Mutations support only 'network-only' or 'no-cache' fetchPolicy strings. The default `network-only` behavior automatically writes mutation results to the cache. Passing `no-cache` skips the cache write."):(0,Q.kG)("network-only"===p||"no-cache"===p,16),e=this.generateMutationId(),n=(t=this.transform(r)).document,s=t.hasClientExports,r=this.cache.transformForLink(n),i=this.getVariables(r,i),!s)return[3,2];return[4,this.localState.addExportedVariables(r,i,v)];case 1:i=b.sent(),b.label=2;case 2:return c=this.mutationStore&&(this.mutationStore[e]={mutation:r,variables:i,loading:!0,error:null}),a&&this.markMutationOptimistic(a,{mutationId:e,document:r,variables:i,fetchPolicy:p,errorPolicy:m,context:v,updateQueries:o,update:f,keepRootFields:g}),this.broadcastQueries(),h=this,[2,new Promise(function(t,n){return nM(h.getObservableFromLink(r,(0,en.pi)((0,en.pi)({},v),{optimisticResponse:a}),i,!1),function(t){if(nO(t)&&"none"===m)throw new tN.cA({graphQLErrors:nA(t)});c&&(c.loading=!1,c.error=null);var n=(0,en.pi)({},t);return"function"==typeof u&&(u=u(n)),"ignore"===m&&nO(n)&&delete n.errors,h.markMutationResult({mutationId:e,result:n,document:r,variables:i,fetchPolicy:p,errorPolicy:m,context:v,update:f,updateQueries:o,awaitRefetchQueries:l,refetchQueries:u,removeOptimistic:a?e:void 0,onQueryUpdated:d,keepRootFields:g})}).subscribe({next:function(e){h.broadcastQueries(),"hasNext"in e&&!1!==e.hasNext||t(e)},error:function(t){c&&(c.loading=!1,c.error=t),a&&h.cache.removeOptimistic(e),h.broadcastQueries(),n(t instanceof tN.cA?t:new tN.cA({networkError:t}))}})})]}})})},e.prototype.markMutationResult=function(e,t){var n=this;void 0===t&&(t=this.cache);var r=e.result,i=[],a="no-cache"===e.fetchPolicy;if(!a&&r7(r,e.errorPolicy)){if(tU(r)||i.push({result:r.data,dataId:"ROOT_MUTATION",query:e.document,variables:e.variables}),tU(r)&&(0,tP.O)(r.incremental)){var o=t.diff({id:"ROOT_MUTATION",query:this.transform(e.document).asQuery,variables:e.variables,optimistic:!1,returnPartialData:!0}),s=void 0;o.result&&(s=tG(o.result,r)),void 0!==s&&(r.data=s,i.push({result:s,dataId:"ROOT_MUTATION",query:e.document,variables:e.variables}))}var u=e.updateQueries;u&&this.queries.forEach(function(e,a){var o=e.observableQuery,s=o&&o.queryName;if(s&&ie.call(u,s)){var c,l=u[s],f=n.queries.get(a),d=f.document,h=f.variables,p=t.diff({query:d,variables:h,returnPartialData:!0,optimistic:!1}),b=p.result;if(p.complete&&b){var m=l(b,{mutationResult:r,queryName:d&&e3(d)||void 0,queryVariables:h});m&&i.push({result:m,dataId:"ROOT_QUERY",query:d,variables:h})}}})}if(i.length>0||e.refetchQueries||e.update||e.onQueryUpdated||e.removeOptimistic){var c=[];if(this.refetchQueries({updateCache:function(t){a||i.forEach(function(e){return t.write(e)});var o=e.update,s=!t$(r)||tU(r)&&!r.hasNext;if(o){if(!a){var u=t.diff({id:"ROOT_MUTATION",query:n.transform(e.document).asQuery,variables:e.variables,optimistic:!1,returnPartialData:!0});u.complete&&("incremental"in(r=(0,en.pi)((0,en.pi)({},r),{data:u.result}))&&delete r.incremental,"hasNext"in r&&delete r.hasNext)}s&&o(t,r,{context:e.context,variables:e.variables})}a||e.keepRootFields||!s||t.modify({id:"ROOT_MUTATION",fields:function(e,t){var n=t.fieldName,r=t.DELETE;return"__typename"===n?e:r}})},include:e.refetchQueries,optimistic:!1,removeOptimistic:e.removeOptimistic,onQueryUpdated:e.onQueryUpdated||null}).forEach(function(e){return c.push(e)}),e.awaitRefetchQueries||e.onQueryUpdated)return Promise.all(c).then(function(){return r})}return Promise.resolve(r)},e.prototype.markMutationOptimistic=function(e,t){var n=this,r="function"==typeof e?e(t.variables):e;return this.cache.recordOptimisticTransaction(function(e){try{n.markMutationResult((0,en.pi)((0,en.pi)({},t),{result:{data:r}}),e)}catch(i){__DEV__&&Q.kG.error(i)}},t.mutationId)},e.prototype.fetchQuery=function(e,t,n){return this.fetchQueryObservable(e,t,n).promise},e.prototype.getQueryStore=function(){var e=Object.create(null);return this.queries.forEach(function(t,n){e[n]={variables:t.variables,networkStatus:t.networkStatus,networkError:t.networkError,graphQLErrors:t.graphQLErrors}}),e},e.prototype.resetErrors=function(e){var t=this.queries.get(e);t&&(t.networkError=void 0,t.graphQLErrors=[])},e.prototype.transform=function(e){var t=this.transformCache;if(!t.has(e)){var n=this.cache.transformDocument(e),r=nY(n),i=this.localState.clientQuery(n),a=r&&this.localState.serverQuery(r),o={document:n,hasClientExports:tm(n),hasForcedResolvers:this.localState.shouldForceResolvers(n),clientQuery:i,serverQuery:a,defaultVars:e8(e2(n)),asQuery:(0,en.pi)((0,en.pi)({},n),{definitions:n.definitions.map(function(e){return"OperationDefinition"===e.kind&&"query"!==e.operation?(0,en.pi)((0,en.pi)({},e),{operation:"query"}):e})})},s=function(e){e&&!t.has(e)&&t.set(e,o)};s(e),s(n),s(i),s(a)}return t.get(e)},e.prototype.getVariables=function(e,t){return(0,en.pi)((0,en.pi)({},this.transform(e).defaultVars),t)},e.prototype.watchQuery=function(e){void 0===(e=(0,en.pi)((0,en.pi)({},e),{variables:this.getVariables(e.query,e.variables)})).notifyOnNetworkStatusChange&&(e.notifyOnNetworkStatusChange=!1);var t=new r8(this),n=new n3({queryManager:this,queryInfo:t,options:e});return this.queries.set(n.queryId,t),t.init({document:n.query,observableQuery:n,variables:n.variables}),n},e.prototype.query=function(e,t){var n=this;return void 0===t&&(t=this.generateQueryId()),__DEV__?(0,Q.kG)(e.query,"query option is required. You must specify your GraphQL document in the query option."):(0,Q.kG)(e.query,17),__DEV__?(0,Q.kG)("Document"===e.query.kind,'You must wrap the query string in a "gql" tag.'):(0,Q.kG)("Document"===e.query.kind,18),__DEV__?(0,Q.kG)(!e.returnPartialData,"returnPartialData option only supported on watchQuery."):(0,Q.kG)(!e.returnPartialData,19),__DEV__?(0,Q.kG)(!e.pollInterval,"pollInterval option only supported on watchQuery."):(0,Q.kG)(!e.pollInterval,20),this.fetchQuery(t,e).finally(function(){return n.stopQuery(t)})},e.prototype.generateQueryId=function(){return String(this.queryIdCounter++)},e.prototype.generateRequestId=function(){return this.requestIdCounter++},e.prototype.generateMutationId=function(){return String(this.mutationIdCounter++)},e.prototype.stopQueryInStore=function(e){this.stopQueryInStoreNoBroadcast(e),this.broadcastQueries()},e.prototype.stopQueryInStoreNoBroadcast=function(e){var t=this.queries.get(e);t&&t.stop()},e.prototype.clearStore=function(e){return void 0===e&&(e={discardWatches:!0}),this.cancelPendingFetches(__DEV__?new Q.ej("Store reset while query was in flight (not completed in link chain)"):new Q.ej(21)),this.queries.forEach(function(e){e.observableQuery?e.networkStatus=nZ.I.loading:e.stop()}),this.mutationStore&&(this.mutationStore=Object.create(null)),this.cache.reset(e)},e.prototype.getObservableQueries=function(e){var t=this;void 0===e&&(e="active");var n=new Map,r=new Map,i=new Set;return Array.isArray(e)&&e.forEach(function(e){"string"==typeof e?r.set(e,!1):eN(e)?r.set(t.transform(e).document,!1):(0,eO.s)(e)&&e.query&&i.add(e)}),this.queries.forEach(function(t,i){var a=t.observableQuery,o=t.document;if(a){if("all"===e){n.set(i,a);return}var s=a.queryName;if("standby"===a.options.fetchPolicy||"active"===e&&!a.hasObservers())return;("active"===e||s&&r.has(s)||o&&r.has(o))&&(n.set(i,a),s&&r.set(s,!0),o&&r.set(o,!0))}}),i.size&&i.forEach(function(e){var r=nG("legacyOneTimeQuery"),i=t.getQuery(r).init({document:e.query,variables:e.variables}),a=new n3({queryManager:t,queryInfo:i,options:(0,en.pi)((0,en.pi)({},e),{fetchPolicy:"network-only"})});(0,Q.kG)(a.queryId===r),i.setObservableQuery(a),n.set(r,a)}),__DEV__&&r.size&&r.forEach(function(e,t){!e&&__DEV__&&Q.kG.warn("Unknown query ".concat("string"==typeof t?"named ":"").concat(JSON.stringify(t,null,2)," requested in refetchQueries options.include array"))}),n},e.prototype.reFetchObservableQueries=function(e){var t=this;void 0===e&&(e=!1);var n=[];return this.getObservableQueries(e?"all":"active").forEach(function(r,i){var a=r.options.fetchPolicy;r.resetLastResults(),(e||"standby"!==a&&"cache-only"!==a)&&n.push(r.refetch()),t.getQuery(i).setDiff(null)}),this.broadcastQueries(),Promise.all(n)},e.prototype.setObservableQuery=function(e){this.getQuery(e.queryId).setObservableQuery(e)},e.prototype.startGraphQLSubscription=function(e){var t=this,n=e.query,r=e.fetchPolicy,i=e.errorPolicy,a=e.variables,o=e.context,s=void 0===o?{}:o;n=this.transform(n).document,a=this.getVariables(n,a);var u=function(e){return t.getObservableFromLink(n,s,e).map(function(a){"no-cache"!==r&&(r7(a,i)&&t.cache.write({query:n,result:a.data,dataId:"ROOT_SUBSCRIPTION",variables:e}),t.broadcastQueries());var o=nO(a),s=(0,tN.ls)(a);if(o||s){var u={};throw o&&(u.graphQLErrors=a.errors),s&&(u.protocolErrors=a.extensions[tN.YG]),new tN.cA(u)}return a})};if(this.transform(n).hasClientExports){var c=this.localState.addExportedVariables(n,a,s).then(u);return new eT(function(e){var t=null;return c.then(function(n){return t=n.subscribe(e)},e.error),function(){return t&&t.unsubscribe()}})}return u(a)},e.prototype.stopQuery=function(e){this.stopQueryNoBroadcast(e),this.broadcastQueries()},e.prototype.stopQueryNoBroadcast=function(e){this.stopQueryInStoreNoBroadcast(e),this.removeQuery(e)},e.prototype.removeQuery=function(e){this.fetchCancelFns.delete(e),this.queries.has(e)&&(this.getQuery(e).stop(),this.queries.delete(e))},e.prototype.broadcastQueries=function(){this.onBroadcast&&this.onBroadcast(),this.queries.forEach(function(e){return e.notify()})},e.prototype.getLocalState=function(){return this.localState},e.prototype.getObservableFromLink=function(e,t,n,r){var i,a,o=this;void 0===r&&(r=null!==(i=null==t?void 0:t.queryDeduplication)&&void 0!==i?i:this.queryDeduplication);var s=this.transform(e).serverQuery;if(s){var u=this,c=u.inFlightLinkObservables,l=u.link,f={query:s,variables:n,operationName:e3(s)||void 0,context:this.prepareContext((0,en.pi)((0,en.pi)({},t),{forceFetch:!r}))};if(t=f.context,r){var d=c.get(s)||new Map;c.set(s,d);var h=nx(n);if(!(a=d.get(h))){var p=new nq([np(l,f)]);d.set(h,a=p),p.beforeNext(function(){d.delete(h)&&d.size<1&&c.delete(s)})}}else a=new nq([np(l,f)])}else a=new nq([eT.of({data:{}})]),t=this.prepareContext(t);var b=this.transform(e).clientQuery;return b&&(a=nM(a,function(e){return o.localState.runResolvers({document:b,remoteResult:e,context:t,variables:n})})),a},e.prototype.getResultsFromLink=function(e,t,n){var r=e.lastRequestId=this.generateRequestId(),i=this.cache.transformForLink(this.transform(e.document).document);return nM(this.getObservableFromLink(i,n.context,n.variables),function(a){var o=nA(a),s=o.length>0;if(r>=e.lastRequestId){if(s&&"none"===n.errorPolicy)throw e.markError(new tN.cA({graphQLErrors:o}));e.markResult(a,i,n,t),e.markReady()}var u={data:a.data,loading:!1,networkStatus:nZ.I.ready};return s&&"ignore"!==n.errorPolicy&&(u.errors=o,u.networkStatus=nZ.I.error),u},function(t){var n=(0,tN.MS)(t)?t:new tN.cA({networkError:t});throw r>=e.lastRequestId&&e.markError(n),n})},e.prototype.fetchQueryObservable=function(e,t,n){return this.fetchConcastWithInfo(e,t,n).concast},e.prototype.fetchConcastWithInfo=function(e,t,n){var r,i,a=this;void 0===n&&(n=nZ.I.loading);var o=this.transform(t.query).document,s=this.getVariables(o,t.variables),u=this.getQuery(e),c=this.defaultOptions.watchQuery,l=t.fetchPolicy,f=void 0===l?c&&c.fetchPolicy||"cache-first":l,d=t.errorPolicy,h=void 0===d?c&&c.errorPolicy||"none":d,p=t.returnPartialData,b=void 0!==p&&p,m=t.notifyOnNetworkStatusChange,g=void 0!==m&&m,v=t.context,y=void 0===v?{}:v,w=Object.assign({},t,{query:o,variables:s,fetchPolicy:f,errorPolicy:h,returnPartialData:b,notifyOnNetworkStatusChange:g,context:y}),_=function(e){w.variables=e;var r=a.fetchQueryByPolicy(u,w,n);return"standby"!==w.fetchPolicy&&r.sources.length>0&&u.observableQuery&&u.observableQuery.applyNextFetchPolicy("after-fetch",t),r},E=function(){return a.fetchCancelFns.delete(e)};if(this.fetchCancelFns.set(e,function(e){E(),setTimeout(function(){return r.cancel(e)})}),this.transform(w.query).hasClientExports)r=new nq(this.localState.addExportedVariables(w.query,w.variables,w.context).then(_).then(function(e){return e.sources})),i=!0;else{var S=_(w.variables);i=S.fromLink,r=new nq(S.sources)}return r.promise.then(E,E),{concast:r,fromLink:i}},e.prototype.refetchQueries=function(e){var t=this,n=e.updateCache,r=e.include,i=e.optimistic,a=void 0!==i&&i,o=e.removeOptimistic,s=void 0===o?a?nG("refetchQueries"):void 0:o,u=e.onQueryUpdated,c=new Map;r&&this.getObservableQueries(r).forEach(function(e,n){c.set(n,{oq:e,lastDiff:t.getQuery(n).getDiff()})});var l=new Map;return n&&this.cache.batch({update:n,optimistic:a&&s||!1,removeOptimistic:s,onWatchUpdated:function(e,t,n){var r=e.watcher instanceof r8&&e.watcher.observableQuery;if(r){if(u){c.delete(r.queryId);var i=u(r,t,n);return!0===i&&(i=r.refetch()),!1!==i&&l.set(r,i),i}null!==u&&c.set(r.queryId,{oq:r,lastDiff:n,diff:t})}}}),c.size&&c.forEach(function(e,n){var r,i=e.oq,a=e.lastDiff,o=e.diff;if(u){if(!o){var s=i.queryInfo;s.reset(),o=s.getDiff()}r=u(i,o,a)}u&&!0!==r||(r=i.refetch()),!1!==r&&l.set(i,r),n.indexOf("legacyOneTimeQuery")>=0&&t.stopQueryNoBroadcast(n)}),s&&this.cache.removeOptimistic(s),l},e.prototype.fetchQueryByPolicy=function(e,t,n){var r=this,i=t.query,a=t.variables,o=t.fetchPolicy,s=t.refetchWritePolicy,u=t.errorPolicy,c=t.returnPartialData,l=t.context,f=t.notifyOnNetworkStatusChange,d=e.networkStatus;e.init({document:this.transform(i).document,variables:a,networkStatus:n});var h=function(){return e.getDiff(a)},p=function(t,n){void 0===n&&(n=e.networkStatus||nZ.I.loading);var o=t.result;!__DEV__||c||(0,nm.D)(o,{})||n6(t.missing);var s=function(e){return eT.of((0,en.pi)({data:e,loading:(0,nZ.O)(n),networkStatus:n},t.complete?null:{partial:!0}))};return o&&r.transform(i).hasForcedResolvers?r.localState.runResolvers({document:i,remoteResult:{data:o},context:l,variables:a,onlyRunForcedResolvers:!0}).then(function(e){return s(e.data||void 0)}):"none"===u&&n===nZ.I.refetch&&Array.isArray(t.missing)?s(void 0):s(o)},b="no-cache"===o?0:n===nZ.I.refetch&&"merge"!==s?1:2,m=function(){return r.getResultsFromLink(e,b,{variables:a,context:l,fetchPolicy:o,errorPolicy:u})},g=f&&"number"==typeof d&&d!==n&&(0,nZ.O)(n);switch(o){default:case"cache-first":var v=h();if(v.complete)return{fromLink:!1,sources:[p(v,e.markReady())]};if(c||g)return{fromLink:!0,sources:[p(v),m()]};return{fromLink:!0,sources:[m()]};case"cache-and-network":var v=h();if(v.complete||c||g)return{fromLink:!0,sources:[p(v),m()]};return{fromLink:!0,sources:[m()]};case"cache-only":return{fromLink:!1,sources:[p(h(),e.markReady())]};case"network-only":if(g)return{fromLink:!0,sources:[p(h()),m()]};return{fromLink:!0,sources:[m()]};case"no-cache":if(g)return{fromLink:!0,sources:[p(e.getDiff()),m(),]};return{fromLink:!0,sources:[m()]};case"standby":return{fromLink:!1,sources:[]}}},e.prototype.getQuery=function(e){return e&&!this.queries.has(e)&&this.queries.set(e,new r8(this,e)),this.queries.get(e)},e.prototype.prepareContext=function(e){void 0===e&&(e={});var t=this.localState.prepareContext(e);return(0,en.pi)((0,en.pi)({},t),{clientAwareness:this.clientAwareness})},e}(),ir=__webpack_require__(14012),ii=!1,ia=function(){function e(e){var t=this;this.resetStoreCallbacks=[],this.clearStoreCallbacks=[];var n=e.uri,r=e.credentials,i=e.headers,a=e.cache,o=e.ssrMode,s=void 0!==o&&o,u=e.ssrForceFetchDelay,c=void 0===u?0:u,l=e.connectToDevTools,f=void 0===l?"object"==typeof window&&!window.__APOLLO_CLIENT__&&__DEV__:l,d=e.queryDeduplication,h=void 0===d||d,p=e.defaultOptions,b=e.assumeImmutableResults,m=void 0!==b&&b,g=e.resolvers,v=e.typeDefs,y=e.fragmentMatcher,w=e.name,_=e.version,E=e.link;if(E||(E=n?new nh({uri:n,credentials:r,headers:i}):ta.empty()),!a)throw __DEV__?new Q.ej("To initialize Apollo Client, you must specify a 'cache' property in the options object. \nFor more information, please visit: https://go.apollo.dev/c/docs"):new Q.ej(9);if(this.link=E,this.cache=a,this.disableNetworkFetches=s||c>0,this.queryDeduplication=h,this.defaultOptions=p||Object.create(null),this.typeDefs=v,c&&setTimeout(function(){return t.disableNetworkFetches=!1},c),this.watchQuery=this.watchQuery.bind(this),this.query=this.query.bind(this),this.mutate=this.mutate.bind(this),this.resetStore=this.resetStore.bind(this),this.reFetchObservableQueries=this.reFetchObservableQueries.bind(this),f&&"object"==typeof window&&(window.__APOLLO_CLIENT__=this),!ii&&f&&__DEV__&&(ii=!0,"undefined"!=typeof window&&window.document&&window.top===window.self&&!window.__APOLLO_DEVTOOLS_GLOBAL_HOOK__)){var S=window.navigator,k=S&&S.userAgent,x=void 0;"string"==typeof k&&(k.indexOf("Chrome/")>-1?x="https://chrome.google.com/webstore/detail/apollo-client-developer-t/jdkknkkbebbapilgoeccciglkfbmbnfm":k.indexOf("Firefox/")>-1&&(x="https://addons.mozilla.org/en-US/firefox/addon/apollo-developer-tools/")),x&&__DEV__&&Q.kG.log("Download the Apollo DevTools for a better development experience: "+x)}this.version=nb,this.localState=new r4({cache:a,client:this,resolvers:g,fragmentMatcher:y}),this.queryManager=new it({cache:this.cache,link:this.link,defaultOptions:this.defaultOptions,queryDeduplication:h,ssrMode:s,clientAwareness:{name:w,version:_},localState:this.localState,assumeImmutableResults:m,onBroadcast:f?function(){t.devToolsHookCb&&t.devToolsHookCb({action:{},state:{queries:t.queryManager.getQueryStore(),mutations:t.queryManager.mutationStore||{}},dataWithOptimisticResults:t.cache.extract(!0)})}:void 0})}return e.prototype.stop=function(){this.queryManager.stop()},e.prototype.watchQuery=function(e){return this.defaultOptions.watchQuery&&(e=(0,ir.J)(this.defaultOptions.watchQuery,e)),this.disableNetworkFetches&&("network-only"===e.fetchPolicy||"cache-and-network"===e.fetchPolicy)&&(e=(0,en.pi)((0,en.pi)({},e),{fetchPolicy:"cache-first"})),this.queryManager.watchQuery(e)},e.prototype.query=function(e){return this.defaultOptions.query&&(e=(0,ir.J)(this.defaultOptions.query,e)),__DEV__?(0,Q.kG)("cache-and-network"!==e.fetchPolicy,"The cache-and-network fetchPolicy does not work with client.query, because client.query can only return a single result. Please use client.watchQuery to receive multiple results from the cache and the network, or consider using a different fetchPolicy, such as cache-first or network-only."):(0,Q.kG)("cache-and-network"!==e.fetchPolicy,10),this.disableNetworkFetches&&"network-only"===e.fetchPolicy&&(e=(0,en.pi)((0,en.pi)({},e),{fetchPolicy:"cache-first"})),this.queryManager.query(e)},e.prototype.mutate=function(e){return this.defaultOptions.mutate&&(e=(0,ir.J)(this.defaultOptions.mutate,e)),this.queryManager.mutate(e)},e.prototype.subscribe=function(e){return this.queryManager.startGraphQLSubscription(e)},e.prototype.readQuery=function(e,t){return void 0===t&&(t=!1),this.cache.readQuery(e,t)},e.prototype.readFragment=function(e,t){return void 0===t&&(t=!1),this.cache.readFragment(e,t)},e.prototype.writeQuery=function(e){var t=this.cache.writeQuery(e);return!1!==e.broadcast&&this.queryManager.broadcastQueries(),t},e.prototype.writeFragment=function(e){var t=this.cache.writeFragment(e);return!1!==e.broadcast&&this.queryManager.broadcastQueries(),t},e.prototype.__actionHookForDevTools=function(e){this.devToolsHookCb=e},e.prototype.__requestRaw=function(e){return np(this.link,e)},e.prototype.resetStore=function(){var e=this;return Promise.resolve().then(function(){return e.queryManager.clearStore({discardWatches:!1})}).then(function(){return Promise.all(e.resetStoreCallbacks.map(function(e){return e()}))}).then(function(){return e.reFetchObservableQueries()})},e.prototype.clearStore=function(){var e=this;return Promise.resolve().then(function(){return e.queryManager.clearStore({discardWatches:!0})}).then(function(){return Promise.all(e.clearStoreCallbacks.map(function(e){return e()}))})},e.prototype.onResetStore=function(e){var t=this;return this.resetStoreCallbacks.push(e),function(){t.resetStoreCallbacks=t.resetStoreCallbacks.filter(function(t){return t!==e})}},e.prototype.onClearStore=function(e){var t=this;return this.clearStoreCallbacks.push(e),function(){t.clearStoreCallbacks=t.clearStoreCallbacks.filter(function(t){return t!==e})}},e.prototype.reFetchObservableQueries=function(e){return this.queryManager.reFetchObservableQueries(e)},e.prototype.refetchQueries=function(e){var t=this.queryManager.refetchQueries(e),n=[],r=[];t.forEach(function(e,t){n.push(t),r.push(e)});var i=Promise.all(r);return i.queries=n,i.results=r,i.catch(function(e){__DEV__&&Q.kG.debug("In client.refetchQueries, Promise.all promise rejected with error ".concat(e))}),i},e.prototype.getObservableQueries=function(e){return void 0===e&&(e="active"),this.queryManager.getObservableQueries(e)},e.prototype.extract=function(e){return this.cache.extract(e)},e.prototype.restore=function(e){return this.cache.restore(e)},e.prototype.addResolvers=function(e){this.localState.addResolvers(e)},e.prototype.setResolvers=function(e){this.localState.setResolvers(e)},e.prototype.getResolvers=function(){return this.localState.getResolvers()},e.prototype.setLocalStateFragmentMatcher=function(e){this.localState.setFragmentMatcher(e)},e.prototype.setLink=function(e){this.link=this.queryManager.link=e},e}(),io=function(){function e(){this.getFragmentDoc=rZ(eA)}return e.prototype.batch=function(e){var t,n=this,r="string"==typeof e.optimistic?e.optimistic:!1===e.optimistic?null:void 0;return this.performTransaction(function(){return t=e.update(n)},r),t},e.prototype.recordOptimisticTransaction=function(e,t){this.performTransaction(e,t)},e.prototype.transformDocument=function(e){return e},e.prototype.transformForLink=function(e){return e},e.prototype.identify=function(e){},e.prototype.gc=function(){return[]},e.prototype.modify=function(e){return!1},e.prototype.readQuery=function(e,t){return void 0===t&&(t=!!e.optimistic),this.read((0,en.pi)((0,en.pi)({},e),{rootId:e.id||"ROOT_QUERY",optimistic:t}))},e.prototype.readFragment=function(e,t){return void 0===t&&(t=!!e.optimistic),this.read((0,en.pi)((0,en.pi)({},e),{query:this.getFragmentDoc(e.fragment,e.fragmentName),rootId:e.id,optimistic:t}))},e.prototype.writeQuery=function(e){var t=e.id,n=e.data,r=(0,en._T)(e,["id","data"]);return this.write(Object.assign(r,{dataId:t||"ROOT_QUERY",result:n}))},e.prototype.writeFragment=function(e){var t=e.id,n=e.data,r=e.fragment,i=e.fragmentName,a=(0,en._T)(e,["id","data","fragment","fragmentName"]);return this.write(Object.assign(a,{query:this.getFragmentDoc(r,i),dataId:t,result:n}))},e.prototype.updateQuery=function(e,t){return this.batch({update:function(n){var r=n.readQuery(e),i=t(r);return null==i?r:(n.writeQuery((0,en.pi)((0,en.pi)({},e),{data:i})),i)}})},e.prototype.updateFragment=function(e,t){return this.batch({update:function(n){var r=n.readFragment(e),i=t(r);return null==i?r:(n.writeFragment((0,en.pi)((0,en.pi)({},e),{data:i})),i)}})},e}(),is=function(e){function t(n,r,i,a){var o,s=e.call(this,n)||this;if(s.message=n,s.path=r,s.query=i,s.variables=a,Array.isArray(s.path)){s.missing=s.message;for(var u=s.path.length-1;u>=0;--u)s.missing=((o={})[s.path[u]]=s.missing,o)}else s.missing=s.path;return s.__proto__=t.prototype,s}return(0,en.ZT)(t,e),t}(Error),iu=__webpack_require__(10542),ic=Object.prototype.hasOwnProperty;function il(e){return null==e}function id(e,t){var n=e.__typename,r=e.id,i=e._id;if("string"==typeof n&&(t&&(t.keyObject=il(r)?il(i)?void 0:{_id:i}:{id:r}),il(r)&&!il(i)&&(r=i),!il(r)))return"".concat(n,":").concat("number"==typeof r||"string"==typeof r?r:JSON.stringify(r))}var ih={dataIdFromObject:id,addTypename:!0,resultCaching:!0,canonizeResults:!1};function ip(e){return(0,n1.o)(ih,e)}function ib(e){var t=e.canonizeResults;return void 0===t?ih.canonizeResults:t}function im(e,t){return eD(t)?e.get(t.__ref,"__typename"):t&&t.__typename}var ig=/^[_a-z][_0-9a-z]*/i;function iv(e){var t=e.match(ig);return t?t[0]:e}function iy(e,t,n){return!!(0,eO.s)(t)&&((0,tP.k)(t)?t.every(function(t){return iy(e,t,n)}):e.selections.every(function(e){if(eQ(e)&&td(e,n)){var r=eX(e);return ic.call(t,r)&&(!e.selectionSet||iy(e.selectionSet,t[r],n))}return!0}))}function iw(e){return(0,eO.s)(e)&&!eD(e)&&!(0,tP.k)(e)}function i_(){return new tB}function iE(e,t){var n=eL(e4(e));return{fragmentMap:n,lookupFragment:function(e){var r=n[e];return!r&&t&&(r=t.lookup(e)),r||null}}}var iS=Object.create(null),ik=function(){return iS},ix=Object.create(null),iT=function(){function e(e,t){var n=this;this.policies=e,this.group=t,this.data=Object.create(null),this.rootIds=Object.create(null),this.refs=Object.create(null),this.getFieldValue=function(e,t){return(0,iu.J)(eD(e)?n.get(e.__ref,t):e&&e[t])},this.canRead=function(e){return eD(e)?n.has(e.__ref):"object"==typeof e},this.toReference=function(e,t){if("string"==typeof e)return eI(e);if(eD(e))return e;var r=n.policies.identify(e)[0];if(r){var i=eI(r);return t&&n.merge(r,e),i}}}return e.prototype.toObject=function(){return(0,en.pi)({},this.data)},e.prototype.has=function(e){return void 0!==this.lookup(e,!0)},e.prototype.get=function(e,t){if(this.group.depend(e,t),ic.call(this.data,e)){var n=this.data[e];if(n&&ic.call(n,t))return n[t]}return"__typename"===t&&ic.call(this.policies.rootTypenamesById,e)?this.policies.rootTypenamesById[e]:this instanceof iL?this.parent.get(e,t):void 0},e.prototype.lookup=function(e,t){return(t&&this.group.depend(e,"__exists"),ic.call(this.data,e))?this.data[e]:this instanceof iL?this.parent.lookup(e,t):this.policies.rootTypenamesById[e]?Object.create(null):void 0},e.prototype.merge=function(e,t){var n,r=this;eD(e)&&(e=e.__ref),eD(t)&&(t=t.__ref);var i="string"==typeof e?this.lookup(n=e):e,a="string"==typeof t?this.lookup(n=t):t;if(a){__DEV__?(0,Q.kG)("string"==typeof n,"store.merge expects a string ID"):(0,Q.kG)("string"==typeof n,1);var o=new tB(iI).merge(i,a);if(this.data[n]=o,o!==i&&(delete this.refs[n],this.group.caching)){var s=Object.create(null);i||(s.__exists=1),Object.keys(a).forEach(function(e){if(!i||i[e]!==o[e]){s[e]=1;var t=iv(e);t===e||r.policies.hasKeyArgs(o.__typename,t)||(s[t]=1),void 0!==o[e]||r instanceof iL||delete o[e]}}),s.__typename&&!(i&&i.__typename)&&this.policies.rootTypenamesById[n]===o.__typename&&delete s.__typename,Object.keys(s).forEach(function(e){return r.group.dirty(n,e)})}}},e.prototype.modify=function(e,t){var n=this,r=this.lookup(e);if(r){var i=Object.create(null),a=!1,o=!0,s={DELETE:iS,INVALIDATE:ix,isReference:eD,toReference:this.toReference,canRead:this.canRead,readField:function(t,r){return n.policies.readField("string"==typeof t?{fieldName:t,from:r||eI(e)}:t,{store:n})}};if(Object.keys(r).forEach(function(u){var c=iv(u),l=r[u];if(void 0!==l){var f="function"==typeof t?t:t[u]||t[c];if(f){var d=f===ik?iS:f((0,iu.J)(l),(0,en.pi)((0,en.pi)({},s),{fieldName:c,storeFieldName:u,storage:n.getStorage(e,u)}));d===ix?n.group.dirty(e,u):(d===iS&&(d=void 0),d!==l&&(i[u]=d,a=!0,l=d))}void 0!==l&&(o=!1)}}),a)return this.merge(e,i),o&&(this instanceof iL?this.data[e]=void 0:delete this.data[e],this.group.dirty(e,"__exists")),!0}return!1},e.prototype.delete=function(e,t,n){var r,i=this.lookup(e);if(i){var a=this.getFieldValue(i,"__typename"),o=t&&n?this.policies.getStoreFieldName({typename:a,fieldName:t,args:n}):t;return this.modify(e,o?((r={})[o]=ik,r):ik)}return!1},e.prototype.evict=function(e,t){var n=!1;return e.id&&(ic.call(this.data,e.id)&&(n=this.delete(e.id,e.fieldName,e.args)),this instanceof iL&&this!==t&&(n=this.parent.evict(e,t)||n),(e.fieldName||n)&&this.group.dirty(e.id,e.fieldName||"__exists")),n},e.prototype.clear=function(){this.replace(null)},e.prototype.extract=function(){var e=this,t=this.toObject(),n=[];return this.getRootIdSet().forEach(function(t){ic.call(e.policies.rootTypenamesById,t)||n.push(t)}),n.length&&(t.__META={extraRootIds:n.sort()}),t},e.prototype.replace=function(e){var t=this;if(Object.keys(this.data).forEach(function(n){e&&ic.call(e,n)||t.delete(n)}),e){var n=e.__META,r=(0,en._T)(e,["__META"]);Object.keys(r).forEach(function(e){t.merge(e,r[e])}),n&&n.extraRootIds.forEach(this.retain,this)}},e.prototype.retain=function(e){return this.rootIds[e]=(this.rootIds[e]||0)+1},e.prototype.release=function(e){if(this.rootIds[e]>0){var t=--this.rootIds[e];return t||delete this.rootIds[e],t}return 0},e.prototype.getRootIdSet=function(e){return void 0===e&&(e=new Set),Object.keys(this.rootIds).forEach(e.add,e),this instanceof iL?this.parent.getRootIdSet(e):Object.keys(this.policies.rootTypenamesById).forEach(e.add,e),e},e.prototype.gc=function(){var e=this,t=this.getRootIdSet(),n=this.toObject();t.forEach(function(r){ic.call(n,r)&&(Object.keys(e.findChildRefIds(r)).forEach(t.add,t),delete n[r])});var r=Object.keys(n);if(r.length){for(var i=this;i instanceof iL;)i=i.parent;r.forEach(function(e){return i.delete(e)})}return r},e.prototype.findChildRefIds=function(e){if(!ic.call(this.refs,e)){var t=this.refs[e]=Object.create(null),n=this.data[e];if(!n)return t;var r=new Set([n]);r.forEach(function(e){eD(e)&&(t[e.__ref]=!0),(0,eO.s)(e)&&Object.keys(e).forEach(function(t){var n=e[t];(0,eO.s)(n)&&r.add(n)})})}return this.refs[e]},e.prototype.makeCacheKey=function(){return this.group.keyMaker.lookupArray(arguments)},e}(),iM=function(){function e(e,t){void 0===t&&(t=null),this.caching=e,this.parent=t,this.d=null,this.resetCaching()}return e.prototype.resetCaching=function(){this.d=this.caching?rW():null,this.keyMaker=new n_(t_.mr)},e.prototype.depend=function(e,t){if(this.d){this.d(iO(e,t));var n=iv(t);n!==t&&this.d(iO(e,n)),this.parent&&this.parent.depend(e,t)}},e.prototype.dirty=function(e,t){this.d&&this.d.dirty(iO(e,t),"__exists"===t?"forget":"setDirty")},e}();function iO(e,t){return t+"#"+e}function iA(e,t){iD(e)&&e.group.depend(t,"__exists")}!function(e){var t=function(e){function t(t){var n=t.policies,r=t.resultCaching,i=void 0===r||r,a=t.seed,o=e.call(this,n,new iM(i))||this;return o.stump=new iC(o),o.storageTrie=new n_(t_.mr),a&&o.replace(a),o}return(0,en.ZT)(t,e),t.prototype.addLayer=function(e,t){return this.stump.addLayer(e,t)},t.prototype.removeLayer=function(){return this},t.prototype.getStorage=function(){return this.storageTrie.lookupArray(arguments)},t}(e);e.Root=t}(iT||(iT={}));var iL=function(e){function t(t,n,r,i){var a=e.call(this,n.policies,i)||this;return a.id=t,a.parent=n,a.replay=r,a.group=i,r(a),a}return(0,en.ZT)(t,e),t.prototype.addLayer=function(e,n){return new t(e,this,n,this.group)},t.prototype.removeLayer=function(e){var t=this,n=this.parent.removeLayer(e);return e===this.id?(this.group.caching&&Object.keys(this.data).forEach(function(e){var r=t.data[e],i=n.lookup(e);i?r?r!==i&&Object.keys(r).forEach(function(n){(0,nm.D)(r[n],i[n])||t.group.dirty(e,n)}):(t.group.dirty(e,"__exists"),Object.keys(i).forEach(function(n){t.group.dirty(e,n)})):t.delete(e)}),n):n===this.parent?this:n.addLayer(this.id,this.replay)},t.prototype.toObject=function(){return(0,en.pi)((0,en.pi)({},this.parent.toObject()),this.data)},t.prototype.findChildRefIds=function(t){var n=this.parent.findChildRefIds(t);return ic.call(this.data,t)?(0,en.pi)((0,en.pi)({},n),e.prototype.findChildRefIds.call(this,t)):n},t.prototype.getStorage=function(){for(var e=this.parent;e.parent;)e=e.parent;return e.getStorage.apply(e,arguments)},t}(iT),iC=function(e){function t(t){return e.call(this,"EntityStore.Stump",t,function(){},new iM(t.group.caching,t.group))||this}return(0,en.ZT)(t,e),t.prototype.removeLayer=function(){return this},t.prototype.merge=function(){return this.parent.merge.apply(this.parent,arguments)},t}(iL);function iI(e,t,n){var r=e[n],i=t[n];return(0,nm.D)(r,i)?r:i}function iD(e){return!!(e instanceof iT&&e.group.caching)}function iN(e){return[e.selectionSet,e.objectOrReference,e.context,e.context.canonizeResults,]}var iP=function(){function e(e){var t=this;this.knownResults=new(t_.mr?WeakMap:Map),this.config=(0,n1.o)(e,{addTypename:!1!==e.addTypename,canonizeResults:ib(e)}),this.canon=e.canon||new nk,this.executeSelectionSet=rZ(function(e){var n,r=e.context.canonizeResults,i=iN(e);i[3]=!r;var a=(n=t.executeSelectionSet).peek.apply(n,i);return a?r?(0,en.pi)((0,en.pi)({},a),{result:t.canon.admit(a.result)}):a:(iA(e.context.store,e.enclosingRef.__ref),t.execSelectionSetImpl(e))},{max:this.config.resultCacheMaxSize,keyArgs:iN,makeCacheKey:function(e,t,n,r){if(iD(n.store))return n.store.makeCacheKey(e,eD(t)?t.__ref:t,n.varString,r)}}),this.executeSubSelectedArray=rZ(function(e){return iA(e.context.store,e.enclosingRef.__ref),t.execSubSelectedArrayImpl(e)},{max:this.config.resultCacheMaxSize,makeCacheKey:function(e){var t=e.field,n=e.array,r=e.context;if(iD(r.store))return r.store.makeCacheKey(t,n,r.varString)}})}return e.prototype.resetCanon=function(){this.canon=new nk},e.prototype.diffQueryAgainstStore=function(e){var t,n=e.store,r=e.query,i=e.rootId,a=void 0===i?"ROOT_QUERY":i,o=e.variables,s=e.returnPartialData,u=void 0===s||s,c=e.canonizeResults,l=void 0===c?this.config.canonizeResults:c,f=this.config.cache.policies;o=(0,en.pi)((0,en.pi)({},e8(e5(r))),o);var d=eI(a),h=this.executeSelectionSet({selectionSet:e9(r).selectionSet,objectOrReference:d,enclosingRef:d,context:(0,en.pi)({store:n,query:r,policies:f,variables:o,varString:nx(o),canonizeResults:l},iE(r,this.config.fragments))});if(h.missing&&(t=[new is(iR(h.missing),h.missing,r,o)],!u))throw t[0];return{result:h.result,complete:!t,missing:t}},e.prototype.isFresh=function(e,t,n,r){if(iD(r.store)&&this.knownResults.get(e)===n){var i=this.executeSelectionSet.peek(n,t,r,this.canon.isKnown(e));if(i&&e===i.result)return!0}return!1},e.prototype.execSelectionSetImpl=function(e){var t,n=this,r=e.selectionSet,i=e.objectOrReference,a=e.enclosingRef,o=e.context;if(eD(i)&&!o.policies.rootTypenamesById[i.__ref]&&!o.store.has(i.__ref))return{result:this.canon.empty,missing:"Dangling reference to missing ".concat(i.__ref," object")};var s=o.variables,u=o.policies,c=o.store.getFieldValue(i,"__typename"),l=[],f=new tB;function d(e,n){var r;return e.missing&&(t=f.merge(t,((r={})[n]=e.missing,r))),e.result}this.config.addTypename&&"string"==typeof c&&!u.rootIdsByTypename[c]&&l.push({__typename:c});var h=new Set(r.selections);h.forEach(function(e){var r,p;if(td(e,s)){if(eQ(e)){var b=u.readField({fieldName:e.name.value,field:e,variables:o.variables,from:i},o),m=eX(e);void 0===b?nj.added(e)||(t=f.merge(t,((r={})[m]="Can't find field '".concat(e.name.value,"' on ").concat(eD(i)?i.__ref+" object":"object "+JSON.stringify(i,null,2)),r))):(0,tP.k)(b)?b=d(n.executeSubSelectedArray({field:e,array:b,enclosingRef:a,context:o}),m):e.selectionSet?null!=b&&(b=d(n.executeSelectionSet({selectionSet:e.selectionSet,objectOrReference:b,enclosingRef:eD(b)?b:a,context:o}),m)):o.canonizeResults&&(b=n.canon.pass(b)),void 0!==b&&l.push(((p={})[m]=b,p))}else{var g=eC(e,o.lookupFragment);if(!g&&e.kind===nL.h.FRAGMENT_SPREAD)throw __DEV__?new Q.ej("No fragment named ".concat(e.name.value)):new Q.ej(5);g&&u.fragmentMatches(g,c)&&g.selectionSet.selections.forEach(h.add,h)}}});var p={result:tF(l),missing:t},b=o.canonizeResults?this.canon.admit(p):(0,iu.J)(p);return b.result&&this.knownResults.set(b.result,r),b},e.prototype.execSubSelectedArrayImpl=function(e){var t,n=this,r=e.field,i=e.array,a=e.enclosingRef,o=e.context,s=new tB;function u(e,n){var r;return e.missing&&(t=s.merge(t,((r={})[n]=e.missing,r))),e.result}return r.selectionSet&&(i=i.filter(o.store.canRead)),i=i.map(function(e,t){return null===e?null:(0,tP.k)(e)?u(n.executeSubSelectedArray({field:r,array:e,enclosingRef:a,context:o}),t):r.selectionSet?u(n.executeSelectionSet({selectionSet:r.selectionSet,objectOrReference:e,enclosingRef:eD(e)?e:a,context:o}),t):(__DEV__&&ij(o.store,r,e),e)}),{result:o.canonizeResults?this.canon.admit(i):i,missing:t}},e}();function iR(e){try{JSON.stringify(e,function(e,t){if("string"==typeof t)throw t;return t})}catch(t){return t}}function ij(e,t,n){if(!t.selectionSet){var r=new Set([n]);r.forEach(function(n){(0,eO.s)(n)&&(__DEV__?(0,Q.kG)(!eD(n),"Missing selection set for object of type ".concat(im(e,n)," returned for query field ").concat(t.name.value)):(0,Q.kG)(!eD(n),6),Object.values(n).forEach(r.add,r))})}}function iF(e){var t=nG("stringifyForDisplay");return JSON.stringify(e,function(e,n){return void 0===n?t:n}).split(JSON.stringify(t)).join("")}var iY=Object.create(null);function iB(e){var t=JSON.stringify(e);return iY[t]||(iY[t]=Object.create(null))}function iU(e){var t=iB(e);return t.keyFieldsFn||(t.keyFieldsFn=function(t,n){var r=function(e,t){return n.readField(t,e)},i=n.keyObject=i$(e,function(e){var i=iW(n.storeObject,e,r);return void 0===i&&t!==n.storeObject&&ic.call(t,e[0])&&(i=iW(t,e,iG)),__DEV__?(0,Q.kG)(void 0!==i,"Missing field '".concat(e.join("."),"' while extracting keyFields from ").concat(JSON.stringify(t))):(0,Q.kG)(void 0!==i,2),i});return"".concat(n.typename,":").concat(JSON.stringify(i))})}function iH(e){var t=iB(e);return t.keyArgsFn||(t.keyArgsFn=function(t,n){var r=n.field,i=n.variables,a=n.fieldName,o=JSON.stringify(i$(e,function(e){var n=e[0],a=n.charAt(0);if("@"===a){if(r&&(0,tP.O)(r.directives)){var o=n.slice(1),s=r.directives.find(function(e){return e.name.value===o}),u=s&&eZ(s,i);return u&&iW(u,e.slice(1))}return}if("$"===a){var c=n.slice(1);if(i&&ic.call(i,c)){var l=e.slice(0);return l[0]=c,iW(i,l)}return}if(t)return iW(t,e)}));return(t||"{}"!==o)&&(a+=":"+o),a})}function i$(e,t){var n=new tB;return iz(e).reduce(function(e,r){var i,a=t(r);if(void 0!==a){for(var o=r.length-1;o>=0;--o)a=((i={})[r[o]]=a,i);e=n.merge(e,a)}return e},Object.create(null))}function iz(e){var t=iB(e);if(!t.paths){var n=t.paths=[],r=[];e.forEach(function(t,i){(0,tP.k)(t)?(iz(t).forEach(function(e){return n.push(r.concat(e))}),r.length=0):(r.push(t),(0,tP.k)(e[i+1])||(n.push(r.slice(0)),r.length=0))})}return t.paths}function iG(e,t){return e[t]}function iW(e,t,n){return n=n||iG,iK(t.reduce(function e(t,r){return(0,tP.k)(t)?t.map(function(t){return e(t,r)}):t&&n(t,r)},e))}function iK(e){return(0,eO.s)(e)?(0,tP.k)(e)?e.map(iK):i$(Object.keys(e).sort(),function(t){return iW(e,t)}):e}function iV(e){return void 0!==e.args?e.args:e.field?eZ(e.field,e.variables):null}eK.setStringify(nx);var iq=function(){},iZ=function(e,t){return t.fieldName},iX=function(e,t,n){return(0,n.mergeObjects)(e,t)},iJ=function(e,t){return t},iQ=function(){function e(e){this.config=e,this.typePolicies=Object.create(null),this.toBeAdded=Object.create(null),this.supertypeMap=new Map,this.fuzzySubtypes=new Map,this.rootIdsByTypename=Object.create(null),this.rootTypenamesById=Object.create(null),this.usingPossibleTypes=!1,this.config=(0,en.pi)({dataIdFromObject:id},e),this.cache=this.config.cache,this.setRootTypename("Query"),this.setRootTypename("Mutation"),this.setRootTypename("Subscription"),e.possibleTypes&&this.addPossibleTypes(e.possibleTypes),e.typePolicies&&this.addTypePolicies(e.typePolicies)}return e.prototype.identify=function(e,t){var n,r,i=this,a=t&&(t.typename||(null===(n=t.storeObject)||void 0===n?void 0:n.__typename))||e.__typename;if(a===this.rootTypenamesById.ROOT_QUERY)return["ROOT_QUERY"];for(var o=t&&t.storeObject||e,s=(0,en.pi)((0,en.pi)({},t),{typename:a,storeObject:o,readField:t&&t.readField||function(){var e=i0(arguments,o);return i.readField(e,{store:i.cache.data,variables:e.variables})}}),u=a&&this.getTypePolicy(a),c=u&&u.keyFn||this.config.dataIdFromObject;c;){var l=c((0,en.pi)((0,en.pi)({},e),o),s);if((0,tP.k)(l))c=iU(l);else{r=l;break}}return r=r?String(r):void 0,s.keyObject?[r,s.keyObject]:[r]},e.prototype.addTypePolicies=function(e){var t=this;Object.keys(e).forEach(function(n){var r=e[n],i=r.queryType,a=r.mutationType,o=r.subscriptionType,s=(0,en._T)(r,["queryType","mutationType","subscriptionType"]);i&&t.setRootTypename("Query",n),a&&t.setRootTypename("Mutation",n),o&&t.setRootTypename("Subscription",n),ic.call(t.toBeAdded,n)?t.toBeAdded[n].push(s):t.toBeAdded[n]=[s]})},e.prototype.updateTypePolicy=function(e,t){var n=this,r=this.getTypePolicy(e),i=t.keyFields,a=t.fields;function o(e,t){e.merge="function"==typeof t?t:!0===t?iX:!1===t?iJ:e.merge}o(r,t.merge),r.keyFn=!1===i?iq:(0,tP.k)(i)?iU(i):"function"==typeof i?i:r.keyFn,a&&Object.keys(a).forEach(function(t){var r=n.getFieldPolicy(e,t,!0),i=a[t];if("function"==typeof i)r.read=i;else{var s=i.keyArgs,u=i.read,c=i.merge;r.keyFn=!1===s?iZ:(0,tP.k)(s)?iH(s):"function"==typeof s?s:r.keyFn,"function"==typeof u&&(r.read=u),o(r,c)}r.read&&r.merge&&(r.keyFn=r.keyFn||iZ)})},e.prototype.setRootTypename=function(e,t){void 0===t&&(t=e);var n="ROOT_"+e.toUpperCase(),r=this.rootTypenamesById[n];t!==r&&(__DEV__?(0,Q.kG)(!r||r===e,"Cannot change root ".concat(e," __typename more than once")):(0,Q.kG)(!r||r===e,3),r&&delete this.rootIdsByTypename[r],this.rootIdsByTypename[t]=n,this.rootTypenamesById[n]=t)},e.prototype.addPossibleTypes=function(e){var t=this;this.usingPossibleTypes=!0,Object.keys(e).forEach(function(n){t.getSupertypeSet(n,!0),e[n].forEach(function(e){t.getSupertypeSet(e,!0).add(n);var r=e.match(ig);r&&r[0]===e||t.fuzzySubtypes.set(e,RegExp(e))})})},e.prototype.getTypePolicy=function(e){var t=this;if(!ic.call(this.typePolicies,e)){var n=this.typePolicies[e]=Object.create(null);n.fields=Object.create(null);var r=this.supertypeMap.get(e);r&&r.size&&r.forEach(function(e){var r=t.getTypePolicy(e),i=r.fields;Object.assign(n,(0,en._T)(r,["fields"])),Object.assign(n.fields,i)})}var i=this.toBeAdded[e];return i&&i.length&&i.splice(0).forEach(function(n){t.updateTypePolicy(e,n)}),this.typePolicies[e]},e.prototype.getFieldPolicy=function(e,t,n){if(e){var r=this.getTypePolicy(e).fields;return r[t]||n&&(r[t]=Object.create(null))}},e.prototype.getSupertypeSet=function(e,t){var n=this.supertypeMap.get(e);return!n&&t&&this.supertypeMap.set(e,n=new Set),n},e.prototype.fragmentMatches=function(e,t,n,r){var i=this;if(!e.typeCondition)return!0;if(!t)return!1;var a=e.typeCondition.name.value;if(t===a)return!0;if(this.usingPossibleTypes&&this.supertypeMap.has(a))for(var o=this.getSupertypeSet(t,!0),s=[o],u=function(e){var t=i.getSupertypeSet(e,!1);t&&t.size&&0>s.indexOf(t)&&s.push(t)},c=!!(n&&this.fuzzySubtypes.size),l=!1,f=0;f1?a:t}:(r=(0,en.pi)({},i),ic.call(r,"from")||(r.from=t)),__DEV__&&void 0===r.from&&__DEV__&&Q.kG.warn("Undefined 'from' passed to readField with arguments ".concat(iF(Array.from(e)))),void 0===r.variables&&(r.variables=n),r}function i2(e){return function(t,n){if((0,tP.k)(t)||(0,tP.k)(n))throw __DEV__?new Q.ej("Cannot automatically merge arrays"):new Q.ej(4);if((0,eO.s)(t)&&(0,eO.s)(n)){var r=e.getFieldValue(t,"__typename"),i=e.getFieldValue(n,"__typename");if(r&&i&&r!==i)return n;if(eD(t)&&iw(n))return e.merge(t.__ref,n),t;if(iw(t)&&eD(n))return e.merge(t,n.__ref),n;if(iw(t)&&iw(n))return(0,en.pi)((0,en.pi)({},t),n)}return n}}function i3(e,t,n){var r="".concat(t).concat(n),i=e.flavors.get(r);return i||e.flavors.set(r,i=e.clientOnly===t&&e.deferred===n?e:(0,en.pi)((0,en.pi)({},e),{clientOnly:t,deferred:n})),i}var i4=function(){function e(e,t,n){this.cache=e,this.reader=t,this.fragments=n}return e.prototype.writeToStore=function(e,t){var n=this,r=t.query,i=t.result,a=t.dataId,o=t.variables,s=t.overwrite,u=e2(r),c=i_();o=(0,en.pi)((0,en.pi)({},e8(u)),o);var l=(0,en.pi)((0,en.pi)({store:e,written:Object.create(null),merge:function(e,t){return c.merge(e,t)},variables:o,varString:nx(o)},iE(r,this.fragments)),{overwrite:!!s,incomingById:new Map,clientOnly:!1,deferred:!1,flavors:new Map}),f=this.processSelectionSet({result:i||Object.create(null),dataId:a,selectionSet:u.selectionSet,mergeTree:{map:new Map},context:l});if(!eD(f))throw __DEV__?new Q.ej("Could not identify object ".concat(JSON.stringify(i))):new Q.ej(7);return l.incomingById.forEach(function(t,r){var i=t.storeObject,a=t.mergeTree,o=t.fieldNodeSet,s=eI(r);if(a&&a.map.size){var u=n.applyMerges(a,s,i,l);if(eD(u))return;i=u}if(__DEV__&&!l.overwrite){var c=Object.create(null);o.forEach(function(e){e.selectionSet&&(c[e.name.value]=!0)});var f=function(e){return!0===c[iv(e)]},d=function(e){var t=a&&a.map.get(e);return Boolean(t&&t.info&&t.info.merge)};Object.keys(i).forEach(function(e){f(e)&&!d(e)&&at(s,i,e,l.store)})}e.merge(r,i)}),e.retain(f.__ref),f},e.prototype.processSelectionSet=function(e){var t=this,n=e.dataId,r=e.result,i=e.selectionSet,a=e.context,o=e.mergeTree,s=this.cache.policies,u=Object.create(null),c=n&&s.rootTypenamesById[n]||eJ(r,i,a.fragmentMap)||n&&a.store.get(n,"__typename");"string"==typeof c&&(u.__typename=c);var l=function(){var e=i0(arguments,u,a.variables);if(eD(e.from)){var t=a.incomingById.get(e.from.__ref);if(t){var n=s.readField((0,en.pi)((0,en.pi)({},e),{from:t.storeObject}),a);if(void 0!==n)return n}}return s.readField(e,a)},f=new Set;this.flattenFields(i,r,a,c).forEach(function(e,n){var i,a=r[eX(n)];if(f.add(n),void 0!==a){var d=s.getStoreFieldName({typename:c,fieldName:n.name.value,field:n,variables:e.variables}),h=i6(o,d),p=t.processFieldValue(a,n,n.selectionSet?i3(e,!1,!1):e,h),b=void 0;n.selectionSet&&(eD(p)||iw(p))&&(b=l("__typename",p));var m=s.getMergeFunction(c,n.name.value,b);m?h.info={field:n,typename:c,merge:m}:i7(o,d),u=e.merge(u,((i={})[d]=p,i))}else __DEV__&&!e.clientOnly&&!e.deferred&&!nj.added(n)&&!s.getReadFunction(c,n.name.value)&&__DEV__&&Q.kG.error("Missing field '".concat(eX(n),"' while writing result ").concat(JSON.stringify(r,null,2)).substring(0,1e3))});try{var d=s.identify(r,{typename:c,selectionSet:i,fragmentMap:a.fragmentMap,storeObject:u,readField:l}),h=d[0],p=d[1];n=n||h,p&&(u=a.merge(u,p))}catch(b){if(!n)throw b}if("string"==typeof n){var m=eI(n),g=a.written[n]||(a.written[n]=[]);if(g.indexOf(i)>=0||(g.push(i),this.reader&&this.reader.isFresh(r,m,i,a)))return m;var v=a.incomingById.get(n);return v?(v.storeObject=a.merge(v.storeObject,u),v.mergeTree=i9(v.mergeTree,o),f.forEach(function(e){return v.fieldNodeSet.add(e)})):a.incomingById.set(n,{storeObject:u,mergeTree:i8(o)?void 0:o,fieldNodeSet:f}),m}return u},e.prototype.processFieldValue=function(e,t,n,r){var i=this;return t.selectionSet&&null!==e?(0,tP.k)(e)?e.map(function(e,a){var o=i.processFieldValue(e,t,n,i6(r,a));return i7(r,a),o}):this.processSelectionSet({result:e,selectionSet:t.selectionSet,context:n,mergeTree:r}):__DEV__?nJ(e):e},e.prototype.flattenFields=function(e,t,n,r){void 0===r&&(r=eJ(t,e,n.fragmentMap));var i=new Map,a=this.cache.policies,o=new n_(!1);return function e(s,u){var c=o.lookup(s,u.clientOnly,u.deferred);c.visited||(c.visited=!0,s.selections.forEach(function(o){if(td(o,n.variables)){var s=u.clientOnly,c=u.deferred;if(!(s&&c)&&(0,tP.O)(o.directives)&&o.directives.forEach(function(e){var t=e.name.value;if("client"===t&&(s=!0),"defer"===t){var r=eZ(e,n.variables);r&&!1===r.if||(c=!0)}}),eQ(o)){var l=i.get(o);l&&(s=s&&l.clientOnly,c=c&&l.deferred),i.set(o,i3(n,s,c))}else{var f=eC(o,n.lookupFragment);if(!f&&o.kind===nL.h.FRAGMENT_SPREAD)throw __DEV__?new Q.ej("No fragment named ".concat(o.name.value)):new Q.ej(8);f&&a.fragmentMatches(f,r,t,n.variables)&&e(f.selectionSet,i3(n,s,c))}}}))}(e,n),i},e.prototype.applyMerges=function(e,t,n,r,i){var a=this;if(e.map.size&&!eD(n)){var o,s,u=!(0,tP.k)(n)&&(eD(t)||iw(t))?t:void 0,c=n;u&&!i&&(i=[eD(u)?u.__ref:u]);var l=function(e,t){return(0,tP.k)(e)?"number"==typeof t?e[t]:void 0:r.store.getFieldValue(e,String(t))};e.map.forEach(function(e,t){var n=l(u,t),o=l(c,t);if(void 0!==o){i&&i.push(t);var f=a.applyMerges(e,n,o,r,i);f!==o&&(s=s||new Map).set(t,f),i&&(0,Q.kG)(i.pop()===t)}}),s&&(n=(0,tP.k)(c)?c.slice(0):(0,en.pi)({},c),s.forEach(function(e,t){n[t]=e}))}return e.info?this.cache.policies.runMergeFunction(t,n,e.info,r,i&&(o=r.store).getStorage.apply(o,i)):n},e}(),i5=[];function i6(e,t){var n=e.map;return n.has(t)||n.set(t,i5.pop()||{map:new Map}),n.get(t)}function i9(e,t){if(e===t||!t||i8(t))return e;if(!e||i8(e))return t;var n=e.info&&t.info?(0,en.pi)((0,en.pi)({},e.info),t.info):e.info||t.info,r=e.map.size&&t.map.size,i=r?new Map:e.map.size?e.map:t.map,a={info:n,map:i};if(r){var o=new Set(t.map.keys());e.map.forEach(function(e,n){a.map.set(n,i9(e,t.map.get(n))),o.delete(n)}),o.forEach(function(n){a.map.set(n,i9(t.map.get(n),e.map.get(n)))})}return a}function i8(e){return!e||!(e.info||e.map.size)}function i7(e,t){var n=e.map,r=n.get(t);r&&i8(r)&&(i5.push(r),n.delete(t))}var ae=new Set;function at(e,t,n,r){var i=function(e){var t=r.getFieldValue(e,n);return"object"==typeof t&&t},a=i(e);if(a){var o=i(t);if(!(!o||eD(a)||(0,nm.D)(a,o)||Object.keys(a).every(function(e){return void 0!==r.getFieldValue(o,e)}))){var s=r.getFieldValue(e,"__typename")||r.getFieldValue(t,"__typename"),u=iv(n),c="".concat(s,".").concat(u);if(!ae.has(c)){ae.add(c);var l=[];(0,tP.k)(a)||(0,tP.k)(o)||[a,o].forEach(function(e){var t=r.getFieldValue(e,"__typename");"string"!=typeof t||l.includes(t)||l.push(t)}),__DEV__&&Q.kG.warn("Cache data may be lost when replacing the ".concat(u," field of a ").concat(s," object.\n\nThis could cause additional (usually avoidable) network requests to fetch data that were otherwise cached.\n\nTo address this problem (which is not a bug in Apollo Client), ").concat(l.length?"either ensure all objects of type "+l.join(" and ")+" have an ID or a custom merge function, or ":"","define a custom merge function for the ").concat(c," field, so InMemoryCache can safely merge these objects:\n\n existing: ").concat(JSON.stringify(a).slice(0,1e3),"\n incoming: ").concat(JSON.stringify(o).slice(0,1e3),"\n\nFor more information about these options, please refer to the documentation:\n\n * Ensuring entity objects have IDs: https://go.apollo.dev/c/generating-unique-identifiers\n * Defining custom merge functions: https://go.apollo.dev/c/merging-non-normalized-objects\n"))}}}}var an=function(e){function t(t){void 0===t&&(t={});var n=e.call(this)||this;return n.watches=new Set,n.typenameDocumentCache=new Map,n.makeVar=r2,n.txCount=0,n.config=ip(t),n.addTypename=!!n.config.addTypename,n.policies=new iQ({cache:n,dataIdFromObject:n.config.dataIdFromObject,possibleTypes:n.config.possibleTypes,typePolicies:n.config.typePolicies}),n.init(),n}return(0,en.ZT)(t,e),t.prototype.init=function(){var e=this.data=new iT.Root({policies:this.policies,resultCaching:this.config.resultCaching});this.optimisticData=e.stump,this.resetResultCache()},t.prototype.resetResultCache=function(e){var t=this,n=this.storeReader,r=this.config.fragments;this.storeWriter=new i4(this,this.storeReader=new iP({cache:this,addTypename:this.addTypename,resultCacheMaxSize:this.config.resultCacheMaxSize,canonizeResults:ib(this.config),canon:e?void 0:n&&n.canon,fragments:r}),r),this.maybeBroadcastWatch=rZ(function(e,n){return t.broadcastWatch(e,n)},{max:this.config.resultCacheMaxSize,makeCacheKey:function(e){var n=e.optimistic?t.optimisticData:t.data;if(iD(n)){var r=e.optimistic,i=e.id,a=e.variables;return n.makeCacheKey(e.query,e.callback,nx({optimistic:r,id:i,variables:a}))}}}),new Set([this.data.group,this.optimisticData.group,]).forEach(function(e){return e.resetCaching()})},t.prototype.restore=function(e){return this.init(),e&&this.data.replace(e),this},t.prototype.extract=function(e){return void 0===e&&(e=!1),(e?this.optimisticData:this.data).extract()},t.prototype.read=function(e){var t=e.returnPartialData,n=void 0!==t&&t;try{return this.storeReader.diffQueryAgainstStore((0,en.pi)((0,en.pi)({},e),{store:e.optimistic?this.optimisticData:this.data,config:this.config,returnPartialData:n})).result||null}catch(r){if(r instanceof is)return null;throw r}},t.prototype.write=function(e){try{return++this.txCount,this.storeWriter.writeToStore(this.data,e)}finally{--this.txCount||!1===e.broadcast||this.broadcastWatches()}},t.prototype.modify=function(e){if(ic.call(e,"id")&&!e.id)return!1;var t=e.optimistic?this.optimisticData:this.data;try{return++this.txCount,t.modify(e.id||"ROOT_QUERY",e.fields)}finally{--this.txCount||!1===e.broadcast||this.broadcastWatches()}},t.prototype.diff=function(e){return this.storeReader.diffQueryAgainstStore((0,en.pi)((0,en.pi)({},e),{store:e.optimistic?this.optimisticData:this.data,rootId:e.id||"ROOT_QUERY",config:this.config}))},t.prototype.watch=function(e){var t=this;return this.watches.size||r0(this),this.watches.add(e),e.immediate&&this.maybeBroadcastWatch(e),function(){t.watches.delete(e)&&!t.watches.size&&r1(t),t.maybeBroadcastWatch.forget(e)}},t.prototype.gc=function(e){nx.reset();var t=this.optimisticData.gc();return e&&!this.txCount&&(e.resetResultCache?this.resetResultCache(e.resetResultIdentities):e.resetResultIdentities&&this.storeReader.resetCanon()),t},t.prototype.retain=function(e,t){return(t?this.optimisticData:this.data).retain(e)},t.prototype.release=function(e,t){return(t?this.optimisticData:this.data).release(e)},t.prototype.identify=function(e){if(eD(e))return e.__ref;try{return this.policies.identify(e)[0]}catch(t){__DEV__&&Q.kG.warn(t)}},t.prototype.evict=function(e){if(!e.id){if(ic.call(e,"id"))return!1;e=(0,en.pi)((0,en.pi)({},e),{id:"ROOT_QUERY"})}try{return++this.txCount,this.optimisticData.evict(e,this.data)}finally{--this.txCount||!1===e.broadcast||this.broadcastWatches()}},t.prototype.reset=function(e){var t=this;return this.init(),nx.reset(),e&&e.discardWatches?(this.watches.forEach(function(e){return t.maybeBroadcastWatch.forget(e)}),this.watches.clear(),r1(this)):this.broadcastWatches(),Promise.resolve()},t.prototype.removeOptimistic=function(e){var t=this.optimisticData.removeLayer(e);t!==this.optimisticData&&(this.optimisticData=t,this.broadcastWatches())},t.prototype.batch=function(e){var t,n=this,r=e.update,i=e.optimistic,a=void 0===i||i,o=e.removeOptimistic,s=e.onWatchUpdated,u=function(e){var i=n,a=i.data,o=i.optimisticData;++n.txCount,e&&(n.data=n.optimisticData=e);try{return t=r(n)}finally{--n.txCount,n.data=a,n.optimisticData=o}},c=new Set;return s&&!this.txCount&&this.broadcastWatches((0,en.pi)((0,en.pi)({},e),{onWatchUpdated:function(e){return c.add(e),!1}})),"string"==typeof a?this.optimisticData=this.optimisticData.addLayer(a,u):!1===a?u(this.data):u(),"string"==typeof o&&(this.optimisticData=this.optimisticData.removeLayer(o)),s&&c.size?(this.broadcastWatches((0,en.pi)((0,en.pi)({},e),{onWatchUpdated:function(e,t){var n=s.call(this,e,t);return!1!==n&&c.delete(e),n}})),c.size&&c.forEach(function(e){return n.maybeBroadcastWatch.dirty(e)})):this.broadcastWatches(e),t},t.prototype.performTransaction=function(e,t){return this.batch({update:e,optimistic:t||null!==t})},t.prototype.transformDocument=function(e){if(this.addTypename){var t=this.typenameDocumentCache.get(e);return t||(t=nj(e),this.typenameDocumentCache.set(e,t),this.typenameDocumentCache.set(t,t)),t}return e},t.prototype.transformForLink=function(e){var t=this.config.fragments;return t?t.transform(e):e},t.prototype.broadcastWatches=function(e){var t=this;this.txCount||this.watches.forEach(function(n){return t.maybeBroadcastWatch(n,e)})},t.prototype.broadcastWatch=function(e,t){var n=e.lastDiff,r=this.diff(e);(!t||(e.optimistic&&"string"==typeof t.optimistic&&(r.fromOptimisticTransaction=!0),!t.onWatchUpdated||!1!==t.onWatchUpdated.call(this,e,r,n)))&&(n&&(0,nm.D)(n.result,r.result)||e.callback(e.lastDiff=r,n))},t}(io),ar={possibleTypes:{ApproveJobProposalSpecPayload:["ApproveJobProposalSpecSuccess","JobAlreadyExistsError","NotFoundError"],BridgePayload:["Bridge","NotFoundError"],CancelJobProposalSpecPayload:["CancelJobProposalSpecSuccess","NotFoundError"],ChainPayload:["Chain","NotFoundError"],CreateAPITokenPayload:["CreateAPITokenSuccess","InputErrors"],CreateBridgePayload:["CreateBridgeSuccess"],CreateCSAKeyPayload:["CSAKeyExistsError","CreateCSAKeySuccess"],CreateFeedsManagerChainConfigPayload:["CreateFeedsManagerChainConfigSuccess","InputErrors","NotFoundError"],CreateFeedsManagerPayload:["CreateFeedsManagerSuccess","InputErrors","NotFoundError","SingleFeedsManagerError"],CreateJobPayload:["CreateJobSuccess","InputErrors"],CreateOCR2KeyBundlePayload:["CreateOCR2KeyBundleSuccess"],CreateOCRKeyBundlePayload:["CreateOCRKeyBundleSuccess"],CreateP2PKeyPayload:["CreateP2PKeySuccess"],DeleteAPITokenPayload:["DeleteAPITokenSuccess","InputErrors"],DeleteBridgePayload:["DeleteBridgeConflictError","DeleteBridgeInvalidNameError","DeleteBridgeSuccess","NotFoundError"],DeleteCSAKeyPayload:["DeleteCSAKeySuccess","NotFoundError"],DeleteFeedsManagerChainConfigPayload:["DeleteFeedsManagerChainConfigSuccess","NotFoundError"],DeleteJobPayload:["DeleteJobSuccess","NotFoundError"],DeleteOCR2KeyBundlePayload:["DeleteOCR2KeyBundleSuccess","NotFoundError"],DeleteOCRKeyBundlePayload:["DeleteOCRKeyBundleSuccess","NotFoundError"],DeleteP2PKeyPayload:["DeleteP2PKeySuccess","NotFoundError"],DeleteVRFKeyPayload:["DeleteVRFKeySuccess","NotFoundError"],DismissJobErrorPayload:["DismissJobErrorSuccess","NotFoundError"],Error:["CSAKeyExistsError","DeleteBridgeConflictError","DeleteBridgeInvalidNameError","InputError","JobAlreadyExistsError","NotFoundError","RunJobCannotRunError","SingleFeedsManagerError"],EthTransactionPayload:["EthTransaction","NotFoundError"],FeaturesPayload:["Features"],FeedsManagerPayload:["FeedsManager","NotFoundError"],GetSQLLoggingPayload:["SQLLogging"],GlobalLogLevelPayload:["GlobalLogLevel"],JobPayload:["Job","NotFoundError"],JobProposalPayload:["JobProposal","NotFoundError"],JobRunPayload:["JobRun","NotFoundError"],JobSpec:["BlockHeaderFeederSpec","BlockhashStoreSpec","BootstrapSpec","CronSpec","DirectRequestSpec","FluxMonitorSpec","GatewaySpec","KeeperSpec","OCR2Spec","OCRSpec","VRFSpec","WebhookSpec"],NodePayload:["Node","NotFoundError"],PaginatedPayload:["BridgesPayload","ChainsPayload","EthTransactionAttemptsPayload","EthTransactionsPayload","JobRunsPayload","JobsPayload","NodesPayload"],RejectJobProposalSpecPayload:["NotFoundError","RejectJobProposalSpecSuccess"],RunJobPayload:["NotFoundError","RunJobCannotRunError","RunJobSuccess"],SetGlobalLogLevelPayload:["InputErrors","SetGlobalLogLevelSuccess"],SetSQLLoggingPayload:["SetSQLLoggingSuccess"],SetServicesLogLevelsPayload:["InputErrors","SetServicesLogLevelsSuccess"],UpdateBridgePayload:["NotFoundError","UpdateBridgeSuccess"],UpdateFeedsManagerChainConfigPayload:["InputErrors","NotFoundError","UpdateFeedsManagerChainConfigSuccess"],UpdateFeedsManagerPayload:["InputErrors","NotFoundError","UpdateFeedsManagerSuccess"],UpdateJobProposalSpecDefinitionPayload:["NotFoundError","UpdateJobProposalSpecDefinitionSuccess"],UpdatePasswordPayload:["InputErrors","UpdatePasswordSuccess"],VRFKeyPayload:["NotFoundError","VRFKeySuccess"]}};let ai=ar;var aa=(r=void 0,location.origin),ao=new nh({uri:"".concat(aa,"/query"),credentials:"include"}),as=new ia({cache:new an({possibleTypes:ai.possibleTypes}),link:ao});if(a.Z.locale(o),u().defaultFormat="YYYY-MM-DD h:mm:ss A","undefined"!=typeof document){var au,ac,al=f().hydrate;ac=X,al(c.createElement(et,{client:as},c.createElement(d.zj,null,c.createElement(i.MuiThemeProvider,{theme:J.r},c.createElement(ac,null)))),document.getElementById("root"))}})()})(); \ No newline at end of file diff --git a/core/web/assets/main.74b124ef5d2ef3614139.js.gz b/core/web/assets/main.74b124ef5d2ef3614139.js.gz new file mode 100644 index 0000000000..667a96c1ef Binary files /dev/null and b/core/web/assets/main.74b124ef5d2ef3614139.js.gz differ diff --git a/core/web/assets/main.8f602c136d4004a835ee.js.gz b/core/web/assets/main.8f602c136d4004a835ee.js.gz deleted file mode 100644 index fceb7ce3cb..0000000000 Binary files a/core/web/assets/main.8f602c136d4004a835ee.js.gz and /dev/null differ diff --git a/core/web/resolver/testdata/config-empty-effective.toml b/core/web/resolver/testdata/config-empty-effective.toml index 7afef95e19..1c2e7b1b4b 100644 --- a/core/web/resolver/testdata/config-empty-effective.toml +++ b/core/web/resolver/testdata/config-empty-effective.toml @@ -41,8 +41,6 @@ MaxBatchSize = 50 SendInterval = '500ms' SendTimeout = '10s' UseBatchSend = true -URL = '' -ServerPubKey = '' [AuditLogger] Enabled = false diff --git a/core/web/resolver/testdata/config-full.toml b/core/web/resolver/testdata/config-full.toml index 91fabc29f4..f30bec52fe 100644 --- a/core/web/resolver/testdata/config-full.toml +++ b/core/web/resolver/testdata/config-full.toml @@ -41,8 +41,6 @@ MaxBatchSize = 4321 SendInterval = '1m0s' SendTimeout = '5s' UseBatchSend = true -URL = '' -ServerPubKey = '' [[TelemetryIngress.Endpoints]] Network = 'EVM' diff --git a/core/web/resolver/testdata/config-multi-chain-effective.toml b/core/web/resolver/testdata/config-multi-chain-effective.toml index f4cb6c1612..4e1a433733 100644 --- a/core/web/resolver/testdata/config-multi-chain-effective.toml +++ b/core/web/resolver/testdata/config-multi-chain-effective.toml @@ -41,8 +41,6 @@ MaxBatchSize = 50 SendInterval = '500ms' SendTimeout = '10s' UseBatchSend = true -URL = '' -ServerPubKey = '' [AuditLogger] Enabled = true diff --git a/core/web/router.go b/core/web/router.go index 5c5e86a12b..6401622e19 100644 --- a/core/web/router.go +++ b/core/web/router.go @@ -32,6 +32,7 @@ import ( mgin "github.com/ulule/limiter/v3/drivers/middleware/gin" "github.com/ulule/limiter/v3/drivers/store/memory" "github.com/unrolled/secure" + "go.opentelemetry.io/contrib/instrumentation/github.com/gin-gonic/gin/otelgin" "github.com/smartcontractkit/chainlink/v2/core/build" "github.com/smartcontractkit/chainlink/v2/core/logger" @@ -60,6 +61,7 @@ func NewRouter(app chainlink.Application, prometheus *ginprom.Prometheus) (*gin. tls := config.WebServer().TLS() engine.Use( + otelgin.Middleware("chainlink-web-routes"), limits.RequestSizeLimiter(config.WebServer().HTTPMaxSize()), loggerFunc(app.GetLogger()), gin.Recovery(), diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index 9085ed426d..83fd0f04f8 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -13,11 +13,29 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - `chainlink health` CLI command and HTML `/health` endpoint, to provide human-readable views of the underlying JSON health data. - New job type `stream` to represent streamspecs. This job type is not yet used anywhere but will be required for Data Streams V1. +- Environment variables `CL_MEDIAN_ENV`, `CL_SOLANA_ENV`, and `CL_STARKNET_ENV` for setting environment variables in LOOP Plugins with an `.env` file. + ``` + echo "Foo=Bar" >> median.env + echo "Baz=Val" >> median.env + CL_MEDIAN_ENV="median.env" + ``` ### Fixed - Fixed the encoding used for transactions when resending in batches +### Removed + +- `P2P.V1` is no longer 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 `TelemetryIngress.URL` and `TelemetryIngress.ServerPubKey` from TOML configuration, these fields are replaced by `[[TelemetryIngress.Endpoints]]`: +```toml + [[TelemetryIngress.Endpoints]] + Network = '...' # e.g. EVM. Solana, Starknet, Cosmos + ChainID = '...' # e.g. 1, 5, devnet, mainnet-beta + URL = '...' + ServerPubKey = '...' +``` + ## 2.8.0 - UNRELEASED ### Added @@ -90,6 +108,11 @@ Starting in `v2.9.0`: ... +## 2.7.2 - 2023-12-14 + +### Fixed + +- Fixed a bug that caused nodes without OCR or OCR2 enabled to fail config validation if `P2P.V2` was not explicitly disabled. With this fix, NOPs will not have to make changes to their config. ## 2.7.1 - 2023-11-21 diff --git a/docs/CONFIG.md b/docs/CONFIG.md index 23f5de82e5..53be48d85f 100644 --- a/docs/CONFIG.md +++ b/docs/CONFIG.md @@ -251,8 +251,6 @@ LeaseRefreshInterval determines how often to refresh the lease lock. Also contro [TelemetryIngress] UniConn = true # Default Logging = false # Default -ServerPubKey = 'test-pub-key' # Example -URL = 'https://prom.test' # Example BufferSize = 100 # Default MaxBatchSize = 50 # Default SendInterval = '500ms' # Default @@ -273,18 +271,6 @@ Logging = false # Default ``` Logging toggles verbose logging of the raw telemetry messages being sent. -### ServerPubKey -```toml -ServerPubKey = 'test-pub-key' # Example -``` -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. This field will be removed in a furture version - ### BufferSize ```toml BufferSize = 100 # Default @@ -5185,6 +5171,7 @@ GasLimit = 14500000 AutoCreateKey = true BlockBackfillDepth = 10 BlockBackfillSkip = false +ChainType = 'scroll' FinalityDepth = 1 FinalityTagEnabled = false LogBackfillBatchSize = 1000 @@ -5265,6 +5252,7 @@ GasLimit = 5300000 AutoCreateKey = true BlockBackfillDepth = 10 BlockBackfillSkip = false +ChainType = 'scroll' FinalityDepth = 1 FinalityTagEnabled = false LogBackfillBatchSize = 1000 @@ -5701,7 +5689,7 @@ BlockBackfillSkip enables skipping of very long backfills. ChainType = 'arbitrum' # Example ``` ChainType is automatically detected from chain ID. Set this to force a certain chain type regardless of chain ID. -Available types: arbitrum, metis, optimismBedrock, xdai, celo, kroma, wemix, zksync +Available types: arbitrum, metis, optimismBedrock, xdai, celo, kroma, wemix, zksync, scroll ### FinalityDepth ```toml diff --git a/go.md b/go.md index 0d2e9bb65d..654e8101e6 100644 --- a/go.md +++ b/go.md @@ -48,6 +48,7 @@ flowchart LR click tdh2/go/tdh2 href "https://github.com/smartcontractkit/tdh2" chainlink/v2 --> wsrpc click wsrpc href "https://github.com/smartcontractkit/wsrpc" + chainlink-automation --> chainlink-common chainlink-automation --> libocr chainlink-common --> libocr chainlink-cosmos --> chainlink-common diff --git a/go.mod b/go.mod index 63beb26dda..b566fb7cc0 100644 --- a/go.mod +++ b/go.mod @@ -13,7 +13,7 @@ require ( github.com/danielkov/gin-helmet v0.0.0-20171108135313-1387e224435e github.com/deckarep/golang-set/v2 v2.3.0 github.com/esote/minmaxheap v1.0.0 - github.com/ethereum/go-ethereum v1.12.2 + github.com/ethereum/go-ethereum v1.13.8 github.com/fatih/color v1.16.0 github.com/fxamacker/cbor/v2 v2.5.0 github.com/gagliardetto/solana-go v1.4.1-0.20220428092759-5250b4abbb27 @@ -34,6 +34,7 @@ require ( github.com/graph-gophers/dataloader v5.0.0+incompatible github.com/graph-gophers/graphql-go v1.3.0 github.com/hashicorp/consul/sdk v0.14.1 + github.com/hashicorp/go-envparse v0.1.0 github.com/hashicorp/go-plugin v1.5.2 github.com/hdevalence/ed25519consensus v0.1.0 github.com/jackc/pgconn v1.14.1 @@ -67,15 +68,15 @@ require ( github.com/shopspring/decimal v1.3.1 github.com/smartcontractkit/caigo v0.0.0-20230621050857-b29a4ca8c704 github.com/smartcontractkit/chain-selectors v1.0.9 - github.com/smartcontractkit/chainlink-automation v1.0.1 - github.com/smartcontractkit/chainlink-common v0.1.7-0.20240108182329-237f56daad6b - github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20231218175426-6e0427c661e5 + github.com/smartcontractkit/chainlink-automation v1.0.2-0.20240118014648-1ab6a88c9429 + github.com/smartcontractkit/chainlink-common v0.1.7-0.20240123141952-a879db9d23b3 + github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20240120192246-4bb04c997ca0 github.com/smartcontractkit/chainlink-data-streams v0.0.0-20231204152908-a6e3fe8ff2a1 - github.com/smartcontractkit/chainlink-feeds v0.0.0-20231127231053-2232d3a6766d - github.com/smartcontractkit/chainlink-solana v1.0.3-0.20231219140448-151a4725f312 - github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20231219014050-0c4a7831293a + github.com/smartcontractkit/chainlink-feeds v0.0.0-20240119021347-3c541a78cdb8 + github.com/smartcontractkit/chainlink-solana v1.0.3-0.20240122152632-38444d2ad8ba + github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20240119162652-3a7274645007 github.com/smartcontractkit/chainlink-vrf v0.0.0-20231120191722-fef03814f868 - github.com/smartcontractkit/libocr v0.0.0-20231130143053-c5102a9c0fb7 + github.com/smartcontractkit/libocr v0.0.0-20240112202000-6359502d2ff1 github.com/smartcontractkit/tdh2/go/ocr2/decryptionplugin v0.0.0-20230906073235-9e478e5e19f1 github.com/smartcontractkit/tdh2/go/tdh2 v0.0.0-20230906073235-9e478e5e19f1 github.com/smartcontractkit/wsrpc v0.7.2 @@ -91,9 +92,10 @@ require ( github.com/urfave/cli v1.22.14 go.dedis.ch/fixbuf v1.0.3 go.dedis.ch/kyber/v3 v3.1.0 + go.opentelemetry.io/contrib/instrumentation/github.com/gin-gonic/gin/otelgin v0.46.1 go.uber.org/multierr v1.11.0 go.uber.org/zap v1.26.0 - golang.org/x/crypto v0.16.0 + golang.org/x/crypto v0.17.0 golang.org/x/exp v0.0.0-20231127185646-65229373498e golang.org/x/sync v0.5.0 golang.org/x/term v0.15.0 @@ -110,7 +112,6 @@ require ( ) require ( - cloud.google.com/go/compute v1.23.3 // indirect contrib.go.opencensus.io/exporter/stackdriver v0.13.5 // indirect cosmossdk.io/api v0.3.1 // indirect cosmossdk.io/core v0.5.1 // indirect @@ -126,14 +127,14 @@ require ( github.com/CosmWasm/wasmvm v1.2.4 // indirect github.com/DataDog/zstd v1.5.2 // indirect github.com/Masterminds/goutils v1.1.1 // indirect - github.com/OneOfOne/xxhash v1.2.8 // indirect - github.com/VictoriaMetrics/fastcache v1.10.0 // indirect + github.com/Microsoft/go-winio v0.6.1 // indirect + github.com/VictoriaMetrics/fastcache v1.12.1 // indirect 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/beorn7/perks v1.0.1 // indirect github.com/bgentry/speakeasy v0.1.1-0.20220910012023-760eaf8b6816 // indirect - github.com/bits-and-blooms/bitset v1.7.0 // indirect + github.com/bits-and-blooms/bitset v1.10.0 // indirect github.com/blendle/zapdriver v1.3.1 // indirect github.com/bytedance/sonic v1.10.1 // indirect github.com/cenkalti/backoff v2.2.1+incompatible // indirect @@ -144,12 +145,13 @@ require ( github.com/chenzhuoyu/iasm v0.9.0 // indirect github.com/cockroachdb/errors v1.9.1 // indirect github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b // indirect - github.com/cockroachdb/pebble v0.0.0-20230906160148-46873a6a7a06 // indirect + github.com/cockroachdb/pebble v0.0.0-20230928194634-aa077af62593 // indirect github.com/cockroachdb/redact v1.1.3 // indirect + github.com/cockroachdb/tokenbucket v0.0.0-20230807174530-cc333fc44b06 // indirect github.com/cometbft/cometbft-db v0.8.0 // indirect github.com/confio/ics23/go v0.9.0 // indirect github.com/consensys/bavard v0.1.13 // indirect - github.com/consensys/gnark-crypto v0.10.0 // indirect + github.com/consensys/gnark-crypto v0.12.1 // indirect github.com/cosmos/btcutil v1.0.5 // indirect github.com/cosmos/cosmos-proto v1.0.0-beta.2 // indirect github.com/cosmos/go-bip39 v1.0.0 // indirect @@ -159,7 +161,8 @@ require ( github.com/cosmos/ics23/go v0.10.0 // indirect github.com/cosmos/ledger-cosmos-go v0.12.1 // indirect github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect - github.com/crate-crypto/go-kzg-4844 v0.3.0 // indirect + github.com/crate-crypto/go-ipa v0.0.0-20231025140028-3c0104f4b233 // indirect + github.com/crate-crypto/go-kzg-4844 v0.7.0 // indirect github.com/danieljoos/wincred v1.1.2 // indirect github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0 // indirect @@ -170,12 +173,13 @@ require ( github.com/docker/distribution v2.8.2+incompatible // indirect github.com/dustin/go-humanize v1.0.1 // indirect github.com/dvsekhvalnov/jose2go v1.5.0 // indirect - github.com/ethereum/c-kzg-4844 v0.3.1 // indirect + github.com/ethereum/c-kzg-4844 v0.4.0 // indirect github.com/fsnotify/fsnotify v1.6.0 // indirect github.com/gabriel-vasile/mimetype v1.4.2 // indirect github.com/gagliardetto/binary v0.7.1 // indirect github.com/gagliardetto/treeout v0.1.4 // indirect github.com/gballet/go-libpcsclite v0.0.0-20191108122812-4678299bea08 // indirect + github.com/gballet/go-verkle v0.1.1-0.20231031103413-a67434b50f46 // indirect github.com/gedex/inflector v0.0.0-20170307190818-16278e9db813 // indirect github.com/gin-contrib/sse v0.1.0 // indirect github.com/go-asn1-ber/asn1-ber v1.5.5 // indirect @@ -189,7 +193,6 @@ require ( github.com/go-playground/locales v0.14.1 // indirect github.com/go-playground/universal-translator v0.18.1 // indirect github.com/go-playground/validator/v10 v10.15.5 // indirect - github.com/go-stack/stack v1.8.1 // indirect github.com/go-webauthn/x v0.1.5 // indirect github.com/goccy/go-json v0.10.2 // indirect github.com/godbus/dbus v0.0.0-20190726142602-4481cbc300e2 // indirect @@ -223,7 +226,7 @@ require ( github.com/hashicorp/yamux v0.0.0-20200609203250-aecfd211c9ce // indirect github.com/holiman/billy v0.0.0-20230718173358-1c7e68d277a7 // indirect github.com/holiman/bloomfilter/v2 v2.0.3 // indirect - github.com/holiman/uint256 v1.2.3 // indirect + github.com/holiman/uint256 v1.2.4 // indirect github.com/huandu/skiplist v1.2.0 // indirect github.com/huandu/xstrings v1.4.0 // indirect github.com/huin/goupnp v1.3.0 // indirect @@ -312,15 +315,13 @@ require ( go.opentelemetry.io/proto/otlp v1.0.0 // indirect go.uber.org/ratelimit v0.2.0 // indirect golang.org/x/arch v0.6.0 // indirect + golang.org/x/mod v0.14.0 // indirect golang.org/x/net v0.19.0 // indirect - golang.org/x/oauth2 v0.15.0 // indirect golang.org/x/sys v0.15.0 // indirect - google.golang.org/appengine v1.6.8 // indirect google.golang.org/genproto v0.0.0-20231030173426-d783a09b4405 // indirect google.golang.org/genproto/googleapis/api v0.0.0-20231016165738-49dd2c1f3d0b // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20231106174013-bbf56f31fb17 // 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 gopkg.in/yaml.v3 v3.0.1 // indirect nhooyr.io/websocket v1.8.7 // indirect diff --git a/go.sum b/go.sum index 03bbd16a50..f1ce043a96 100644 --- a/go.sum +++ b/go.sum @@ -116,11 +116,11 @@ github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5 github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5 h1:TngWCqHvy9oXAN6lEVMRuU21PR1EtLVZJmdB18Gu3Rw= github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5/go.mod h1:lmUJ/7eu/Q8D7ML55dXQrVaamCz2vxCfdQBasLZfHKk= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= -github.com/OneOfOne/xxhash v1.2.8 h1:31czK/TI9sNkxIKfaUfGlU47BAxQ0ztGgd9vPyqimf8= -github.com/OneOfOne/xxhash v1.2.8/go.mod h1:eZbhyaAYD41SGSSsnmcpxVoRiQ/MPUTjUdIIOT9Um7Q= +github.com/OneOfOne/xxhash v1.2.5 h1:zl/OfRA6nftbBK9qTohYBJ5xvw6C/oNKizR7cZGl3cI= +github.com/OneOfOne/xxhash v1.2.5/go.mod h1:eZbhyaAYD41SGSSsnmcpxVoRiQ/MPUTjUdIIOT9Um7Q= github.com/Shopify/goreferrer v0.0.0-20181106222321-ec9c9a553398/go.mod h1:a1uqRtAwp2Xwc6WNPJEufxJ7fx3npB4UV/JOLmbu5I0= -github.com/VictoriaMetrics/fastcache v1.10.0 h1:5hDJnLsKLpnUEToub7ETuRu8RCkb40woBZAUiKonXzY= -github.com/VictoriaMetrics/fastcache v1.10.0/go.mod h1:tjiYeEfYXCqacuvYw/7UoDIeJaNxq6132xHICNP77w8= +github.com/VictoriaMetrics/fastcache v1.12.1 h1:i0mICQuojGDL3KblA7wUNlY5lOK6a4bwt3uRKnkZU40= +github.com/VictoriaMetrics/fastcache v1.12.1/go.mod h1:tX04vaqcNoQeGLD+ra5pU5sWkuxnzWhEzLwhP9w653o= github.com/VividCortex/gohistogram v1.0.0 h1:6+hBz+qvs0JOrrNhhmR7lFxo5sINxBCGXrdtl/UvroE= github.com/VividCortex/gohistogram v1.0.0/go.mod h1:Pf5mBqqDxYaXu3hDrrU+w6nw50o/4+TcAqDqk/vUH7g= github.com/ajg/form v1.5.1/go.mod h1:uL1WgH+h2mgNtvBq0339dVnzXdBETtL2LeUXaIv25UY= @@ -168,8 +168,8 @@ github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d/go.mod h1:6QX/PXZ github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= github.com/bgentry/speakeasy v0.1.1-0.20220910012023-760eaf8b6816 h1:41iFGWnSlI2gVpmOtVTJZNodLdLQLn/KsJqFvXwnd/s= github.com/bgentry/speakeasy v0.1.1-0.20220910012023-760eaf8b6816/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= -github.com/bits-and-blooms/bitset v1.7.0 h1:YjAGVd3XmtK9ktAbX8Zg2g2PwLIMjGREZJHlV4j7NEo= -github.com/bits-and-blooms/bitset v1.7.0/go.mod h1:gIdJ4wp64HaoK2YrL1Q5/N7Y16edYb8uY+O0FJTyyDA= +github.com/bits-and-blooms/bitset v1.10.0 h1:ePXTeiPEazB5+opbv5fr8umg2R/1NlzgDsyepwsSr88= +github.com/bits-and-blooms/bitset v1.10.0/go.mod h1:7hO7Gc7Pp1vODcmWvKMRA9BNmbv6a/7QIWpPxHddWR8= github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJmJgSg28kpZDP6UIiPt0e0Oz0kqKNGyRaWEPv84= github.com/blendle/zapdriver v1.3.1 h1:C3dydBOWYRiOk+B8X9IVZ5IOe+7cl+tGOexN4QqHfpE= github.com/blendle/zapdriver v1.3.1/go.mod h1:mdXfREi6u5MArG4j9fewC+FGnXaBR+T4Ox4J2u4eHCc= @@ -197,7 +197,6 @@ github.com/cespare/cp v1.1.1/go.mod h1:SOGHArjBr4JWaSDEVpWpo/hNg6RoKrls6Oh40hiwW github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko= github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= -github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/chenzhuoyu/base64x v0.0.0-20211019084208-fb5309c8db06/go.mod h1:DH46F32mSOjUmXrMHnKwZdA8wcEefY7UVqBKYGjpdQY= @@ -226,17 +225,19 @@ github.com/cockroachdb/apd/v2 v2.0.2/go.mod h1:DDxRlzC2lo3/vSlmSoS7JkqbbrARPuFOG github.com/cockroachdb/apd/v3 v3.1.0 h1:MK3Ow7LH0W8zkd5GMKA1PvS9qG3bWFI95WaVNfyZJ/w= github.com/cockroachdb/apd/v3 v3.1.0/go.mod h1:6qgPBMXjATAdD/VefbRP9NoSLKjbB4LCoA7gN4LpHs4= github.com/cockroachdb/datadriven v1.0.2/go.mod h1:a9RdTaap04u637JoCzcUoIcDmvwSUtcUFtT/C3kJlTU= -github.com/cockroachdb/datadriven v1.0.3-0.20230801171734-e384cf455877 h1:1MLK4YpFtIEo3ZtMA5C795Wtv5VuUnrXX7mQG+aHg6o= -github.com/cockroachdb/datadriven v1.0.3-0.20230801171734-e384cf455877/go.mod h1:a9RdTaap04u637JoCzcUoIcDmvwSUtcUFtT/C3kJlTU= +github.com/cockroachdb/datadriven v1.0.3-0.20230413201302-be42291fc80f h1:otljaYPt5hWxV3MUfO5dFPFiOXg9CyG5/kCfayTqsJ4= +github.com/cockroachdb/datadriven v1.0.3-0.20230413201302-be42291fc80f/go.mod h1:a9RdTaap04u637JoCzcUoIcDmvwSUtcUFtT/C3kJlTU= github.com/cockroachdb/errors v1.9.1 h1:yFVvsI0VxmRShfawbt/laCIDy/mtTqqnvoNgiy5bEV8= github.com/cockroachdb/errors v1.9.1/go.mod h1:2sxOtL2WIc096WSZqZ5h8fa17rdDq9HZOZLBCor4mBk= github.com/cockroachdb/logtags v0.0.0-20211118104740-dabe8e521a4f/go.mod h1:Vz9DsVWQQhf3vs21MhPMZpMGSht7O/2vFW2xusFUVOs= github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b h1:r6VH0faHjZeQy818SGhaone5OnYfxFR/+AzdY3sf5aE= github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b/go.mod h1:Vz9DsVWQQhf3vs21MhPMZpMGSht7O/2vFW2xusFUVOs= -github.com/cockroachdb/pebble v0.0.0-20230906160148-46873a6a7a06 h1:T+Np/xtzIjYM/P5NAw0e2Rf1FGvzDau1h54MKvx8G7w= -github.com/cockroachdb/pebble v0.0.0-20230906160148-46873a6a7a06/go.mod h1:bynZ3gvVyhlvjLI7PT6dmZ7g76xzJ7HpxfjgkzCGz6s= +github.com/cockroachdb/pebble v0.0.0-20230928194634-aa077af62593 h1:aPEJyR4rPBvDmeyi+l/FS/VtA00IWvjeFvjen1m1l1A= +github.com/cockroachdb/pebble v0.0.0-20230928194634-aa077af62593/go.mod h1:6hk1eMY/u5t+Cf18q5lFMUA1Rc+Sm5I6Ra1QuPyxXCo= github.com/cockroachdb/redact v1.1.3 h1:AKZds10rFSIj7qADf0g46UixK8NNLwWTNdCIGS5wfSQ= github.com/cockroachdb/redact v1.1.3/go.mod h1:BVNblN9mBWFyMyqK1k3AAiSxhvhfK2oOZZ2lK+dpvRg= +github.com/cockroachdb/tokenbucket v0.0.0-20230807174530-cc333fc44b06 h1:zuQyyAKVxetITBuuhv3BI9cMrmStnpT18zmgmTxunpo= +github.com/cockroachdb/tokenbucket v0.0.0-20230807174530-cc333fc44b06/go.mod h1:7nc4anLGjupUW/PeY5qiNYsdNXj7zopG+eqsS7To5IQ= github.com/codegangsta/inject v0.0.0-20150114235600-33e0aa1cb7c0/go.mod h1:4Zcjuz89kmFXt9morQgcfYZAYZ5n8WHjt81YYWIwtTM= github.com/coinbase/rosetta-sdk-go/types v1.0.0 h1:jpVIwLcPoOeCR6o1tU+Xv7r5bMONNbHU7MuEHboiFuA= github.com/coinbase/rosetta-sdk-go/types v1.0.0/go.mod h1:eq7W2TMRH22GTW0N0beDnN931DW0/WOI1R2sdHNHG4c= @@ -248,8 +249,8 @@ github.com/confio/ics23/go v0.9.0 h1:cWs+wdbS2KRPZezoaaj+qBleXgUk5WOQFMP3CQFGTr4 github.com/confio/ics23/go v0.9.0/go.mod h1:4LPZ2NYqnYIVRklaozjNR1FScgDJ2s5Xrp+e/mYVRak= github.com/consensys/bavard v0.1.13 h1:oLhMLOFGTLdlda/kma4VOJazblc7IM5y5QPd2A/YjhQ= github.com/consensys/bavard v0.1.13/go.mod h1:9ItSMtA/dXMAiL7BG6bqW2m3NdSEObYWoH223nGHukI= -github.com/consensys/gnark-crypto v0.10.0 h1:zRh22SR7o4K35SoNqouS9J/TKHTyU2QWaj5ldehyXtA= -github.com/consensys/gnark-crypto v0.10.0/go.mod h1:Iq/P3HHl0ElSjsg2E1gsMwhAyxnxoKK5nVyZKd+/KhU= +github.com/consensys/gnark-crypto v0.12.1 h1:lHH39WuuFgVHONRl3J0LRBtuYdQTumFSDtJF7HpyG8M= +github.com/consensys/gnark-crypto v0.12.1/go.mod h1:v2Gy7L/4ZRosZ7Ivs+9SfUDr0f5UlG+EM5t7MPHiLuY= github.com/containerd/continuity v0.4.3 h1:6HVkalIp+2u1ZLH1J/pYX2oBVXlJZvh1X1A7bEZ9Su8= github.com/containerd/continuity v0.4.3/go.mod h1:F6PTNCKepoxEaXLQp3wDAjygEnImnZ/7o4JzpodfroQ= github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= @@ -289,8 +290,10 @@ github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwc github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/cpuguy83/go-md2man/v2 v2.0.2 h1:p1EgwI/C7NhT0JmVkwCD2ZBK8j4aeHQX2pMHHBfMQ6w= github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= -github.com/crate-crypto/go-kzg-4844 v0.3.0 h1:UBlWE0CgyFqqzTI+IFyCzA7A3Zw4iip6uzRv5NIXG0A= -github.com/crate-crypto/go-kzg-4844 v0.3.0/go.mod h1:SBP7ikXEgDnUPONgm33HtuDZEDtWa3L4QtN1ocJSEQ4= +github.com/crate-crypto/go-ipa v0.0.0-20231025140028-3c0104f4b233 h1:d28BXYi+wUpz1KBmiF9bWrjEMacUEREV6MBi2ODnrfQ= +github.com/crate-crypto/go-ipa v0.0.0-20231025140028-3c0104f4b233/go.mod h1:geZJZH3SzKCqnz5VT0q/DyIG/tvu/dZk+VIfXicupJs= +github.com/crate-crypto/go-kzg-4844 v0.7.0 h1:C0vgZRk4q4EZ/JgPfzuSoxdCq3C3mOZMBShovmncxvA= +github.com/crate-crypto/go-kzg-4844 v0.7.0/go.mod h1:1kMhvPgI0Ky3yIa+9lFySEBUBXkYxeOi8ZF1sYioxhc= github.com/creachadair/taskgroup v0.4.2 h1:jsBLdAJE42asreGss2xZGZ8fJra7WtwnHWeJFxv2Li8= github.com/creachadair/taskgroup v0.4.2/go.mod h1:qiXUOSrbwAY3u0JPGTzObbE3yf9hcXHDKBZ2ZjpCbgM= github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= @@ -362,10 +365,10 @@ github.com/envoyproxy/protoc-gen-validate v1.0.2/go.mod h1:GpiZQP3dDbg4JouG/NNS7 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= -github.com/ethereum/c-kzg-4844 v0.3.1 h1:sR65+68+WdnMKxseNWxSJuAv2tsUrihTpVBTfM/U5Zg= -github.com/ethereum/c-kzg-4844 v0.3.1/go.mod h1:VewdlzQmpT5QSrVhbBuGoCdFJkpaJlO1aQputP83wc0= -github.com/ethereum/go-ethereum v1.12.2 h1:eGHJ4ij7oyVqUQn48LBz3B7pvQ8sV0wGJiIE6gDq/6Y= -github.com/ethereum/go-ethereum v1.12.2/go.mod h1:1cRAEV+rp/xX0zraSCBnu9Py3HQ+geRMj3HdR+k0wfI= +github.com/ethereum/c-kzg-4844 v0.4.0 h1:3MS1s4JtA868KpJxroZoepdV0ZKBp3u/O5HcZ7R3nlY= +github.com/ethereum/c-kzg-4844 v0.4.0/go.mod h1:VewdlzQmpT5QSrVhbBuGoCdFJkpaJlO1aQputP83wc0= +github.com/ethereum/go-ethereum v1.13.8 h1:1od+thJel3tM52ZUNQwvpYOeRHlbkVFZ5S8fhi0Lgsg= +github.com/ethereum/go-ethereum v1.13.8/go.mod h1:sc48XYQxCzH3fG9BcrXCOOgQk2JfZzNAmIKnceogzsA= github.com/fasthttp-contrib/websocket v0.0.0-20160511215533-1f3b11f56072/go.mod h1:duJ4Jxv5lDcvg4QuQr0oowTf7dz4/CR8NtyCooz9HL8= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU= @@ -402,6 +405,8 @@ github.com/gagliardetto/treeout v0.1.4/go.mod h1:loUefvXTrlRG5rYmJmExNryyBRh8f89 github.com/gavv/httpexpect v2.0.0+incompatible/go.mod h1:x+9tiU1YnrOvnB725RkpoLv1M62hOWzwo5OXotisrKc= github.com/gballet/go-libpcsclite v0.0.0-20191108122812-4678299bea08 h1:f6D9Hr8xV8uYKlyuj8XIruxlh9WjVjdh1gIicAS7ays= github.com/gballet/go-libpcsclite v0.0.0-20191108122812-4678299bea08/go.mod h1:x7DCsMOv1taUwEWCzT4cmDeAkigA5/QCwUodaVOe8Ww= +github.com/gballet/go-verkle v0.1.1-0.20231031103413-a67434b50f46 h1:BAIP2GihuqhwdILrV+7GJel5lyPV3u1+PgzrWLc0TkE= +github.com/gballet/go-verkle v0.1.1-0.20231031103413-a67434b50f46/go.mod h1:QNpY22eby74jVhqH4WhDLDwxc/vqsern6pW+u2kbkpc= github.com/gedex/inflector v0.0.0-20170307190818-16278e9db813 h1:Uc+IZ7gYqAf/rSGFplbWBSHaGolEQlNLgMgSE3ccnIQ= github.com/gedex/inflector v0.0.0-20170307190818-16278e9db813/go.mod h1:P+oSoE9yhSRvsmYyZsshflcR6ePWYLql6UU1amW13IM= github.com/getsentry/sentry-go v0.12.0/go.mod h1:NSap0JBYWzHND8oMbyi0+XZhUalc1TBdRL1M71JZW2c= @@ -480,8 +485,6 @@ github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LB github.com/go-sql-driver/mysql v1.7.1 h1:lUIinVbN1DY0xBg0eMOzmmtGoHwWBbvnWubQUrtU8EI= github.com/go-sql-driver/mysql v1.7.1/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= -github.com/go-stack/stack v1.8.1 h1:ntEHSVwIt7PNXNpgPmVfMrNhLtgjlmnZha2kOpuRiDw= -github.com/go-stack/stack v1.8.1/go.mod h1:dcoOX6HbPZSZptuspn9bctJ+N/CnF5gGygcUP3XYfe4= github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI= github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls= @@ -614,8 +617,8 @@ github.com/google/uuid v1.2.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+ github.com/google/uuid v1.3.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.4.0 h1:MtMxsa51/r9yyhkyLsVeVt0B+BGQZzpQiTQ4eHZ8bc4= github.com/google/uuid v1.4.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/googleapis/enterprise-certificate-proxy v0.3.2 h1:Vie5ybvEvT75RniqhfFxPRy3Bf7vr3h0cechB90XaQs= -github.com/googleapis/enterprise-certificate-proxy v0.3.2/go.mod h1:VLSiSSBs/ksPL8kq3OBOQ6WRI2QnaFynd1DCjZ62+V0= +github.com/googleapis/enterprise-certificate-proxy v0.3.1 h1:SBWmZhjUDRorQxrN0nwzf+AHBxnbFjViHQS4P0yVpmQ= +github.com/googleapis/enterprise-certificate-proxy v0.3.1/go.mod h1:VLSiSSBs/ksPL8kq3OBOQ6WRI2QnaFynd1DCjZ62+V0= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= github.com/googleapis/gax-go/v2 v2.12.0 h1:A+gCJKdRfqXkr+BIRGtZLibNXf0m1f9E4HG56etFpas= @@ -676,6 +679,8 @@ github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtng github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ= github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48= +github.com/hashicorp/go-envparse v0.1.0 h1:bE++6bhIsNCPLvgDZkYqo3nA+/PFI51pkrHdmPSDFPY= +github.com/hashicorp/go-envparse v0.1.0/go.mod h1:OHheN1GoygLlAkTlXLXvAdnXdZxy8JUweQ1rAXx1xnc= github.com/hashicorp/go-getter v1.7.1 h1:SWiSWN/42qdpR0MdhaOc/bLR48PLuP1ZQtYLRlM69uY= github.com/hashicorp/go-getter v1.7.1/go.mod h1:W7TalhMmbPmsSMdNjD0ZskARur/9GJ17cfHTRtXV744= github.com/hashicorp/go-hclog v1.5.0 h1:bI2ocEMgcVlz55Oj1xZNBsVi900c7II+fWDyV9o+13c= @@ -718,8 +723,8 @@ github.com/holiman/billy v0.0.0-20230718173358-1c7e68d277a7 h1:3JQNjnMRil1yD0IfZ github.com/holiman/billy v0.0.0-20230718173358-1c7e68d277a7/go.mod h1:5GuXa7vkL8u9FkFuWdVvfR5ix8hRB7DbOAaYULamFpc= github.com/holiman/bloomfilter/v2 v2.0.3 h1:73e0e/V0tCydx14a0SCYS/EWCxgwLZ18CZcZKVu0fao= github.com/holiman/bloomfilter/v2 v2.0.3/go.mod h1:zpoh+gs7qcpqrHr3dB55AMiJwo0iURXE7ZOP9L9hSkA= -github.com/holiman/uint256 v1.2.3 h1:K8UWO1HUJpRMXBxbmaY1Y8IAMZC/RsKB+ArEnnK4l5o= -github.com/holiman/uint256 v1.2.3/go.mod h1:SC8Ryt4n+UBbPbIBKaG9zbbDlp4jOru9xFZmPzLUTxw= +github.com/holiman/uint256 v1.2.4 h1:jUc4Nk8fm9jZabQuqr2JzednajVmBpC+oiTiXZJEApU= +github.com/holiman/uint256 v1.2.4/go.mod h1:EOMSn4q6Nyt9P6efbI3bueV4e1b3dGlUCXeiRV4ng7E= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/huandu/go-assert v1.1.5 h1:fjemmA7sSfYHJD7CUqs9qTwwfdNAx7/j2/ZlHXzNB3c= github.com/huandu/go-assert v1.1.5/go.mod h1:yOLvuqZwmcHIC5rIzrBhT7D3Q9c3GFnd0JrPVhn/06U= @@ -1154,28 +1159,28 @@ 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/chain-selectors v1.0.9 h1:Zof8tl3Huvv/Yi0q1CKVg1iAx9J39IUPaQOZUq5Qmps= github.com/smartcontractkit/chain-selectors v1.0.9/go.mod h1:d4Hi+E1zqjy9HqMkjBE5q1vcG9VGgxf5VxiRHfzi2kE= -github.com/smartcontractkit/chainlink-automation v1.0.1 h1:vVjBFq2Zsz21kPy1Pb0wpjF9zrbJX+zjXphDeeR4XZk= -github.com/smartcontractkit/chainlink-automation v1.0.1/go.mod h1:INSchkV3ntyDdlZKGWA030MPDpp6pbeuiRkRKYFCm2k= -github.com/smartcontractkit/chainlink-common v0.1.7-0.20240108182329-237f56daad6b h1:PRuvHgPka1gIGPKASuJHvqUvYWhZO7z5B/kKapjkZaM= -github.com/smartcontractkit/chainlink-common v0.1.7-0.20240108182329-237f56daad6b/go.mod h1:f+0ei9N4PlTJHu7pbGzEjTnBUr45syPdGFu5+31lS5Q= -github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20231218175426-6e0427c661e5 h1:kBnmjv3fxU7krVIqZFvo1m4F6qBc4vPURQFX/mcChhI= -github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20231218175426-6e0427c661e5/go.mod h1:EoM7wQ81mov7wsUzG4zEnnr0EH0POEo/I0hRDg433TU= +github.com/smartcontractkit/chainlink-automation v1.0.2-0.20240118014648-1ab6a88c9429 h1:xkejUBZhcBpBrTSfxc91Iwzadrb6SXw8ks69bHIQ9Ww= +github.com/smartcontractkit/chainlink-automation v1.0.2-0.20240118014648-1ab6a88c9429/go.mod h1:wJmVvDf4XSjsahWtfUq3wvIAYEAuhr7oxmxYnEL/LGQ= +github.com/smartcontractkit/chainlink-common v0.1.7-0.20240123141952-a879db9d23b3 h1:uSLn+JbClhldYn7zm0GEALGvi6KAfrY5Kp46IX9sy0E= +github.com/smartcontractkit/chainlink-common v0.1.7-0.20240123141952-a879db9d23b3/go.mod h1:05rRF84QKlIOF5LfTBPkHdw4UpBI2G3zxRcuZ65bPjk= +github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20240120192246-4bb04c997ca0 h1:NALwENz6vQ972DuD9AZjqRjyNSxH9ptNapizQGLI+2s= +github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20240120192246-4bb04c997ca0/go.mod h1:NcVAT/GETDBvIoAej5K6OYqAtDOkF6vO5pYw/hLuYVU= github.com/smartcontractkit/chainlink-data-streams v0.0.0-20231204152908-a6e3fe8ff2a1 h1:xYqRgZO0nMSO8CBCMR0r3WA+LZ4kNL8a6bnbyk/oBtQ= github.com/smartcontractkit/chainlink-data-streams v0.0.0-20231204152908-a6e3fe8ff2a1/go.mod h1:GuPvyXryvbiUZIHmPeLBz4L+yJKeyGUjrDfd1KNne+o= -github.com/smartcontractkit/chainlink-feeds v0.0.0-20231127231053-2232d3a6766d h1:w4MsbOtNk6nD/mcXLstHWk9hB6g7QLtcAfhPjhwvOaQ= -github.com/smartcontractkit/chainlink-feeds v0.0.0-20231127231053-2232d3a6766d/go.mod h1:YPAfLNowdBwiKiYOwgwtbJHi8AJWbcxkbOY0ItAvkfc= -github.com/smartcontractkit/chainlink-solana v1.0.3-0.20231219140448-151a4725f312 h1:ziqC+WW/2/UI6w3DShy7HGzJMWWLIYHT5ev2Qaa3h6I= -github.com/smartcontractkit/chainlink-solana v1.0.3-0.20231219140448-151a4725f312/go.mod h1:vqnojBNdzHNI6asWezJlottUiVEXudMEGf2Mz5R+xps= -github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20231219014050-0c4a7831293a h1:atCXqF8e5U2zfEaA87cKJs+K1MAbOVh3V05gEd60fR0= -github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20231219014050-0c4a7831293a/go.mod h1:YWKpf+hO9XMlzIWQT8yGoky3aeFLzMUVsjbs80LD77M= +github.com/smartcontractkit/chainlink-feeds v0.0.0-20240119021347-3c541a78cdb8 h1:1BcjXuviSAKttOX7BZoVHRZZGfxqoA2+AL8tykmkdoc= +github.com/smartcontractkit/chainlink-feeds v0.0.0-20240119021347-3c541a78cdb8/go.mod h1:vy1L7NybTy2F/Yv7BOh+oZBa1MACD6gzd1+DkcSkfp8= +github.com/smartcontractkit/chainlink-solana v1.0.3-0.20240122152632-38444d2ad8ba h1:6rnQrD8NaLfLOPHszW1hbpviqpU8011gzdZk6wKP1xY= +github.com/smartcontractkit/chainlink-solana v1.0.3-0.20240122152632-38444d2ad8ba/go.mod h1:OZfzyayUdwsVBqxvbEMqwUntQT8HbFbgyqoudvwfVN0= +github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20240119162652-3a7274645007 h1:KwB0H2P/gxJgt823Ku1fTcFLDKMj6zsP3wbQGlBOm4U= +github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20240119162652-3a7274645007/go.mod h1:EbZAlb/2K6mKr26u3+3cLBe/caJaqCHw786On94C43g= github.com/smartcontractkit/chainlink-vrf v0.0.0-20231120191722-fef03814f868 h1:FFdvEzlYwcuVHkdZ8YnZR/XomeMGbz5E2F2HZI3I3w8= github.com/smartcontractkit/chainlink-vrf v0.0.0-20231120191722-fef03814f868/go.mod h1:Kn1Hape05UzFZ7bOUnm3GVsHzP0TNrVmpfXYNHdqGGs= 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-20231130143053-c5102a9c0fb7 h1:AA7vf29c6lFsZm+MtIEtXtg6VUOQV6waJo5MUuHfRjQ= -github.com/smartcontractkit/libocr v0.0.0-20231130143053-c5102a9c0fb7/go.mod h1:WcuWFMskcGK0MYZuH5hEhGJOzdJRUFeNEM4PAKlejI4= +github.com/smartcontractkit/libocr v0.0.0-20240112202000-6359502d2ff1 h1:3y9WsXkZ5lxFrmfH7DQHs/q308lylKId5l/3VC0QAdM= +github.com/smartcontractkit/libocr v0.0.0-20240112202000-6359502d2ff1/go.mod h1:kC0qmVPUaVkFqGiZMNhmRmjdphuUmeyLEdlWFOQzFWI= github.com/smartcontractkit/tdh2/go/ocr2/decryptionplugin v0.0.0-20230906073235-9e478e5e19f1 h1:yiKnypAqP8l0OX0P3klzZ7SCcBUxy5KqTAKZmQOvSQE= github.com/smartcontractkit/tdh2/go/ocr2/decryptionplugin v0.0.0-20230906073235-9e478e5e19f1/go.mod h1:q6f4fe39oZPdsh1i57WznEZgxd8siidMaSFq3wdPmVg= github.com/smartcontractkit/tdh2/go/tdh2 v0.0.0-20230906073235-9e478e5e19f1 h1:Dai1bn+Q5cpeGMQwRdjOdVjG8mmFFROVkSKuUgBErRQ= @@ -1354,8 +1359,12 @@ 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/github.com/gin-gonic/gin/otelgin v0.46.1 h1:mMv2jG58h6ZI5t5S9QCVGdzCmAsTakMa3oxVgpSD44g= +go.opentelemetry.io/contrib/instrumentation/github.com/gin-gonic/gin/otelgin v0.46.1/go.mod h1:oqRuNKG0upTaDPbLVCG8AD0G2ETrfDtmh7jViy7ox6M= go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.46.1 h1:SpGay3w+nEwMpfVnbqOLH5gY52/foP8RE8UzTZ1pdSE= go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.46.1/go.mod h1:4UoMYEZOC0yN/sPGH76KPkkU7zgiEWYWL9vwmbnTJPE= +go.opentelemetry.io/contrib/propagators/b3 v1.21.1 h1:WPYiUgmw3+b7b3sQ1bFBFAf0q+Di9dvNc3AtYfnT4RQ= +go.opentelemetry.io/contrib/propagators/b3 v1.21.1/go.mod h1:EmzokPoSqsYMBVK4nRnhsfm5mbn8J1eDuz/U1UaQaWg= go.opentelemetry.io/otel v1.21.0 h1:hzLeKBZEL7Okw2mGzZ0cc4k/A7Fta0uoPgaJCr8fsFc= go.opentelemetry.io/otel v1.21.0/go.mod h1:QZzNPQPm1zLX4gZK4cMi+71eaorMSGT3A4znnUvNNEo= go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.21.0 h1:cl5P5/GIfFh4t6xyruOgJP5QiA1pw4fYYdv6nc6CBWw= @@ -1427,8 +1436,8 @@ golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0 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.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc= -golang.org/x/crypto v0.16.0 h1:mMMrFzRSCF0GvB7Ne27XVtVAaXLrPmgPC7/v0tkwHaY= -golang.org/x/crypto v0.16.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4= +golang.org/x/crypto v0.17.0 h1:r8bRNjWL3GshPW3gkd+RpvzWrZAwPS49OmTGZ/uhM4k= +golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4= 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= @@ -1627,7 +1636,6 @@ golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220209214540-3681064d5158/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220405052023-b1e9470b6e64/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -1663,7 +1671,6 @@ golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= -golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= @@ -1775,8 +1782,8 @@ google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz513 google.golang.org/api v0.35.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg= google.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34qYtE= google.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8= -google.golang.org/api v0.149.0 h1:b2CqT6kG+zqJIVKRQ3ELJVLN1PwHZ6DJ3dW8yl82rgY= -google.golang.org/api v0.149.0/go.mod h1:Mwn1B7JTXrzXtnvmzQE2BD6bYZQ8DShKZDZbeN9I7qI= +google.golang.org/api v0.147.0 h1:Can3FaQo9LlVqxJCodNmeZW/ib3/qKAY3rFeXiHo5gc= +google.golang.org/api v0.147.0/go.mod h1:pQ/9j83DcmPd/5C9e2nFOdjjNkDZ1G+zkbK2uvdkJMs= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= @@ -1902,8 +1909,6 @@ gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/mgo.v2 v2.0.0-20180705113604-9856a29383ce/go.mod h1:yeKp02qBN3iKW1OzL3MGk2IdtZzaj7SFntXj72NppTA= gopkg.in/natefinch/lumberjack.v2 v2.2.1 h1:bBRl1b0OH9s/DuPhuXpNl+VtCaJXFZ5/uEFST95x9zc= gopkg.in/natefinch/lumberjack.v2 v2.2.1/go.mod h1:YD8tP3GAjkrDg1eZH7EGmyESg/lsYskCTPBJVb9jqSc= -gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce h1:+JknDZhAj8YMt7GC73Ei8pv4MzjDUNPHgQWJdtMAaDU= -gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce/go.mod h1:5AcXVHNjg+BDxry382+8OKon8SEWiKktQR07RKPsv1c= gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= diff --git a/integration-tests/.root_dir b/integration-tests/.root_dir new file mode 100644 index 0000000000..e69de29bb2 diff --git a/integration-tests/Makefile b/integration-tests/Makefile index d1e9bdd89e..8415c00f9c 100644 --- a/integration-tests/Makefile +++ b/integration-tests/Makefile @@ -60,12 +60,12 @@ lint: golangci-lint --color=always run ./... --fix -v build: - @go build ./... && SELECTED_NETWORKS=SIMULATED go test -run=^# ./... + @go build ./... go test -run=^# ./... # Builds the test image # tag: the tag for the test image being built, example: tag=tate # base_tag: the tag for the base-test-image to use, example: base_tag=latest -# suite: the test suites to build into the image, example: suite="chaos soak smoke reorg migration performance" +# suite: the test suites to build into the image, example: suite="chaos soak smoke reorg migration" # push: set to true if you want the image pushed or leave blank if not, example: push=true .PHONY: build_test_image build_test_image: @@ -89,10 +89,11 @@ run_tracing: ## Test Runner .PHONY: run -run: # Need to set network first in case it's unset. Doesn't matter for the runner - SELECTED_NETWORKS="SIMULATED" go run . +run: + go run . ## All commands will use 16 threads to run tests in parallel. To change this, use -test.parallel n +## Remember to set selected_networks and CL image in the TOML file (e.g. overrides.toml) # Smoke .PHONY: test_smoke_product @@ -122,23 +123,15 @@ test_chaos_network: install_gotestfmt ## Run all smoke tests test_chaos_verbose: ## Run all smoke tests with verbose logging go test -timeout 24h -count=1 -v $(args) ./chaos -# Performance -.PHONY: test_perf -test_perf: ## Run core node performance tests. - TEST_LOG_LEVEL="disabled" \ - SELECTED_NETWORKS="SIMULATED,SIMULATED_1,SIMULATED_2" \ - go test -timeout 1h -count=1 -json $(args) ./performance 2>&1 | tee /tmp/gotest.log | gotestfmt - # Migrations .PHONY: test_node_migrations -test_node_migrations: install_gotestfmt ## Run all node migration tests +test_node_migrations: install_gotestfmt ## Run all node migration tests. TEST_LOG_LEVEL="disabled" \ go test -timeout 1h -count=1 -json $(args) ./migration 2>&1 | tee /tmp/gotest.log | gotestfmt .PHONY: test_node_migrations_simulated -test_node_migrations_simulated: install_gotestfmt +test_node_migrations_simulated: install_gotestfmt TEST_LOG_LEVEL="disabled" \ - SELECTED_NETWORKS="SIMULATED,SIMULATED_1,SIMULATED_2" \ go test -timeout 1h -count=1 -json $(args) ./migration 2>&1 | tee /tmp/gotest.log | gotestfmt .PHONY: test_node_migrations_verbose @@ -147,7 +140,6 @@ test_node_migrations_verbose: .PHONY: test_node_migrations_simulated_verbose test_node_migrations_simulated_verbose: - SELECTED_NETWORKS="SIMULATED,SIMULATED_1,SIMULATED_2" \ go test -timeout 1h -count=1 -v $(args) ./migration # Soak @@ -157,7 +149,7 @@ test_soak_ocr: .PHONY: test_soak_ocr_simulated test_soak_ocr_simulated: - SELECTED_NETWORKS="SIMULATED" go test -v -count=1 -run TestOCRSoak ./soak + go test -v -count=1 -run TestOCRSoak ./soak .PHONY: test_soak_forwarder_ocr test_soak_forwarder_ocr: @@ -165,7 +157,7 @@ test_soak_forwarder_ocr: .PHONY: test_soak_forwarder_ocr_simulated test_soak_forwarder_ocr_simulated: - SELECTED_NETWORKS="SIMULATED" go test -v -count=1 -run TestForwarderOCRSoak ./soak + go test -v -count=1 -run TestForwarderOCRSoak ./soak .PHONY: test_soak_automation test_soak_automation: @@ -173,8 +165,6 @@ test_soak_automation: .PHONY: test_soak_automation_simulated test_soak_automation_simulated: - SELECTED_NETWORKS="SIMULATED" \ - TEST_INPUTS="TEST_TYPE=SOAK,NUMBEROFCONTRACTS=50,BLOCKRANGE=1000,BLOCKINTERVAL=50,GRAFANA_DASHBOARD_URL=https://chainlinklabs.grafana.net/d/Q8n6m1unz/chainlink-keepers-qa?orgId=1" \ go test -v -run ^TestAutomationBenchmark$$ ./benchmark -count=1 .PHONY: test_benchmark_automation @@ -204,11 +194,14 @@ build_plugin_docker_image: # args: the args to pass to the test runner, example: args="--focus @cron -p" # product: the product to run tests for, example: product=cron # example usage: make run_test_with_local_image image=chainlink tag=latest-dev product=cron +# remember to put the case CL image name and tag in the TOML config (and don't forget about selected network configuration) .PHONY: run_test_with_local_image run_test_with_local_image: build_docker_image - CHAINLINK_IMAGE=$(image) \ - CHAINLINK_VERSION=$(tag) \ - SELECTED_NETWORKS="SIMULATED,SIMULATED_1,SIMULATED_2" \ ARGS="$(args)" \ PRODUCT=$(product) \ ./scripts/run_product_tests + +# removes all occurrences of .run.id file in current folder and it's subdirectories +# before making any changes lists all file locations and awaits user confirmation +remove_test_execution_artefacts: + ./scripts/search_and_delete.sh .run.id \ No newline at end of file diff --git a/integration-tests/actions/actions.go b/integration-tests/actions/actions.go index 624df39c47..95b538129c 100644 --- a/integration-tests/actions/actions.go +++ b/integration-tests/actions/actions.go @@ -4,6 +4,7 @@ package actions import ( "crypto/ecdsa" "encoding/json" + "errors" "fmt" "math/big" "strings" @@ -258,10 +259,11 @@ func TeardownSuite( chainlinkNodes []*client.ChainlinkK8sClient, optionalTestReporter testreporters.TestReporter, // Optionally pass in a test reporter to log further metrics failingLogLevel zapcore.Level, // Examines logs after the test, and fails the test if any Chainlink logs are found at or above provided level + grafnaUrlProvider testreporters.GrafanaURLProvider, clients ...blockchain.EVMClient, ) error { l := logging.GetTestLogger(t) - if err := testreporters.WriteTeardownLogs(t, env, optionalTestReporter, failingLogLevel); err != nil { + if err := testreporters.WriteTeardownLogs(t, env, optionalTestReporter, failingLogLevel, grafnaUrlProvider); err != nil { return fmt.Errorf("Error dumping environment logs, leaving environment running for manual retrieval, err: %w", err) } // Delete all jobs to stop depleting the funds @@ -302,11 +304,12 @@ func TeardownRemoteSuite( namespace string, chainlinkNodes []*client.ChainlinkK8sClient, optionalTestReporter testreporters.TestReporter, // Optionally pass in a test reporter to log further metrics + grafnaUrlProvider testreporters.GrafanaURLProvider, client blockchain.EVMClient, ) error { l := logging.GetTestLogger(t) var err error - if err = testreporters.SendReport(t, namespace, "./", optionalTestReporter); err != nil { + if err = testreporters.SendReport(t, namespace, "./", optionalTestReporter, grafnaUrlProvider); err != nil { l.Warn().Err(err).Msg("Error writing test report") } // Delete all jobs to stop depleting the funds @@ -415,8 +418,8 @@ func UpgradeChainlinkNodeVersions( newImage, newVersion string, nodes ...*client.ChainlinkK8sClient, ) error { - if newImage == "" && newVersion == "" { - return fmt.Errorf("unable to upgrade node version, found empty image and version, must provide either a new image or a new version") + if newImage == "" || newVersion == "" { + return errors.New("New image and new version is needed to upgrade the node") } for _, node := range nodes { if err := node.UpgradeVersion(testEnvironment, newImage, newVersion); err != nil { diff --git a/integration-tests/actions/actions_local.go b/integration-tests/actions/actions_local.go index d4913cabd8..8ac623d884 100644 --- a/integration-tests/actions/actions_local.go +++ b/integration-tests/actions/actions_local.go @@ -2,8 +2,6 @@ package actions import ( - "fmt" - "github.com/smartcontractkit/chainlink/integration-tests/docker/test_env" ) @@ -13,9 +11,6 @@ func UpgradeChainlinkNodeVersionsLocal( newImage, newVersion string, nodes ...*test_env.ClNode, ) error { - if newImage == "" && newVersion == "" { - return fmt.Errorf("unable to upgrade node version, found empty image and version, must provide either a new image or a new version") - } for _, node := range nodes { if err := node.UpgradeVersion(newImage, newVersion); err != nil { return err diff --git a/integration-tests/actions/ocr2_helpers.go b/integration-tests/actions/ocr2_helpers.go index 37db348815..829d85a849 100644 --- a/integration-tests/actions/ocr2_helpers.go +++ b/integration-tests/actions/ocr2_helpers.go @@ -22,6 +22,7 @@ import ( "github.com/smartcontractkit/chainlink-testing-framework/blockchain" ctfClient "github.com/smartcontractkit/chainlink-testing-framework/client" + "github.com/smartcontractkit/chainlink/v2/core/services/job" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/chaintype" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/testhelpers" @@ -376,6 +377,7 @@ func StartNewOCR2Round( timeout time.Duration, logger zerolog.Logger, ) error { + time.Sleep(5 * time.Second) for i := 0; i < len(ocrInstances); i++ { err := ocrInstances[i].RequestNewRound() if err != nil { @@ -383,9 +385,12 @@ func StartNewOCR2Round( } ocrRound := contracts.NewOffchainAggregatorV2RoundConfirmer(ocrInstances[i], big.NewInt(roundNumber), timeout, logger) client.AddHeaderEventSubscription(ocrInstances[i].Address(), ocrRound) - err = client.WaitForEvents() + err = ocrRound.Wait() // wait for OCR Round to complete if err != nil { - return fmt.Errorf("failed to wait for event subscriptions of OCR instance %d: %w", i+1, err) + return fmt.Errorf("failed to wait for OCR Round %d to complete instance %d", roundNumber, i) + } + if !ocrRound.Complete() { + return fmt.Errorf("failed to complete OCR Round %d for ocr instance %d", roundNumber, i) } } return nil diff --git a/integration-tests/actions/ocr2_helpers_local.go b/integration-tests/actions/ocr2_helpers_local.go index 4a08921b8d..8a0a02c050 100644 --- a/integration-tests/actions/ocr2_helpers_local.go +++ b/integration-tests/actions/ocr2_helpers_local.go @@ -18,7 +18,9 @@ import ( "golang.org/x/sync/errgroup" "gopkg.in/guregu/null.v4" + "github.com/smartcontractkit/chainlink-common/pkg/codec" "github.com/smartcontractkit/chainlink-testing-framework/docker/test_env" + evmtypes "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/types" "github.com/smartcontractkit/chainlink/v2/core/services/job" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/chaintype" @@ -38,6 +40,7 @@ func CreateOCRv2JobsLocal( mockAdapterValue int, // Value to get from the mock server when querying the path chainId uint64, // EVM chain ID forwardingAllowed bool, + enableChainReaderAndCodec bool, ) error { // Collect P2P ID bootstrapP2PIds, err := bootstrapNode.MustReadP2PKeys() @@ -125,6 +128,43 @@ func CreateOCRv2JobsLocal( P2PV2Bootstrappers: pq.StringArray{p2pV2Bootstrapper}, // bootstrap node key and address @bootstrap:6690 }, } + if enableChainReaderAndCodec { + ocrSpec.OCR2OracleSpec.RelayConfig["chainReader"] = evmtypes.ChainReaderConfig{ + Contracts: map[string]evmtypes.ChainContractReader{ + "median": { + ContractABI: `[{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"requester","type":"address"},{"indexed":false,"internalType":"bytes32","name":"configDigest","type":"bytes32"},{"indexed":false,"internalType":"uint32","name":"epoch","type":"uint32"},{"indexed":false,"internalType":"uint8","name":"round","type":"uint8"}],"name":"RoundRequested","type":"event"},{"inputs":[],"name":"latestTransmissionDetails","outputs":[{"internalType":"bytes32","name":"configDigest","type":"bytes32"},{"internalType":"uint32","name":"epoch","type":"uint32"},{"internalType":"uint8","name":"round","type":"uint8"},{"internalType":"int192","name":"latestAnswer_","type":"int192"},{"internalType":"uint64","name":"latestTimestamp_","type":"uint64"}],"stateMutability":"view","type":"function"}]`, + Configs: map[string]*evmtypes.ChainReaderDefinition{ + "LatestTransmissionDetails": { + ChainSpecificName: "latestTransmissionDetails", + OutputModifications: codec.ModifiersConfig{ + &codec.EpochToTimeModifierConfig{ + Fields: []string{"LatestTimestamp_"}, + }, + &codec.RenameModifierConfig{ + Fields: map[string]string{ + "LatestAnswer_": "LatestAnswer", + "LatestTimestamp_": "LatestTimestamp", + }, + }, + }, + }, + "LatestRoundRequested": { + ChainSpecificName: "RoundRequested", + ReadType: evmtypes.Event, + }, + }, + }, + }, + } + ocrSpec.OCR2OracleSpec.RelayConfig["codec"] = evmtypes.CodecConfig{ + Configs: map[string]evmtypes.ChainCodecConfig{ + "MedianReport": { + TypeABI: `[{"Name": "Timestamp","Type": "uint32"},{"Name": "Observers","Type": "bytes32"},{"Name": "Observations","Type": "int192[]"},{"Name": "JuelsPerFeeCoin","Type": "int192"}]`, + }, + }, + } + } + _, err = chainlinkNode.MustCreateJob(ocrSpec) if err != nil { return fmt.Errorf("creating OCR task job on OCR node have failed: %w", err) diff --git a/integration-tests/actions/private_network.go b/integration-tests/actions/private_network.go index c7556f8061..7f8bfe8bb2 100644 --- a/integration-tests/actions/private_network.go +++ b/integration-tests/actions/private_network.go @@ -1,33 +1,28 @@ package actions import ( - "errors" - "github.com/rs/zerolog" ctf_test_env "github.com/smartcontractkit/chainlink-testing-framework/docker/test_env" + tc "github.com/smartcontractkit/chainlink/integration-tests/testconfig" ) -func EthereumNetworkConfigFromEnvOrDefault(l zerolog.Logger) (network ctf_test_env.EthereumNetwork, err error) { - chainConfig := ctf_test_env.EthereumChainConfig{ - SecondsPerSlot: 8, - SlotsPerEpoch: 4, - } - - ethBuilder := ctf_test_env.NewEthereumNetworkBuilder() - network, err = ethBuilder. - WithExecClientFromEnvVar(). - WithEthereumChainConfig(chainConfig). - Build() - - if errors.Is(err, ctf_test_env.ErrMissingExecClientEnvVar) { - l.Warn().Msg("No exec client env var set, will use old geth") - ethBuilder = ctf_test_env.NewEthereumNetworkBuilder() +func EthereumNetworkConfigFromConfig(l zerolog.Logger, config tc.GlobalTestConfig) (network ctf_test_env.EthereumNetwork, err error) { + if config.GetPrivateEthereumNetworkConfig() == nil { + l.Warn().Msg("No TOML private ethereum network config found, will use old geth") + ethBuilder := ctf_test_env.NewEthereumNetworkBuilder() network, err = ethBuilder. WithConsensusType(ctf_test_env.ConsensusType_PoW). WithExecutionLayer(ctf_test_env.ExecutionLayer_Geth). Build() + + return } + ethBuilder := ctf_test_env.NewEthereumNetworkBuilder() + network, err = ethBuilder. + WithExistingConfig(*config.GetPrivateEthereumNetworkConfig()). + Build() + return } diff --git a/integration-tests/actions/vrfv2_actions/vrfv2_config/config.go b/integration-tests/actions/vrfv2_actions/vrfv2_config/config.go deleted file mode 100644 index aa2ac7f59e..0000000000 --- a/integration-tests/actions/vrfv2_actions/vrfv2_config/config.go +++ /dev/null @@ -1,54 +0,0 @@ -package vrfv2_config - -import "time" - -type VRFV2Config struct { - ChainlinkNodeFunding float64 `envconfig:"CHAINLINK_NODE_FUNDING" default:".1"` // Amount of native currency to fund each chainlink node with - CLNodeMaxGasPriceGWei int64 `envconfig:"MAX_GAS_PRICE_GWEI" default:"1000"` // Max gas price in GWei for the chainlink node - 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 float64 `envconfig:"SUBSCRIPTION_FUNDING_AMOUNT_LINK" default:"5"` // Amount of LINK 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 - FulfillmentFlatFeeLinkPPMTier1 uint32 `envconfig:"FULFILLMENT_FLAT_FEE_LINK_PPM_TIER_1" default:"500"` - FulfillmentFlatFeeLinkPPMTier2 uint32 `envconfig:"FULFILLMENT_FLAT_FEE_LINK_PPM_TIER_2" default:"500"` - FulfillmentFlatFeeLinkPPMTier3 uint32 `envconfig:"FULFILLMENT_FLAT_FEE_LINK_PPM_TIER_3" default:"500"` - FulfillmentFlatFeeLinkPPMTier4 uint32 `envconfig:"FULFILLMENT_FLAT_FEE_LINK_PPM_TIER_4" default:"500"` - FulfillmentFlatFeeLinkPPMTier5 uint32 `envconfig:"FULFILLMENT_FLAT_FEE_LINK_PPM_TIER_5" default:"500"` - ReqsForTier2 int64 `envconfig:"REQS_FOR_TIER_2" default:"0"` - ReqsForTier3 int64 `envconfig:"REQS_FOR_TIER_3" default:"0"` - ReqsForTier4 int64 `envconfig:"REQS_FOR_TIER_4" default:"0"` - ReqsForTier5 int64 `envconfig:"REQS_FOR_TIER_5" default:"0"` - - NumberOfSubToCreate int `envconfig:"NUMBER_OF_SUB_TO_CREATE" default:"1"` // Number of subscriptions to create - - 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 - - RandomWordsFulfilledEventTimeout time.Duration `envconfig:"RANDOM_WORDS_FULFILLED_EVENT_TIMEOUT" default:"2m"` // How long to wait for the RandomWordsFulfilled event to be emitted - - //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 - LinkAddress string `envconfig:"LINK_ADDRESS" default:""` // Link address - SubID uint64 `envconfig:"SUB_ID" default:""` // Subscription ID - KeyHash string `envconfig:"KEY_HASH" default:""` -} diff --git a/integration-tests/actions/vrfv2_actions/vrfv2_models.go b/integration-tests/actions/vrfv2_actions/vrfv2_models.go index aa594a753d..54449eef37 100644 --- a/integration-tests/actions/vrfv2_actions/vrfv2_models.go +++ b/integration-tests/actions/vrfv2_actions/vrfv2_models.go @@ -19,6 +19,7 @@ type VRFV2JobInfo struct { type VRFV2Contracts struct { Coordinator contracts.VRFCoordinatorV2 + VRFOwner contracts.VRFOwner BHS contracts.BlockHashStore LoadTestConsumers []contracts.VRFv2LoadTestConsumer } diff --git a/integration-tests/actions/vrfv2_actions/vrfv2_steps.go b/integration-tests/actions/vrfv2_actions/vrfv2_steps.go index d6288e58bf..1a95854896 100644 --- a/integration-tests/actions/vrfv2_actions/vrfv2_steps.go +++ b/integration-tests/actions/vrfv2_actions/vrfv2_steps.go @@ -12,10 +12,10 @@ import ( commonassets "github.com/smartcontractkit/chainlink-common/pkg/assets" "github.com/smartcontractkit/chainlink-testing-framework/utils/conversions" - "github.com/smartcontractkit/chainlink/integration-tests/actions/vrfv2_actions/vrfv2_config" "github.com/smartcontractkit/chainlink/integration-tests/docker/test_env" "github.com/smartcontractkit/chainlink/integration-tests/types/config/node" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/vrf_coordinator_v2" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/vrf_owner" "github.com/google/uuid" @@ -25,6 +25,9 @@ import ( "github.com/smartcontractkit/chainlink/integration-tests/actions" "github.com/smartcontractkit/chainlink/integration-tests/client" "github.com/smartcontractkit/chainlink/integration-tests/contracts" + + tc "github.com/smartcontractkit/chainlink/integration-tests/testconfig" + "github.com/smartcontractkit/chainlink/integration-tests/types" ) var ( @@ -48,54 +51,106 @@ var ( ErrAddConsumerToSub = "error adding consumer to VRF Subscription" ErrFundSubWithLinkToken = "error funding subscription with Link tokens" ErrCreateVRFV2Jobs = "error creating VRF V2 Jobs" - ErrGetPrimaryKey = "error getting primary ETH key address" ErrRestartCLNode = "error restarting CL node" ErrWaitTXsComplete = "error waiting for TXs to complete" ErrRequestRandomness = "error requesting randomness" + ErrLoadingCoordinator = "error loading coordinator contract" ErrWaitRandomWordsRequestedEvent = "error waiting for RandomWordsRequested event" ErrWaitRandomWordsFulfilledEvent = "error waiting for RandomWordsFulfilled event" ErrDeployWrapper = "error deploying VRFV2PlusWrapper" ) +type VRFOwnerConfig struct { + OwnerAddress string + useVRFOwner bool +} + +type VRFJobSpecConfig struct { + ForwardingAllowed bool + CoordinatorAddress string + FromAddresses []string + EVMChainID string + MinIncomingConfirmations int + PublicKey string + BatchFulfillmentEnabled bool + BatchFulfillmentGasMultiplier float64 + EstimateGasMultiplier float64 + PollPeriod time.Duration + RequestTimeout time.Duration + VRFOwnerConfig VRFOwnerConfig +} + func DeployVRFV2Contracts( - contractDeployer contracts.ContractDeployer, - chainClient blockchain.EVMClient, + env *test_env.CLClusterTestEnv, linkTokenContract contracts.LinkToken, linkEthFeedContract contracts.MockETHLINKFeed, consumerContractsAmount int, + useVRFOwner bool, + useTestCoordinator bool, ) (*VRFV2Contracts, error) { - bhs, err := contractDeployer.DeployBlockhashStore() + bhs, err := env.ContractDeployer.DeployBlockhashStore() if err != nil { return nil, fmt.Errorf("%s, err %w", ErrDeployBlockHashStore, err) } - err = chainClient.WaitForEvents() + err = env.EVMClient.WaitForEvents() if err != nil { return nil, fmt.Errorf("%s, err %w", ErrWaitTXsComplete, err) } - coordinator, err := contractDeployer.DeployVRFCoordinatorV2(linkTokenContract.Address(), bhs.Address(), linkEthFeedContract.Address()) + + var coordinatorAddress string + if useTestCoordinator { + testCoordinator, err := env.ContractDeployer.DeployVRFCoordinatorTestV2(linkTokenContract.Address(), bhs.Address(), linkEthFeedContract.Address()) + if err != nil { + return nil, fmt.Errorf("%s, err %w", ErrDeployCoordinator, err) + } + err = env.EVMClient.WaitForEvents() + if err != nil { + return nil, fmt.Errorf("%s, err %w", ErrWaitTXsComplete, err) + } + coordinatorAddress = testCoordinator.Address() + } else { + coordinator, err := env.ContractDeployer.DeployVRFCoordinatorV2(linkTokenContract.Address(), bhs.Address(), linkEthFeedContract.Address()) + if err != nil { + return nil, fmt.Errorf("%s, err %w", ErrDeployCoordinator, err) + } + err = env.EVMClient.WaitForEvents() + if err != nil { + return nil, fmt.Errorf("%s, err %w", ErrWaitTXsComplete, err) + } + coordinatorAddress = coordinator.Address() + } + consumers, err := DeployVRFV2Consumers(env.ContractDeployer, coordinatorAddress, consumerContractsAmount) if err != nil { - return nil, fmt.Errorf("%s, err %w", ErrDeployCoordinator, err) + return nil, err } - err = chainClient.WaitForEvents() + err = env.EVMClient.WaitForEvents() if err != nil { return nil, fmt.Errorf("%s, err %w", ErrWaitTXsComplete, err) } - consumers, err := DeployVRFV2Consumers(contractDeployer, coordinator, consumerContractsAmount) + + coordinator, err := env.ContractLoader.LoadVRFCoordinatorV2(coordinatorAddress) if err != nil { - return nil, err + return nil, fmt.Errorf("%s, err %w", ErrLoadingCoordinator, err) } - err = chainClient.WaitForEvents() - if err != nil { - return nil, fmt.Errorf("%s, err %w", ErrWaitTXsComplete, err) + if useVRFOwner { + vrfOwner, err := env.ContractDeployer.DeployVRFOwner(coordinatorAddress) + if err != nil { + return nil, fmt.Errorf("%s, err %w", ErrDeployCoordinator, err) + } + err = env.EVMClient.WaitForEvents() + if err != nil { + return nil, fmt.Errorf("%s, err %w", ErrWaitTXsComplete, err) + } + return &VRFV2Contracts{coordinator, vrfOwner, bhs, consumers}, nil } - return &VRFV2Contracts{coordinator, bhs, consumers}, nil + return &VRFV2Contracts{coordinator, nil, bhs, consumers}, nil } -func DeployVRFV2Consumers(contractDeployer contracts.ContractDeployer, coordinator contracts.VRFCoordinatorV2, consumerContractsAmount int) ([]contracts.VRFv2LoadTestConsumer, error) { +func DeployVRFV2Consumers(contractDeployer contracts.ContractDeployer, coordinatorAddress string, consumerContractsAmount int) ([]contracts.VRFv2LoadTestConsumer, error) { var consumers []contracts.VRFv2LoadTestConsumer for i := 1; i <= consumerContractsAmount; i++ { - loadTestConsumer, err := contractDeployer.DeployVRFv2LoadTestConsumer(coordinator.Address()) + loadTestConsumer, err := contractDeployer.DeployVRFv2LoadTestConsumer(coordinatorAddress) if err != nil { return nil, fmt.Errorf("%s, err %w", ErrAdvancedConsumer, err) } @@ -146,36 +201,47 @@ func DeployVRFV2DirectFundingContracts( func CreateVRFV2Job( chainlinkNode *client.ChainlinkClient, - coordinatorAddress string, - nativeTokenKeyAddresses []string, - pubKeyCompressed string, - chainID string, - minIncomingConfirmations uint16, + vrfJobSpecConfig VRFJobSpecConfig, ) (*client.Job, error) { jobUUID := uuid.New() os := &client.VRFV2TxPipelineSpec{ - Address: coordinatorAddress, + Address: vrfJobSpecConfig.CoordinatorAddress, + EstimateGasMultiplier: vrfJobSpecConfig.EstimateGasMultiplier, + FromAddress: vrfJobSpecConfig.FromAddresses[0], } ost, err := os.String() if err != nil { return nil, fmt.Errorf("%s, err %w", ErrParseJob, err) } - job, err := chainlinkNode.MustCreateJob(&client.VRFV2JobSpec{ - Name: fmt.Sprintf("vrf-v2-%s", jobUUID), - CoordinatorAddress: coordinatorAddress, - FromAddresses: nativeTokenKeyAddresses, - EVMChainID: chainID, - MinIncomingConfirmations: int(minIncomingConfirmations), - PublicKey: pubKeyCompressed, - ExternalJobID: jobUUID.String(), - ObservationSource: ost, - BatchFulfillmentEnabled: false, - }) + spec := &client.VRFV2JobSpec{ + Name: fmt.Sprintf("vrf-v2-%s", jobUUID), + ForwardingAllowed: vrfJobSpecConfig.ForwardingAllowed, + CoordinatorAddress: vrfJobSpecConfig.CoordinatorAddress, + FromAddresses: vrfJobSpecConfig.FromAddresses, + EVMChainID: vrfJobSpecConfig.EVMChainID, + MinIncomingConfirmations: vrfJobSpecConfig.MinIncomingConfirmations, + PublicKey: vrfJobSpecConfig.PublicKey, + ExternalJobID: jobUUID.String(), + ObservationSource: ost, + BatchFulfillmentEnabled: vrfJobSpecConfig.BatchFulfillmentEnabled, + BatchFulfillmentGasMultiplier: vrfJobSpecConfig.BatchFulfillmentGasMultiplier, + PollPeriod: vrfJobSpecConfig.PollPeriod, + RequestTimeout: vrfJobSpecConfig.RequestTimeout, + } + if vrfJobSpecConfig.VRFOwnerConfig.useVRFOwner { + spec.VRFOwner = vrfJobSpecConfig.VRFOwnerConfig.OwnerAddress + spec.UseVRFOwner = true + } + + if err != nil { + return nil, fmt.Errorf("%s, err %w", ErrParseJob, err) + + } + job, err := chainlinkNode.MustCreateJob(spec) if err != nil { return nil, fmt.Errorf("%s, err %w", ErrCreatingVRFv2Job, err) } - return job, nil } @@ -219,7 +285,9 @@ func FundVRFCoordinatorV2Subscription( // SetupVRFV2Environment will create specified number of subscriptions and add the same conumer/s to each of them func SetupVRFV2Environment( env *test_env.CLClusterTestEnv, - vrfv2Config vrfv2_config.VRFV2Config, + vrfv2TestConfig types.VRFv2TestConfig, + useVRFOwner bool, + useTestCoordinator bool, linkToken contracts.LinkToken, mockNativeLINKFeed contracts.MockETHLINKFeed, registerProvingKeyAgainstAddress string, @@ -231,33 +299,35 @@ func SetupVRFV2Environment( l.Info().Msg("Starting VRFV2 environment setup") l.Info().Msg("Deploying VRFV2 contracts") vrfv2Contracts, err := DeployVRFV2Contracts( - env.ContractDeployer, - env.EVMClient, + env, linkToken, mockNativeLINKFeed, numberOfConsumers, + useVRFOwner, + useTestCoordinator, ) if err != nil { return nil, nil, nil, fmt.Errorf("%s, err %w", ErrDeployVRFV2Contracts, err) } + vrfv2Config := vrfv2TestConfig.GetVRFv2Config().General vrfCoordinatorV2FeeConfig := vrf_coordinator_v2.VRFCoordinatorV2FeeConfig{ - FulfillmentFlatFeeLinkPPMTier1: vrfv2Config.FulfillmentFlatFeeLinkPPMTier1, - FulfillmentFlatFeeLinkPPMTier2: vrfv2Config.FulfillmentFlatFeeLinkPPMTier2, - FulfillmentFlatFeeLinkPPMTier3: vrfv2Config.FulfillmentFlatFeeLinkPPMTier3, - FulfillmentFlatFeeLinkPPMTier4: vrfv2Config.FulfillmentFlatFeeLinkPPMTier4, - FulfillmentFlatFeeLinkPPMTier5: vrfv2Config.FulfillmentFlatFeeLinkPPMTier5, - ReqsForTier2: big.NewInt(vrfv2Config.ReqsForTier2), - ReqsForTier3: big.NewInt(vrfv2Config.ReqsForTier3), - ReqsForTier4: big.NewInt(vrfv2Config.ReqsForTier4), - ReqsForTier5: big.NewInt(vrfv2Config.ReqsForTier5)} + FulfillmentFlatFeeLinkPPMTier1: *vrfv2Config.FulfillmentFlatFeeLinkPPMTier1, + FulfillmentFlatFeeLinkPPMTier2: *vrfv2Config.FulfillmentFlatFeeLinkPPMTier2, + FulfillmentFlatFeeLinkPPMTier3: *vrfv2Config.FulfillmentFlatFeeLinkPPMTier3, + FulfillmentFlatFeeLinkPPMTier4: *vrfv2Config.FulfillmentFlatFeeLinkPPMTier4, + FulfillmentFlatFeeLinkPPMTier5: *vrfv2Config.FulfillmentFlatFeeLinkPPMTier5, + ReqsForTier2: big.NewInt(*vrfv2Config.ReqsForTier2), + ReqsForTier3: big.NewInt(*vrfv2Config.ReqsForTier3), + ReqsForTier4: big.NewInt(*vrfv2Config.ReqsForTier4), + ReqsForTier5: big.NewInt(*vrfv2Config.ReqsForTier5)} l.Info().Str("Coordinator", vrfv2Contracts.Coordinator.Address()).Msg("Setting Coordinator Config") err = vrfv2Contracts.Coordinator.SetConfig( - vrfv2Config.MinimumConfirmations, - vrfv2Config.MaxGasLimitCoordinatorConfig, - vrfv2Config.StalenessSeconds, - vrfv2Config.GasAfterPaymentCalculation, - big.NewInt(vrfv2Config.LinkNativeFeedResponse), + *vrfv2Config.MinimumConfirmations, + *vrfv2Config.MaxGasLimitCoordinatorConfig, + *vrfv2Config.StalenessSeconds, + *vrfv2Config.GasAfterPaymentCalculation, + big.NewInt(*vrfv2Config.FallbackWeiPerUnitLink), vrfCoordinatorV2FeeConfig, ) if err != nil { @@ -273,7 +343,7 @@ func SetupVRFV2Environment( Msg("Creating and funding subscriptions, adding consumers") subIDs, err := CreateFundSubsAndAddConsumers( env, - vrfv2Config, + big.NewFloat(*vrfv2Config.SubscriptionFundingAmountLink), linkToken, vrfv2Contracts.Coordinator, vrfv2Contracts.LoadTestConsumers, numberOfSubToCreate) if err != nil { @@ -297,7 +367,7 @@ func SetupVRFV2Environment( } chainID := env.EVMClient.GetChainID() - newNativeTokenKeyAddresses, err := CreateAndFundSendingKeys(env, vrfv2Config, numberOfTxKeysToCreate, chainID) + newNativeTokenKeyAddresses, err := CreateAndFundSendingKeys(env, vrfv2TestConfig, numberOfTxKeysToCreate, chainID) if err != nil { return nil, nil, nil, err } @@ -305,16 +375,49 @@ func SetupVRFV2Environment( if err != nil { return nil, nil, nil, fmt.Errorf("%s, err %w", ErrNodePrimaryKey, err) } - allNativeTokenKeyAddresses := append(newNativeTokenKeyAddresses, nativeTokenPrimaryKeyAddress) + allNativeTokenKeyAddressStrings := append(newNativeTokenKeyAddresses, nativeTokenPrimaryKeyAddress) + allNativeTokenKeyAddresses := make([]common.Address, len(allNativeTokenKeyAddressStrings)) + + for _, addressString := range allNativeTokenKeyAddressStrings { + allNativeTokenKeyAddresses = append(allNativeTokenKeyAddresses, common.HexToAddress(addressString)) + } + + var vrfOwnerConfig VRFOwnerConfig + if useVRFOwner { + err := setupVRFOwnerContract(env, vrfv2Contracts, allNativeTokenKeyAddressStrings, allNativeTokenKeyAddresses, l) + if err != nil { + return nil, nil, nil, err + } + vrfOwnerConfig = VRFOwnerConfig{ + OwnerAddress: vrfv2Contracts.VRFOwner.Address(), + useVRFOwner: useVRFOwner, + } + } else { + vrfOwnerConfig = VRFOwnerConfig{ + OwnerAddress: "", + useVRFOwner: useVRFOwner, + } + } + + vrfJobSpecConfig := VRFJobSpecConfig{ + ForwardingAllowed: false, + CoordinatorAddress: vrfv2Contracts.Coordinator.Address(), + FromAddresses: allNativeTokenKeyAddressStrings, + EVMChainID: chainID.String(), + MinIncomingConfirmations: int(*vrfv2Config.MinimumConfirmations), + PublicKey: pubKeyCompressed, + EstimateGasMultiplier: 1, + BatchFulfillmentEnabled: false, + BatchFulfillmentGasMultiplier: 1.15, + PollPeriod: time.Second * 1, + RequestTimeout: time.Hour * 24, + VRFOwnerConfig: vrfOwnerConfig, + } - l.Info().Msg("Creating VRFV2 Job") + l.Info().Msg("Creating VRFV2 Job") vrfV2job, err := CreateVRFV2Job( env.ClCluster.NodeAPIs()[0], - vrfv2Contracts.Coordinator.Address(), - allNativeTokenKeyAddresses, - pubKeyCompressed, - chainID.String(), - vrfv2Config.MinimumConfirmations, + vrfJobSpecConfig, ) if err != nil { return nil, nil, nil, fmt.Errorf("%s, err %w", ErrCreateVRFV2Jobs, err) @@ -324,7 +427,7 @@ func SetupVRFV2Environment( // [[EVM.KeySpecific]] // Key = '...' nodeConfig := node.NewConfig(env.ClCluster.Nodes[0].NodeConfig, - node.WithVRFv2EVMEstimator(allNativeTokenKeyAddresses, vrfv2Config.CLNodeMaxGasPriceGWei), + node.WithVRFv2EVMEstimator(allNativeTokenKeyAddressStrings, *vrfv2Config.CLNodeMaxGasPriceGWei), ) l.Info().Msg("Restarting Node with new sending key PriceMax configuration") err = env.ClCluster.Nodes[0].Restart(nodeConfig) @@ -349,9 +452,49 @@ func SetupVRFV2Environment( return vrfv2Contracts, subIDs, &data, nil } +func setupVRFOwnerContract(env *test_env.CLClusterTestEnv, vrfv2Contracts *VRFV2Contracts, allNativeTokenKeyAddressStrings []string, allNativeTokenKeyAddresses []common.Address, l zerolog.Logger) error { + l.Info().Msg("Setting up VRFOwner contract") + l.Info(). + Str("Coordinator", vrfv2Contracts.Coordinator.Address()). + Str("VRFOwner", vrfv2Contracts.VRFOwner.Address()). + Msg("Transferring ownership of Coordinator to VRFOwner") + err := vrfv2Contracts.Coordinator.TransferOwnership(common.HexToAddress(vrfv2Contracts.VRFOwner.Address())) + if err != nil { + return nil + } + err = env.EVMClient.WaitForEvents() + if err != nil { + return nil + } + l.Info(). + Str("VRFOwner", vrfv2Contracts.VRFOwner.Address()). + Msg("Accepting VRF Ownership") + err = vrfv2Contracts.VRFOwner.AcceptVRFOwnership() + if err != nil { + return nil + } + err = env.EVMClient.WaitForEvents() + if err != nil { + return nil + } + l.Info(). + Strs("Authorized Senders", allNativeTokenKeyAddressStrings). + Str("VRFOwner", vrfv2Contracts.VRFOwner.Address()). + Msg("Setting authorized senders for VRFOwner contract") + err = vrfv2Contracts.VRFOwner.SetAuthorizedSenders(allNativeTokenKeyAddresses) + if err != nil { + return nil + } + err = env.EVMClient.WaitForEvents() + if err != nil { + return fmt.Errorf("%s, err %w", ErrWaitTXsComplete, err) + } + return err +} + func SetupVRFV2WrapperEnvironment( env *test_env.CLClusterTestEnv, - vrfv2Config vrfv2_config.VRFV2Config, + vrfv2TestConfig tc.VRFv2TestConfig, linkToken contracts.LinkToken, mockNativeLINKFeed contracts.MockETHLINKFeed, coordinator contracts.VRFCoordinatorV2, @@ -375,13 +518,15 @@ func SetupVRFV2WrapperEnvironment( return nil, nil, fmt.Errorf("%s, err %w", ErrWaitTXsComplete, err) } + vrfv2Config := vrfv2TestConfig.GetVRFv2Config() + // Configure VRF v2 wrapper contract err = wrapperContracts.VRFV2Wrapper.SetConfig( - vrfv2Config.WrapperGasOverhead, - vrfv2Config.CoordinatorGasOverhead, - vrfv2Config.WrapperPremiumPercentage, + *vrfv2Config.General.WrapperGasOverhead, + *vrfv2Config.General.CoordinatorGasOverhead, + *vrfv2Config.General.WrapperPremiumPercentage, keyHash, - vrfv2Config.WrapperMaxNumberOfWords, + *vrfv2Config.General.WrapperMaxNumberOfWords, ) if err != nil { return nil, nil, err @@ -402,7 +547,7 @@ func SetupVRFV2WrapperEnvironment( } // Fund wrapper subscription - err = FundSubscriptions(env, vrfv2Config, linkToken, coordinator, []uint64{wrapperSubID}) + err = FundSubscriptions(env, big.NewFloat(*vrfv2Config.General.SubscriptionFundingAmountLink), linkToken, coordinator, []uint64{wrapperSubID}) if err != nil { return nil, nil, err } @@ -410,7 +555,7 @@ func SetupVRFV2WrapperEnvironment( // Fund consumer with LINK err = linkToken.Transfer( wrapperContracts.LoadTestConsumers[0].Address(), - big.NewInt(0).Mul(big.NewInt(1e18), big.NewInt(vrfv2Config.WrapperConsumerFundingAmountLink)), + big.NewInt(0).Mul(big.NewInt(1e18), big.NewInt(*vrfv2Config.General.WrapperConsumerFundingAmountLink)), ) if err != nil { return nil, nil, err @@ -423,7 +568,7 @@ func SetupVRFV2WrapperEnvironment( return wrapperContracts, &wrapperSubID, nil } -func CreateAndFundSendingKeys(env *test_env.CLClusterTestEnv, vrfv2Config vrfv2_config.VRFV2Config, numberOfNativeTokenAddressesToCreate int, chainID *big.Int) ([]string, error) { +func CreateAndFundSendingKeys(env *test_env.CLClusterTestEnv, testConfig tc.CommonTestConfig, numberOfNativeTokenAddressesToCreate int, chainID *big.Int) ([]string, error) { var newNativeTokenKeyAddresses []string for i := 0; i < numberOfNativeTokenAddressesToCreate; i++ { newTxKey, response, err := env.ClCluster.NodeAPIs()[0].CreateTxKey("evm", chainID.String()) @@ -434,7 +579,7 @@ func CreateAndFundSendingKeys(env *test_env.CLClusterTestEnv, vrfv2Config vrfv2_ return nil, fmt.Errorf("error creating transaction key - response code, err %d", response.StatusCode) } newNativeTokenKeyAddresses = append(newNativeTokenKeyAddresses, newTxKey.Data.ID) - err = actions.FundAddress(env.EVMClient, newTxKey.Data.ID, big.NewFloat(vrfv2Config.ChainlinkNodeFunding)) + err = actions.FundAddress(env.EVMClient, newTxKey.Data.ID, big.NewFloat(*testConfig.GetCommonConfig().ChainlinkNodeFunding)) if err != nil { return nil, err } @@ -444,13 +589,13 @@ func CreateAndFundSendingKeys(env *test_env.CLClusterTestEnv, vrfv2Config vrfv2_ func CreateFundSubsAndAddConsumers( env *test_env.CLClusterTestEnv, - vrfv2Config vrfv2_config.VRFV2Config, + subscriptionFundingAmountLink *big.Float, linkToken contracts.LinkToken, coordinator contracts.VRFCoordinatorV2, consumers []contracts.VRFv2LoadTestConsumer, numberOfSubToCreate int, ) ([]uint64, error) { - subIDs, err := CreateSubsAndFund(env, vrfv2Config, linkToken, coordinator, numberOfSubToCreate) + subIDs, err := CreateSubsAndFund(env, subscriptionFundingAmountLink, linkToken, coordinator, numberOfSubToCreate) if err != nil { return nil, err } @@ -478,7 +623,7 @@ func CreateFundSubsAndAddConsumers( func CreateSubsAndFund( env *test_env.CLClusterTestEnv, - vrfv2Config vrfv2_config.VRFV2Config, + subscriptionFundingAmountLink *big.Float, linkToken contracts.LinkToken, coordinator contracts.VRFCoordinatorV2, subAmountToCreate int, @@ -491,7 +636,7 @@ func CreateSubsAndFund( if err != nil { return nil, fmt.Errorf("%s, err %w", ErrWaitTXsComplete, err) } - err = FundSubscriptions(env, vrfv2Config, linkToken, coordinator, subs) + err = FundSubscriptions(env, subscriptionFundingAmountLink, linkToken, coordinator, subs) if err != nil { return nil, err } @@ -553,14 +698,14 @@ func CreateSubAndFindSubID(env *test_env.CLClusterTestEnv, coordinator contracts func FundSubscriptions( env *test_env.CLClusterTestEnv, - vrfv2Config vrfv2_config.VRFV2Config, + subscriptionFundingAmountLink *big.Float, linkAddress contracts.LinkToken, coordinator contracts.VRFCoordinatorV2, subIDs []uint64, ) error { for _, subID := range subIDs { //Link Billing - amountJuels := conversions.EtherToWei(big.NewFloat(vrfv2Config.SubscriptionFundingAmountLink)) + amountJuels := conversions.EtherToWei(subscriptionFundingAmountLink) err := FundVRFCoordinatorV2Subscription(linkAddress, coordinator, env.EVMClient, subID, amountJuels) if err != nil { return fmt.Errorf("%s, err %w", ErrFundSubWithLinkToken, err) @@ -574,20 +719,23 @@ func FundSubscriptions( } func DirectFundingRequestRandomnessAndWaitForFulfillment( + l zerolog.Logger, consumer contracts.VRFv2WrapperLoadTestConsumer, coordinator contracts.VRFCoordinatorV2, - vrfv2Data *VRFV2Data, subID uint64, + vrfv2Data *VRFV2Data, + minimumConfirmations uint16, + callbackGasLimit uint32, + numberOfWords uint32, randomnessRequestCountPerRequest uint16, - vrfv2Config vrfv2_config.VRFV2Config, + randomnessRequestCountPerRequestDeviation uint16, randomWordsFulfilledEventTimeout time.Duration, - l zerolog.Logger, ) (*vrf_coordinator_v2.VRFCoordinatorV2RandomWordsFulfilled, error) { - logRandRequest(consumer.Address(), coordinator.Address(), subID, vrfv2Config, l) + logRandRequest(l, consumer.Address(), coordinator.Address(), subID, minimumConfirmations, callbackGasLimit, numberOfWords, randomnessRequestCountPerRequest, randomnessRequestCountPerRequestDeviation) _, err := consumer.RequestRandomness( - vrfv2Config.MinimumConfirmations, - vrfv2Config.CallbackGasLimit, - vrfv2Config.NumberOfWords, + minimumConfirmations, + callbackGasLimit, + numberOfWords, randomnessRequestCountPerRequest, ) if err != nil { @@ -609,22 +757,25 @@ func DirectFundingRequestRandomnessAndWaitForFulfillment( } func RequestRandomnessAndWaitForFulfillment( + l zerolog.Logger, consumer contracts.VRFv2LoadTestConsumer, coordinator contracts.VRFCoordinatorV2, - vrfv2Data *VRFV2Data, subID uint64, + vrfv2Data *VRFV2Data, + minimumConfirmations uint16, + callbackGasLimit uint32, + numberOfWords uint32, randomnessRequestCountPerRequest uint16, - vrfv2Config vrfv2_config.VRFV2Config, + randomnessRequestCountPerRequestDeviation uint16, randomWordsFulfilledEventTimeout time.Duration, - l zerolog.Logger, ) (*vrf_coordinator_v2.VRFCoordinatorV2RandomWordsFulfilled, error) { - logRandRequest(consumer.Address(), coordinator.Address(), subID, vrfv2Config, l) + logRandRequest(l, consumer.Address(), coordinator.Address(), subID, minimumConfirmations, callbackGasLimit, numberOfWords, randomnessRequestCountPerRequest, randomnessRequestCountPerRequestDeviation) _, err := consumer.RequestRandomness( vrfv2Data.KeyHash, subID, - vrfv2Config.MinimumConfirmations, - vrfv2Config.CallbackGasLimit, - vrfv2Config.NumberOfWords, + minimumConfirmations, + callbackGasLimit, + numberOfWords, randomnessRequestCountPerRequest, ) if err != nil { @@ -642,6 +793,107 @@ func RequestRandomnessAndWaitForFulfillment( return fulfillmentEvents, err } +func RequestRandomnessWithForceFulfillAndWaitForFulfillment( + l zerolog.Logger, + consumer contracts.VRFv2LoadTestConsumer, + coordinator contracts.VRFCoordinatorV2, + vrfOwner contracts.VRFOwner, + vrfv2Data *VRFV2Data, + minimumConfirmations uint16, + callbackGasLimit uint32, + numberOfWords uint32, + randomnessRequestCountPerRequest uint16, + randomnessRequestCountPerRequestDeviation uint16, + subTopUpAmount *big.Int, + linkAddress common.Address, + randomWordsFulfilledEventTimeout time.Duration, +) (*vrf_coordinator_v2.VRFCoordinatorV2ConfigSet, *vrf_coordinator_v2.VRFCoordinatorV2RandomWordsFulfilled, *vrf_owner.VRFOwnerRandomWordsForced, error) { + logRandRequest(l, consumer.Address(), coordinator.Address(), 0, minimumConfirmations, callbackGasLimit, numberOfWords, randomnessRequestCountPerRequest, randomnessRequestCountPerRequestDeviation) + _, err := consumer.RequestRandomWordsWithForceFulfill( + vrfv2Data.KeyHash, + minimumConfirmations, + callbackGasLimit, + numberOfWords, + randomnessRequestCountPerRequest, + subTopUpAmount, + linkAddress, + ) + if err != nil { + return nil, nil, nil, fmt.Errorf("%s, err %w", ErrRequestRandomness, err) + } + + randomWordsRequestedEvent, err := coordinator.WaitForRandomWordsRequestedEvent( + [][32]byte{vrfv2Data.KeyHash}, + nil, + []common.Address{common.HexToAddress(consumer.Address())}, + time.Minute*1, + ) + if err != nil { + return nil, nil, nil, fmt.Errorf("%s, err %w", ErrWaitRandomWordsRequestedEvent, err) + } + LogRandomnessRequestedEvent(l, coordinator, randomWordsRequestedEvent) + + errorChannel := make(chan error) + configSetEventChannel := make(chan *vrf_coordinator_v2.VRFCoordinatorV2ConfigSet) + randWordsFulfilledEventChannel := make(chan *vrf_coordinator_v2.VRFCoordinatorV2RandomWordsFulfilled) + randWordsForcedEventChannel := make(chan *vrf_owner.VRFOwnerRandomWordsForced) + + go func() { + configSetEvent, err := coordinator.WaitForConfigSetEvent( + randomWordsFulfilledEventTimeout, + ) + if err != nil { + l.Error().Err(err).Msg("error waiting for ConfigSetEvent") + errorChannel <- err + } + configSetEventChannel <- configSetEvent + }() + + go func() { + randomWordsFulfilledEvent, err := coordinator.WaitForRandomWordsFulfilledEvent( + []*big.Int{randomWordsRequestedEvent.RequestId}, + randomWordsFulfilledEventTimeout, + ) + if err != nil { + l.Error().Err(err).Msg("error waiting for RandomWordsFulfilledEvent") + errorChannel <- err + } + randWordsFulfilledEventChannel <- randomWordsFulfilledEvent + }() + + go func() { + randomWordsForcedEvent, err := vrfOwner.WaitForRandomWordsForcedEvent( + []*big.Int{randomWordsRequestedEvent.RequestId}, + nil, + nil, + randomWordsFulfilledEventTimeout, + ) + if err != nil { + l.Error().Err(err).Msg("error waiting for RandomWordsForcedEvent") + errorChannel <- err + } + randWordsForcedEventChannel <- randomWordsForcedEvent + }() + + var configSetEvent *vrf_coordinator_v2.VRFCoordinatorV2ConfigSet + var randomWordsFulfilledEvent *vrf_coordinator_v2.VRFCoordinatorV2RandomWordsFulfilled + var randomWordsForcedEvent *vrf_owner.VRFOwnerRandomWordsForced + for i := 0; i < 3; i++ { + select { + case err = <-errorChannel: + return nil, nil, nil, err + case configSetEvent = <-configSetEventChannel: + case randomWordsFulfilledEvent = <-randWordsFulfilledEventChannel: + LogRandomWordsFulfilledEvent(l, coordinator, randomWordsFulfilledEvent) + case randomWordsForcedEvent = <-randWordsForcedEventChannel: + LogRandomWordsForcedEvent(l, vrfOwner, randomWordsForcedEvent) + case <-time.After(randomWordsFulfilledEventTimeout): + err = fmt.Errorf("timeout waiting for ConfigSet, RandomWordsFulfilled and RandomWordsForced events") + } + } + return configSetEvent, randomWordsFulfilledEvent, randomWordsForcedEvent, err +} + func WaitForRequestAndFulfillmentEvents( consumerAddress string, coordinator contracts.VRFCoordinatorV2, @@ -759,20 +1011,39 @@ func LogRandomWordsFulfilledEvent( Msg("RandomWordsFulfilled Event (TX metadata)") } +func LogRandomWordsForcedEvent( + l zerolog.Logger, + vrfOwner contracts.VRFOwner, + randomWordsForcedEvent *vrf_owner.VRFOwnerRandomWordsForced, +) { + l.Debug(). + Str("VRFOwner", vrfOwner.Address()). + Uint64("Sub ID", randomWordsForcedEvent.SubId). + Str("TX Hash", randomWordsForcedEvent.Raw.TxHash.String()). + Str("Request ID", randomWordsForcedEvent.RequestId.String()). + Str("Sender", randomWordsForcedEvent.Sender.String()). + Msg("RandomWordsForced Event (TX metadata)") +} + func logRandRequest( + l zerolog.Logger, consumer string, coordinator string, subID uint64, - vrfv2Config vrfv2_config.VRFV2Config, - l zerolog.Logger, + minimumConfirmations uint16, + callbackGasLimit uint32, + numberOfWords uint32, + randomnessRequestCountPerRequest uint16, + randomnessRequestCountPerRequestDeviation uint16, ) { l.Debug(). Str("Consumer", consumer). Str("Coordinator", coordinator). Uint64("SubID", subID). - Uint16("MinimumConfirmations", vrfv2Config.MinimumConfirmations). - Uint32("CallbackGasLimit", vrfv2Config.CallbackGasLimit). - Uint16("RandomnessRequestCountPerRequest", vrfv2Config.RandomnessRequestCountPerRequest). - Uint16("RandomnessRequestCountPerRequestDeviation", vrfv2Config.RandomnessRequestCountPerRequestDeviation). + Uint16("MinimumConfirmations", minimumConfirmations). + Uint32("CallbackGasLimit", callbackGasLimit). + Uint32("NumberOfWords", numberOfWords). + Uint16("RandomnessRequestCountPerRequest", randomnessRequestCountPerRequest). + Uint16("RandomnessRequestCountPerRequestDeviation", randomnessRequestCountPerRequestDeviation). Msg("Requesting randomness") } diff --git a/integration-tests/actions/vrfv2plus/vrfv2plus_config/config.go b/integration-tests/actions/vrfv2plus/vrfv2plus_config/config.go deleted file mode 100644 index 8cd6e0a8ce..0000000000 --- a/integration-tests/actions/vrfv2plus/vrfv2plus_config/config.go +++ /dev/null @@ -1,48 +0,0 @@ -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 - CLNodeMaxGasPriceGWei int64 `envconfig:"MAX_GAS_PRICE_GWEI" default:"1000"` // Max gas price in GWei for the chainlink node - 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 float64 `envconfig:"SUBSCRIPTION_FUNDING_AMOUNT_LINK" default:"5"` // Amount of LINK to fund the subscription with - SubscriptionFundingAmountNative float64 `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 - - NumberOfSubToCreate int `envconfig:"NUMBER_OF_SUB_TO_CREATE" default:"1"` // Number of subscriptions to create - - 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 - - RandomWordsFulfilledEventTimeout time.Duration `envconfig:"RANDOM_WORDS_FULFILLED_EVENT_TIMEOUT" default:"2m"` // How long to wait for the RandomWordsFulfilled event to be emitted - - //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 - LinkAddress string `envconfig:"LINK_ADDRESS" default:""` // Link address - SubID string `envconfig:"SUB_ID" default:""` // Subscription ID - KeyHash string `envconfig:"KEY_HASH" default:""` -} diff --git a/integration-tests/actions/vrfv2plus/vrfv2plus_steps.go b/integration-tests/actions/vrfv2plus/vrfv2plus_steps.go index d0c83e8584..fc2a47f53e 100644 --- a/integration-tests/actions/vrfv2plus/vrfv2plus_steps.go +++ b/integration-tests/actions/vrfv2plus/vrfv2plus_steps.go @@ -18,10 +18,12 @@ import ( "github.com/smartcontractkit/chainlink-testing-framework/blockchain" "github.com/smartcontractkit/chainlink/integration-tests/actions" - "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" + tc "github.com/smartcontractkit/chainlink/integration-tests/testconfig" + vrfv2plus_config "github.com/smartcontractkit/chainlink/integration-tests/testconfig/vrfv2plus" + "github.com/smartcontractkit/chainlink/integration-tests/types" "github.com/smartcontractkit/chainlink/integration-tests/types/config/node" chainlinkutils "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/vrf_coordinator_v2_5" @@ -65,6 +67,20 @@ var ( ErrDeployWrapper = "error deploying VRFV2PlusWrapper" ) +type VRFJobSpecConfig struct { + ForwardingAllowed bool + CoordinatorAddress string + FromAddresses []string + EVMChainID string + MinIncomingConfirmations int + PublicKey string + BatchFulfillmentEnabled bool + BatchFulfillmentGasMultiplier float64 + EstimateGasMultiplier float64 + PollPeriod time.Duration + RequestTimeout time.Duration +} + func DeployVRFV2_5Contracts( contractDeployer contracts.ContractDeployer, chainClient blockchain.EVMClient, @@ -111,15 +127,13 @@ func DeployVRFV2PlusConsumers(contractDeployer contracts.ContractDeployer, coord func CreateVRFV2PlusJob( chainlinkNode *client.ChainlinkClient, - coordinatorAddress string, - nativeTokenKeyAddresses []string, - pubKeyCompressed string, - chainID string, - minIncomingConfirmations uint16, + vrfJobSpecConfig VRFJobSpecConfig, ) (*client.Job, error) { jobUUID := uuid.New() os := &client.VRFV2PlusTxPipelineSpec{ - Address: coordinatorAddress, + Address: vrfJobSpecConfig.CoordinatorAddress, + EstimateGasMultiplier: vrfJobSpecConfig.EstimateGasMultiplier, + FromAddress: vrfJobSpecConfig.FromAddresses[0], } ost, err := os.String() if err != nil { @@ -127,16 +141,18 @@ func CreateVRFV2PlusJob( } job, err := chainlinkNode.MustCreateJob(&client.VRFV2PlusJobSpec{ - Name: fmt.Sprintf("vrf-v2-plus-%s", jobUUID), - CoordinatorAddress: coordinatorAddress, - FromAddresses: nativeTokenKeyAddresses, - EVMChainID: chainID, - MinIncomingConfirmations: int(minIncomingConfirmations), - PublicKey: pubKeyCompressed, - ExternalJobID: jobUUID.String(), - ObservationSource: ost, - BatchFulfillmentEnabled: false, - PollPeriod: time.Second, + Name: fmt.Sprintf("vrf-v2-plus-%s", jobUUID), + CoordinatorAddress: vrfJobSpecConfig.CoordinatorAddress, + FromAddresses: vrfJobSpecConfig.FromAddresses, + EVMChainID: vrfJobSpecConfig.EVMChainID, + MinIncomingConfirmations: vrfJobSpecConfig.MinIncomingConfirmations, + PublicKey: vrfJobSpecConfig.PublicKey, + ExternalJobID: jobUUID.String(), + ObservationSource: ost, + BatchFulfillmentEnabled: vrfJobSpecConfig.BatchFulfillmentEnabled, + BatchFulfillmentGasMultiplier: vrfJobSpecConfig.BatchFulfillmentGasMultiplier, + PollPeriod: vrfJobSpecConfig.PollPeriod, + RequestTimeout: vrfJobSpecConfig.RequestTimeout, }) if err != nil { return nil, fmt.Errorf("%s, err %w", ErrCreatingVRFv2PlusJob, err) @@ -200,7 +216,7 @@ func FundVRFCoordinatorV2_5Subscription( // 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, + vrfv2PlusTestConfig types.VRFv2PlusTestConfig, linkToken contracts.LinkToken, mockNativeLINKFeed contracts.MockETHLINKFeed, numberOfTxKeysToCreate int, @@ -216,15 +232,16 @@ func SetupVRFV2_5Environment( } l.Info().Str("Coordinator", vrfv2_5Contracts.Coordinator.Address()).Msg("Setting Coordinator Config") + vrfv2PlusConfig := vrfv2PlusTestConfig.GetVRFv2PlusConfig().General err = vrfv2_5Contracts.Coordinator.SetConfig( - vrfv2PlusConfig.MinimumConfirmations, - vrfv2PlusConfig.MaxGasLimitCoordinatorConfig, - vrfv2PlusConfig.StalenessSeconds, - vrfv2PlusConfig.GasAfterPaymentCalculation, - big.NewInt(vrfv2PlusConfig.LinkNativeFeedResponse), + *vrfv2PlusConfig.MinimumConfirmations, + *vrfv2PlusConfig.MaxGasLimitCoordinatorConfig, + *vrfv2PlusConfig.StalenessSeconds, + *vrfv2PlusConfig.GasAfterPaymentCalculation, + big.NewInt(*vrfv2PlusConfig.FallbackWeiPerUnitLink), vrf_coordinator_v2_5.VRFCoordinatorV25FeeConfig{ - FulfillmentFlatFeeLinkPPM: vrfv2PlusConfig.FulfillmentFlatFeeLinkPPM, - FulfillmentFlatFeeNativePPM: vrfv2PlusConfig.FulfillmentFlatFeeNativePPM, + FulfillmentFlatFeeLinkPPM: *vrfv2PlusConfig.FulfillmentFlatFeeLinkPPM, + FulfillmentFlatFeeNativePPM: *vrfv2PlusConfig.FulfillmentFlatFeeNativePPM, }, ) if err != nil { @@ -246,9 +263,12 @@ func SetupVRFV2_5Environment( Msg("Creating and funding subscriptions, adding consumers") subIDs, err := CreateFundSubsAndAddConsumers( env, - vrfv2PlusConfig, + big.NewFloat(*vrfv2PlusConfig.SubscriptionFundingAmountNative), + big.NewFloat(*vrfv2PlusConfig.SubscriptionFundingAmountLink), linkToken, - vrfv2_5Contracts.Coordinator, vrfv2_5Contracts.LoadTestConsumers, numberOfSubToCreate) + vrfv2_5Contracts.Coordinator, vrfv2_5Contracts.LoadTestConsumers, + numberOfSubToCreate, + vrfv2plus_config.BillingType(*vrfv2PlusConfig.SubscriptionBillingType)) if err != nil { return nil, nil, nil, err } @@ -270,7 +290,7 @@ func SetupVRFV2_5Environment( } chainID := env.EVMClient.GetChainID() - newNativeTokenKeyAddresses, err := CreateAndFundSendingKeys(env, vrfv2PlusConfig, numberOfTxKeysToCreate, chainID) + newNativeTokenKeyAddresses, err := CreateAndFundSendingKeys(env, vrfv2PlusTestConfig, numberOfTxKeysToCreate, chainID) if err != nil { return nil, nil, nil, err } @@ -280,14 +300,24 @@ func SetupVRFV2_5Environment( } allNativeTokenKeyAddresses := append(newNativeTokenKeyAddresses, nativeTokenPrimaryKeyAddress) + vrfJobSpecConfig := VRFJobSpecConfig{ + ForwardingAllowed: false, + CoordinatorAddress: vrfv2_5Contracts.Coordinator.Address(), + FromAddresses: allNativeTokenKeyAddresses, + EVMChainID: chainID.String(), + MinIncomingConfirmations: int(*vrfv2PlusConfig.MinimumConfirmations), + PublicKey: pubKeyCompressed, + EstimateGasMultiplier: 1, + BatchFulfillmentEnabled: false, + BatchFulfillmentGasMultiplier: 1.15, + PollPeriod: time.Second * 1, + RequestTimeout: time.Hour * 24, + } + l.Info().Msg("Creating VRFV2 Plus Job") job, err := CreateVRFV2PlusJob( env.ClCluster.NodeAPIs()[0], - vrfv2_5Contracts.Coordinator.Address(), - allNativeTokenKeyAddresses, - pubKeyCompressed, - chainID.String(), - vrfv2PlusConfig.MinimumConfirmations, + vrfJobSpecConfig, ) if err != nil { return nil, nil, nil, fmt.Errorf("%s, err %w", ErrCreateVRFV2PlusJobs, err) @@ -298,7 +328,7 @@ func SetupVRFV2_5Environment( // Key = '...' nodeConfig := node.NewConfig(env.ClCluster.Nodes[0].NodeConfig, node.WithLogPollInterval(1*time.Second), - node.WithVRFv2EVMEstimator(allNativeTokenKeyAddresses, vrfv2PlusConfig.CLNodeMaxGasPriceGWei), + node.WithVRFv2EVMEstimator(allNativeTokenKeyAddresses, *vrfv2PlusConfig.CLNodeMaxGasPriceGWei), ) l.Info().Msg("Restarting Node with new sending key PriceMax configuration and log poll period configuration") err = env.ClCluster.Nodes[0].Restart(nodeConfig) @@ -323,7 +353,7 @@ func SetupVRFV2_5Environment( return vrfv2_5Contracts, subIDs, &data, nil } -func CreateAndFundSendingKeys(env *test_env.CLClusterTestEnv, vrfv2PlusConfig vrfv2plus_config.VRFV2PlusConfig, numberOfNativeTokenAddressesToCreate int, chainID *big.Int) ([]string, error) { +func CreateAndFundSendingKeys(env *test_env.CLClusterTestEnv, commonTestConfig tc.CommonTestConfig, numberOfNativeTokenAddressesToCreate int, chainID *big.Int) ([]string, error) { var newNativeTokenKeyAddresses []string for i := 0; i < numberOfNativeTokenAddressesToCreate; i++ { newTxKey, response, err := env.ClCluster.NodeAPIs()[0].CreateTxKey("evm", chainID.String()) @@ -334,7 +364,7 @@ func CreateAndFundSendingKeys(env *test_env.CLClusterTestEnv, vrfv2PlusConfig vr return nil, fmt.Errorf("error creating transaction key - response code, err %d", response.StatusCode) } newNativeTokenKeyAddresses = append(newNativeTokenKeyAddresses, newTxKey.Data.ID) - err = actions.FundAddress(env.EVMClient, newTxKey.Data.ID, big.NewFloat(vrfv2PlusConfig.ChainlinkNodeFunding)) + err = actions.FundAddress(env.EVMClient, newTxKey.Data.ID, big.NewFloat(*commonTestConfig.GetCommonConfig().ChainlinkNodeFunding)) if err != nil { return nil, err } @@ -344,13 +374,23 @@ func CreateAndFundSendingKeys(env *test_env.CLClusterTestEnv, vrfv2PlusConfig vr func CreateFundSubsAndAddConsumers( env *test_env.CLClusterTestEnv, - vrfv2PlusConfig vrfv2plus_config.VRFV2PlusConfig, + subscriptionFundingAmountNative *big.Float, + subscriptionFundingAmountLink *big.Float, linkToken contracts.LinkToken, coordinator contracts.VRFCoordinatorV2_5, consumers []contracts.VRFv2PlusLoadTestConsumer, numberOfSubToCreate int, + subscriptionBillingType vrfv2plus_config.BillingType, ) ([]*big.Int, error) { - subIDs, err := CreateSubsAndFund(env, vrfv2PlusConfig, linkToken, coordinator, numberOfSubToCreate) + subIDs, err := CreateSubsAndFund( + env, + subscriptionFundingAmountNative, + subscriptionFundingAmountLink, + linkToken, + coordinator, + numberOfSubToCreate, + subscriptionBillingType, + ) if err != nil { return nil, err } @@ -378,10 +418,12 @@ func CreateFundSubsAndAddConsumers( func CreateSubsAndFund( env *test_env.CLClusterTestEnv, - vrfv2PlusConfig vrfv2plus_config.VRFV2PlusConfig, + subscriptionFundingAmountNative *big.Float, + subscriptionFundingAmountLink *big.Float, linkToken contracts.LinkToken, coordinator contracts.VRFCoordinatorV2_5, subAmountToCreate int, + subscriptionBillingType vrfv2plus_config.BillingType, ) ([]*big.Int, error) { subs, err := CreateSubs(env, coordinator, subAmountToCreate) if err != nil { @@ -391,7 +433,15 @@ func CreateSubsAndFund( if err != nil { return nil, fmt.Errorf("%s, err %w", ErrWaitTXsComplete, err) } - err = FundSubscriptions(env, vrfv2PlusConfig, linkToken, coordinator, subs) + err = FundSubscriptions( + env, + subscriptionFundingAmountNative, + subscriptionFundingAmountLink, + linkToken, + coordinator, + subs, + subscriptionBillingType, + ) if err != nil { return nil, err } @@ -453,26 +503,50 @@ func CreateSubAndFindSubID(env *test_env.CLClusterTestEnv, coordinator contracts func FundSubscriptions( env *test_env.CLClusterTestEnv, - vrfv2PlusConfig vrfv2plus_config.VRFV2PlusConfig, + subscriptionFundingAmountNative *big.Float, + subscriptionFundingAmountLink *big.Float, linkAddress contracts.LinkToken, coordinator contracts.VRFCoordinatorV2_5, subIDs []*big.Int, + subscriptionBillingType vrfv2plus_config.BillingType, ) error { for _, subID := range subIDs { - //Native Billing - amountWei := conversions.EtherToWei(big.NewFloat(vrfv2PlusConfig.SubscriptionFundingAmountNative)) - err := coordinator.FundSubscriptionWithNative( - subID, - amountWei, - ) - if err != nil { - return fmt.Errorf("%s, err %w", ErrFundSubWithNativeToken, err) - } - //Link Billing - amountJuels := conversions.EtherToWei(big.NewFloat(vrfv2PlusConfig.SubscriptionFundingAmountLink)) - err = FundVRFCoordinatorV2_5Subscription(linkAddress, coordinator, env.EVMClient, subID, amountJuels) - if err != nil { - return fmt.Errorf("%s, err %w", ErrFundSubWithLinkToken, err) + switch subscriptionBillingType { + case vrfv2plus_config.BillingType_Native: + //Native Billing + amountWei := conversions.EtherToWei(subscriptionFundingAmountNative) + err := coordinator.FundSubscriptionWithNative( + subID, + amountWei, + ) + if err != nil { + return fmt.Errorf("%s, err %w", ErrFundSubWithNativeToken, err) + } + case vrfv2plus_config.BillingType_Link: + //Link Billing + amountJuels := conversions.EtherToWei(subscriptionFundingAmountLink) + err := FundVRFCoordinatorV2_5Subscription(linkAddress, coordinator, env.EVMClient, subID, amountJuels) + if err != nil { + return fmt.Errorf("%s, err %w", ErrFundSubWithLinkToken, err) + } + case vrfv2plus_config.BillingType_Link_and_Native: + //Native Billing + amountWei := conversions.EtherToWei(subscriptionFundingAmountNative) + err := coordinator.FundSubscriptionWithNative( + subID, + amountWei, + ) + if err != nil { + return fmt.Errorf("%s, err %w", ErrFundSubWithNativeToken, err) + } + //Link Billing + amountJuels := conversions.EtherToWei(subscriptionFundingAmountLink) + err = FundVRFCoordinatorV2_5Subscription(linkAddress, coordinator, env.EVMClient, subID, amountJuels) + if err != nil { + return fmt.Errorf("%s, err %w", ErrFundSubWithLinkToken, err) + } + default: + return fmt.Errorf("invalid billing type: %s", subscriptionBillingType) } } err := env.EVMClient.WaitForEvents() @@ -512,19 +586,22 @@ func RequestRandomnessAndWaitForFulfillment( vrfv2PlusData *VRFV2PlusData, subID *big.Int, isNativeBilling bool, + minimumConfirmations uint16, + callbackGasLimit uint32, + numberOfWords uint32, randomnessRequestCountPerRequest uint16, - vrfv2PlusConfig vrfv2plus_config.VRFV2PlusConfig, + randomnessRequestCountPerRequestDeviation uint16, randomWordsFulfilledEventTimeout time.Duration, l zerolog.Logger, ) (*vrf_coordinator_v2_5.VRFCoordinatorV25RandomWordsFulfilled, error) { - logRandRequest(consumer.Address(), coordinator.Address(), subID, isNativeBilling, vrfv2PlusConfig, l) + logRandRequest(l, consumer.Address(), coordinator.Address(), subID, isNativeBilling, minimumConfirmations, callbackGasLimit, numberOfWords, randomnessRequestCountPerRequest, randomnessRequestCountPerRequestDeviation) _, err := consumer.RequestRandomness( vrfv2PlusData.KeyHash, subID, - vrfv2PlusConfig.MinimumConfirmations, - vrfv2PlusConfig.CallbackGasLimit, + minimumConfirmations, + callbackGasLimit, isNativeBilling, - vrfv2PlusConfig.NumberOfWords, + numberOfWords, randomnessRequestCountPerRequest, ) if err != nil { @@ -548,18 +625,22 @@ func RequestRandomnessAndWaitForFulfillmentUpgraded( vrfv2PlusData *VRFV2PlusData, subID *big.Int, isNativeBilling bool, - vrfv2PlusConfig vrfv2plus_config.VRFV2PlusConfig, + minimumConfirmations uint16, + callbackGasLimit uint32, + numberOfWords uint32, + randomnessRequestCountPerRequest uint16, + randomnessRequestCountPerRequestDeviation uint16, l zerolog.Logger, ) (*vrf_v2plus_upgraded_version.VRFCoordinatorV2PlusUpgradedVersionRandomWordsFulfilled, error) { - logRandRequest(consumer.Address(), coordinator.Address(), subID, isNativeBilling, vrfv2PlusConfig, l) + logRandRequest(l, consumer.Address(), coordinator.Address(), subID, isNativeBilling, minimumConfirmations, callbackGasLimit, numberOfWords, randomnessRequestCountPerRequest, randomnessRequestCountPerRequestDeviation) _, err := consumer.RequestRandomness( vrfv2PlusData.KeyHash, subID, - vrfv2PlusConfig.MinimumConfirmations, - vrfv2PlusConfig.CallbackGasLimit, + minimumConfirmations, + callbackGasLimit, isNativeBilling, - vrfv2PlusConfig.NumberOfWords, - vrfv2PlusConfig.RandomnessRequestCountPerRequest, + numberOfWords, + randomnessRequestCountPerRequest, ) if err != nil { return nil, fmt.Errorf("%s, err %w", ErrRequestRandomness, err) @@ -592,14 +673,14 @@ func RequestRandomnessAndWaitForFulfillmentUpgraded( func SetupVRFV2PlusWrapperEnvironment( env *test_env.CLClusterTestEnv, - vrfv2PlusConfig vrfv2plus_config.VRFV2PlusConfig, + vrfv2PlusTestConfig types.VRFv2PlusTestConfig, linkToken contracts.LinkToken, mockNativeLINKFeed contracts.MockETHLINKFeed, coordinator contracts.VRFCoordinatorV2_5, keyHash [32]byte, wrapperConsumerContractsAmount int, ) (*VRFV2PlusWrapperContracts, *big.Int, error) { - + vrfv2PlusConfig := vrfv2PlusTestConfig.GetVRFv2PlusConfig().General wrapperContracts, err := DeployVRFV2PlusDirectFundingContracts( env.ContractDeployer, env.EVMClient, @@ -618,15 +699,15 @@ func SetupVRFV2PlusWrapperEnvironment( return nil, nil, fmt.Errorf("%s, err %w", ErrWaitTXsComplete, err) } err = wrapperContracts.VRFV2PlusWrapper.SetConfig( - vrfv2PlusConfig.WrapperGasOverhead, - vrfv2PlusConfig.CoordinatorGasOverhead, - vrfv2PlusConfig.WrapperPremiumPercentage, + *vrfv2PlusConfig.WrapperGasOverhead, + *vrfv2PlusConfig.CoordinatorGasOverhead, + *vrfv2PlusConfig.WrapperPremiumPercentage, keyHash, - vrfv2PlusConfig.WrapperMaxNumberOfWords, - vrfv2PlusConfig.StalenessSeconds, - big.NewInt(vrfv2PlusConfig.FallbackWeiPerUnitLink), - vrfv2PlusConfig.FulfillmentFlatFeeLinkPPM, - vrfv2PlusConfig.FulfillmentFlatFeeNativePPM, + *vrfv2PlusConfig.WrapperMaxNumberOfWords, + *vrfv2PlusConfig.StalenessSeconds, + big.NewInt(*vrfv2PlusConfig.FallbackWeiPerUnitLink), + *vrfv2PlusConfig.FulfillmentFlatFeeLinkPPM, + *vrfv2PlusConfig.FulfillmentFlatFeeNativePPM, ) if err != nil { return nil, nil, err @@ -648,7 +729,7 @@ func SetupVRFV2PlusWrapperEnvironment( return nil, nil, fmt.Errorf("%s, err %w", ErrWaitTXsComplete, err) } - err = FundSubscriptions(env, vrfv2PlusConfig, linkToken, coordinator, []*big.Int{wrapperSubID}) + err = FundSubscriptions(env, big.NewFloat(*vrfv2PlusTestConfig.GetVRFv2PlusConfig().General.SubscriptionFundingAmountNative), big.NewFloat(*vrfv2PlusTestConfig.GetVRFv2PlusConfig().General.SubscriptionFundingAmountLink), linkToken, coordinator, []*big.Int{wrapperSubID}, vrfv2plus_config.BillingType(*vrfv2PlusTestConfig.GetVRFv2PlusConfig().General.SubscriptionBillingType)) if err != nil { return nil, nil, err } @@ -656,7 +737,7 @@ func SetupVRFV2PlusWrapperEnvironment( //fund consumer with Link err = linkToken.Transfer( wrapperContracts.LoadTestConsumers[0].Address(), - big.NewInt(0).Mul(big.NewInt(1e18), big.NewInt(vrfv2PlusConfig.WrapperConsumerFundingAmountLink)), + big.NewInt(0).Mul(big.NewInt(1e18), big.NewInt(*vrfv2PlusConfig.WrapperConsumerFundingAmountLink)), ) if err != nil { return nil, nil, err @@ -667,7 +748,7 @@ func SetupVRFV2PlusWrapperEnvironment( } //fund consumer with Eth - err = wrapperContracts.LoadTestConsumers[0].Fund(big.NewFloat(vrfv2PlusConfig.WrapperConsumerFundingAmountNativeToken)) + err = wrapperContracts.LoadTestConsumers[0].Fund(big.NewFloat(*vrfv2PlusConfig.WrapperConsumerFundingAmountNativeToken)) if err != nil { return nil, nil, err } @@ -725,27 +806,31 @@ func DirectFundingRequestRandomnessAndWaitForFulfillment( vrfv2PlusData *VRFV2PlusData, subID *big.Int, isNativeBilling bool, - vrfv2PlusConfig vrfv2plus_config.VRFV2PlusConfig, + minimumConfirmations uint16, + callbackGasLimit uint32, + numberOfWords uint32, + randomnessRequestCountPerRequest uint16, + randomnessRequestCountPerRequestDeviation uint16, randomWordsFulfilledEventTimeout time.Duration, l zerolog.Logger, ) (*vrf_coordinator_v2_5.VRFCoordinatorV25RandomWordsFulfilled, error) { - logRandRequest(consumer.Address(), coordinator.Address(), subID, isNativeBilling, vrfv2PlusConfig, l) + logRandRequest(l, consumer.Address(), coordinator.Address(), subID, isNativeBilling, minimumConfirmations, callbackGasLimit, numberOfWords, randomnessRequestCountPerRequest, randomnessRequestCountPerRequestDeviation) if isNativeBilling { _, err := consumer.RequestRandomnessNative( - vrfv2PlusConfig.MinimumConfirmations, - vrfv2PlusConfig.CallbackGasLimit, - vrfv2PlusConfig.NumberOfWords, - vrfv2PlusConfig.RandomnessRequestCountPerRequest, + minimumConfirmations, + callbackGasLimit, + numberOfWords, + randomnessRequestCountPerRequest, ) if err != nil { return nil, fmt.Errorf("%s, err %w", ErrRequestRandomnessDirectFundingNativePayment, err) } } else { _, err := consumer.RequestRandomness( - vrfv2PlusConfig.MinimumConfirmations, - vrfv2PlusConfig.CallbackGasLimit, - vrfv2PlusConfig.NumberOfWords, - vrfv2PlusConfig.RandomnessRequestCountPerRequest, + minimumConfirmations, + callbackGasLimit, + numberOfWords, + randomnessRequestCountPerRequest, ) if err != nil { return nil, fmt.Errorf("%s, err %w", ErrRequestRandomnessDirectFundingLinkPayment, err) @@ -1019,20 +1104,25 @@ func LogFulfillmentDetailsNativeBilling( } func logRandRequest( + l zerolog.Logger, consumer string, coordinator string, subID *big.Int, isNativeBilling bool, - vrfv2PlusConfig vrfv2plus_config.VRFV2PlusConfig, - l zerolog.Logger) { + minimumConfirmations uint16, + callbackGasLimit uint32, + numberOfWords uint32, + randomnessRequestCountPerRequest uint16, + randomnessRequestCountPerRequestDeviation uint16) { 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). + Uint16("MinimumConfirmations", minimumConfirmations). + Uint32("CallbackGasLimit", callbackGasLimit). + Uint32("NumberOfWords", numberOfWords). + Uint16("RandomnessRequestCountPerRequest", randomnessRequestCountPerRequest). + Uint16("RandomnessRequestCountPerRequestDeviation", randomnessRequestCountPerRequestDeviation). Msg("Requesting randomness") } diff --git a/integration-tests/benchmark/keeper_test.go b/integration-tests/benchmark/keeper_test.go index d5a82a51e0..8997289a7e 100644 --- a/integration-tests/benchmark/keeper_test.go +++ b/integration-tests/benchmark/keeper_test.go @@ -3,8 +3,6 @@ package benchmark import ( "fmt" "math/big" - "os" - "strconv" "strings" "testing" "time" @@ -12,6 +10,7 @@ import ( "github.com/stretchr/testify/require" "github.com/smartcontractkit/chainlink-testing-framework/blockchain" + ctf_config "github.com/smartcontractkit/chainlink-testing-framework/config" env_client "github.com/smartcontractkit/chainlink-testing-framework/k8s/client" "github.com/smartcontractkit/chainlink-testing-framework/k8s/environment" "github.com/smartcontractkit/chainlink-testing-framework/k8s/pkg/cdk8s/blockscout" @@ -25,6 +24,9 @@ import ( "github.com/smartcontractkit/chainlink/integration-tests/contracts" eth_contracts "github.com/smartcontractkit/chainlink/integration-tests/contracts/ethereum" "github.com/smartcontractkit/chainlink/integration-tests/testsetups" + "github.com/smartcontractkit/chainlink/integration-tests/types" + + tc "github.com/smartcontractkit/chainlink/integration-tests/testconfig" ) var ( @@ -110,27 +112,6 @@ LimitDefault = 5_000_000` } ) -var ( - NumberOfNodes, _ = strconv.Atoi(getEnv("NUMBEROFNODES", "6")) - RegistryToTest = getEnv("REGISTRY", "2_1") - NumberOfUpkeeps, _ = strconv.Atoi(getEnv("NUMBEROFUPKEEPS", "500")) - CheckGasToBurn, _ = strconv.ParseInt(getEnv("CHECKGASTOBURN", "100000"), 0, 64) - PerformGasToBurn, _ = strconv.ParseInt(getEnv("PERFORMGASTOBURN", "50000"), 0, 64) - BlockRange, _ = strconv.ParseInt(getEnv("BLOCKRANGE", "3600"), 0, 64) - BlockInterval, _ = strconv.ParseInt(getEnv("BLOCKINTERVAL", "20"), 0, 64) - ChainlinkNodeFunding, _ = strconv.ParseFloat(getEnv("CHAINLINKNODEFUNDING", "0.5"), 64) - MaxPerformGas, _ = strconv.ParseInt(getEnv("MAXPERFORMGAS", "5000000"), 0, 32) - UpkeepGasLimit, _ = strconv.ParseInt(getEnv("UPKEEPGASLIMIT", fmt.Sprint(PerformGasToBurn+100000)), 0, 64) - NumberOfRegistries, _ = strconv.Atoi(getEnv("NUMBEROFREGISTRIES", "1")) - ForceSingleTxnKey, _ = strconv.ParseBool(getEnv("FORCESINGLETXNKEY", "false")) - DeleteJobsOnEnd, _ = strconv.ParseBool(getEnv("DELETEJOBSONEND", "true")) - RegistryAddress = getEnv("REGISTRYADDRESS", "") - RegistrarAddress = getEnv("REGISTRARADDRESS", "") - LinkTokenAddress = getEnv("LINKTOKENADDRESS", "") - EthFeedAddress = getEnv("ETHFEEDADDRESS", "") - GasFeedAddress = getEnv("GASFEEDADDRESS", "") -) - type NetworkConfig struct { upkeepSLA int64 blockTime time.Duration @@ -140,20 +121,26 @@ type NetworkConfig struct { func TestAutomationBenchmark(t *testing.T) { l := logging.GetTestLogger(t) - testEnvironment, benchmarkNetwork := SetupAutomationBenchmarkEnv(t) + testType, err := tc.GetConfigurationNameFromEnv() + require.NoError(t, err, "Error getting test type") + + config, err := tc.GetConfig(testType, tc.Keeper) + require.NoError(t, err, "Error getting test config") + + testEnvironment, benchmarkNetwork := SetupAutomationBenchmarkEnv(t, &config) if testEnvironment.WillUseRemoteRunner() { return } networkName := strings.ReplaceAll(benchmarkNetwork.Name, " ", "") - testName := fmt.Sprintf("%s%s", networkName, RegistryToTest) - l.Info().Str("Test Name", testName).Str("Test Inputs", os.Getenv("TEST_INPUTS")).Msg("Running Benchmark Test") - benchmarkTestNetwork := networkConfig[networkName] + testName := fmt.Sprintf("%s%s", networkName, *config.Keeper.Common.RegistryToTest) + l.Info().Str("Test Name", testName).Msg("Running Benchmark Test") + benchmarkTestNetwork := getNetworkConfig(networkName, &config) l.Info().Str("Namespace", testEnvironment.Cfg.Namespace).Msg("Connected to Keepers Benchmark Environment") chainClient, err := blockchain.NewEVMClient(benchmarkNetwork, testEnvironment, l) require.NoError(t, err, "Error connecting to blockchain") - registryVersions := addRegistry(RegistryToTest) + registryVersions := addRegistry(&config) keeperBenchmarkTest := testsetups.NewKeeperBenchmarkTest(t, testsetups.KeeperBenchmarkTestInputs{ BlockchainClient: chainClient, @@ -165,7 +152,7 @@ func TestAutomationBenchmark(t *testing.T) { CheckGasLimit: uint32(45_000_000), //45M StalenessSeconds: big.NewInt(90_000), GasCeilingMultiplier: uint16(2), - MaxPerformGas: uint32(MaxPerformGas), + MaxPerformGas: uint32(*config.Keeper.Common.MaxPerformGas), MinUpkeepSpend: big.NewInt(0), FallbackGasPrice: big.NewInt(2e11), FallbackLinkPrice: big.NewInt(2e18), @@ -173,27 +160,27 @@ func TestAutomationBenchmark(t *testing.T) { MaxPerformDataSize: uint32(5_000), }, Upkeeps: &testsetups.UpkeepConfig{ - NumberOfUpkeeps: NumberOfUpkeeps, - CheckGasToBurn: CheckGasToBurn, - PerformGasToBurn: PerformGasToBurn, - BlockRange: BlockRange, - BlockInterval: BlockInterval, - UpkeepGasLimit: UpkeepGasLimit, + NumberOfUpkeeps: *config.Keeper.Common.NumberOfUpkeeps, + CheckGasToBurn: *config.Keeper.Common.CheckGasToBurn, + PerformGasToBurn: *config.Keeper.Common.PerformGasToBurn, + BlockRange: *config.Keeper.Common.BlockRange, + BlockInterval: *config.Keeper.Common.BlockInterval, + UpkeepGasLimit: *config.Keeper.Common.UpkeepGasLimit, FirstEligibleBuffer: 1, }, Contracts: &testsetups.PreDeployedContracts{ - RegistrarAddress: RegistrarAddress, - RegistryAddress: RegistryAddress, - LinkTokenAddress: LinkTokenAddress, - EthFeedAddress: EthFeedAddress, - GasFeedAddress: GasFeedAddress, + RegistrarAddress: *config.Keeper.Common.RegistrarAddress, + RegistryAddress: *config.Keeper.Common.RegistryAddress, + LinkTokenAddress: *config.Keeper.Common.LinkTokenAddress, + EthFeedAddress: *config.Keeper.Common.EthFeedAddress, + GasFeedAddress: *config.Keeper.Common.GasFeedAddress, }, ChainlinkNodeFunding: benchmarkTestNetwork.funding, UpkeepSLA: benchmarkTestNetwork.upkeepSLA, BlockTime: benchmarkTestNetwork.blockTime, DeltaStage: benchmarkTestNetwork.deltaStage, - ForceSingleTxnKey: ForceSingleTxnKey, - DeleteJobsOnEnd: DeleteJobsOnEnd, + ForceSingleTxnKey: *config.Keeper.Common.ForceSingleTxKey, + DeleteJobsOnEnd: *config.Keeper.Common.DeleteJobsOnEnd, }, ) t.Cleanup(func() { @@ -201,12 +188,12 @@ func TestAutomationBenchmark(t *testing.T) { l.Error().Err(err).Msg("Error when tearing down remote suite") } }) - keeperBenchmarkTest.Setup(testEnvironment) + keeperBenchmarkTest.Setup(testEnvironment, &config) keeperBenchmarkTest.Run() } -func addRegistry(registryToTest string) []eth_contracts.KeeperRegistryVersion { - switch registryToTest { +func addRegistry(config *tc.TestConfig) []eth_contracts.KeeperRegistryVersion { + switch *config.Keeper.Common.RegistryToTest { case "1_1": return []eth_contracts.KeeperRegistryVersion{eth_contracts.RegistryVersion_1_1} case "1_2": @@ -223,9 +210,9 @@ func addRegistry(registryToTest string) []eth_contracts.KeeperRegistryVersion { return []eth_contracts.KeeperRegistryVersion{eth_contracts.RegistryVersion_2_1, eth_contracts.RegistryVersion_2_0, eth_contracts.RegistryVersion_1_3} case "2_0-Multiple": - return repeatRegistries(eth_contracts.RegistryVersion_2_0, NumberOfRegistries) + return repeatRegistries(eth_contracts.RegistryVersion_2_0, *config.Keeper.Common.NumberOfRegistries) case "2_1-Multiple": - return repeatRegistries(eth_contracts.RegistryVersion_2_1, NumberOfRegistries) + return repeatRegistries(eth_contracts.RegistryVersion_2_1, *config.Keeper.Common.NumberOfRegistries) default: return []eth_contracts.KeeperRegistryVersion{eth_contracts.RegistryVersion_2_0} } @@ -239,6 +226,22 @@ func repeatRegistries(registryVersion eth_contracts.KeeperRegistryVersion, numbe return repeatedRegistries } +func getNetworkConfig(networkName string, config *tc.TestConfig) NetworkConfig { + var nc NetworkConfig + var ok bool + if nc, ok = networkConfig[networkName]; !ok { + return NetworkConfig{} + } + + if networkName == "SimulatedGeth" || networkName == "geth" { + return nc + } + + nc.funding = big.NewFloat(*config.Common.ChainlinkNodeFunding) + + return nc +} + var networkConfig = map[string]NetworkConfig{ "SimulatedGeth": { upkeepSLA: int64(120), //2 minutes @@ -256,93 +259,71 @@ var networkConfig = map[string]NetworkConfig{ upkeepSLA: int64(4), blockTime: 12 * time.Second, deltaStage: time.Duration(0), - funding: big.NewFloat(ChainlinkNodeFunding), }, "ArbitrumGoerli": { upkeepSLA: int64(20), blockTime: time.Second, deltaStage: time.Duration(0), - funding: big.NewFloat(ChainlinkNodeFunding), }, "OptimismGoerli": { upkeepSLA: int64(20), blockTime: time.Second, deltaStage: time.Duration(0), - funding: big.NewFloat(ChainlinkNodeFunding), }, "SepoliaTestnet": { upkeepSLA: int64(4), blockTime: 12 * time.Second, deltaStage: time.Duration(0), - funding: big.NewFloat(ChainlinkNodeFunding), }, "PolygonMumbai": { upkeepSLA: int64(4), blockTime: 12 * time.Second, deltaStage: time.Duration(0), - funding: big.NewFloat(ChainlinkNodeFunding), }, "BaseGoerli": { upkeepSLA: int64(60), blockTime: 2 * time.Second, deltaStage: 20 * time.Second, - funding: big.NewFloat(ChainlinkNodeFunding), }, "ArbitrumSepolia": { upkeepSLA: int64(120), blockTime: time.Second, deltaStage: 20 * time.Second, - funding: big.NewFloat(ChainlinkNodeFunding), + }, + "LineaGoerli": { + upkeepSLA: int64(120), + blockTime: time.Second, + deltaStage: 20 * time.Second, }, } -func getEnv(key, fallback string) string { - if inputs, ok := os.LookupEnv("TEST_INPUTS"); ok { - values := strings.Split(inputs, ",") - for _, value := range values { - if strings.Contains(value, key) { - return strings.Split(value, "=")[1] - } - } - } - return fallback -} - -func SetupAutomationBenchmarkEnv(t *testing.T) (*environment.Environment, blockchain.EVMNetwork) { +func SetupAutomationBenchmarkEnv(t *testing.T, keeperTestConfig types.KeeperBenchmarkTestConfig) (*environment.Environment, blockchain.EVMNetwork) { l := logging.GetTestLogger(t) - testNetwork := networks.MustGetSelectedNetworksFromEnv()[0] // Environment currently being used to run benchmark test on + testNetwork := networks.MustGetSelectedNetworkConfig(keeperTestConfig.GetNetworkConfig())[0] // Environment currently being used to run benchmark test on blockTime := "1" networkDetailTOML := `MinIncomingConfirmations = 1` - if strings.Contains(RegistryToTest, "2_") { - NumberOfNodes++ + numberOfNodes := *keeperTestConfig.GetKeeperConfig().Common.NumberOfNodes + + if strings.Contains(*keeperTestConfig.GetKeeperConfig().Common.RegistryToTest, "2_") { + numberOfNodes++ } - testType := strings.ToLower(getEnv("TEST_TYPE", "benchmark")) testEnvironment := environment.New(&environment.Config{ TTL: time.Hour * 720, // 30 days, NamespacePrefix: fmt.Sprintf( "automation-%s-%s-%s", - testType, + strings.ToLower(keeperTestConfig.GetConfigurationName()), strings.ReplaceAll(strings.ToLower(testNetwork.Name), " ", "-"), - strings.ReplaceAll(strings.ToLower(RegistryToTest), "_", "-"), + strings.ReplaceAll(strings.ToLower(*keeperTestConfig.GetKeeperConfig().Common.RegistryToTest), "_", "-"), ), Test: t, PreventPodEviction: true, }) - // propagate TEST_INPUTS to remote runner - if testEnvironment.WillUseRemoteRunner() { - key := "TEST_INPUTS" - err := os.Setenv(fmt.Sprintf("TEST_%s", key), os.Getenv(key)) - require.NoError(t, err, "failed to set the environment variable TEST_INPUTS for remote runner") - key = "GRAFANA_DASHBOARD_URL" - err = os.Setenv(fmt.Sprintf("TEST_%s", key), getEnv(key, "")) - require.NoError(t, err, "failed to set the environment variable GRAFANA_DASHBOARD_URL for remote runner") - } dbResources := performanceDbResources chainlinkResources := performanceChainlinkResources - if testType == "soak" { + if strings.ToLower(keeperTestConfig.GetConfigurationName()) == "soak" { chainlinkResources = soakChainlinkResources dbResources = soakDbResources } @@ -356,7 +337,7 @@ func SetupAutomationBenchmarkEnv(t *testing.T) (*environment.Environment, blockc Values: map[string]interface{}{ "geth": map[string]interface{}{ "tx": map[string]interface{}{ - "replicas": NumberOfNodes, + "replicas": numberOfNodes, }, "miner": map[string]interface{}{ "replicas": 2, @@ -406,7 +387,7 @@ func SetupAutomationBenchmarkEnv(t *testing.T) (*environment.Environment, blockc // separate RPC urls per CL node internalWsURLs := make([]string, 0) internalHttpURLs := make([]string, 0) - for i := 0; i < NumberOfNodes; i++ { + for i := 0; i < numberOfNodes; i++ { // for simulated-nod-dev each CL node gets its own RPC node if testNetwork.Name == networks.SimulatedEVMNonDev.Name { podName := fmt.Sprintf("%s-ethereum-geth:%d", testNetwork.Name, i) @@ -428,14 +409,22 @@ func SetupAutomationBenchmarkEnv(t *testing.T) (*environment.Environment, blockc } l.Debug().Strs("internalWsURLs", internalWsURLs).Strs("internalHttpURLs", internalHttpURLs).Msg("internalURLs") - for i := 0; i < NumberOfNodes; i++ { + for i := 0; i < numberOfNodes; i++ { testNetwork.HTTPURLs = []string{internalHttpURLs[i]} testNetwork.URLs = []string{internalWsURLs[i]} - testEnvironment.AddHelm(chainlink.New(i, map[string]any{ - "toml": networks.AddNetworkDetailedConfig(keeperBenchmarkBaseTOML, networkDetailTOML, testNetwork), + + var overrideFn = func(_ interface{}, target interface{}) { + ctf_config.MustConfigOverrideChainlinkVersion(keeperTestConfig.GetChainlinkImageConfig(), target) + ctf_config.MightConfigOverridePyroscopeKey(keeperTestConfig.GetPyroscopeConfig(), target) + } + + cd := chainlink.NewWithOverride(i, map[string]any{ + "toml": networks.AddNetworkDetailedConfig(keeperBenchmarkBaseTOML, keeperTestConfig.GetPyroscopeConfig(), networkDetailTOML, testNetwork), "chainlink": chainlinkResources, "db": dbResources, - })) + }, keeperTestConfig.GetChainlinkImageConfig(), overrideFn) + + testEnvironment.AddHelm(cd) } err = testEnvironment.Run() require.NoError(t, err, "Error launching test environment") diff --git a/integration-tests/ccip-tests/testconfig/global.go b/integration-tests/ccip-tests/testconfig/global.go index d46a66a4d4..9b6adcd8e6 100644 --- a/integration-tests/ccip-tests/testconfig/global.go +++ b/integration-tests/ccip-tests/testconfig/global.go @@ -5,17 +5,21 @@ import ( _ "embed" "encoding/base64" "fmt" + "strings" "github.com/AlekSi/pointer" "github.com/pelletier/go-toml/v2" "github.com/pkg/errors" "github.com/rs/zerolog/log" - "github.com/smartcontractkit/chainlink-testing-framework/blockchain" + "github.com/smartcontractkit/chainlink-testing-framework/docker/test_env" "github.com/smartcontractkit/chainlink-testing-framework/networks" + + "github.com/smartcontractkit/chainlink-testing-framework/blockchain" "github.com/smartcontractkit/chainlink-testing-framework/utils/osutil" "github.com/smartcontractkit/chainlink-common/pkg/config" + ctfconfig "github.com/smartcontractkit/chainlink-testing-framework/config" ) const ( @@ -28,7 +32,7 @@ const ( ) var ( - //go:embed tomls/default.toml + //go:embed tomls/ccip-default.toml DefaultConfig []byte ) @@ -122,15 +126,14 @@ func NewConfig() (*Config, error) { // Common is the generic config struct which can be used with product specific configs. // It contains generic DON and networks config which can be applied to all product based tests. type Common struct { - EnvUser string `toml:",omitempty"` - TTL *config.Duration `toml:",omitempty"` - Chainlink *Chainlink `toml:",omitempty"` - Networks []string `toml:",omitempty"` + EnvUser string `toml:",omitempty"` + TTL *config.Duration `toml:",omitempty"` + Chainlink *Chainlink `toml:",omitempty"` + Network *ctfconfig.NetworkConfig `toml:",omitempty"` + Logging *ctfconfig.LoggingConfig `toml:"Logging"` } func (p *Common) ReadSecrets() error { - // read secrets for all products and test types - // TODO: as of now we read network secrets through networks.SetNetworks, change this to generic secret reading mechanism return p.Chainlink.ReadSecrets() } @@ -144,8 +147,8 @@ func (p *Common) ApplyOverrides(from *Common) error { if from.TTL != nil { p.TTL = from.TTL } - if from.Networks != nil { - p.Networks = from.Networks + if from.Network != nil { + p.Network = from.Network } if from.Chainlink != nil { if p.Chainlink == nil { @@ -157,14 +160,68 @@ func (p *Common) ApplyOverrides(from *Common) error { } func (p *Common) Validate() error { - if p.Networks == nil { + if err := p.Logging.Validate(); err != nil { + return fmt.Errorf("error validating logging config %w", err) + } + if p.Network == nil { return errors.New("no networks specified") } + if err := p.Network.Validate(); err != nil { + return fmt.Errorf("error validating networks config %w", err) + } return p.Chainlink.Validate() } -func (p *Common) EVMNetworks() []blockchain.EVMNetwork { - return networks.SetNetworks(p.Networks) +func (p *Common) EVMNetworks() ([]blockchain.EVMNetwork, error) { + p.Network.UpperCaseNetworkNames() + err := p.Network.Default() + if err != nil { + return nil, fmt.Errorf("error reading default network config %w", err) + } + return networks.MustSetNetworks(*p.Network), nil +} + +func (p *Common) GetLoggingConfig() *ctfconfig.LoggingConfig { + return p.Logging +} + +func (p *Common) GetChainlinkImageConfig() *ctfconfig.ChainlinkImageConfig { + return p.Chainlink.Common.ChainlinkImage +} + +func (p *Common) GetPyroscopeConfig() *ctfconfig.PyroscopeConfig { + return nil +} + +func (p *Common) GetPrivateEthereumNetworkConfig() *test_env.EthereumNetwork { + return nil +} + +func (p *Common) GetNetworkConfig() *ctfconfig.NetworkConfig { + return p.Network +} + +// Returns Grafana URL from Logging config +func (p *Common) GetGrafanaBaseURL() (string, error) { + if p.Logging.Grafana == nil || p.Logging.Grafana.BaseUrl == nil { + return "", errors.New("grafana base url not set") + } + + return strings.TrimSuffix(*p.Logging.Grafana.BaseUrl, "/"), nil +} + +// Returns Grafana Dashboard URL from Logging config +func (p *Common) GetGrafanaDashboardURL() (string, error) { + if p.Logging.Grafana == nil || p.Logging.Grafana.DashboardUrl == nil { + return "", errors.New("grafana dashboard url not set") + } + + url := *p.Logging.Grafana.DashboardUrl + if !strings.HasPrefix(url, "/") { + url = "/" + url + } + + return url, nil } type Chainlink struct { @@ -223,47 +280,46 @@ func (c *Chainlink) ApplyOverrides(from *Chainlink) { } } +// TODO change this later to directly reading from toml instead of reading from env vars func (c *Chainlink) ReadSecrets() error { image, _ := osutil.GetEnv("CHAINLINK_IMAGE") - if image != "" { - c.Common.Image = image - } tag, _ := osutil.GetEnv("CHAINLINK_VERSION") - if tag != "" { - c.Common.Tag = tag + if image != "" && tag != "" { + c.Common.ChainlinkImage = &ctfconfig.ChainlinkImageConfig{ + Image: &image, + Version: &tag, + } } + upgradeImage, _ := osutil.GetEnv("UPGRADE_IMAGE") - if upgradeImage != "" { - c.Common.UpgradeImage = upgradeImage - } upgradeTag, _ := osutil.GetEnv("UPGRADE_VERSION") - if upgradeTag != "" { - c.Common.UpgradeTag = upgradeTag + if upgradeImage != "" && upgradeTag != "" { + c.Common.ChainlinkUpgradeImage = &ctfconfig.ChainlinkImageConfig{ + Image: &upgradeImage, + Version: &upgradeTag, + } } - for i, node := range c.Nodes { + + for i := range c.Nodes { image, _ := osutil.GetEnv(fmt.Sprintf("CHAINLINK_IMAGE-%d", i+1)) - if image != "" { - node.Image = image - } else { - node.Image = c.Common.Image - } tag, _ := osutil.GetEnv(fmt.Sprintf("CHAINLINK_VERSION-%d", i+1)) - if tag != "" { - node.Tag = tag + if image != "" && tag != "" { + c.Nodes[i].ChainlinkImage = &ctfconfig.ChainlinkImageConfig{ + Image: &image, + Version: &tag, + } } else { - node.Tag = c.Common.Tag + c.Nodes[i].ChainlinkImage = c.Common.ChainlinkImage } upgradeImage, _ := osutil.GetEnv(fmt.Sprintf("UPGRADE_IMAGE-%d", i+1)) - if upgradeImage != "" { - node.UpgradeImage = upgradeImage - } else { - node.UpgradeImage = c.Common.UpgradeImage - } upgradeTag, _ := osutil.GetEnv(fmt.Sprintf("UPGRADE_VERSION-%d", i+1)) - if upgradeTag != "" { - node.UpgradeTag = upgradeTag + if upgradeImage != "" && upgradeTag != "" { + c.Nodes[i].ChainlinkUpgradeImage = &ctfconfig.ChainlinkImageConfig{ + Image: &upgradeImage, + Version: &upgradeTag, + } } else { - node.UpgradeTag = c.Common.UpgradeTag + c.Nodes[i].ChainlinkUpgradeImage = c.Common.ChainlinkUpgradeImage } } return nil @@ -273,8 +329,8 @@ func (c *Chainlink) Validate() error { if c.Common == nil { return errors.New("common config can't be empty") } - if c.Common.Image == "" || c.Common.Tag == "" { - return errors.New("must provide chainlink image and tag") + if err := c.Common.ChainlinkImage.Validate(); err != nil { + return err } if c.Common.DBImage == "" || c.Common.DBTag == "" { return errors.New("must provide db image and tag") @@ -292,16 +348,14 @@ func (c *Chainlink) Validate() error { } type Node struct { - Name string `toml:",omitempty"` - Image string `toml:",omitempty"` - Tag string `toml:",omitempty"` - UpgradeImage string `toml:",omitempty"` - UpgradeTag string `toml:",omitempty"` - BaseConfigTOML string `toml:",omitempty"` - CommonChainConfigTOML string `toml:",omitempty"` - ChainConfigTOMLByChain map[string]string `toml:",omitempty"` // key is chainID - DBImage string `toml:",omitempty"` - DBTag string `toml:",omitempty"` + Name string `toml:",omitempty"` + ChainlinkImage *ctfconfig.ChainlinkImageConfig `toml:"ChainlinkImage"` + ChainlinkUpgradeImage *ctfconfig.ChainlinkImageConfig `toml:"ChainlinkUpgradeImage"` + BaseConfigTOML string `toml:",omitempty"` + CommonChainConfigTOML string `toml:",omitempty"` + ChainConfigTOMLByChain map[string]string `toml:",omitempty"` // key is chainID + DBImage string `toml:",omitempty"` + DBTag string `toml:",omitempty"` } func (n *Node) Merge(from *Node) { @@ -311,18 +365,38 @@ func (n *Node) Merge(from *Node) { if n.Name == "" { n.Name = from.Name } - if n.Image == "" { - n.Image = from.Image - } - if n.Tag == "" { - n.Tag = from.Tag - } - if n.UpgradeImage == "" { - n.UpgradeImage = from.UpgradeImage + if n.ChainlinkImage == nil { + if from.ChainlinkImage != nil { + n.ChainlinkImage = &ctfconfig.ChainlinkImageConfig{ + Image: from.ChainlinkImage.Image, + Version: from.ChainlinkImage.Version, + } + } + } else { + if n.ChainlinkImage.Image == nil && from.ChainlinkImage != nil { + n.ChainlinkImage.Image = from.ChainlinkImage.Image + } + if n.ChainlinkImage.Version == nil && from.ChainlinkImage != nil { + n.ChainlinkImage.Version = from.ChainlinkImage.Version + } } - if n.UpgradeTag == "" { - n.UpgradeTag = from.UpgradeTag + + if n.ChainlinkUpgradeImage == nil { + if from.ChainlinkUpgradeImage != nil { + n.ChainlinkUpgradeImage = &ctfconfig.ChainlinkImageConfig{ + Image: from.ChainlinkUpgradeImage.Image, + Version: from.ChainlinkUpgradeImage.Version, + } + } + } else { + if n.ChainlinkUpgradeImage.Image == nil && from.ChainlinkUpgradeImage != nil { + n.ChainlinkUpgradeImage.Image = from.ChainlinkUpgradeImage.Image + } + if n.ChainlinkUpgradeImage.Version == nil && from.ChainlinkUpgradeImage != nil { + n.ChainlinkUpgradeImage.Version = from.ChainlinkUpgradeImage.Version + } } + if n.DBImage == "" { n.DBImage = from.DBImage } @@ -356,17 +430,29 @@ func (n *Node) ApplyOverrides(from *Node) { if from.Name != "" { n.Name = from.Name } - if from.Image != "" { - n.Image = from.Image - } - if from.Tag != "" { - n.Tag = from.Tag - } - if from.UpgradeImage != "" { - n.UpgradeImage = from.UpgradeImage + if from.ChainlinkImage != nil { + if n.ChainlinkImage == nil { + n.ChainlinkImage = from.ChainlinkImage + } else { + if from.ChainlinkImage.Image != nil { + n.ChainlinkImage.Image = from.ChainlinkImage.Image + } + if from.ChainlinkImage.Version != nil { + n.ChainlinkImage.Version = from.ChainlinkImage.Version + } + } } - if from.UpgradeTag != "" { - n.UpgradeTag = from.UpgradeTag + if from.ChainlinkUpgradeImage != nil { + if n.ChainlinkUpgradeImage == nil { + n.ChainlinkUpgradeImage = from.ChainlinkUpgradeImage + } else { + if from.ChainlinkUpgradeImage.Image != nil { + n.ChainlinkUpgradeImage.Image = from.ChainlinkUpgradeImage.Image + } + if from.ChainlinkUpgradeImage.Version != nil { + n.ChainlinkUpgradeImage.Version = from.ChainlinkUpgradeImage.Version + } + } } if from.DBImage != "" { n.DBImage = from.DBImage diff --git a/integration-tests/ccip-tests/testconfig/tomls/default.toml b/integration-tests/ccip-tests/testconfig/tomls/ccip-default.toml similarity index 96% rename from integration-tests/ccip-tests/testconfig/tomls/default.toml rename to integration-tests/ccip-tests/testconfig/tomls/ccip-default.toml index c8a63d2c3c..d1f9b59125 100644 --- a/integration-tests/ccip-tests/testconfig/tomls/default.toml +++ b/integration-tests/ccip-tests/testconfig/tomls/ccip-default.toml @@ -9,7 +9,19 @@ TTL = '5h' # for example , if Networks = ['SIMULATED_1', 'SIMULATED_2', 'SIMULATED_3'], # then lanes will be set up between SIMULATED_1 and SIMULATED_2, SIMULATED_1 and SIMULATED_3, SIMULATED_2 and SIMULATED_3 # default value is ['SIMULATED_1', 'SIMULATED_2'] which means that test will create two private geth networks from scratch and set up lanes between them -Networks = ['SIMULATED_1', 'SIMULATED_2'] +[CCIP.Env.Network] +selected_networks= ['SIMULATED_1', 'SIMULATED_2'] + +[CCIP.Env.Logging] +test_log_collect=false # if set to true will save logs even if test did not fail + +[CCIP.Env.Logging.LogStream] +# supported targets: file, loki, in-memory. if empty no logs will be persistet +log_targets=["file"] +# context timeout for starting log producer and also time-frame for requesting logs +log_producer_timeout="10s" +# number of retries before log producer gives up and stops listening to logs +log_producer_retry_limit=10 # these values will be used to set up chainlink DON # along with these values, the secrets needs to be specified as part of .env variables diff --git a/integration-tests/ccip-tests/testreporters/ccip.go b/integration-tests/ccip-tests/testreporters/ccip.go index 68d46e6e65..52fd6d07de 100644 --- a/integration-tests/ccip-tests/testreporters/ccip.go +++ b/integration-tests/ccip-tests/testreporters/ccip.go @@ -210,7 +210,7 @@ type CCIPTestReporter struct { mu *sync.Mutex } -func (r *CCIPTestReporter) SendSlackNotification(t *testing.T, slackClient *slack.Client) error { +func (r *CCIPTestReporter) SendSlackNotification(t *testing.T, slackClient *slack.Client, _ testreporters.GrafanaURLProvider) error { // do not send slack notification for soak and load tests if !strings.Contains(strings.ToLower(r.t.Name()), "soak") && !strings.Contains(strings.ToLower(r.t.Name()), "load") { return nil diff --git a/integration-tests/ccip-tests/testsetups/ccip.go b/integration-tests/ccip-tests/testsetups/ccip.go index ce16f1b056..911587938b 100644 --- a/integration-tests/ccip-tests/testsetups/ccip.go +++ b/integration-tests/ccip-tests/testsetups/ccip.go @@ -107,39 +107,45 @@ func (p *CCIPTestConfig) AddPairToNetworkList(networkA, networkB blockchain.EVMN func (p *CCIPTestConfig) SetNetworkPairs(lggr zerolog.Logger) error { var allError error - + var err error + p.SelectedNetworks, err = p.EnvInput.EVMNetworks() + if err != nil { + allError = multierr.Append(allError, fmt.Errorf("failed to get networks: %w", err)) + return allError + } + networkByChainID := make(map[string]blockchain.EVMNetwork) + for _, net := range p.SelectedNetworks { + networkByChainID[net.Name] = net + } // if network pairs are provided, then use them if p.TestGroupInput.NetworkPairs != nil { networkPairs := p.TestGroupInput.NetworkPairs - networkByChainID := make(map[int64]blockchain.EVMNetwork) + for _, pair := range networkPairs { networkNames := strings.Split(pair, ",") if len(networkNames) != 2 { allError = multierr.Append(allError, fmt.Errorf("invalid network pair")) } - nets := networks.SetNetworks(networkNames) - if _, ok := networkByChainID[nets[0].ChainID]; !ok { - networkByChainID[nets[0].ChainID] = nets[0] + network1, ok := networkByChainID[networkNames[0]] + if !ok { + allError = multierr.Append(allError, fmt.Errorf("network %s not found in network config", networkNames[0])) } - if _, ok := networkByChainID[nets[1].ChainID]; !ok { - networkByChainID[nets[1].ChainID] = nets[1] + network2, ok := networkByChainID[networkNames[1]] + if !ok { + allError = multierr.Append(allError, fmt.Errorf("network %s not found in network config", networkNames[1])) } - p.AddPairToNetworkList(nets[0], nets[1]) - } - - for _, net := range networkByChainID { - p.SelectedNetworks = append(p.SelectedNetworks, net) + p.AddPairToNetworkList(network1, network2) } + lggr.Info().Int("Pairs", len(p.NetworkPairs)).Msg("No Of Lanes") return allError } - p.SelectedNetworks = p.EnvInput.EVMNetworks() if p.TestGroupInput.NoOfNetworks == 0 { p.TestGroupInput.NoOfNetworks = len(p.SelectedNetworks) } // TODO remove this when CTF network timeout is fixed for i := range p.SelectedNetworks { - p.SelectedNetworks[i].Timeout = blockchain.JSONStrDuration{ + p.SelectedNetworks[i].Timeout = blockchain.StrDuration{ Duration: 3 * time.Minute, } } @@ -748,7 +754,7 @@ func CCIPDefaultTestSetUp( } lggr.Info().Msg("Tearing down the environment") err = integrationactions.TeardownSuite(t, ccipEnv.K8Env, ccipEnv.CLNodes, setUpArgs.Reporter, - zapcore.ErrorLevel, chains...) + zapcore.ErrorLevel, setUpArgs.Cfg.EnvInput, chains...) require.NoError(t, err, "Environment teardown shouldn't fail") } else { //just print diff --git a/integration-tests/ccip-tests/testsetups/test_env.go b/integration-tests/ccip-tests/testsetups/test_env.go index d6c2b91852..24c127cb9f 100644 --- a/integration-tests/ccip-tests/testsetups/test_env.go +++ b/integration-tests/ccip-tests/testsetups/test_env.go @@ -111,8 +111,8 @@ func ChainlinkChart( clProps["chainlink"] = map[string]interface{}{ "resources": SetResourceProfile(testInputs.EnvInput.Chainlink.NodeCPU, testInputs.EnvInput.Chainlink.NodeMemory), "image": map[string]any{ - "image": testInputs.EnvInput.Chainlink.Common.Image, - "version": testInputs.EnvInput.Chainlink.Common.Tag, + "image": pointer.GetString(testInputs.EnvInput.Chainlink.Common.ChainlinkImage.Image), + "version": pointer.GetString(testInputs.EnvInput.Chainlink.Common.ChainlinkImage.Version), }, } @@ -140,8 +140,8 @@ func ChainlinkChart( "name": clNode.Name, "chainlink": map[string]any{ "image": map[string]any{ - "image": clNode.Image, - "version": clNode.Tag, + "image": pointer.GetString(clNode.ChainlinkImage.Image), + "version": pointer.GetString(clNode.ChainlinkImage.Version), }, }, "db": map[string]any{ @@ -174,6 +174,7 @@ func DeployLocalCluster( ) (*test_env.CLClusterTestEnv, func() error) { selectedNetworks := testInputs.SelectedNetworks env, err := test_env.NewCLTestEnvBuilder(). + WithTestConfig(testInputs.EnvInput). WithTestInstance(t). WithPrivateGethChains(selectedNetworks). WithMockAdapter(). @@ -209,7 +210,8 @@ func DeployLocalCluster( } ccipNode, err := test_env.NewClNode( []string{env.Network.Name}, - clNode.Image, clNode.Tag, toml, + pointer.GetString(clNode.ChainlinkImage.Image), + pointer.GetString(clNode.ChainlinkImage.Version), toml, test_env.WithPgDBOptions( ctftestenv.WithPostgresImageName(clNode.DBImage), ctftestenv.WithPostgresImageVersion(clNode.DBTag)), @@ -235,8 +237,8 @@ func DeployLocalCluster( } ccipNode, err := test_env.NewClNode( []string{env.Network.Name}, - testInputs.EnvInput.Chainlink.Common.Image, - testInputs.EnvInput.Chainlink.Common.Tag, + pointer.GetString(testInputs.EnvInput.Chainlink.Common.ChainlinkImage.Image), + pointer.GetString(testInputs.EnvInput.Chainlink.Common.ChainlinkImage.Version), toml, test_env.WithPgDBOptions( ctftestenv.WithPostgresImageName(testInputs.EnvInput.Chainlink.Common.DBImage), ctftestenv.WithPostgresImageVersion(testInputs.EnvInput.Chainlink.Common.DBTag)), @@ -272,13 +274,13 @@ func UpgradeNodes( env := ccipEnv.LocalCluster for i, clNode := range env.ClCluster.Nodes { if i <= startIndex || i >= endIndex { - upgradeImage := testInputs.EnvInput.Chainlink.Common.UpgradeImage - upgradeTag := testInputs.EnvInput.Chainlink.Common.UpgradeTag + upgradeImage := pointer.GetString(testInputs.EnvInput.Chainlink.Common.ChainlinkUpgradeImage.Image) + upgradeTag := pointer.GetString(testInputs.EnvInput.Chainlink.Common.ChainlinkUpgradeImage.Version) // if individual node upgrade image is provided, use that if len(testInputs.EnvInput.Chainlink.Nodes) > 0 { if i < len(testInputs.EnvInput.Chainlink.Nodes) { - upgradeImage = testInputs.EnvInput.Chainlink.Nodes[i].UpgradeImage - upgradeTag = testInputs.EnvInput.Chainlink.Nodes[i].UpgradeTag + upgradeImage = pointer.GetString(testInputs.EnvInput.Chainlink.Nodes[i].ChainlinkUpgradeImage.Image) + upgradeTag = pointer.GetString(testInputs.EnvInput.Chainlink.Nodes[i].ChainlinkUpgradeImage.Version) } } err := clNode.UpgradeVersion(upgradeImage, upgradeTag) @@ -300,17 +302,17 @@ func UpgradeNodes( var clientsToUpgrade []*integrationclient.ChainlinkK8sClient for i, clNode := range nodeClients { if i <= startIndex || i >= endIndex { - upgradeImage := testInputs.EnvInput.Chainlink.Common.UpgradeImage - upgradeTag := testInputs.EnvInput.Chainlink.Common.UpgradeTag + upgradeImage := testInputs.EnvInput.Chainlink.Common.ChainlinkUpgradeImage.Image + upgradeTag := testInputs.EnvInput.Chainlink.Common.ChainlinkUpgradeImage.Version // if individual node upgrade image is provided, use that if len(testInputs.EnvInput.Chainlink.Nodes) > 0 { if i < len(testInputs.EnvInput.Chainlink.Nodes) { - upgradeImage = testInputs.EnvInput.Chainlink.Nodes[i].UpgradeImage - upgradeTag = testInputs.EnvInput.Chainlink.Nodes[i].UpgradeTag + upgradeImage = testInputs.EnvInput.Chainlink.Nodes[i].ChainlinkUpgradeImage.Image + upgradeTag = testInputs.EnvInput.Chainlink.Nodes[i].ChainlinkUpgradeImage.Version } } clientsToUpgrade = append(clientsToUpgrade, clNode) - err := clNode.UpgradeVersion(k8Env, upgradeImage, upgradeTag) + err := clNode.UpgradeVersion(k8Env, pointer.GetString(upgradeImage), pointer.GetString(upgradeTag)) if err != nil { return err } diff --git a/integration-tests/chaos/automation_chaos_test.go b/integration-tests/chaos/automation_chaos_test.go index 06352a93d7..711a355730 100644 --- a/integration-tests/chaos/automation_chaos_test.go +++ b/integration-tests/chaos/automation_chaos_test.go @@ -11,6 +11,7 @@ import ( "go.uber.org/zap/zapcore" "github.com/smartcontractkit/chainlink-testing-framework/blockchain" + ctf_config "github.com/smartcontractkit/chainlink-testing-framework/config" "github.com/smartcontractkit/chainlink-testing-framework/k8s/chaos" "github.com/smartcontractkit/chainlink-testing-framework/k8s/environment" "github.com/smartcontractkit/chainlink-testing-framework/k8s/pkg/cdk8s/blockscout" @@ -25,6 +26,8 @@ import ( "github.com/smartcontractkit/chainlink/integration-tests/client" "github.com/smartcontractkit/chainlink/integration-tests/contracts" eth_contracts "github.com/smartcontractkit/chainlink/integration-tests/contracts/ethereum" + + tc "github.com/smartcontractkit/chainlink/integration-tests/testconfig" ) var ( @@ -41,7 +44,7 @@ ListenAddresses = ["0.0.0.0:6690"]` defaultAutomationSettings = map[string]interface{}{ "replicas": 6, - "toml": networks.AddNetworksConfig(baseTOML, networks.MustGetSelectedNetworksFromEnv()[0]), + "toml": "", "db": map[string]interface{}{ "stateful": true, "capacity": "1Gi", @@ -58,11 +61,7 @@ ListenAddresses = ["0.0.0.0:6690"]` }, } - defaultEthereumSettings = ðereum.Props{ - // utils.MustGetSelectedNetworksFromEnv() - NetworkName: networks.MustGetSelectedNetworksFromEnv()[0].Name, - Simulated: networks.MustGetSelectedNetworksFromEnv()[0].Simulated, - WsURLs: networks.MustGetSelectedNetworksFromEnv()[0].URLs, + defaultEthereumSettings = ethereum.Props{ Values: map[string]interface{}{ "resources": map[string]interface{}{ "requests": map[string]interface{}{ @@ -96,6 +95,20 @@ ListenAddresses = ["0.0.0.0:6690"]` } ) +func getDefaultAutomationSettings(config *tc.TestConfig) map[string]interface{} { + defaultAutomationSettings["toml"] = networks.AddNetworksConfig(baseTOML, config.Pyroscope, networks.MustGetSelectedNetworkConfig(config.Network)[0]) + return defaultAutomationSettings +} + +func getDefaultEthereumSettings(config *tc.TestConfig) *ethereum.Props { + network := networks.MustGetSelectedNetworkConfig(config.Network)[0] + defaultEthereumSettings.NetworkName = network.Name + defaultEthereumSettings.Simulated = network.Simulated + defaultEthereumSettings.WsURLs = network.URLs + + return &defaultEthereumSettings +} + type KeeperConsumerContracts int32 const ( @@ -120,6 +133,18 @@ func TestAutomationChaos(t *testing.T) { t.Run(name, func(t *testing.T) { t.Parallel() + config, err := tc.GetConfig("Chaos", tc.Automation) + if err != nil { + t.Fatal(err) + } + + var overrideFn = func(_ interface{}, target interface{}) { + ctf_config.MustConfigOverrideChainlinkVersion(config.ChainlinkImage, target) + ctf_config.MightConfigOverridePyroscopeKey(config.Pyroscope, target) + } + + chainlinkCfg := chainlink.NewWithOverride(0, getDefaultAutomationSettings(&config), config.ChainlinkImage, overrideFn) + testCases := map[string]struct { networkChart environment.ConnectedChart clChart environment.ConnectedChart @@ -128,8 +153,8 @@ func TestAutomationChaos(t *testing.T) { }{ // see ocr_chaos.test.go for comments PodChaosFailMinorityNodes: { - ethereum.New(defaultEthereumSettings), - chainlink.New(0, defaultAutomationSettings), + ethereum.New(getDefaultEthereumSettings(&config)), + chainlinkCfg, chaos.NewFailPods, &chaos.Props{ LabelsSelector: &map[string]*string{ChaosGroupMinority: ptr.Ptr("1")}, @@ -137,8 +162,8 @@ func TestAutomationChaos(t *testing.T) { }, }, PodChaosFailMajorityNodes: { - ethereum.New(defaultEthereumSettings), - chainlink.New(0, defaultAutomationSettings), + ethereum.New(getDefaultEthereumSettings(&config)), + chainlinkCfg, chaos.NewFailPods, &chaos.Props{ LabelsSelector: &map[string]*string{ChaosGroupMajority: ptr.Ptr("1")}, @@ -146,8 +171,8 @@ func TestAutomationChaos(t *testing.T) { }, }, PodChaosFailMajorityDB: { - ethereum.New(defaultEthereumSettings), - chainlink.New(0, defaultAutomationSettings), + ethereum.New(getDefaultEthereumSettings(&config)), + chainlinkCfg, chaos.NewFailPods, &chaos.Props{ LabelsSelector: &map[string]*string{ChaosGroupMajority: ptr.Ptr("1")}, @@ -156,8 +181,8 @@ func TestAutomationChaos(t *testing.T) { }, }, NetworkChaosFailMajorityNetwork: { - ethereum.New(defaultEthereumSettings), - chainlink.New(0, defaultAutomationSettings), + ethereum.New(getDefaultEthereumSettings(&config)), + chainlinkCfg, chaos.NewNetworkPartition, &chaos.Props{ FromLabels: &map[string]*string{ChaosGroupMajority: ptr.Ptr("1")}, @@ -166,8 +191,8 @@ func TestAutomationChaos(t *testing.T) { }, }, NetworkChaosFailBlockchainNode: { - ethereum.New(defaultEthereumSettings), - chainlink.New(0, defaultAutomationSettings), + ethereum.New(getDefaultEthereumSettings(&config)), + chainlinkCfg, chaos.NewNetworkPartition, &chaos.Props{ FromLabels: &map[string]*string{"app": ptr.Ptr("geth")}, @@ -182,7 +207,7 @@ func TestAutomationChaos(t *testing.T) { testCase := testCase t.Run(fmt.Sprintf("Automation_%s", name), func(t *testing.T) { t.Parallel() - network := networks.MustGetSelectedNetworksFromEnv()[0] // Need a new copy of the network for each test + network := networks.MustGetSelectedNetworkConfig(config.Network)[0] // Need a new copy of the network for each test testEnvironment := environment. New(&environment.Config{ @@ -224,7 +249,7 @@ func TestAutomationChaos(t *testing.T) { if chainClient != nil { chainClient.GasStats().PrintStats() } - err := actions.TeardownSuite(t, testEnvironment, chainlinkNodes, nil, zapcore.PanicLevel, chainClient) + err := actions.TeardownSuite(t, testEnvironment, chainlinkNodes, nil, zapcore.PanicLevel, &config, chainClient) require.NoError(t, err, "Error tearing down environment") }) diff --git a/integration-tests/chaos/ocr2vrf_chaos_test.go b/integration-tests/chaos/ocr2vrf_chaos_test.go index 200114ddaf..eda60a37f3 100644 --- a/integration-tests/chaos/ocr2vrf_chaos_test.go +++ b/integration-tests/chaos/ocr2vrf_chaos_test.go @@ -11,6 +11,7 @@ import ( "go.uber.org/zap/zapcore" "github.com/smartcontractkit/chainlink-testing-framework/blockchain" + ctf_config "github.com/smartcontractkit/chainlink-testing-framework/config" "github.com/smartcontractkit/chainlink-testing-framework/k8s/chaos" "github.com/smartcontractkit/chainlink-testing-framework/k8s/environment" "github.com/smartcontractkit/chainlink-testing-framework/k8s/pkg/helm/chainlink" @@ -26,17 +27,24 @@ import ( "github.com/smartcontractkit/chainlink/integration-tests/client" "github.com/smartcontractkit/chainlink/integration-tests/config" "github.com/smartcontractkit/chainlink/integration-tests/contracts" + tc "github.com/smartcontractkit/chainlink/integration-tests/testconfig" ) func TestOCR2VRFChaos(t *testing.T) { t.Parallel() l := logging.GetTestLogger(t) - loadedNetwork := networks.MustGetSelectedNetworksFromEnv()[0] + testconfig, err := tc.GetConfig("Chaos", tc.OCR2VRF) + if err != nil { + t.Fatal(err) + } + + loadedNetwork := networks.MustGetSelectedNetworkConfig(testconfig.Network)[0] defaultOCR2VRFSettings := map[string]interface{}{ "replicas": 6, "toml": networks.AddNetworkDetailedConfig( config.BaseOCR2Config, + testconfig.Pyroscope, config.DefaultOCR2VRFNetworkDetailTomlConfig, loadedNetwork, ), @@ -48,6 +56,13 @@ func TestOCR2VRFChaos(t *testing.T) { WsURLs: loadedNetwork.URLs, } + var overrideFn = func(_ interface{}, target interface{}) { + ctf_config.MustConfigOverrideChainlinkVersion(testconfig.ChainlinkImage, target) + ctf_config.MightConfigOverridePyroscopeKey(testconfig.Pyroscope, target) + } + + chainlinkCfg := chainlink.NewWithOverride(0, defaultOCR2VRFSettings, testconfig.ChainlinkImage, overrideFn) + testCases := map[string]struct { networkChart environment.ConnectedChart clChart environment.ConnectedChart @@ -65,7 +80,7 @@ func TestOCR2VRFChaos(t *testing.T) { //4. verify VRF request gets fulfilled PodChaosFailMinorityNodes: { ethereum.New(defaultOCR2VRFEthereumSettings), - chainlink.New(0, defaultOCR2VRFSettings), + chainlinkCfg, chaos.NewFailPods, &chaos.Props{ LabelsSelector: &map[string]*string{ChaosGroupMinority: ptr.Ptr("1")}, @@ -75,7 +90,7 @@ func TestOCR2VRFChaos(t *testing.T) { //todo - currently failing, need to investigate deeper //PodChaosFailMajorityNodes: { // ethereum.New(defaultOCR2VRFEthereumSettings), - // chainlink.New(0, defaultOCR2VRFSettings), + // chainlinkCfg, // chaos.NewFailPods, // &chaos.Props{ // LabelsSelector: &map[string]*string{ChaosGroupMajority: ptr.Ptr("1")}, @@ -85,7 +100,7 @@ func TestOCR2VRFChaos(t *testing.T) { //todo - do we need these chaos tests? //PodChaosFailMajorityDB: { // ethereum.New(defaultOCR2VRFEthereumSettings), - // chainlink.New(0, defaultOCR2VRFSettings), + // chainlinkCfg, // chaos.NewFailPods, // &chaos.Props{ // LabelsSelector: &map[string]*string{ChaosGroupMajority: ptr.Ptr("1")}, @@ -95,7 +110,7 @@ func TestOCR2VRFChaos(t *testing.T) { //}, //NetworkChaosFailMajorityNetwork: { // ethereum.New(defaultOCR2VRFEthereumSettings), - // chainlink.New(0, defaultOCR2VRFSettings), + // chainlinkCfg, // chaos.NewNetworkPartition, // &chaos.Props{ // FromLabels: &map[string]*string{ChaosGroupMajority: ptr.Ptr("1")}, @@ -105,7 +120,7 @@ func TestOCR2VRFChaos(t *testing.T) { //}, //NetworkChaosFailBlockchainNode: { // ethereum.New(defaultOCR2VRFEthereumSettings), - // chainlink.New(0, defaultOCR2VRFSettings), + // chainlinkCfg, // chaos.NewNetworkPartition, // &chaos.Props{ // FromLabels: &map[string]*string{"app": ptr.Ptr("geth")}, @@ -119,7 +134,7 @@ func TestOCR2VRFChaos(t *testing.T) { testCase := tc t.Run(fmt.Sprintf("OCR2VRF_%s", testCaseName), func(t *testing.T) { t.Parallel() - testNetwork := networks.MustGetSelectedNetworksFromEnv()[0] // Need a new copy of the network for each test + testNetwork := networks.MustGetSelectedNetworkConfig(testconfig.Network)[0] // Need a new copy of the network for each test testEnvironment := environment. New(&environment.Config{ NamespacePrefix: fmt.Sprintf( @@ -150,7 +165,7 @@ func TestOCR2VRFChaos(t *testing.T) { require.NoError(t, err, "Retrieving on-chain wallet addresses for chainlink nodes shouldn't fail") t.Cleanup(func() { - err := actions.TeardownSuite(t, testEnvironment, chainlinkNodes, nil, zapcore.PanicLevel, chainClient) + err := actions.TeardownSuite(t, testEnvironment, chainlinkNodes, nil, zapcore.PanicLevel, &testconfig, chainClient) require.NoError(t, err, "Error tearing down environment") }) diff --git a/integration-tests/chaos/ocr_chaos_test.go b/integration-tests/chaos/ocr_chaos_test.go index a59a0a028c..97f7c67d1b 100644 --- a/integration-tests/chaos/ocr_chaos_test.go +++ b/integration-tests/chaos/ocr_chaos_test.go @@ -3,7 +3,6 @@ package chaos import ( "fmt" "math/big" - "os" "testing" "github.com/onsi/gomega" @@ -12,6 +11,7 @@ import ( "github.com/smartcontractkit/chainlink-testing-framework/blockchain" ctfClient "github.com/smartcontractkit/chainlink-testing-framework/client" + ctf_config "github.com/smartcontractkit/chainlink-testing-framework/config" "github.com/smartcontractkit/chainlink-testing-framework/k8s/chaos" "github.com/smartcontractkit/chainlink-testing-framework/k8s/environment" "github.com/smartcontractkit/chainlink-testing-framework/k8s/pkg/helm/chainlink" @@ -25,8 +25,8 @@ import ( "github.com/smartcontractkit/chainlink/integration-tests/actions" "github.com/smartcontractkit/chainlink/integration-tests/client" - "github.com/smartcontractkit/chainlink/integration-tests/config" "github.com/smartcontractkit/chainlink/integration-tests/contracts" + tc "github.com/smartcontractkit/chainlink/integration-tests/testconfig" ) var ( @@ -51,14 +51,26 @@ var ( chaosEndRound int64 = 4 ) -func TestMain(m *testing.M) { - defaultOCRSettings["toml"] = networks.AddNetworksConfig(config.BaseOCR1Config, networks.MustGetSelectedNetworksFromEnv()[0]) - os.Exit(m.Run()) +func getDefaultOcrSettings(config *tc.TestConfig) map[string]interface{} { + defaultOCRSettings["toml"] = networks.AddNetworksConfig(baseTOML, config.Pyroscope, networks.MustGetSelectedNetworkConfig(config.Network)[0]) + return defaultAutomationSettings } func TestOCRChaos(t *testing.T) { t.Parallel() l := logging.GetTestLogger(t) + config, err := tc.GetConfig("Chaos", tc.OCR) + if err != nil { + t.Fatal(err) + } + + var overrideFn = func(_ interface{}, target interface{}) { + ctf_config.MustConfigOverrideChainlinkVersion(config.ChainlinkImage, target) + ctf_config.MightConfigOverridePyroscopeKey(config.Pyroscope, target) + } + + chainlinkCfg := chainlink.NewWithOverride(0, getDefaultOcrSettings(&config), config.ChainlinkImage, overrideFn) + testCases := map[string]struct { networkChart environment.ConnectedChart clChart environment.ConnectedChart @@ -77,7 +89,7 @@ func TestOCRChaos(t *testing.T) { // https://github.com/smartcontractkit/chainlink-testing-framework/k8s/blob/master/README.md NetworkChaosFailMajorityNetwork: { ethereum.New(nil), - chainlink.New(0, defaultOCRSettings), + chainlinkCfg, chaos.NewNetworkPartition, &chaos.Props{ FromLabels: &map[string]*string{ChaosGroupMajority: ptr.Ptr("1")}, @@ -87,7 +99,7 @@ func TestOCRChaos(t *testing.T) { }, NetworkChaosFailBlockchainNode: { ethereum.New(nil), - chainlink.New(0, defaultOCRSettings), + chainlinkCfg, chaos.NewNetworkPartition, &chaos.Props{ FromLabels: &map[string]*string{"app": ptr.Ptr("geth")}, @@ -97,7 +109,7 @@ func TestOCRChaos(t *testing.T) { }, PodChaosFailMinorityNodes: { ethereum.New(nil), - chainlink.New(0, defaultOCRSettings), + chainlinkCfg, chaos.NewFailPods, &chaos.Props{ LabelsSelector: &map[string]*string{ChaosGroupMinority: ptr.Ptr("1")}, @@ -106,7 +118,7 @@ func TestOCRChaos(t *testing.T) { }, PodChaosFailMajorityNodes: { ethereum.New(nil), - chainlink.New(0, defaultOCRSettings), + chainlinkCfg, chaos.NewFailPods, &chaos.Props{ LabelsSelector: &map[string]*string{ChaosGroupMajority: ptr.Ptr("1")}, @@ -115,7 +127,7 @@ func TestOCRChaos(t *testing.T) { }, PodChaosFailMajorityDB: { ethereum.New(nil), - chainlink.New(0, defaultOCRSettings), + chainlinkCfg, chaos.NewFailPods, &chaos.Props{ LabelsSelector: &map[string]*string{ChaosGroupMajority: ptr.Ptr("1")}, @@ -164,7 +176,7 @@ func TestOCRChaos(t *testing.T) { if chainClient != nil { chainClient.GasStats().PrintStats() } - err := actions.TeardownSuite(t, testEnvironment, chainlinkNodes, nil, zapcore.PanicLevel, chainClient) + err := actions.TeardownSuite(t, testEnvironment, chainlinkNodes, nil, zapcore.PanicLevel, &config, chainClient) require.NoError(t, err, "Error tearing down environment") }) diff --git a/integration-tests/client/chainlink_k8s.go b/integration-tests/client/chainlink_k8s.go index 27fd956103..ab4ce34158 100644 --- a/integration-tests/client/chainlink_k8s.go +++ b/integration-tests/client/chainlink_k8s.go @@ -2,7 +2,6 @@ package client import ( - "fmt" "os" "regexp" @@ -42,16 +41,8 @@ func NewChainlinkK8sClient(c *ChainlinkConfig, podName, chartName string) (*Chai // Note: You need to call Run() on the test environment for changes to take effect // Note: This function is not thread safe, call from a single thread func (c *ChainlinkK8sClient) UpgradeVersion(testEnvironment *environment.Environment, newImage, newVersion string) error { - if newVersion == "" { - return fmt.Errorf("new version is empty") - } - if newImage == "" { - newImage = os.Getenv("CHAINLINK_IMAGE") - } log.Info(). Str("Chart Name", c.ChartName). - Str("Old Image", os.Getenv("CHAINLINK_IMAGE")). - Str("Old Version", os.Getenv("CHAINLINK_VERSION")). Str("New Image", newImage). Str("New Version", newVersion). Msg("Upgrading Chainlink Node") diff --git a/integration-tests/client/chainlink_models.go b/integration-tests/client/chainlink_models.go index e6e1de25e4..665ff3c746 100644 --- a/integration-tests/client/chainlink_models.go +++ b/integration-tests/client/chainlink_models.go @@ -6,6 +6,7 @@ import ( "text/template" "time" + "github.com/pelletier/go-toml/v2" "gopkg.in/guregu/null.v4" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" @@ -628,7 +629,9 @@ func (d *PipelineSpec) String() (string, error) { // VRFV2TxPipelineSpec VRFv2 request with tx callback type VRFV2PlusTxPipelineSpec struct { - Address string + Address string + EstimateGasMultiplier float64 + FromAddress string } // Type returns the type of the pipeline @@ -650,9 +653,10 @@ generate_proof [type=vrfv2plus topics="$(jobRun.logTopics)"] estimate_gas [type=estimategaslimit to="{{ .Address }}" - multiplier="1.1" + multiplier="{{ .EstimateGasMultiplier }}" data="$(generate_proof.output)"] simulate_fulfillment [type=ethcall + from="{{ .FromAddress }}" to="{{ .Address }}" gas="$(estimate_gas)" gasPrice="$(jobSpec.maxGasPrice)" @@ -665,7 +669,9 @@ decode_log->generate_proof->estimate_gas->simulate_fulfillment` // VRFV2TxPipelineSpec VRFv2 request with tx callback type VRFV2TxPipelineSpec struct { - Address string + Address string + EstimateGasMultiplier float64 + FromAddress string } // Type returns the type of the pipeline @@ -687,9 +693,10 @@ vrf [type=vrfv2 topics="$(jobRun.logTopics)"] estimate_gas [type=estimategaslimit to="{{ .Address }}" - multiplier="1.1" + multiplier="{{ .EstimateGasMultiplier }}" data="$(vrf.output)"] simulate [type=ethcall + from="{{ .FromAddress }}" to="{{ .Address }}" gas="$(estimate_gas)" gasPrice="$(jobSpec.maxGasPrice)" @@ -1027,6 +1034,12 @@ func (o *OCR2TaskJobSpec) String() (string, error) { if o.OCR2OracleSpec.FeedID != nil { feedID = o.OCR2OracleSpec.FeedID.Hex() } + relayConfig, err := toml.Marshal(struct { + RelayConfig job.JSONConfig `toml:"relayConfig"` + }{RelayConfig: o.OCR2OracleSpec.RelayConfig}) + if err != nil { + return "", fmt.Errorf("failed to marshal relay config: %w", err) + } specWrap := struct { Name string JobType string @@ -1036,7 +1049,7 @@ func (o *OCR2TaskJobSpec) String() (string, error) { FeedID string Relay string PluginType string - RelayConfig map[string]interface{} + RelayConfig string PluginConfig map[string]interface{} P2PV2Bootstrappers []string OCRKeyBundleID string @@ -1056,7 +1069,7 @@ func (o *OCR2TaskJobSpec) String() (string, error) { FeedID: feedID, Relay: string(o.OCR2OracleSpec.Relay), PluginType: string(o.OCR2OracleSpec.PluginType), - RelayConfig: o.OCR2OracleSpec.RelayConfig, + RelayConfig: string(relayConfig), PluginConfig: o.OCR2OracleSpec.PluginConfig, P2PV2Bootstrappers: o.OCR2OracleSpec.P2PV2Bootstrappers, OCRKeyBundleID: o.OCR2OracleSpec.OCRKeyBundleID.String, @@ -1071,37 +1084,37 @@ func (o *OCR2TaskJobSpec) String() (string, error) { type = "{{ .JobType }}" name = "{{.Name}}" forwardingAllowed = {{.ForwardingAllowed}} -{{if .MaxTaskDuration}} +{{- if .MaxTaskDuration}} maxTaskDuration = "{{ .MaxTaskDuration }}" {{end}} -{{if .PluginType}} +{{- if .PluginType}} pluginType = "{{ .PluginType }}" {{end}} relay = "{{.Relay}}" schemaVersion = 1 contractID = "{{.ContractID}}" -{{if .FeedID}} +{{- if .FeedID}} feedID = "{{.FeedID}}" {{end}} -{{if eq .JobType "offchainreporting2" }} +{{- if eq .JobType "offchainreporting2" }} ocrKeyBundleID = "{{.OCRKeyBundleID}}" {{end}} -{{if eq .JobType "offchainreporting2" }} +{{- if eq .JobType "offchainreporting2" }} transmitterID = "{{.TransmitterID}}" {{end}} -{{if .BlockchainTimeout}} +{{- if .BlockchainTimeout}} blockchainTimeout = "{{.BlockchainTimeout}}" {{end}} -{{if .ContractConfirmations}} +{{- if .ContractConfirmations}} contractConfigConfirmations = {{.ContractConfirmations}} {{end}} -{{if .TrackerPollInterval}} +{{- if .TrackerPollInterval}} contractConfigTrackerPollInterval = "{{.TrackerPollInterval}}" {{end}} -{{if .TrackerSubscribeInterval}} +{{- if .TrackerSubscribeInterval}} contractConfigTrackerSubscribeInterval = "{{.TrackerSubscribeInterval}}" {{end}} -{{if .P2PV2Bootstrappers}} +{{- if .P2PV2Bootstrappers}} p2pv2Bootstrappers = [{{range .P2PV2Bootstrappers}}"{{.}}",{{end}}]{{end}} -{{if .MonitoringEndpoint}} +{{- if .MonitoringEndpoint}} monitoringEndpoint = "{{.MonitoringEndpoint}}" {{end}} -{{if .ObservationSource}} +{{- if .ObservationSource}} observationSource = """ {{.ObservationSource}} """{{end}} @@ -1109,26 +1122,28 @@ observationSource = """ [pluginConfig]{{range $key, $value := .PluginConfig}} {{$key}} = {{$value}}{{end}} {{end}} -[relayConfig]{{range $key, $value := .RelayConfig}} -{{$key}} = {{$value}}{{end}} +{{.RelayConfig}} ` return MarshallTemplate(specWrap, "OCR2 Job", ocr2TemplateString) } // VRFV2PlusJobSpec represents a VRFV2 job type VRFV2PlusJobSpec struct { - Name string `toml:"name"` - CoordinatorAddress string `toml:"coordinatorAddress"` // Address of the VRF CoordinatorV2 contract - PublicKey string `toml:"publicKey"` // Public key of the proving key - ExternalJobID string `toml:"externalJobID"` - ObservationSource string `toml:"observationSource"` // List of commands for the Chainlink node - MinIncomingConfirmations int `toml:"minIncomingConfirmations"` - FromAddresses []string `toml:"fromAddresses"` - EVMChainID string `toml:"evmChainID"` - BatchFulfillmentEnabled bool `toml:"batchFulfillmentEnabled"` - BackOffInitialDelay time.Duration `toml:"backOffInitialDelay"` - BackOffMaxDelay time.Duration `toml:"backOffMaxDelay"` - PollPeriod time.Duration `toml:"pollPeriod"` + Name string `toml:"name"` + CoordinatorAddress string `toml:"coordinatorAddress"` // Address of the VRF CoordinatorV2 contract + PublicKey string `toml:"publicKey"` // Public key of the proving key + ExternalJobID string `toml:"externalJobID"` + ObservationSource string `toml:"observationSource"` // List of commands for the Chainlink node + MinIncomingConfirmations int `toml:"minIncomingConfirmations"` + FromAddresses []string `toml:"fromAddresses"` + EVMChainID string `toml:"evmChainID"` + ForwardingAllowed bool `toml:"forwardingAllowed"` + BatchFulfillmentEnabled bool `toml:"batchFulfillmentEnabled"` + BatchFulfillmentGasMultiplier float64 `toml:"batchFulfillmentGasMultiplier"` + BackOffInitialDelay time.Duration `toml:"backOffInitialDelay"` + BackOffMaxDelay time.Duration `toml:"backOffMaxDelay"` + PollPeriod time.Duration `toml:"pollPeriod"` + RequestTimeout time.Duration `toml:"requestTimeout"` } // Type returns the type of the job @@ -1147,8 +1162,11 @@ minIncomingConfirmations = {{.MinIncomingConfirmations}} publicKey = "{{.PublicKey}}" externalJobID = "{{.ExternalJobID}}" batchFulfillmentEnabled = {{.BatchFulfillmentEnabled}} +batchFulfillmentGasMultiplier = {{.BatchFulfillmentGasMultiplier}} backoffInitialDelay = "{{.BackOffInitialDelay}}" backoffMaxDelay = "{{.BackOffMaxDelay}}" +pollPeriod = "{{.PollPeriod}}" +requestTimeout = "{{.RequestTimeout}}" observationSource = """ {{.ObservationSource}} """ @@ -1158,17 +1176,24 @@ observationSource = """ // VRFV2JobSpec represents a VRFV2 job type VRFV2JobSpec struct { - Name string `toml:"name"` - CoordinatorAddress string `toml:"coordinatorAddress"` // Address of the VRF CoordinatorV2 contract - PublicKey string `toml:"publicKey"` // Public key of the proving key - ExternalJobID string `toml:"externalJobID"` - ObservationSource string `toml:"observationSource"` // List of commands for the Chainlink node - MinIncomingConfirmations int `toml:"minIncomingConfirmations"` - FromAddresses []string `toml:"fromAddresses"` - EVMChainID string `toml:"evmChainID"` - BatchFulfillmentEnabled bool `toml:"batchFulfillmentEnabled"` - BackOffInitialDelay time.Duration `toml:"backOffInitialDelay"` - BackOffMaxDelay time.Duration `toml:"backOffMaxDelay"` + Name string `toml:"name"` + CoordinatorAddress string `toml:"coordinatorAddress"` // Address of the VRF CoordinatorV2 contract + PublicKey string `toml:"publicKey"` // Public key of the proving key + ExternalJobID string `toml:"externalJobID"` + ObservationSource string `toml:"observationSource"` // List of commands for the Chainlink node + MinIncomingConfirmations int `toml:"minIncomingConfirmations"` + FromAddresses []string `toml:"fromAddresses"` + EVMChainID string `toml:"evmChainID"` + UseVRFOwner bool `toml:"useVRFOwner"` + VRFOwner string `toml:"vrfOwnerAddress"` + ForwardingAllowed bool `toml:"forwardingAllowed"` + CustomRevertsPipelineEnabled bool `toml:"customRevertsPipelineEnabled"` + PollPeriod time.Duration `toml:"pollPeriod"` + RequestTimeout time.Duration `toml:"requestTimeout"` + BatchFulfillmentEnabled bool `toml:"batchFulfillmentEnabled"` + BatchFulfillmentGasMultiplier float64 `toml:"batchFulfillmentGasMultiplier"` + BackOffInitialDelay time.Duration `toml:"backOffInitialDelay"` + BackOffMaxDelay time.Duration `toml:"backOffMaxDelay"` } // Type returns the type of the job @@ -1180,6 +1205,7 @@ func (v *VRFV2JobSpec) String() (string, error) { type = "vrf" schemaVersion = 1 name = "{{.Name}}" +forwardingAllowed = {{.ForwardingAllowed}} coordinatorAddress = "{{.CoordinatorAddress}}" fromAddresses = [{{range .FromAddresses}}"{{.}}",{{end}}] evmChainID = "{{.EVMChainID}}" @@ -1187,8 +1213,13 @@ minIncomingConfirmations = {{.MinIncomingConfirmations}} publicKey = "{{.PublicKey}}" externalJobID = "{{.ExternalJobID}}" batchFulfillmentEnabled = {{.BatchFulfillmentEnabled}} +batchFulfillmentGasMultiplier = {{.BatchFulfillmentGasMultiplier}} backoffInitialDelay = "{{.BackOffInitialDelay}}" backoffMaxDelay = "{{.BackOffMaxDelay}}" +pollPeriod = "{{.PollPeriod}}" +requestTimeout = "{{.RequestTimeout}}" +customRevertsPipelineEnabled = true +{{ if .UseVRFOwner }}vrfOwnerAddress = "{{.VRFOwner}}"{{ else }}{{ end }} observationSource = """ {{.ObservationSource}} """ diff --git a/integration-tests/client/chainlink_models_test.go b/integration-tests/client/chainlink_models_test.go new file mode 100644 index 0000000000..5dbac2c27c --- /dev/null +++ b/integration-tests/client/chainlink_models_test.go @@ -0,0 +1,135 @@ +package client + +import ( + "testing" + + "github.com/stretchr/testify/require" + + "github.com/smartcontractkit/chainlink-common/pkg/codec" + "github.com/smartcontractkit/chainlink/v2/core/services/job" + evmtypes "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/types" +) + +func TestOCR2TaskJobSpec_String(t *testing.T) { + for _, tt := range []struct { + name string + spec OCR2TaskJobSpec + exp string + }{ + { + name: "chain-reader-codec", + spec: OCR2TaskJobSpec{ + OCR2OracleSpec: job.OCR2OracleSpec{ + RelayConfig: map[string]interface{}{ + "chainID": 1337, + "fromBlock": 42, + "chainReader": evmtypes.ChainReaderConfig{ + Contracts: map[string]evmtypes.ChainContractReader{ + "median": { + ContractABI: `[ + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "requester", + "type": "address" + } + ], + "name": "RoundRequested", + "type": "event" + } +] +`, + Configs: map[string]*evmtypes.ChainReaderDefinition{ + "LatestTransmissionDetails": { + ChainSpecificName: "latestTransmissionDetails", + OutputModifications: codec.ModifiersConfig{ + &codec.EpochToTimeModifierConfig{ + Fields: []string{"LatestTimestamp_"}, + }, + &codec.RenameModifierConfig{ + Fields: map[string]string{ + "LatestAnswer_": "LatestAnswer", + "LatestTimestamp_": "LatestTimestamp", + }, + }, + }, + }, + "LatestRoundRequested": { + ChainSpecificName: "RoundRequested", + ReadType: evmtypes.Event, + }, + }, + }, + }, + }, + "codec": evmtypes.CodecConfig{ + Configs: map[string]evmtypes.ChainCodecConfig{ + "MedianReport": { + TypeABI: `[ + { + "Name": "Timestamp", + "Type": "uint32" + } +] +`, + }, + }, + }, + }, + PluginConfig: map[string]interface{}{"juelsPerFeeCoinSource": ` // data source 1 + ds1 [type=bridge name="%s"]; + ds1_parse [type=jsonparse path="data"]; + ds1_multiply [type=multiply times=2]; + + // data source 2 + ds2 [type=http method=GET url="%s"]; + ds2_parse [type=jsonparse path="data"]; + ds2_multiply [type=multiply times=2]; + + ds1 -> ds1_parse -> ds1_multiply -> answer1; + ds2 -> ds2_parse -> ds2_multiply -> answer1; + + answer1 [type=median index=0]; +`, + }, + }, + }, + exp: ` +type = "" +name = "" +forwardingAllowed = false +relay = "" +schemaVersion = 1 +contractID = "" + +[relayConfig] +chainID = 1337 +fromBlock = 42 + +[relayConfig.chainReader] +[relayConfig.chainReader.contracts] +[relayConfig.chainReader.contracts.median] +contractABI = "[\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"requester\",\n \"type\": \"address\"\n }\n ],\n \"name\": \"RoundRequested\",\n \"type\": \"event\"\n }\n]\n" + +[relayConfig.chainReader.contracts.median.configs] +LatestRoundRequested = "{\n \"chainSpecificName\": \"RoundRequested\",\n \"readType\": \"event\"\n}\n" +LatestTransmissionDetails = "{\n \"chainSpecificName\": \"latestTransmissionDetails\",\n \"output_modifications\": [\n {\n \"Fields\": [\n \"LatestTimestamp_\"\n ],\n \"Type\": \"epoch to time\"\n },\n {\n \"Fields\": {\n \"LatestAnswer_\": \"LatestAnswer\",\n \"LatestTimestamp_\": \"LatestTimestamp\"\n },\n \"Type\": \"rename\"\n }\n ]\n}\n" + +[relayConfig.codec] +[relayConfig.codec.configs] +[relayConfig.codec.configs.MedianReport] +typeABI = "[\n {\n \"Name\": \"Timestamp\",\n \"Type\": \"uint32\"\n }\n]\n" + +`, + }, + } { + t.Run(tt.name, func(t *testing.T) { + got, err := tt.spec.String() + require.NoError(t, err) + require.Equal(t, tt.exp, got) + }) + } +} diff --git a/integration-tests/contracts/contract_deployer.go b/integration-tests/contracts/contract_deployer.go index 40694aa5e4..2acc0a2109 100644 --- a/integration-tests/contracts/contract_deployer.go +++ b/integration-tests/contracts/contract_deployer.go @@ -21,6 +21,7 @@ import ( ocrConfigHelper "github.com/smartcontractkit/libocr/offchainreporting/confighelper" "github.com/smartcontractkit/chainlink-testing-framework/blockchain" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/vrf_mock_ethlink_aggregator" "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" @@ -87,6 +88,7 @@ type ContractDeployer interface { LoadOffChainAggregator(address *common.Address) (OffchainAggregator, error) DeployVRFContract() (VRF, error) DeployMockETHLINKFeed(answer *big.Int) (MockETHLINKFeed, error) + DeployVRFMockETHLINKFeed(answer *big.Int) (VRFMockETHLINKFeed, error) LoadETHLINKFeed(address common.Address) (MockETHLINKFeed, error) DeployMockGasFeed(answer *big.Int) (MockGasFeed, error) LoadGasFeed(address common.Address) (MockGasFeed, error) @@ -113,6 +115,8 @@ type ContractDeployer interface { DeployUpkeepCounter(testRange *big.Int, interval *big.Int) (UpkeepCounter, error) DeployUpkeepPerformCounterRestrictive(testRange *big.Int, averageEligibilityCadence *big.Int) (UpkeepPerformCounterRestrictive, error) DeployVRFConsumer(linkAddr string, coordinatorAddr string) (VRFConsumer, error) + DeployVRFOwner(coordinatorAddr string) (VRFOwner, error) + DeployVRFCoordinatorTestV2(linkAddr string, bhsAddr string, linkEthFeedAddr string) (*EthereumVRFCoordinatorTestV2, error) DeployVRFConsumerV2(linkAddr string, coordinatorAddr string) (VRFConsumerV2, error) DeployVRFv2Consumer(coordinatorAddr string) (VRFv2Consumer, error) DeployVRFv2LoadTestConsumer(coordinatorAddr string) (VRFv2LoadTestConsumer, error) @@ -700,6 +704,23 @@ func (e *EthereumContractDeployer) DeployMockETHLINKFeed(answer *big.Int) (MockE }, err } +func (e *EthereumContractDeployer) DeployVRFMockETHLINKFeed(answer *big.Int) (VRFMockETHLINKFeed, error) { + address, _, instance, err := e.client.DeployContract("VRFMockETHLINKAggregator", func( + auth *bind.TransactOpts, + backend bind.ContractBackend, + ) (common.Address, *types.Transaction, interface{}, error) { + return vrf_mock_ethlink_aggregator.DeployVRFMockETHLINKAggregator(auth, backend, answer) + }) + if err != nil { + return nil, err + } + return &EthereumVRFMockETHLINKFeed{ + client: e.client, + feed: instance.(*vrf_mock_ethlink_aggregator.VRFMockETHLINKAggregator), + address: address, + }, err +} + // LoadETHLINKFeed returns deployed on given address EthereumMockETHLINKFeed func (e *EthereumContractDeployer) LoadETHLINKFeed(address common.Address) (MockETHLINKFeed, error) { instance, err := e.client.LoadContract("MockETHLINKFeed", address, func( diff --git a/integration-tests/contracts/contract_vrf_models.go b/integration-tests/contracts/contract_vrf_models.go index 44bc3ec2a2..2faf97df16 100644 --- a/integration-tests/contracts/contract_vrf_models.go +++ b/integration-tests/contracts/contract_vrf_models.go @@ -11,6 +11,7 @@ import ( "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_owner" "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" @@ -38,6 +39,9 @@ type VRFCoordinator interface { type VRFCoordinatorV2 interface { GetRequestConfig(ctx context.Context) (GetRequestConfig, error) + GetConfig(ctx context.Context) (vrf_coordinator_v2.GetConfig, error) + GetFallbackWeiPerUnitLink(ctx context.Context) (*big.Int, error) + GetFeeConfig(ctx context.Context) (vrf_coordinator_v2.GetFeeConfig, error) SetConfig( minimumRequestConfirmations uint16, maxGasLimit uint32, @@ -50,11 +54,13 @@ type VRFCoordinatorV2 interface { oracleAddr string, publicProvingKey [2]*big.Int, ) error + TransferOwnership(to common.Address) error HashOfKey(ctx context.Context, pubKey [2]*big.Int) ([32]byte, error) CreateSubscription() (*types.Transaction, error) AddConsumer(subId uint64, consumerAddress string) error Address() string GetSubscription(ctx context.Context, subID uint64) (vrf_coordinator_v2.GetSubscription, error) + GetOwner(ctx context.Context) (common.Address, error) PendingRequestsExist(ctx context.Context, subID uint64) (bool, error) OwnerCancelSubscription(subID uint64) (*types.Transaction, error) CancelSubscription(subID uint64, to common.Address) (*types.Transaction, error) @@ -62,6 +68,11 @@ type VRFCoordinatorV2 interface { WaitForRandomWordsFulfilledEvent(requestID []*big.Int, timeout time.Duration) (*vrf_coordinator_v2.VRFCoordinatorV2RandomWordsFulfilled, error) WaitForRandomWordsRequestedEvent(keyHash [][32]byte, subID []uint64, sender []common.Address, timeout time.Duration) (*vrf_coordinator_v2.VRFCoordinatorV2RandomWordsRequested, error) WaitForSubscriptionCanceledEvent(subID []uint64, timeout time.Duration) (*vrf_coordinator_v2.VRFCoordinatorV2SubscriptionCanceled, error) + WaitForSubscriptionConsumerAdded(subID []uint64, timeout time.Duration) (*vrf_coordinator_v2.VRFCoordinatorV2SubscriptionConsumerAdded, error) + WaitForSubscriptionConsumerRemoved(subID []uint64, timeout time.Duration) (*vrf_coordinator_v2.VRFCoordinatorV2SubscriptionConsumerRemoved, error) + WaitForSubscriptionCreatedEvent(subID []uint64, timeout time.Duration) (*vrf_coordinator_v2.VRFCoordinatorV2SubscriptionCreated, error) + WaitForSubscriptionFunded(subID []uint64, timeout time.Duration) (*vrf_coordinator_v2.VRFCoordinatorV2SubscriptionFunded, error) + WaitForConfigSetEvent(timeout time.Duration) (*vrf_coordinator_v2.VRFCoordinatorV2ConfigSet, error) OracleWithdraw(recipient common.Address, amount *big.Int) error } @@ -150,6 +161,13 @@ type VRFV2PlusWrapper interface { GetSubID(ctx context.Context) (*big.Int, error) } +type VRFOwner interface { + Address() string + SetAuthorizedSenders(senders []common.Address) error + AcceptVRFOwnership() error + WaitForRandomWordsForcedEvent(requestIDs []*big.Int, subIds []uint64, senders []common.Address, timeout time.Duration) (*vrf_owner.VRFOwnerRandomWordsForced, error) +} + type VRFConsumer interface { Address() string RequestRandomness(hash [32]byte, fee *big.Int) error @@ -180,6 +198,15 @@ type VRFv2Consumer interface { type VRFv2LoadTestConsumer interface { Address() string RequestRandomness(hash [32]byte, subID uint64, confs uint16, gasLimit uint32, numWords uint32, requestCount uint16) (*types.Transaction, error) + RequestRandomWordsWithForceFulfill( + keyHash [32]byte, + requestConfirmations uint16, + callbackGasLimit uint32, + numWords uint32, + requestCount uint16, + subTopUpAmount *big.Int, + linkAddress common.Address, + ) (*types.Transaction, error) GetRequestStatus(ctx context.Context, requestID *big.Int) (vrf_load_test_with_metrics.GetRequestStatus, error) GetLastRequestId(ctx context.Context) (*big.Int, error) GetLoadTestMetrics(ctx context.Context) (*VRFLoadTestMetrics, error) @@ -281,6 +308,13 @@ type BatchBlockhashStore interface { Address() string } +type VRFMockETHLINKFeed interface { + Address() string + LatestRoundData() (*big.Int, error) + LatestRoundDataUpdatedAt() (*big.Int, error) + SetBlockTimestampDeduction(blockTimestampDeduction *big.Int) error +} + type RequestStatus struct { Fulfilled bool RandomWords []*big.Int diff --git a/integration-tests/contracts/ethereum_keeper_contracts.go b/integration-tests/contracts/ethereum_keeper_contracts.go index ad191d65d1..a15fcfc7ae 100644 --- a/integration-tests/contracts/ethereum_keeper_contracts.go +++ b/integration-tests/contracts/ethereum_keeper_contracts.go @@ -19,7 +19,6 @@ import ( "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/chains/evm/utils" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/automation_consumer_benchmark" @@ -42,6 +41,7 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/upkeep_transcoder" "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" diff --git a/integration-tests/contracts/ethereum_vrfv2_contracts.go b/integration-tests/contracts/ethereum_vrfv2_contracts.go index 579174e07c..7501521ac3 100644 --- a/integration-tests/contracts/ethereum_vrfv2_contracts.go +++ b/integration-tests/contracts/ethereum_vrfv2_contracts.go @@ -14,6 +14,9 @@ import ( "github.com/rs/zerolog/log" "github.com/smartcontractkit/chainlink-testing-framework/blockchain" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/vrf_coordinator_test_v2" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/vrf_mock_ethlink_aggregator" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/vrf_owner" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/vrf_consumer_v2" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/vrf_coordinator_v2" @@ -31,6 +34,18 @@ type EthereumVRFCoordinatorV2 struct { coordinator *vrf_coordinator_v2.VRFCoordinatorV2 } +type EthereumVRFOwner struct { + address *common.Address + client blockchain.EVMClient + vrfOwner *vrf_owner.VRFOwner +} + +type EthereumVRFCoordinatorTestV2 struct { + address *common.Address + client blockchain.EVMClient + coordinator *vrf_coordinator_test_v2.VRFCoordinatorTestV2 +} + // EthereumVRFConsumerV2 represents VRFv2 consumer contract type EthereumVRFConsumerV2 struct { address *common.Address @@ -70,6 +85,12 @@ type GetRequestConfig struct { ProvingKeyHashes [32]byte } +type EthereumVRFMockETHLINKFeed struct { + client blockchain.EVMClient + feed *vrf_mock_ethlink_aggregator.VRFMockETHLINKAggregator + address *common.Address +} + // DeployVRFCoordinatorV2 deploys VRFV2 coordinator contract func (e *EthereumContractDeployer) DeployVRFCoordinatorV2(linkAddr string, bhsAddr string, linkEthFeedAddr string) (VRFCoordinatorV2, error) { address, _, instance, err := e.client.DeployContract("VRFCoordinatorV2", func( @@ -88,6 +109,40 @@ func (e *EthereumContractDeployer) DeployVRFCoordinatorV2(linkAddr string, bhsAd }, err } +func (e *EthereumContractDeployer) DeployVRFOwner(coordinatorAddr string) (VRFOwner, error) { + address, _, instance, err := e.client.DeployContract("VRFOwner", func( + auth *bind.TransactOpts, + backend bind.ContractBackend, + ) (common.Address, *types.Transaction, interface{}, error) { + return vrf_owner.DeployVRFOwner(auth, backend, common.HexToAddress(coordinatorAddr)) + }) + if err != nil { + return nil, err + } + return &EthereumVRFOwner{ + client: e.client, + vrfOwner: instance.(*vrf_owner.VRFOwner), + address: address, + }, err +} + +func (e *EthereumContractDeployer) DeployVRFCoordinatorTestV2(linkAddr string, bhsAddr string, linkEthFeedAddr string) (*EthereumVRFCoordinatorTestV2, error) { + address, _, instance, err := e.client.DeployContract("VRFCoordinatorTestV2", func( + auth *bind.TransactOpts, + backend bind.ContractBackend, + ) (common.Address, *types.Transaction, interface{}, error) { + return vrf_coordinator_test_v2.DeployVRFCoordinatorTestV2(auth, backend, common.HexToAddress(linkAddr), common.HexToAddress(bhsAddr), common.HexToAddress(linkEthFeedAddr)) + }) + if err != nil { + return nil, err + } + return &EthereumVRFCoordinatorTestV2{ + client: e.client, + coordinator: instance.(*vrf_coordinator_test_v2.VRFCoordinatorTestV2), + address: address, + }, err +} + // DeployVRFConsumerV2 deploys VRFv@ consumer contract func (e *EthereumContractDeployer) DeployVRFConsumerV2(linkAddr string, coordinatorAddr string) (VRFConsumerV2, error) { address, _, instance, err := e.client.DeployContract("VRFConsumerV2", func( @@ -203,6 +258,18 @@ func (v *EthereumVRFCoordinatorV2) GetSubscription(ctx context.Context, subID ui return subscription, nil } +func (v *EthereumVRFCoordinatorV2) GetOwner(ctx context.Context) (common.Address, error) { + opts := &bind.CallOpts{ + From: common.HexToAddress(v.client.GetDefaultWallet().Address()), + Context: ctx, + } + coordinatorOwnerAddress, err := v.coordinator.Owner(opts) + if err != nil { + return common.Address{}, err + } + return coordinatorOwnerAddress, nil +} + func (v *EthereumVRFCoordinatorV2) GetRequestConfig(ctx context.Context) (GetRequestConfig, error) { opts := &bind.CallOpts{ From: common.HexToAddress(v.client.GetDefaultWallet().Address()), @@ -221,6 +288,42 @@ func (v *EthereumVRFCoordinatorV2) GetRequestConfig(ctx context.Context) (GetReq return requestConfig, nil } +func (v *EthereumVRFCoordinatorV2) GetConfig(ctx context.Context) (vrf_coordinator_v2.GetConfig, error) { + opts := &bind.CallOpts{ + From: common.HexToAddress(v.client.GetDefaultWallet().Address()), + Context: ctx, + } + config, err := v.coordinator.GetConfig(opts) + if err != nil { + return vrf_coordinator_v2.GetConfig{}, err + } + return config, nil +} + +func (v *EthereumVRFCoordinatorV2) GetFallbackWeiPerUnitLink(ctx context.Context) (*big.Int, error) { + opts := &bind.CallOpts{ + From: common.HexToAddress(v.client.GetDefaultWallet().Address()), + Context: ctx, + } + fallbackWeiPerUnitLink, err := v.coordinator.GetFallbackWeiPerUnitLink(opts) + if err != nil { + return nil, err + } + return fallbackWeiPerUnitLink, nil +} + +func (v *EthereumVRFCoordinatorV2) GetFeeConfig(ctx context.Context) (vrf_coordinator_v2.GetFeeConfig, error) { + opts := &bind.CallOpts{ + From: common.HexToAddress(v.client.GetDefaultWallet().Address()), + Context: ctx, + } + config, err := v.coordinator.GetFeeConfig(opts) + if err != nil { + return vrf_coordinator_v2.GetFeeConfig{}, err + } + return config, nil +} + func (v *EthereumVRFCoordinatorV2) SetConfig(minimumRequestConfirmations uint16, maxGasLimit uint32, stalenessSeconds uint32, gasAfterPaymentCalculation uint32, fallbackWeiPerUnitLink *big.Int, feeConfig vrf_coordinator_v2.VRFCoordinatorV2FeeConfig) error { opts, err := v.client.TransactionOpts(v.client.GetDefaultWallet()) if err != nil { @@ -256,6 +359,18 @@ func (v *EthereumVRFCoordinatorV2) RegisterProvingKey( return v.client.ProcessTransaction(tx) } +func (v *EthereumVRFCoordinatorV2) TransferOwnership(to common.Address) error { + opts, err := v.client.TransactionOpts(v.client.GetDefaultWallet()) + if err != nil { + return err + } + tx, err := v.coordinator.TransferOwnership(opts, to) + if err != nil { + return err + } + return v.client.ProcessTransaction(tx) +} + func (v *EthereumVRFCoordinatorV2) CreateSubscription() (*types.Transaction, error) { opts, err := v.client.TransactionOpts(v.client.GetDefaultWallet()) if err != nil { @@ -403,6 +518,26 @@ func (v *EthereumVRFCoordinatorV2) WaitForRandomWordsRequestedEvent(keyHash [][3 } } +func (v *EthereumVRFCoordinatorV2) WaitForSubscriptionFunded(subID []uint64, timeout time.Duration) (*vrf_coordinator_v2.VRFCoordinatorV2SubscriptionFunded, error) { + eventsChannel := make(chan *vrf_coordinator_v2.VRFCoordinatorV2SubscriptionFunded) + subscription, err := v.coordinator.WatchSubscriptionFunded(nil, eventsChannel, subID) + 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 SubscriptionFunded event") + case event := <-eventsChannel: + return event, nil + } + } +} + func (v *EthereumVRFCoordinatorV2) WaitForSubscriptionCanceledEvent(subID []uint64, timeout time.Duration) (*vrf_coordinator_v2.VRFCoordinatorV2SubscriptionCanceled, error) { eventsChannel := make(chan *vrf_coordinator_v2.VRFCoordinatorV2SubscriptionCanceled) subscription, err := v.coordinator.WatchSubscriptionCanceled(nil, eventsChannel, subID) @@ -423,6 +558,86 @@ func (v *EthereumVRFCoordinatorV2) WaitForSubscriptionCanceledEvent(subID []uint } } +func (v *EthereumVRFCoordinatorV2) WaitForSubscriptionCreatedEvent(subID []uint64, timeout time.Duration) (*vrf_coordinator_v2.VRFCoordinatorV2SubscriptionCreated, error) { + eventsChannel := make(chan *vrf_coordinator_v2.VRFCoordinatorV2SubscriptionCreated) + subscription, err := v.coordinator.WatchSubscriptionCreated(nil, eventsChannel, subID) + 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 event := <-eventsChannel: + return event, nil + } + } +} + +func (v *EthereumVRFCoordinatorV2) WaitForSubscriptionConsumerAdded(subID []uint64, timeout time.Duration) (*vrf_coordinator_v2.VRFCoordinatorV2SubscriptionConsumerAdded, error) { + eventsChannel := make(chan *vrf_coordinator_v2.VRFCoordinatorV2SubscriptionConsumerAdded) + subscription, err := v.coordinator.WatchSubscriptionConsumerAdded(nil, eventsChannel, subID) + 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 SubscriptionConsumerAdded event") + case event := <-eventsChannel: + return event, nil + } + } +} + +func (v *EthereumVRFCoordinatorV2) WaitForSubscriptionConsumerRemoved(subID []uint64, timeout time.Duration) (*vrf_coordinator_v2.VRFCoordinatorV2SubscriptionConsumerRemoved, error) { + eventsChannel := make(chan *vrf_coordinator_v2.VRFCoordinatorV2SubscriptionConsumerRemoved) + subscription, err := v.coordinator.WatchSubscriptionConsumerRemoved(nil, eventsChannel, subID) + 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 SubscriptionConsumerRemoved event") + case event := <-eventsChannel: + return event, nil + } + } +} + +func (v *EthereumVRFCoordinatorV2) WaitForConfigSetEvent(timeout time.Duration) (*vrf_coordinator_v2.VRFCoordinatorV2ConfigSet, error) { + eventsChannel := make(chan *vrf_coordinator_v2.VRFCoordinatorV2ConfigSet) + subscription, err := v.coordinator.WatchConfigSet(nil, eventsChannel) + 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 ConfigSet event") + case event := <-eventsChannel: + return event, nil + } + } +} + // GetAllRandomWords get all VRFv2 randomness output words func (v *EthereumVRFConsumerV2) GetAllRandomWords(ctx context.Context, num int) ([]*big.Int, error) { words := make([]*big.Int, 0) @@ -584,6 +799,35 @@ func (v *EthereumVRFv2LoadTestConsumer) RequestRandomness( return tx, v.client.ProcessTransaction(tx) } +func (v *EthereumVRFv2LoadTestConsumer) RequestRandomWordsWithForceFulfill( + keyHash [32]byte, + requestConfirmations uint16, + callbackGasLimit uint32, + numWords uint32, + requestCount uint16, + subTopUpAmount *big.Int, + linkAddress common.Address, +) (*types.Transaction, error) { + opts, err := v.client.TransactionOpts(v.client.GetDefaultWallet()) + if err != nil { + return nil, err + } + tx, err := v.consumer.RequestRandomWordsWithForceFulfill( + opts, + requestConfirmations, + keyHash, + callbackGasLimit, + numWords, + requestCount, + subTopUpAmount, + linkAddress, + ) + if err != nil { + return nil, err + } + return tx, v.client.ProcessTransaction(tx) +} + 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()), @@ -794,3 +1038,96 @@ func (v *EthereumVRFV2WrapperLoadTestConsumer) GetLoadTestMetrics(ctx context.Co fastestFulfillment, }, nil } + +func (v *EthereumVRFOwner) Address() string { + return v.address.Hex() +} + +func (v *EthereumVRFOwner) SetAuthorizedSenders(senders []common.Address) error { + opts, err := v.client.TransactionOpts(v.client.GetDefaultWallet()) + if err != nil { + return err + } + tx, err := v.vrfOwner.SetAuthorizedSenders( + opts, + senders, + ) + if err != nil { + return err + } + return v.client.ProcessTransaction(tx) +} + +func (v *EthereumVRFOwner) AcceptVRFOwnership() error { + opts, err := v.client.TransactionOpts(v.client.GetDefaultWallet()) + if err != nil { + return err + } + tx, err := v.vrfOwner.AcceptVRFOwnership(opts) + if err != nil { + return err + } + return v.client.ProcessTransaction(tx) +} + +func (v *EthereumVRFOwner) WaitForRandomWordsForcedEvent(requestIDs []*big.Int, subIds []uint64, senders []common.Address, timeout time.Duration) (*vrf_owner.VRFOwnerRandomWordsForced, error) { + eventsChannel := make(chan *vrf_owner.VRFOwnerRandomWordsForced) + subscription, err := v.vrfOwner.WatchRandomWordsForced(nil, eventsChannel, requestIDs, subIds, senders) + 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 RandomWordsForced event") + case event := <-eventsChannel: + return event, nil + } + } +} + +func (v *EthereumVRFCoordinatorTestV2) Address() string { + return v.address.Hex() +} + +func (v *EthereumVRFMockETHLINKFeed) Address() string { + return v.address.Hex() +} + +func (v *EthereumVRFMockETHLINKFeed) LatestRoundData() (*big.Int, error) { + data, err := v.feed.LatestRoundData(&bind.CallOpts{ + From: common.HexToAddress(v.client.GetDefaultWallet().Address()), + Context: context.Background(), + }) + if err != nil { + return nil, err + } + return data.Ans, nil +} + +func (v *EthereumVRFMockETHLINKFeed) LatestRoundDataUpdatedAt() (*big.Int, error) { + data, err := v.feed.LatestRoundData(&bind.CallOpts{ + From: common.HexToAddress(v.client.GetDefaultWallet().Address()), + Context: context.Background(), + }) + if err != nil { + return nil, err + } + return data.UpdatedAt, nil +} + +func (v *EthereumVRFMockETHLINKFeed) SetBlockTimestampDeduction(blockTimestampDeduction *big.Int) error { + opts, err := v.client.TransactionOpts(v.client.GetDefaultWallet()) + if err != nil { + return err + } + tx, err := v.feed.SetBlockTimestampDeduction(opts, blockTimestampDeduction) + if err != nil { + return err + } + return v.client.ProcessTransaction(tx) +} diff --git a/integration-tests/docker/test_env/cl_node.go b/integration-tests/docker/test_env/cl_node.go index 1466d03c6f..2ffd49b877 100644 --- a/integration-tests/docker/test_env/cl_node.go +++ b/integration-tests/docker/test_env/cl_node.go @@ -52,12 +52,8 @@ type ClNode struct { UserEmail string `json:"userEmail"` UserPassword string `json:"userPassword"` AlwaysPullImage bool `json:"-"` - PostStartsHooks []tc.ContainerHook `json:"-"` - PostStopsHooks []tc.ContainerHook `json:"-"` - PreTerminatesHooks []tc.ContainerHook `json:"-"` t *testing.T l zerolog.Logger - ls *logstream.LogStream } type ClNodeOption = func(c *ClNode) @@ -97,7 +93,7 @@ func WithDbContainerName(name string) ClNodeOption { func WithLogStream(ls *logstream.LogStream) ClNodeOption { return func(c *ClNode) { - c.ls = ls + c.LogStream = ls } } @@ -150,25 +146,6 @@ func NewClNode(networks []string, imageName, imageVersion string, nodeConfig *ch return n, nil } -func (n *ClNode) SetDefaultHooks() { - n.PostStartsHooks = []tc.ContainerHook{ - func(ctx context.Context, c tc.Container) error { - if n.ls != nil { - return n.ls.ConnectContainer(ctx, c, "cl-node") - } - return nil - }, - } - n.PostStopsHooks = []tc.ContainerHook{ - func(ctx context.Context, c tc.Container) error { - if n.ls != nil { - return n.ls.DisconnectContainer(c) - } - return nil - }, - } -} - func (n *ClNode) SetTestLogger(t *testing.T) { n.l = logging.GetTestLogger(t) n.t = t @@ -186,16 +163,10 @@ func (n *ClNode) Restart(cfg *chainlink.Config) error { // UpgradeVersion restarts the cl node with new image and version func (n *ClNode) UpgradeVersion(newImage, newVersion string) error { - if newVersion == "" { - return fmt.Errorf("new version is empty") - } - if newImage == "" { - newImage = os.Getenv("CHAINLINK_IMAGE") - } n.l.Info(). Str("Name", n.ContainerName). - Str("Old Image", os.Getenv("CHAINLINK_IMAGE")). - Str("Old Version", os.Getenv("CHAINLINK_VERSION")). + Str("Old Image", newImage). + Str("Old Version", newVersion). Str("New Image", newImage). Str("New Version", newVersion). Msg("Upgrading Chainlink Node") @@ -463,6 +434,7 @@ func (n *ClNode) getContainerRequest(secrets string) ( AlwaysPullImage: n.AlwaysPullImage, Image: fmt.Sprintf("%s:%s", n.ContainerImage, n.ContainerVersion), ExposedPorts: []string{"6688/tcp"}, + Env: n.ContainerEnvs, Entrypoint: []string{"chainlink", "-c", configPath, "-s", secretsPath, diff --git a/integration-tests/docker/test_env/test_env.go b/integration-tests/docker/test_env/test_env.go index b928bc9e66..e6d1451627 100644 --- a/integration-tests/docker/test_env/test_env.go +++ b/integration-tests/docker/test_env/test_env.go @@ -1,11 +1,9 @@ package test_env import ( - "context" "encoding/json" "fmt" "math/big" - "os" "runtime/debug" "testing" @@ -19,10 +17,14 @@ import ( "github.com/smartcontractkit/chainlink-testing-framework/docker/test_env" "github.com/smartcontractkit/chainlink-testing-framework/logging" "github.com/smartcontractkit/chainlink-testing-framework/logstream" + "github.com/smartcontractkit/chainlink-testing-framework/utils/runid" + "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" "github.com/smartcontractkit/chainlink/integration-tests/client" "github.com/smartcontractkit/chainlink/integration-tests/contracts" + + core_testconfig "github.com/smartcontractkit/chainlink/integration-tests/testconfig" ) var ( @@ -65,7 +67,7 @@ func (te *CLClusterTestEnv) WithTestEnvConfig(cfg *TestEnvConfig) *CLClusterTest te.Cfg = cfg if cfg.MockAdapter.ContainerName != "" { n := []string{te.Network.Name} - te.MockAdapter = test_env.NewKillgrave(n, te.Cfg.MockAdapter.ImpostersPath, test_env.WithContainerName(te.Cfg.MockAdapter.ContainerName)) + te.MockAdapter = test_env.NewKillgrave(n, te.Cfg.MockAdapter.ImpostersPath, test_env.WithContainerName(te.Cfg.MockAdapter.ContainerName), test_env.WithLogStream(te.LogStream)) } return te } @@ -149,14 +151,15 @@ func (te *CLClusterTestEnv) StartMockAdapter() error { return te.MockAdapter.StartContainer() } -func (te *CLClusterTestEnv) StartClCluster(nodeConfig *chainlink.Config, count int, secretsConfig string, opts ...ClNodeOption) error { +// pass config here +func (te *CLClusterTestEnv) StartClCluster(nodeConfig *chainlink.Config, count int, secretsConfig string, testconfig core_testconfig.GlobalTestConfig, opts ...ClNodeOption) error { if te.Cfg != nil && te.Cfg.ClCluster != nil { te.ClCluster = te.Cfg.ClCluster } else { - opts = append(opts, WithSecrets(secretsConfig)) + opts = append(opts, WithSecrets(secretsConfig), WithLogStream(te.LogStream)) te.ClCluster = &ClCluster{} for i := 0; i < count; i++ { - ocrNode, err := NewClNode([]string{te.Network.Name}, os.Getenv("CHAINLINK_IMAGE"), os.Getenv("CHAINLINK_VERSION"), nodeConfig, opts...) + ocrNode, err := NewClNode([]string{te.Network.Name}, *testconfig.GetChainlinkImageConfig().Image, *testconfig.GetChainlinkImageConfig().Version, nodeConfig, opts...) if err != nil { return err } @@ -171,18 +174,6 @@ func (te *CLClusterTestEnv) StartClCluster(nodeConfig *chainlink.Config, count i } } - if te.LogStream != nil { - for _, node := range te.ClCluster.Nodes { - node.ls = te.LogStream - } - if te.MockAdapter != nil { - err := te.LogStream.ConnectContainer(context.Background(), te.MockAdapter.Container, "mock-adapter") - if err != nil { - return err - } - } - } - // Start/attach node containers return te.ClCluster.Start() } @@ -206,9 +197,16 @@ func (te *CLClusterTestEnv) Terminate() error { // 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") + + runIdErr := runid.RemoveLocalRunId() + if runIdErr != nil { + te.l.Warn().Msgf("Failed to remove .run.id file due to: %s (not a big deal, you can still remove it manually)", runIdErr.Error()) + } + if te.t == nil { return fmt.Errorf("cannot cleanup test environment without a testing.T") } + if te.ClCluster == nil || len(te.ClCluster.Nodes) == 0 { return fmt.Errorf("chainlink nodes are nil, unable cleanup chainlink nodes") } diff --git a/integration-tests/docker/test_env/test_env_builder.go b/integration-tests/docker/test_env/test_env_builder.go index bd73d33d9b..0b1cd30c1b 100644 --- a/integration-tests/docker/test_env/test_env_builder.go +++ b/integration-tests/docker/test_env/test_env_builder.go @@ -16,12 +16,15 @@ import ( "github.com/smartcontractkit/chainlink-testing-framework/logstream" "github.com/smartcontractkit/chainlink-testing-framework/networks" "github.com/smartcontractkit/chainlink-testing-framework/utils/osutil" + "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" evmcfg "github.com/smartcontractkit/chainlink/v2/core/chains/evm/config/toml" "github.com/smartcontractkit/chainlink/integration-tests/contracts" "github.com/smartcontractkit/chainlink/integration-tests/types/config/node" + + tc "github.com/smartcontractkit/chainlink/integration-tests/testconfig" ) type CleanUpType string @@ -52,6 +55,7 @@ type CLTestEnvBuilder struct { chainOptionsFn []ChainOption evmClientNetworkOption []EVMClientNetworkOption ethereumNetwork *test_env.EthereumNetwork + testConfig tc.GlobalTestConfig /* funding */ ETHFunds *big.Float @@ -113,6 +117,11 @@ func (b *CLTestEnvBuilder) WithCLNodes(clNodesCount int) *CLTestEnvBuilder { return b } +func (b *CLTestEnvBuilder) WithTestConfig(cfg tc.GlobalTestConfig) *CLTestEnvBuilder { + b.testConfig = cfg + return b +} + func (b *CLTestEnvBuilder) WithCLNodeOptions(opt ...ClNodeOption) *CLTestEnvBuilder { b.clNodesOpts = append(b.clNodesOpts, opt...) return b @@ -213,6 +222,10 @@ func (b *CLTestEnvBuilder) EVMClientNetworkOptions(opts ...EVMClientNetworkOptio } func (b *CLTestEnvBuilder) Build() (*CLClusterTestEnv, error) { + if b.testConfig == nil { + return nil, fmt.Errorf("test config must be set") + } + if b.te == nil { var err error b, err = b.WithTestEnv(nil) @@ -227,7 +240,7 @@ func (b *CLTestEnvBuilder) Build() (*CLClusterTestEnv, error) { } if b.hasLogStream { - b.te.LogStream, err = logstream.NewLogStream(b.te.t, nil) + b.te.LogStream, err = logstream.NewLogStream(b.te.t, b.testConfig.GetLoggingConfig()) if err != nil { return nil, err } @@ -238,7 +251,7 @@ func (b *CLTestEnvBuilder) Build() (*CLClusterTestEnv, error) { return nil, fmt.Errorf("test environment builder failed: %w", fmt.Errorf("cannot start mock adapter without a network")) } - b.te.MockAdapter = test_env.NewKillgrave([]string{b.te.Network.Name}, "") + b.te.MockAdapter = test_env.NewKillgrave([]string{b.te.Network.Name}, "", test_env.WithLogStream(b.te.LogStream)) err = b.te.StartMockAdapter() if err != nil { @@ -267,13 +280,13 @@ func (b *CLTestEnvBuilder) Build() (*CLClusterTestEnv, error) { if b.te.LogStream != nil { b.t.Cleanup(func() { - b.l.Warn().Msg("Shutting down LogStream") + b.l.Info().Msg("Shutting down LogStream") logPath, err := osutil.GetAbsoluteFolderPath("logs") if err != nil { b.l.Info().Str("Absolute path", logPath).Msg("LogStream logs folder location") } - if b.t.Failed() || os.Getenv("TEST_LOG_COLLECT") == "true" { + if b.t.Failed() || *b.testConfig.GetLoggingConfig().TestLogCollect { // we can't do much if this fails, so we just log the error in logstream _ = b.te.LogStream.FlushAndShutdown() b.te.LogStream.PrintLogTargetsLocations() @@ -303,27 +316,26 @@ func (b *CLTestEnvBuilder) Build() (*CLClusterTestEnv, error) { return nil, fmt.Errorf("cannot create nodes with custom config without nonDevNetworks") } - err = b.te.StartClCluster(b.clNodeConfig, b.clNodesCount, b.secretsConfig, b.clNodesOpts...) + err = b.te.StartClCluster(b.clNodeConfig, b.clNodesCount, b.secretsConfig, b.testConfig, b.clNodesOpts...) if err != nil { return nil, err } return b.te, nil } - networkConfig := networks.MustGetSelectedNetworksFromEnv()[0] + networkConfig := networks.MustGetSelectedNetworkConfig(b.testConfig.GetNetworkConfig())[0] var rpcProvider test_env.RpcProvider if b.ethereumNetwork != nil && networkConfig.Simulated { // TODO here we should save the ethereum network config to te.Cfg, but it doesn't exist at this point // in general it seems we have no methods for saving config to file and we only load it from file // but I don't know how that config file is to be created or whether anyone ever done that - var enCfg test_env.EthereumNetwork b.ethereumNetwork.DockerNetworkNames = []string{b.te.Network.Name} networkConfig, rpcProvider, err = b.te.StartEthereumNetwork(b.ethereumNetwork) if err != nil { return nil, err } b.te.RpcProvider = rpcProvider - b.te.PrivateEthereumConfig = &enCfg + b.te.PrivateEthereumConfig = b.ethereumNetwork } if !b.isNonEVM { @@ -387,7 +399,7 @@ func (b *CLTestEnvBuilder) Build() (*CLClusterTestEnv, error) { } } - err := b.te.StartClCluster(cfg, b.clNodesCount, b.secretsConfig, b.clNodesOpts...) + err := b.te.StartClCluster(cfg, b.clNodesCount, b.secretsConfig, b.testConfig, b.clNodesOpts...) if err != nil { return nil, err } diff --git a/integration-tests/example.env b/integration-tests/example.env index bbc76bb0c0..35db626364 100644 --- a/integration-tests/example.env +++ b/integration-tests/example.env @@ -2,11 +2,8 @@ # `source ./integration-tests/.env` ########## General Test Settings ########## -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 @@ -19,52 +16,7 @@ export SLACK_API_KEY="xoxb-example-key" # API key used to report soak test resul export SLACK_CHANNEL="C000000000" # Channel ID for the slack bot to post test results export SLACK_USER="U000000000" # User ID of the person running the soak tests to properly notify them -# OCR Soak Test Settings -export OCR_TEST_DURATION="15m" # For an OCRv1 soak test, how long to run the test for -export OCR_CHAINLINK_NODE_FUNDING=".01" # For an OCRv1 soak test, how much ETH to send to each node -export OCR_TIME_BETWEEN_ROUNDS="1m" # For an OCRv1 soak test, how long to wait between starting new rounds - -# Node Version Upgrade Settings -export TEST_UPGRADE_IMAGE="" # Image path to use for the node version upgrade test, likely empty -export TEST_UPGRADE_VERSION="2.0.0" # Version of the Chainlink image to upgrade to for upgrade tests. Should be newer than the current version - ########## Network Settings ########## - -# If running on a live network, you must set the following values -# Select a pre-defined network(s) -export SELECTED_NETWORKS="SIMULATED" -# General private values that will be retrieved when running on non-simulated networks -export EVM_URLS="wss://evm.url,wss://other.url" # Comma-sparated list of websocket URLs to use when running on live networks -export EVM_HTTP_URLS="https://evm.url,https://other.url" # Comma-sparated list of HTTP URLs to use when running on live networks -export EVM_KEYS="private,funding,keys" # Comma-separated list of private keys to use when running on live networks - -# Specific private values retrieved when running on specified chains -# Will override the general values above if the SELECTED_NETWORKS contains the network name -# Goerli -export GOERLI_URLS="wss://goerli.io/ws" -export GOERLI_HTTP_URLS="http://goerli.io/ws" -export GOERLI_KEYS="goerli,funding,keys" -# Sepolia -export SEPOLIA_URLS="wss://sepolia.io/ws" -export SEPOLIA_HTTP_URLS="http://sepolia.io/ws" -export SEPOLIA_KEYS="sepolia,funding,keys" -# Klaytn Baobab -export KLAYTN_BAOBAB_URLS="wss://klaytn.io/ws" -export KLAYTN_BAOBAB_HTTP_URLS="http://klaytn.io/ws" -export KLAYTN_BAOBAB_KEYS="klaytn,funding,keys" -# Metis Stardust -export METIS_STARDUST_URLS="wss://metis.io/ws" -export METIS_STARDUST_HTTP_URLS="http://metis.io/ws" -export METIS_STARDUST_KEYS="metis,funding,keys" -# Arbitrum Goerli -export ARBITRUM_GOERLI_URLS="wss://arbitrum.io/ws" -export ARBITRUM_GOERLI_HTTP_URLS="http://arbitrum.io/ws" -export ARBITRUM_GOERLI_KEYS="arbitrum,funding,keys" -# Optimism Goerli -export OPTIMISM_GOERLI_URLS="wss://optimism.io/ws" -export OPTIMISM_GOERLI_HTTP_URLS="http://optimism.io/ws" -export OPTIMISM_GOERLI_KEYS="optimism,funding,keys" - # General EVM Settings, used only for quick prototyping when using GENERAL as the SELECTED_NETWORK export EVM_NAME="General EVM" export EVM_CHAIN_ID="1" diff --git a/integration-tests/go.mod b/integration-tests/go.mod index 21afd83e5c..36d71d1414 100644 --- a/integration-tests/go.mod +++ b/integration-tests/go.mod @@ -6,16 +6,15 @@ go 1.21.4 replace github.com/smartcontractkit/chainlink/v2 => ../ require ( - cosmossdk.io/errors v1.0.0 github.com/AlekSi/pointer v1.1.0 github.com/K-Phoen/grabana v0.21.17 + github.com/barkimedes/go-deepcopy v0.0.0-20220514131651-17c30cfc62df github.com/cli/go-gh/v2 v2.0.0 - github.com/ethereum/go-ethereum v1.12.2 + github.com/ethereum/go-ethereum v1.13.8 github.com/go-resty/resty/v2 v2.7.0 github.com/google/go-cmp v0.6.0 github.com/google/uuid v1.4.0 github.com/jmoiron/sqlx v1.3.5 - github.com/kelseyhightower/envconfig v1.4.0 github.com/lib/pq v1.10.9 github.com/manifoldco/promptui v0.9.0 github.com/onsi/gomega v1.30.0 @@ -27,17 +26,18 @@ require ( github.com/segmentio/ksuid v1.0.4 github.com/slack-go/slack v0.12.2 github.com/smartcontractkit/chain-selectors v1.0.9 - github.com/smartcontractkit/chainlink-automation v1.0.1 - github.com/smartcontractkit/chainlink-common v0.1.7-0.20240108182329-237f56daad6b - github.com/smartcontractkit/chainlink-testing-framework v1.22.7 + github.com/smartcontractkit/chainlink-automation v1.0.2-0.20240118014648-1ab6a88c9429 + github.com/smartcontractkit/chainlink-common v0.1.7-0.20240123141952-a879db9d23b3 + github.com/smartcontractkit/chainlink-testing-framework v1.23.1 github.com/smartcontractkit/chainlink-vrf v0.0.0-20231120191722-fef03814f868 github.com/smartcontractkit/chainlink/integration-tests v0.0.0-00010101000000-000000000000 github.com/smartcontractkit/chainlink/v2 v2.0.0-00010101000000-000000000000 - github.com/smartcontractkit/libocr v0.0.0-20231130143053-c5102a9c0fb7 + github.com/smartcontractkit/libocr v0.0.0-20240112202000-6359502d2ff1 github.com/smartcontractkit/tdh2/go/tdh2 v0.0.0-20230906073235-9e478e5e19f1 - github.com/smartcontractkit/wasp v0.4.0 + github.com/smartcontractkit/wasp v0.4.1 github.com/spf13/cobra v1.7.0 github.com/stretchr/testify v1.8.4 + github.com/test-go/testify v1.1.4 github.com/testcontainers/testcontainers-go v0.23.0 github.com/umbracle/ethgo v0.1.3 go.dedis.ch/kyber/v3 v3.1.0 @@ -47,6 +47,7 @@ require ( go.uber.org/zap v1.26.0 golang.org/x/crypto v0.17.0 golang.org/x/sync v0.5.0 + golang.org/x/text v0.14.0 gopkg.in/guregu/null.v4 v4.0.0 ) @@ -54,7 +55,6 @@ require ( exclude github.com/hashicorp/consul v1.2.1 replace ( - // Required until https://github.com/testcontainers/testcontainers-go/pull/1971 is merged github.com/testcontainers/testcontainers-go => github.com/Tofel/testcontainers-go v0.0.0-20231130110817-e6fbf9498b56 // Pin K8s versions as their updates are highly disruptive and go mod keeps wanting to update them k8s.io/api => k8s.io/api v0.25.11 @@ -67,6 +67,7 @@ require ( cosmossdk.io/api v0.3.1 // indirect cosmossdk.io/core v0.5.1 // indirect cosmossdk.io/depinject v1.0.0-alpha.3 // indirect + cosmossdk.io/errors v1.0.0 // indirect cosmossdk.io/math v1.0.1 // indirect dario.cat/mergo v1.0.0 // indirect filippo.io/edwards25519 v1.0.0 // indirect @@ -89,7 +90,7 @@ require ( github.com/Masterminds/sprig/v3 v3.2.3 // indirect github.com/Microsoft/go-winio v0.6.1 // indirect github.com/Microsoft/hcsshim v0.11.1 // indirect - github.com/VictoriaMetrics/fastcache v1.10.0 // indirect + github.com/VictoriaMetrics/fastcache v1.12.1 // indirect github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137 // indirect github.com/andres-erbsen/clock v0.0.0-20160526145045-9e14626cd129 // indirect github.com/armon/go-metrics v0.4.1 // indirect @@ -102,7 +103,7 @@ require ( github.com/aybabtme/rgbterm v0.0.0-20170906152045-cc83f3b3ce59 // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/bgentry/speakeasy v0.1.1-0.20220910012023-760eaf8b6816 // indirect - github.com/bits-and-blooms/bitset v1.7.0 // indirect + github.com/bits-and-blooms/bitset v1.10.0 // indirect github.com/blendle/zapdriver v1.3.1 // indirect github.com/btcsuite/btcd/btcec/v2 v2.3.2 // indirect github.com/buger/jsonparser v1.1.1 // indirect @@ -122,13 +123,14 @@ require ( github.com/cli/safeexec v1.0.0 // indirect github.com/cockroachdb/errors v1.9.1 // indirect github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b // indirect - github.com/cockroachdb/pebble v0.0.0-20230906160148-46873a6a7a06 // indirect + github.com/cockroachdb/pebble v0.0.0-20230928194634-aa077af62593 // indirect github.com/cockroachdb/redact v1.1.3 // indirect + github.com/cockroachdb/tokenbucket v0.0.0-20230807174530-cc333fc44b06 // indirect github.com/cometbft/cometbft v0.37.2 // indirect github.com/cometbft/cometbft-db v0.8.0 // indirect github.com/confio/ics23/go v0.9.0 // indirect github.com/consensys/bavard v0.1.13 // indirect - github.com/consensys/gnark-crypto v0.10.0 // indirect + github.com/consensys/gnark-crypto v0.12.1 // indirect github.com/containerd/containerd v1.7.7 // indirect github.com/containerd/log v0.1.0 // indirect github.com/coreos/go-semver v0.3.0 // indirect @@ -143,7 +145,8 @@ require ( github.com/cosmos/ics23/go v0.10.0 // indirect github.com/cosmos/ledger-cosmos-go v0.12.1 // indirect github.com/cpuguy83/dockercfg v0.3.1 // indirect - github.com/crate-crypto/go-kzg-4844 v0.3.0 // indirect + github.com/crate-crypto/go-ipa v0.0.0-20231025140028-3c0104f4b233 // indirect + github.com/crate-crypto/go-kzg-4844 v0.7.0 // indirect github.com/danieljoos/wincred v1.1.2 // indirect github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect github.com/deckarep/golang-set/v2 v2.3.0 // indirect @@ -163,7 +166,7 @@ require ( github.com/edsrzf/mmap-go v1.1.0 // indirect github.com/emicklei/go-restful/v3 v3.10.2 // indirect github.com/esote/minmaxheap v1.0.0 // indirect - github.com/ethereum/c-kzg-4844 v0.3.1 // indirect + github.com/ethereum/c-kzg-4844 v0.4.0 // indirect github.com/evanphx/json-patch v5.6.0+incompatible // indirect github.com/evanphx/json-patch/v5 v5.6.0 // indirect github.com/exponent-io/jsonpath v0.0.0-20210407135951-1de76d718b3f // indirect @@ -179,6 +182,7 @@ require ( github.com/gagliardetto/solana-go v1.4.1-0.20220428092759-5250b4abbb27 // indirect github.com/gagliardetto/treeout v0.1.4 // indirect github.com/gballet/go-libpcsclite v0.0.0-20191108122812-4678299bea08 // indirect + github.com/gballet/go-verkle v0.1.1-0.20231031103413-a67434b50f46 // indirect github.com/getsentry/sentry-go v0.19.0 // indirect github.com/gin-contrib/sessions v0.0.5 // indirect github.com/gin-contrib/sse v0.1.0 // indirect @@ -206,7 +210,6 @@ require ( github.com/go-playground/universal-translator v0.18.1 // indirect github.com/go-playground/validator/v10 v10.15.5 // indirect github.com/go-redis/redis/v8 v8.11.5 // indirect - github.com/go-stack/stack v1.8.1 // indirect github.com/go-webauthn/webauthn v0.9.4 // indirect github.com/go-webauthn/x v0.1.5 // indirect github.com/goccy/go-json v0.10.2 // indirect @@ -255,6 +258,7 @@ require ( github.com/hashicorp/consul/sdk v0.14.1 // indirect github.com/hashicorp/errwrap v1.1.0 // indirect github.com/hashicorp/go-cleanhttp v0.5.2 // indirect + github.com/hashicorp/go-envparse v0.1.0 // indirect github.com/hashicorp/go-hclog v1.5.0 // indirect github.com/hashicorp/go-immutable-radix v1.3.1 // indirect github.com/hashicorp/go-msgpack v0.5.5 // indirect @@ -270,7 +274,7 @@ require ( github.com/hdevalence/ed25519consensus v0.1.0 // indirect github.com/holiman/billy v0.0.0-20230718173358-1c7e68d277a7 // indirect github.com/holiman/bloomfilter/v2 v2.0.3 // indirect - github.com/holiman/uint256 v1.2.3 // indirect + github.com/holiman/uint256 v1.2.4 // indirect github.com/huandu/skiplist v1.2.0 // indirect github.com/huandu/xstrings v1.4.0 // indirect github.com/huin/goupnp v1.3.0 // indirect @@ -291,6 +295,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/kelseyhightower/envconfig v1.4.0 // indirect github.com/klauspost/compress v1.17.2 // indirect github.com/klauspost/cpuid/v2 v2.2.5 // indirect github.com/kr/pretty v0.3.1 // indirect @@ -371,11 +376,11 @@ require ( 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.20231218175426-6e0427c661e5 // indirect + github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20240120192246-4bb04c997ca0 // indirect github.com/smartcontractkit/chainlink-data-streams v0.0.0-20231204152908-a6e3fe8ff2a1 // indirect - github.com/smartcontractkit/chainlink-feeds v0.0.0-20231127231053-2232d3a6766d // indirect - github.com/smartcontractkit/chainlink-solana v1.0.3-0.20231219140448-151a4725f312 // indirect - github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20231219014050-0c4a7831293a // indirect + github.com/smartcontractkit/chainlink-feeds v0.0.0-20240119021347-3c541a78cdb8 // indirect + github.com/smartcontractkit/chainlink-solana v1.0.3-0.20240122152632-38444d2ad8ba // indirect + github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20240119162652-3a7274645007 // indirect github.com/smartcontractkit/tdh2/go/ocr2/decryptionplugin v0.0.0-20230906073235-9e478e5e19f1 // indirect github.com/smartcontractkit/wsrpc v0.7.2 // indirect github.com/soheilhy/cmux v0.1.5 // indirect @@ -392,7 +397,6 @@ require ( github.com/syndtr/goleveldb v1.0.1-0.20220721030215-126854af5e6d // indirect github.com/tendermint/go-amino v0.16.0 // indirect github.com/teris-io/shortid v0.0.0-20201117134242-e59966efd125 // indirect - github.com/test-go/testify v1.1.4 // indirect github.com/theodesp/go-heaps v0.0.0-20190520121037-88e35354fe0a // indirect github.com/tidwall/btree v1.6.0 // indirect github.com/tidwall/gjson v1.17.0 // indirect @@ -440,7 +444,6 @@ require ( golang.org/x/oauth2 v0.15.0 // indirect golang.org/x/sys v0.15.0 // indirect golang.org/x/term v0.15.0 // indirect - golang.org/x/text v0.14.0 // indirect golang.org/x/time v0.5.0 // indirect golang.org/x/tools v0.16.0 // indirect gomodules.xyz/jsonpatch/v2 v2.2.0 // indirect @@ -455,7 +458,6 @@ require ( gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect - gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce // indirect gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect k8s.io/api v0.28.2 // indirect @@ -490,6 +492,8 @@ replace ( // 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 + // type func(a Label, b Label) bool of func(a, b Label) bool {…} does not match inferred type func(a Label, b Label) int for func(a E, b E) int + github.com/prometheus/prometheus => github.com/prometheus/prometheus v0.47.2-0.20231010075449-4b9c19fe5510 github.com/smartcontractkit/chainlink/integration-tests => ../integration-tests diff --git a/integration-tests/go.sum b/integration-tests/go.sum index f83744ec1c..c1a0140c24 100644 --- a/integration-tests/go.sum +++ b/integration-tests/go.sum @@ -81,19 +81,31 @@ github.com/AlekSi/pointer v1.1.0 h1:SSDMPcXD9jSl8FPy9cRzoRaMJtm9g9ggGTxecRUbQoI= github.com/AlekSi/pointer v1.1.0/go.mod h1:y7BvfRI3wXPWKXEBhU71nbnIEEZX0QTSB2Bj48UJIZE= github.com/AndreasBriese/bbloom v0.0.0-20190306092124-e2d15f34fcf9/go.mod h1:bOvUY6CB00SOBii9/FifXqc0awNKxLFCL/+pkDPuyl8= github.com/Azure/azure-sdk-for-go v65.0.0+incompatible h1:HzKLt3kIwMm4KeJYTdx9EbjRYTySD/t8i1Ee/W5EGXw= +github.com/Azure/azure-sdk-for-go v65.0.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= github.com/Azure/azure-sdk-for-go/sdk/azcore v1.8.0 h1:9kDVnTz3vbfweTqAUmk/a/pH5pWFCHtvRpHYC0G/dcA= github.com/Azure/azure-sdk-for-go/sdk/azcore v1.8.0/go.mod h1:3Ug6Qzto9anB6mGlEdgYMDF5zHQ+wwhEaYR4s17PHMw= github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.4.0 h1:BMAjVKJM0U/CYF27gA0ZMmXGkOcvfFtD0oHVZ1TIPRI= github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.4.0/go.mod h1:1fXstnBMas5kzG+S3q8UoJcmyU6nUeunJcMDHcRYHhs= github.com/Azure/azure-sdk-for-go/sdk/internal v1.3.0 h1:sXr+ck84g/ZlZUOZiNELInmMgOsuGwdjjVkEIde0OtY= github.com/Azure/azure-sdk-for-go/sdk/internal v1.3.0/go.mod h1:okt5dMMTOFjX/aovMlrjvvXoPMBVSPzk9185BT0+eZM= -github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/compute/armcompute/v4 v4.2.1 h1:UPeCRD+XY7QlaGQte2EVI2iOcWvUYA2XY8w5T/8v0NQ= -github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/compute/armcompute/v4 v4.2.1/go.mod h1:oGV6NlB0cvi1ZbYRR2UN44QHxWFyGk+iylgD0qaMXjA= -github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/network/armnetwork v1.1.0 h1:QM6sE5k2ZT/vI5BEe0r7mqjsUSnhVBFbOsVkEuaEfiA= -github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/network/armnetwork/v2 v2.2.1 h1:bWh0Z2rOEDfB/ywv/l0iHN1JgyazE6kW/aIA89+CEK0= -github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/network/armnetwork/v2 v2.2.1/go.mod h1:Bzf34hhAE9NSxailk8xVeLEZbUjOXcC+GnU1mMKdhLw= github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 h1:L/gRVlceqvL25UVaW/CKtUDjefjrs0SPonmDGUVOYP0= github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= +github.com/Azure/go-autorest v14.2.0+incompatible h1:V5VMDjClD3GiElqLWO7mz2MxNAK/vTfRHdAubSIPRgs= +github.com/Azure/go-autorest v14.2.0+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24= +github.com/Azure/go-autorest/autorest v0.11.29 h1:I4+HL/JDvErx2LjyzaVxllw2lRDB5/BT2Bm4g20iqYw= +github.com/Azure/go-autorest/autorest v0.11.29/go.mod h1:ZtEzC4Jy2JDrZLxvWs8LrBWEBycl1hbT1eknI8MtfAs= +github.com/Azure/go-autorest/autorest/adal v0.9.23 h1:Yepx8CvFxwNKpH6ja7RZ+sKX+DWYNldbLiALMC3BTz8= +github.com/Azure/go-autorest/autorest/adal v0.9.23/go.mod h1:5pcMqFkdPhviJdlEy3kC/v1ZLnQl0MH6XA5YCcMhy4c= +github.com/Azure/go-autorest/autorest/date v0.3.0 h1:7gUk1U5M/CQbp9WoqinNzJar+8KY+LPI6wiWrP/myHw= +github.com/Azure/go-autorest/autorest/date v0.3.0/go.mod h1:BI0uouVdmngYNUzGWeSYnokU+TrmwEsOqdt8Y6sso74= +github.com/Azure/go-autorest/autorest/to v0.4.0 h1:oXVqrxakqqV1UZdSazDOPOLvOIz+XA683u8EctwboHk= +github.com/Azure/go-autorest/autorest/to v0.4.0/go.mod h1:fE8iZBn7LQR7zH/9XU2NcPR4o9jEImooCeWJcYV/zLE= +github.com/Azure/go-autorest/autorest/validation v0.3.1 h1:AgyqjAd94fwNAoTjl/WQXg4VvFeRFpO+UhNyRXqF1ac= +github.com/Azure/go-autorest/autorest/validation v0.3.1/go.mod h1:yhLgjC0Wda5DYXl6JAsWyUe4KVNffhoDhG0zVzUMo3E= +github.com/Azure/go-autorest/logger v0.2.1 h1:IG7i4p/mDa2Ce4TRyAO8IHnVhAVF3RFU+ZtXWSmf4Tg= +github.com/Azure/go-autorest/logger v0.2.1/go.mod h1:T9E3cAhj2VqvPOtCYAvby9aBXkZmbF5NWuPV8+WeEW8= +github.com/Azure/go-autorest/tracing v0.6.0 h1:TYi4+3m5t6K48TGI9AUdb+IzbnSxvnvUMfuitfgcfuo= +github.com/Azure/go-autorest/tracing v0.6.0/go.mod h1:+vhtPC754Xsa23ID7GlGsrdKBpUA79WCAKPPZVC2DeU= github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358 h1:mFRzDkZVAjdal+s7s0MwaRv9igoPqLRdzOLzw/8Xvq8= github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358/go.mod h1:chxPXzSsl7ZWRAuOIE23GDNzjWuZquvFlgA8xmpunjU= github.com/AzureAD/microsoft-authentication-library-for-go v1.1.1 h1:WpB/QDNLpMw72xHJc34BNNykqSOeEJDAWkhf0u12/Jk= @@ -146,8 +158,8 @@ github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdko github.com/Shopify/goreferrer v0.0.0-20181106222321-ec9c9a553398/go.mod h1:a1uqRtAwp2Xwc6WNPJEufxJ7fx3npB4UV/JOLmbu5I0= github.com/Tofel/testcontainers-go v0.0.0-20231130110817-e6fbf9498b56 h1:HItfr1XKD/4xnsJE56m3uxnkMQ9lbg8xDnkf9qoZCH0= github.com/Tofel/testcontainers-go v0.0.0-20231130110817-e6fbf9498b56/go.mod h1:ICriE9bLX5CLxL9OFQ2N+2N+f+803LNJ1utJb1+Inx0= -github.com/VictoriaMetrics/fastcache v1.10.0 h1:5hDJnLsKLpnUEToub7ETuRu8RCkb40woBZAUiKonXzY= -github.com/VictoriaMetrics/fastcache v1.10.0/go.mod h1:tjiYeEfYXCqacuvYw/7UoDIeJaNxq6132xHICNP77w8= +github.com/VictoriaMetrics/fastcache v1.12.1 h1:i0mICQuojGDL3KblA7wUNlY5lOK6a4bwt3uRKnkZU40= +github.com/VictoriaMetrics/fastcache v1.12.1/go.mod h1:tX04vaqcNoQeGLD+ra5pU5sWkuxnzWhEzLwhP9w653o= github.com/VividCortex/gohistogram v1.0.0 h1:6+hBz+qvs0JOrrNhhmR7lFxo5sINxBCGXrdtl/UvroE= github.com/VividCortex/gohistogram v1.0.0/go.mod h1:Pf5mBqqDxYaXu3hDrrU+w6nw50o/4+TcAqDqk/vUH7g= github.com/Workiva/go-datastructures v1.1.0 h1:hu20UpgZneBhQ3ZvwiOGlqJSKIosin2Rd5wAKUHEO/k= @@ -204,6 +216,8 @@ github.com/aws/jsii-runtime-go v1.75.0/go.mod h1:TKCyrtM0pygEPo4rDZzbMSDNCDNTSYS github.com/aybabtme/rgbterm v0.0.0-20170906152045-cc83f3b3ce59 h1:WWB576BN5zNSZc/M9d/10pqEx5VHNhaQ/yOVAkmj5Yo= github.com/aybabtme/rgbterm v0.0.0-20170906152045-cc83f3b3ce59/go.mod h1:q/89r3U2H7sSsE2t6Kca0lfwTK8JdoNGS/yzM/4iH5I= github.com/aymerick/raymond v2.0.3-0.20180322193309-b565731e1464+incompatible/go.mod h1:osfaiScAUVup+UC9Nfq76eWqDhXlp+4UYaA8uhTBO6g= +github.com/barkimedes/go-deepcopy v0.0.0-20220514131651-17c30cfc62df h1:GSoSVRLoBaFpOOds6QyY1L8AX7uoY+Ln3BHc22W40X0= +github.com/barkimedes/go-deepcopy v0.0.0-20220514131651-17c30cfc62df/go.mod h1:hiVxq5OP2bUGBRNS3Z/bt/reCLFNbdcST6gISi1fiOM= github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= github.com/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= @@ -214,8 +228,8 @@ github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d/go.mod h1:6QX/PXZ github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= github.com/bgentry/speakeasy v0.1.1-0.20220910012023-760eaf8b6816 h1:41iFGWnSlI2gVpmOtVTJZNodLdLQLn/KsJqFvXwnd/s= github.com/bgentry/speakeasy v0.1.1-0.20220910012023-760eaf8b6816/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= -github.com/bits-and-blooms/bitset v1.7.0 h1:YjAGVd3XmtK9ktAbX8Zg2g2PwLIMjGREZJHlV4j7NEo= -github.com/bits-and-blooms/bitset v1.7.0/go.mod h1:gIdJ4wp64HaoK2YrL1Q5/N7Y16edYb8uY+O0FJTyyDA= +github.com/bits-and-blooms/bitset v1.10.0 h1:ePXTeiPEazB5+opbv5fr8umg2R/1NlzgDsyepwsSr88= +github.com/bits-and-blooms/bitset v1.10.0/go.mod h1:7hO7Gc7Pp1vODcmWvKMRA9BNmbv6a/7QIWpPxHddWR8= github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJmJgSg28kpZDP6UIiPt0e0Oz0kqKNGyRaWEPv84= github.com/blendle/zapdriver v1.3.1 h1:C3dydBOWYRiOk+B8X9IVZ5IOe+7cl+tGOexN4QqHfpE= github.com/blendle/zapdriver v1.3.1/go.mod h1:mdXfREi6u5MArG4j9fewC+FGnXaBR+T4Ox4J2u4eHCc= @@ -252,7 +266,6 @@ github.com/cespare/cp v1.1.1/go.mod h1:SOGHArjBr4JWaSDEVpWpo/hNg6RoKrls6Oh40hiwW github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko= github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= -github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/chai2010/gettext-go v1.0.2 h1:1Lwwip6Q2QGsAdl/ZKPCwTe9fe0CjlUbqj5bFNSjIRk= @@ -296,17 +309,19 @@ github.com/cockroachdb/apd/v2 v2.0.2/go.mod h1:DDxRlzC2lo3/vSlmSoS7JkqbbrARPuFOG github.com/cockroachdb/apd/v3 v3.1.0 h1:MK3Ow7LH0W8zkd5GMKA1PvS9qG3bWFI95WaVNfyZJ/w= github.com/cockroachdb/apd/v3 v3.1.0/go.mod h1:6qgPBMXjATAdD/VefbRP9NoSLKjbB4LCoA7gN4LpHs4= github.com/cockroachdb/datadriven v1.0.2/go.mod h1:a9RdTaap04u637JoCzcUoIcDmvwSUtcUFtT/C3kJlTU= -github.com/cockroachdb/datadriven v1.0.3-0.20230801171734-e384cf455877 h1:1MLK4YpFtIEo3ZtMA5C795Wtv5VuUnrXX7mQG+aHg6o= -github.com/cockroachdb/datadriven v1.0.3-0.20230801171734-e384cf455877/go.mod h1:a9RdTaap04u637JoCzcUoIcDmvwSUtcUFtT/C3kJlTU= +github.com/cockroachdb/datadriven v1.0.3-0.20230413201302-be42291fc80f h1:otljaYPt5hWxV3MUfO5dFPFiOXg9CyG5/kCfayTqsJ4= +github.com/cockroachdb/datadriven v1.0.3-0.20230413201302-be42291fc80f/go.mod h1:a9RdTaap04u637JoCzcUoIcDmvwSUtcUFtT/C3kJlTU= github.com/cockroachdb/errors v1.9.1 h1:yFVvsI0VxmRShfawbt/laCIDy/mtTqqnvoNgiy5bEV8= github.com/cockroachdb/errors v1.9.1/go.mod h1:2sxOtL2WIc096WSZqZ5h8fa17rdDq9HZOZLBCor4mBk= github.com/cockroachdb/logtags v0.0.0-20211118104740-dabe8e521a4f/go.mod h1:Vz9DsVWQQhf3vs21MhPMZpMGSht7O/2vFW2xusFUVOs= github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b h1:r6VH0faHjZeQy818SGhaone5OnYfxFR/+AzdY3sf5aE= github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b/go.mod h1:Vz9DsVWQQhf3vs21MhPMZpMGSht7O/2vFW2xusFUVOs= -github.com/cockroachdb/pebble v0.0.0-20230906160148-46873a6a7a06 h1:T+Np/xtzIjYM/P5NAw0e2Rf1FGvzDau1h54MKvx8G7w= -github.com/cockroachdb/pebble v0.0.0-20230906160148-46873a6a7a06/go.mod h1:bynZ3gvVyhlvjLI7PT6dmZ7g76xzJ7HpxfjgkzCGz6s= +github.com/cockroachdb/pebble v0.0.0-20230928194634-aa077af62593 h1:aPEJyR4rPBvDmeyi+l/FS/VtA00IWvjeFvjen1m1l1A= +github.com/cockroachdb/pebble v0.0.0-20230928194634-aa077af62593/go.mod h1:6hk1eMY/u5t+Cf18q5lFMUA1Rc+Sm5I6Ra1QuPyxXCo= github.com/cockroachdb/redact v1.1.3 h1:AKZds10rFSIj7qADf0g46UixK8NNLwWTNdCIGS5wfSQ= github.com/cockroachdb/redact v1.1.3/go.mod h1:BVNblN9mBWFyMyqK1k3AAiSxhvhfK2oOZZ2lK+dpvRg= +github.com/cockroachdb/tokenbucket v0.0.0-20230807174530-cc333fc44b06 h1:zuQyyAKVxetITBuuhv3BI9cMrmStnpT18zmgmTxunpo= +github.com/cockroachdb/tokenbucket v0.0.0-20230807174530-cc333fc44b06/go.mod h1:7nc4anLGjupUW/PeY5qiNYsdNXj7zopG+eqsS7To5IQ= github.com/codegangsta/inject v0.0.0-20150114235600-33e0aa1cb7c0/go.mod h1:4Zcjuz89kmFXt9morQgcfYZAYZ5n8WHjt81YYWIwtTM= github.com/coinbase/rosetta-sdk-go/types v1.0.0 h1:jpVIwLcPoOeCR6o1tU+Xv7r5bMONNbHU7MuEHboiFuA= github.com/coinbase/rosetta-sdk-go/types v1.0.0/go.mod h1:eq7W2TMRH22GTW0N0beDnN931DW0/WOI1R2sdHNHG4c= @@ -318,8 +333,8 @@ github.com/confio/ics23/go v0.9.0 h1:cWs+wdbS2KRPZezoaaj+qBleXgUk5WOQFMP3CQFGTr4 github.com/confio/ics23/go v0.9.0/go.mod h1:4LPZ2NYqnYIVRklaozjNR1FScgDJ2s5Xrp+e/mYVRak= github.com/consensys/bavard v0.1.13 h1:oLhMLOFGTLdlda/kma4VOJazblc7IM5y5QPd2A/YjhQ= github.com/consensys/bavard v0.1.13/go.mod h1:9ItSMtA/dXMAiL7BG6bqW2m3NdSEObYWoH223nGHukI= -github.com/consensys/gnark-crypto v0.10.0 h1:zRh22SR7o4K35SoNqouS9J/TKHTyU2QWaj5ldehyXtA= -github.com/consensys/gnark-crypto v0.10.0/go.mod h1:Iq/P3HHl0ElSjsg2E1gsMwhAyxnxoKK5nVyZKd+/KhU= +github.com/consensys/gnark-crypto v0.12.1 h1:lHH39WuuFgVHONRl3J0LRBtuYdQTumFSDtJF7HpyG8M= +github.com/consensys/gnark-crypto v0.12.1/go.mod h1:v2Gy7L/4ZRosZ7Ivs+9SfUDr0f5UlG+EM5t7MPHiLuY= github.com/containerd/containerd v1.7.7 h1:QOC2K4A42RQpcrZyptP6z9EJZnlHfHJUfZrAAHe15q4= github.com/containerd/containerd v1.7.7/go.mod h1:3c4XZv6VeT9qgf9GMTxNTMFxGJrGpI2vz1yk4ye+YY8= github.com/containerd/continuity v0.4.2 h1:v3y/4Yz5jwnvqPKJJ+7Wf93fyWoCB3F5EclWG023MDM= @@ -368,8 +383,10 @@ github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwc github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/cpuguy83/go-md2man/v2 v2.0.2 h1:p1EgwI/C7NhT0JmVkwCD2ZBK8j4aeHQX2pMHHBfMQ6w= github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= -github.com/crate-crypto/go-kzg-4844 v0.3.0 h1:UBlWE0CgyFqqzTI+IFyCzA7A3Zw4iip6uzRv5NIXG0A= -github.com/crate-crypto/go-kzg-4844 v0.3.0/go.mod h1:SBP7ikXEgDnUPONgm33HtuDZEDtWa3L4QtN1ocJSEQ4= +github.com/crate-crypto/go-ipa v0.0.0-20231025140028-3c0104f4b233 h1:d28BXYi+wUpz1KBmiF9bWrjEMacUEREV6MBi2ODnrfQ= +github.com/crate-crypto/go-ipa v0.0.0-20231025140028-3c0104f4b233/go.mod h1:geZJZH3SzKCqnz5VT0q/DyIG/tvu/dZk+VIfXicupJs= +github.com/crate-crypto/go-kzg-4844 v0.7.0 h1:C0vgZRk4q4EZ/JgPfzuSoxdCq3C3mOZMBShovmncxvA= +github.com/crate-crypto/go-kzg-4844 v0.7.0/go.mod h1:1kMhvPgI0Ky3yIa+9lFySEBUBXkYxeOi8ZF1sYioxhc= github.com/creachadair/taskgroup v0.4.2 h1:jsBLdAJE42asreGss2xZGZ8fJra7WtwnHWeJFxv2Li8= github.com/creachadair/taskgroup v0.4.2/go.mod h1:qiXUOSrbwAY3u0JPGTzObbE3yf9hcXHDKBZ2ZjpCbgM= github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= @@ -415,8 +432,8 @@ github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13/go.mod h1:SqUrOPUn github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78= github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc= github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= -github.com/digitalocean/godo v1.104.1 h1:SZNxjAsskM/su0YW9P8Wx3gU0W1Z13b6tZlYNpl5BnA= -github.com/digitalocean/godo v1.104.1/go.mod h1:VAI/L5YDzMuPRU01lEEUSQ/sp5Z//1HnnFv/RBTEdbg= +github.com/digitalocean/godo v1.99.0 h1:gUHO7n9bDaZFWvbzOum4bXE0/09ZuYA9yA8idQHX57E= +github.com/digitalocean/godo v1.99.0/go.mod h1:SsS2oXo2rznfM/nORlZ/6JaUJZFhmKTib1YhopUc8NA= github.com/dnaeon/go-vcr v1.2.0 h1:zHCHvJYTMh1N7xnV7zf1m1GPBF9Ad0Jk/whtQ1663qI= github.com/dnaeon/go-vcr v1.2.0/go.mod h1:R4UdLID7HZT3taECzJs4YgbbH6PIGXB6W/sc5OLb6RQ= github.com/docker/distribution v2.8.2+incompatible h1:T3de5rq0dB1j30rp0sA2rER+m322EBzniBPB6ZIzuh8= @@ -455,10 +472,10 @@ github.com/envoyproxy/protoc-gen-validate v1.0.2/go.mod h1:GpiZQP3dDbg4JouG/NNS7 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= -github.com/ethereum/c-kzg-4844 v0.3.1 h1:sR65+68+WdnMKxseNWxSJuAv2tsUrihTpVBTfM/U5Zg= -github.com/ethereum/c-kzg-4844 v0.3.1/go.mod h1:VewdlzQmpT5QSrVhbBuGoCdFJkpaJlO1aQputP83wc0= -github.com/ethereum/go-ethereum v1.12.2 h1:eGHJ4ij7oyVqUQn48LBz3B7pvQ8sV0wGJiIE6gDq/6Y= -github.com/ethereum/go-ethereum v1.12.2/go.mod h1:1cRAEV+rp/xX0zraSCBnu9Py3HQ+geRMj3HdR+k0wfI= +github.com/ethereum/c-kzg-4844 v0.4.0 h1:3MS1s4JtA868KpJxroZoepdV0ZKBp3u/O5HcZ7R3nlY= +github.com/ethereum/c-kzg-4844 v0.4.0/go.mod h1:VewdlzQmpT5QSrVhbBuGoCdFJkpaJlO1aQputP83wc0= +github.com/ethereum/go-ethereum v1.13.8 h1:1od+thJel3tM52ZUNQwvpYOeRHlbkVFZ5S8fhi0Lgsg= +github.com/ethereum/go-ethereum v1.13.8/go.mod h1:sc48XYQxCzH3fG9BcrXCOOgQk2JfZzNAmIKnceogzsA= github.com/evanphx/json-patch v0.5.2/go.mod h1:ZWS5hhDbVDyob71nXKNL0+PWn6ToqBHMikGIFbs31qQ= github.com/evanphx/json-patch v5.6.0+incompatible h1:jBYDEEiFBPxA0v50tFdvOzQQTCvpL6mnFh5mB2/l16U= github.com/evanphx/json-patch v5.6.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= @@ -509,6 +526,8 @@ github.com/gagliardetto/treeout v0.1.4/go.mod h1:loUefvXTrlRG5rYmJmExNryyBRh8f89 github.com/gavv/httpexpect v2.0.0+incompatible/go.mod h1:x+9tiU1YnrOvnB725RkpoLv1M62hOWzwo5OXotisrKc= github.com/gballet/go-libpcsclite v0.0.0-20191108122812-4678299bea08 h1:f6D9Hr8xV8uYKlyuj8XIruxlh9WjVjdh1gIicAS7ays= github.com/gballet/go-libpcsclite v0.0.0-20191108122812-4678299bea08/go.mod h1:x7DCsMOv1taUwEWCzT4cmDeAkigA5/QCwUodaVOe8Ww= +github.com/gballet/go-verkle v0.1.1-0.20231031103413-a67434b50f46 h1:BAIP2GihuqhwdILrV+7GJel5lyPV3u1+PgzrWLc0TkE= +github.com/gballet/go-verkle v0.1.1-0.20231031103413-a67434b50f46/go.mod h1:QNpY22eby74jVhqH4WhDLDwxc/vqsern6pW+u2kbkpc= github.com/gedex/inflector v0.0.0-20170307190818-16278e9db813 h1:Uc+IZ7gYqAf/rSGFplbWBSHaGolEQlNLgMgSE3ccnIQ= github.com/gedex/inflector v0.0.0-20170307190818-16278e9db813/go.mod h1:P+oSoE9yhSRvsmYyZsshflcR6ePWYLql6UU1amW13IM= github.com/getsentry/sentry-go v0.12.0/go.mod h1:NSap0JBYWzHND8oMbyi0+XZhUalc1TBdRL1M71JZW2c= @@ -621,8 +640,6 @@ github.com/go-resty/resty/v2 v2.7.0/go.mod h1:9PWDzw47qPphMRFfhsyk0NnSgvluHcljSM github.com/go-sql-driver/mysql v1.6.0 h1:BCTh4TKNUYmOmMUcQ3IipzF5prigylS7XXjEkfCHuOE= github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= -github.com/go-stack/stack v1.8.1 h1:ntEHSVwIt7PNXNpgPmVfMrNhLtgjlmnZha2kOpuRiDw= -github.com/go-stack/stack v1.8.1/go.mod h1:dcoOX6HbPZSZptuspn9bctJ+N/CnF5gGygcUP3XYfe4= github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI= github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls= @@ -785,8 +802,8 @@ github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLe github.com/google/pprof v0.0.0-20231023181126-ff6d637d2a7b h1:RMpPgZTSApbPf7xaVel+QkoGPRLFLrwFO89uDUHEGf0= github.com/google/pprof v0.0.0-20231023181126-ff6d637d2a7b/go.mod h1:czg5+yv1E0ZGTi6S6vVK1mke0fV+FaUhNGcd6VRS9Ik= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= -github.com/google/s2a-go v0.1.7 h1:60BLSyTrOV4/haCDW4zb1guZItoSq8foHCXrAnjBo/o= -github.com/google/s2a-go v0.1.7/go.mod h1:50CgR4k1jNlWBu4UfS4AcfhVe1r6pdZPygJ3R8F0Qdw= +github.com/google/s2a-go v0.1.4 h1:1kZ/sQM3srePvKs3tXAvQzo66XfcReoqFpIpIccE7Oc= +github.com/google/s2a-go v0.1.4/go.mod h1:Ej+mSEMGRnqRzjc7VtF+jdBwYG5fuJfiZ8ELkjEwM0A= github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4= github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ= github.com/google/subcommands v1.2.0/go.mod h1:ZjhPrFU+Olkh9WazFPsl27BQ4UPiG37m3yTrtFlrHVk= @@ -796,15 +813,15 @@ github.com/google/uuid v1.2.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+ github.com/google/uuid v1.3.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.4.0 h1:MtMxsa51/r9yyhkyLsVeVt0B+BGQZzpQiTQ4eHZ8bc4= github.com/google/uuid v1.4.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/googleapis/enterprise-certificate-proxy v0.3.1 h1:SBWmZhjUDRorQxrN0nwzf+AHBxnbFjViHQS4P0yVpmQ= -github.com/googleapis/enterprise-certificate-proxy v0.3.1/go.mod h1:VLSiSSBs/ksPL8kq3OBOQ6WRI2QnaFynd1DCjZ62+V0= +github.com/googleapis/enterprise-certificate-proxy v0.2.5 h1:UR4rDjcgpgEnqpIEvkiqTYKBCKLNmlge2eVjoZfySzM= +github.com/googleapis/enterprise-certificate-proxy v0.2.5/go.mod h1:RxW0N9901Cko1VOCW3SXCpWP+mlIEkk2tP7jnHy9a3w= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= github.com/googleapis/gax-go/v2 v2.12.0 h1:A+gCJKdRfqXkr+BIRGtZLibNXf0m1f9E4HG56etFpas= github.com/googleapis/gax-go/v2 v2.12.0/go.mod h1:y+aIqrI5eb1YGMVJfuV3185Ts/D7qKpsEkdD5+I6QGU= github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g= -github.com/gophercloud/gophercloud v1.7.0 h1:fyJGKh0LBvIZKLvBWvQdIgkaV5yTM3Jh9EYUh+UNCAs= -github.com/gophercloud/gophercloud v1.7.0/go.mod h1:aAVqcocTSXh2vYFZ1JTvx4EQmfgzxRcNupUfxZbBNDM= +github.com/gophercloud/gophercloud v1.5.0 h1:cDN6XFCLKiiqvYpjQLq9AiM7RDRbIC9450WpPH+yvXo= +github.com/gophercloud/gophercloud v1.5.0/go.mod h1:aAVqcocTSXh2vYFZ1JTvx4EQmfgzxRcNupUfxZbBNDM= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gorilla/context v1.1.1 h1:AWwleXJkX/nhcU9bZSnZoi3h/qGYqQAGhq6zZe/aQW8= github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg= @@ -883,6 +900,8 @@ github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtng github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ= github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48= +github.com/hashicorp/go-envparse v0.1.0 h1:bE++6bhIsNCPLvgDZkYqo3nA+/PFI51pkrHdmPSDFPY= +github.com/hashicorp/go-envparse v0.1.0/go.mod h1:OHheN1GoygLlAkTlXLXvAdnXdZxy8JUweQ1rAXx1xnc= github.com/hashicorp/go-getter v1.7.1 h1:SWiSWN/42qdpR0MdhaOc/bLR48PLuP1ZQtYLRlM69uY= github.com/hashicorp/go-getter v1.7.1/go.mod h1:W7TalhMmbPmsSMdNjD0ZskARur/9GJ17cfHTRtXV744= github.com/hashicorp/go-hclog v1.5.0 h1:bI2ocEMgcVlz55Oj1xZNBsVi900c7II+fWDyV9o+13c= @@ -930,8 +949,8 @@ github.com/hashicorp/mdns v1.0.4/go.mod h1:mtBihi+LeNXGtG8L9dX59gAEa12BDtBQSp4v/ github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I= github.com/hashicorp/memberlist v0.5.0 h1:EtYPN8DpAURiapus508I4n9CzHs2W+8NZGbmmR/prTM= github.com/hashicorp/memberlist v0.5.0/go.mod h1:yvyXLpo0QaGE59Y7hDTsTzDD25JYBZ4mHgHUZ8lrOI0= -github.com/hashicorp/nomad/api v0.0.0-20230721134942-515895c7690c h1:Nc3Mt2BAnq0/VoLEntF/nipX+K1S7pG+RgwiitSv6v0= -github.com/hashicorp/nomad/api v0.0.0-20230721134942-515895c7690c/go.mod h1:O23qLAZuCx4htdY9zBaO4cJPXgleSFEdq6D/sezGgYE= +github.com/hashicorp/nomad/api v0.0.0-20230718173136-3a687930bd3e h1:sr4lujmn9heD030xx/Pd4B/JSmvRhFzuotNXaaV0WLs= +github.com/hashicorp/nomad/api v0.0.0-20230718173136-3a687930bd3e/go.mod h1:O23qLAZuCx4htdY9zBaO4cJPXgleSFEdq6D/sezGgYE= github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc= github.com/hashicorp/serf v0.10.1 h1:Z1H2J60yRKvfDYAOZLd2MU0ND4AH/WDz7xYHDWQsIPY= github.com/hashicorp/serf v0.10.1/go.mod h1:yL2t6BqATOLGc5HF7qbFkTfXoPIY0WZdWHfEvMqbG+4= @@ -941,14 +960,14 @@ github.com/hdevalence/ed25519consensus v0.1.0 h1:jtBwzzcHuTmFrQN6xQZn6CQEO/V9f7H github.com/hdevalence/ed25519consensus v0.1.0/go.mod h1:w3BHWjwJbFU29IRHL1Iqkw3sus+7FctEyM4RqDxYNzo= github.com/henvic/httpretty v0.0.6 h1:JdzGzKZBajBfnvlMALXXMVQWxWMF/ofTy8C3/OSUTxs= github.com/henvic/httpretty v0.0.6/go.mod h1:X38wLjWXHkXT7r2+uK8LjCMne9rsuNaBLJ+5cU2/Pmo= -github.com/hetznercloud/hcloud-go/v2 v2.4.0 h1:MqlAE+w125PLvJRCpAJmEwrIxoVdUdOyuFUhE/Ukbok= -github.com/hetznercloud/hcloud-go/v2 v2.4.0/go.mod h1:l7fA5xsncFBzQTyw29/dw5Yr88yEGKKdc6BHf24ONS0= +github.com/hetznercloud/hcloud-go/v2 v2.0.0 h1:Sg1DJ+MAKvbYAqaBaq9tPbwXBS2ckPIaMtVdUjKu+4g= +github.com/hetznercloud/hcloud-go/v2 v2.0.0/go.mod h1:4iUG2NG8b61IAwNx6UsMWQ6IfIf/i1RsG0BbsKAyR5Q= github.com/holiman/billy v0.0.0-20230718173358-1c7e68d277a7 h1:3JQNjnMRil1yD0IfZKHF9GxxWKDJGj8I0IqOUol//sw= github.com/holiman/billy v0.0.0-20230718173358-1c7e68d277a7/go.mod h1:5GuXa7vkL8u9FkFuWdVvfR5ix8hRB7DbOAaYULamFpc= github.com/holiman/bloomfilter/v2 v2.0.3 h1:73e0e/V0tCydx14a0SCYS/EWCxgwLZ18CZcZKVu0fao= github.com/holiman/bloomfilter/v2 v2.0.3/go.mod h1:zpoh+gs7qcpqrHr3dB55AMiJwo0iURXE7ZOP9L9hSkA= -github.com/holiman/uint256 v1.2.3 h1:K8UWO1HUJpRMXBxbmaY1Y8IAMZC/RsKB+ArEnnK4l5o= -github.com/holiman/uint256 v1.2.3/go.mod h1:SC8Ryt4n+UBbPbIBKaG9zbbDlp4jOru9xFZmPzLUTxw= +github.com/holiman/uint256 v1.2.4 h1:jUc4Nk8fm9jZabQuqr2JzednajVmBpC+oiTiXZJEApU= +github.com/holiman/uint256 v1.2.4/go.mod h1:EOMSn4q6Nyt9P6efbI3bueV4e1b3dGlUCXeiRV4ng7E= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/huandu/go-assert v1.1.5 h1:fjemmA7sSfYHJD7CUqs9qTwwfdNAx7/j2/ZlHXzNB3c= github.com/huandu/go-assert v1.1.5/go.mod h1:yOLvuqZwmcHIC5rIzrBhT7D3Q9c3GFnd0JrPVhn/06U= @@ -971,8 +990,8 @@ github.com/improbable-eng/grpc-web v0.15.0/go.mod h1:1sy9HKV4Jt9aEs9JSnkWlRJPuPt github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= -github.com/ionos-cloud/sdk-go/v6 v6.1.9 h1:Iq3VIXzeEbc8EbButuACgfLMiY5TPVWUPNrF+Vsddo4= -github.com/ionos-cloud/sdk-go/v6 v6.1.9/go.mod h1:EzEgRIDxBELvfoa/uBN0kOQaqovLjUWEB7iW4/Q+t4k= +github.com/ionos-cloud/sdk-go/v6 v6.1.8 h1:493wE/BkZxJf7x79UCE0cYGPZoqQcPiEBALvt7uVGY0= +github.com/ionos-cloud/sdk-go/v6 v6.1.8/go.mod h1:EzEgRIDxBELvfoa/uBN0kOQaqovLjUWEB7iW4/Q+t4k= github.com/iris-contrib/blackfriday v2.0.0+incompatible/go.mod h1:UzZ2bDEoaSGPbkg6SAB4att1aAwTmVIx/5gCVqeyUdI= github.com/iris-contrib/go.uuid v2.0.0+incompatible/go.mod h1:iz2lgM/1UnEf1kP0L/+fafWORmlnuysV2EMP8MW+qe0= github.com/iris-contrib/jade v1.1.3/go.mod h1:H/geBymxJhShH5kecoiOCSssPX7QWYH7UaeZTSWddIk= @@ -1123,8 +1142,8 @@ github.com/libp2p/go-buffer-pool v0.1.0 h1:oK4mSFcQz7cTQIfqbe4MIj9gLW+mnanjyFtc6 github.com/libp2p/go-buffer-pool v0.1.0/go.mod h1:N+vh8gMqimBzdKkSMVuydVDq+UV5QTWy5HSiZacSbPg= github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de h1:9TO3cAIGXtEhnIaL+V+BEER86oLrvS+kWobKpbJuye0= github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de/go.mod h1:zAbeS9B/r2mtpb6U+EI2rYA5OAXxsYw6wTamcNW+zcE= -github.com/linode/linodego v1.23.0 h1:s0ReCZtuN9Z1IoUN9w1RLeYO1dMZUGPwOQ/IBFsBHtU= -github.com/linode/linodego v1.23.0/go.mod h1:0U7wj/UQOqBNbKv1FYTXiBUXueR8DY4HvIotwE0ENgg= +github.com/linode/linodego v1.19.0 h1:n4WJrcr9+30e9JGZ6DI0nZbm5SdAj1kSwvvt/998YUw= +github.com/linode/linodego v1.19.0/go.mod h1:XZFR+yJ9mm2kwf6itZ6SCpu+6w3KnIevV0Uu5HNWJgQ= github.com/linxGnu/grocksdb v1.7.16 h1:Q2co1xrpdkr5Hx3Fp+f+f7fRGhQFQhvi/+226dtLmA8= github.com/linxGnu/grocksdb v1.7.16/go.mod h1:JkS7pl5qWpGpuVb3bPqTz8nC12X3YtPZT+Xq7+QfQo4= github.com/logrusorgru/aurora v2.0.3+incompatible h1:tOpm7WcpBTn4fjmVfgpQq0EfczGlG91VSDkswnjF5A8= @@ -1309,8 +1328,8 @@ github.com/otiai10/copy v1.14.0 h1:dCI/t1iTdYGtkvCuBG2BgR6KZa83PTclw4U5n2wAllU= github.com/otiai10/copy v1.14.0/go.mod h1:ECfuL02W+/FkTWZWgQqXPWZgW9oeKCSQ5qVfSc4qc4w= github.com/otiai10/mint v1.5.1 h1:XaPLeE+9vGbuyEHem1JNk3bYc7KKqyI/na0/mLd/Kks= github.com/otiai10/mint v1.5.1/go.mod h1:MJm72SBthJjz8qhefc4z1PYEieWmy8Bku7CjcAqyUSM= -github.com/ovh/go-ovh v1.4.3 h1:Gs3V823zwTFpzgGLZNI6ILS4rmxZgJwJCz54Er9LwD0= -github.com/ovh/go-ovh v1.4.3/go.mod h1:AkPXVtgwB6xlKblMjRKJJmjRp+ogrE7fz2lVgcQY8SY= +github.com/ovh/go-ovh v1.4.1 h1:VBGa5wMyQtTP7Zb+w97zRCh9sLtM/2YKRyy+MEJmWaM= +github.com/ovh/go-ovh v1.4.1/go.mod h1:6bL6pPyUT7tBfI0pqOegJgRjgjuO+mOo+MyXd1EEC0M= github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY= github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= @@ -1387,8 +1406,8 @@ github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4O github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= 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.48.1 h1:CTszphSNTXkuCG6O0IfpKdHcJkvvnAAE1GbELKS+NFk= -github.com/prometheus/prometheus v0.48.1/go.mod h1:SRw624aMAxTfryAcP8rOjg4S/sHHaetx2lyJJ2nM83g= +github.com/prometheus/prometheus v0.47.2-0.20231010075449-4b9c19fe5510 h1:6ksZ7t1hNOzGPPs8DK7SvXQf6UfWzi+W5Z7PCBl8gx4= +github.com/prometheus/prometheus v0.47.2-0.20231010075449-4b9c19fe5510/go.mod h1:UC0TwJiF90m2T3iYPQBKnGu8gv3s55dF/EgpTq8gyvo= github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= github.com/pyroscope-io/client v0.7.1 h1:yFRhj3vbgjBxehvxQmedmUWJQ4CAfCHhn+itPsuWsHw= github.com/pyroscope-io/client v0.7.1/go.mod h1:4h21iOU4pUOq0prKyDlvYRL+SCKsBc5wKiEtV+rJGqU= @@ -1436,8 +1455,8 @@ github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFo github.com/sasha-s/go-deadlock v0.3.1 h1:sqv7fDNShgjcaxkO0JNcOAlr8B9+cV5Ey/OB71efZx0= github.com/sasha-s/go-deadlock v0.3.1/go.mod h1:F73l+cr82YSh10GxyRI6qZiCgK64VaZjwesgfQ1/iLM= github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= -github.com/scaleway/scaleway-sdk-go v1.0.0-beta.21 h1:yWfiTPwYxB0l5fGMhl/G+liULugVIHD9AU77iNLrURQ= -github.com/scaleway/scaleway-sdk-go v1.0.0-beta.21/go.mod h1:fCa7OJZ/9DRTnOKmxvT6pn+LPWUptQAmHF/SBJUGEcg= +github.com/scaleway/scaleway-sdk-go v1.0.0-beta.20 h1:a9hSJdJcd16e0HoMsnFvaHvxB3pxSD+SC7+CISp7xY0= +github.com/scaleway/scaleway-sdk-go v1.0.0-beta.20/go.mod h1:fCa7OJZ/9DRTnOKmxvT6pn+LPWUptQAmHF/SBJUGEcg= github.com/schollz/closestmatch v2.1.0+incompatible/go.mod h1:RtP1ddjLong6gTkbtmuhtR2uUrrJOpYzYRvbcPAid+g= github.com/scylladb/go-reflectx v1.0.1 h1:b917wZM7189pZdlND9PbIJ6NQxfDPfBvUaQ7cjj1iZQ= github.com/scylladb/go-reflectx v1.0.1/go.mod h1:rWnOfDIRWBGN0miMLIcoPt/Dhi2doCMZqwMCJ3KupFc= @@ -1478,36 +1497,36 @@ 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/chain-selectors v1.0.9 h1:Zof8tl3Huvv/Yi0q1CKVg1iAx9J39IUPaQOZUq5Qmps= github.com/smartcontractkit/chain-selectors v1.0.9/go.mod h1:d4Hi+E1zqjy9HqMkjBE5q1vcG9VGgxf5VxiRHfzi2kE= -github.com/smartcontractkit/chainlink-automation v1.0.1 h1:vVjBFq2Zsz21kPy1Pb0wpjF9zrbJX+zjXphDeeR4XZk= -github.com/smartcontractkit/chainlink-automation v1.0.1/go.mod h1:INSchkV3ntyDdlZKGWA030MPDpp6pbeuiRkRKYFCm2k= -github.com/smartcontractkit/chainlink-common v0.1.7-0.20240108182329-237f56daad6b h1:PRuvHgPka1gIGPKASuJHvqUvYWhZO7z5B/kKapjkZaM= -github.com/smartcontractkit/chainlink-common v0.1.7-0.20240108182329-237f56daad6b/go.mod h1:f+0ei9N4PlTJHu7pbGzEjTnBUr45syPdGFu5+31lS5Q= -github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20231218175426-6e0427c661e5 h1:kBnmjv3fxU7krVIqZFvo1m4F6qBc4vPURQFX/mcChhI= -github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20231218175426-6e0427c661e5/go.mod h1:EoM7wQ81mov7wsUzG4zEnnr0EH0POEo/I0hRDg433TU= +github.com/smartcontractkit/chainlink-automation v1.0.2-0.20240118014648-1ab6a88c9429 h1:xkejUBZhcBpBrTSfxc91Iwzadrb6SXw8ks69bHIQ9Ww= +github.com/smartcontractkit/chainlink-automation v1.0.2-0.20240118014648-1ab6a88c9429/go.mod h1:wJmVvDf4XSjsahWtfUq3wvIAYEAuhr7oxmxYnEL/LGQ= +github.com/smartcontractkit/chainlink-common v0.1.7-0.20240123141952-a879db9d23b3 h1:uSLn+JbClhldYn7zm0GEALGvi6KAfrY5Kp46IX9sy0E= +github.com/smartcontractkit/chainlink-common v0.1.7-0.20240123141952-a879db9d23b3/go.mod h1:05rRF84QKlIOF5LfTBPkHdw4UpBI2G3zxRcuZ65bPjk= +github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20240120192246-4bb04c997ca0 h1:NALwENz6vQ972DuD9AZjqRjyNSxH9ptNapizQGLI+2s= +github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20240120192246-4bb04c997ca0/go.mod h1:NcVAT/GETDBvIoAej5K6OYqAtDOkF6vO5pYw/hLuYVU= github.com/smartcontractkit/chainlink-data-streams v0.0.0-20231204152908-a6e3fe8ff2a1 h1:xYqRgZO0nMSO8CBCMR0r3WA+LZ4kNL8a6bnbyk/oBtQ= github.com/smartcontractkit/chainlink-data-streams v0.0.0-20231204152908-a6e3fe8ff2a1/go.mod h1:GuPvyXryvbiUZIHmPeLBz4L+yJKeyGUjrDfd1KNne+o= -github.com/smartcontractkit/chainlink-feeds v0.0.0-20231127231053-2232d3a6766d h1:w4MsbOtNk6nD/mcXLstHWk9hB6g7QLtcAfhPjhwvOaQ= -github.com/smartcontractkit/chainlink-feeds v0.0.0-20231127231053-2232d3a6766d/go.mod h1:YPAfLNowdBwiKiYOwgwtbJHi8AJWbcxkbOY0ItAvkfc= -github.com/smartcontractkit/chainlink-solana v1.0.3-0.20231219140448-151a4725f312 h1:ziqC+WW/2/UI6w3DShy7HGzJMWWLIYHT5ev2Qaa3h6I= -github.com/smartcontractkit/chainlink-solana v1.0.3-0.20231219140448-151a4725f312/go.mod h1:vqnojBNdzHNI6asWezJlottUiVEXudMEGf2Mz5R+xps= -github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20231219014050-0c4a7831293a h1:atCXqF8e5U2zfEaA87cKJs+K1MAbOVh3V05gEd60fR0= -github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20231219014050-0c4a7831293a/go.mod h1:YWKpf+hO9XMlzIWQT8yGoky3aeFLzMUVsjbs80LD77M= -github.com/smartcontractkit/chainlink-testing-framework v1.22.7 h1:UnSJ5XGMUshggE0TgIacZ1TXWlOY7BXIi3K2AR5Eaa4= -github.com/smartcontractkit/chainlink-testing-framework v1.22.7/go.mod h1:FBRC6elqaqO8jiMZMfa3UKrvwzZhMGUtYqVTGYmfFrA= +github.com/smartcontractkit/chainlink-feeds v0.0.0-20240119021347-3c541a78cdb8 h1:1BcjXuviSAKttOX7BZoVHRZZGfxqoA2+AL8tykmkdoc= +github.com/smartcontractkit/chainlink-feeds v0.0.0-20240119021347-3c541a78cdb8/go.mod h1:vy1L7NybTy2F/Yv7BOh+oZBa1MACD6gzd1+DkcSkfp8= +github.com/smartcontractkit/chainlink-solana v1.0.3-0.20240122152632-38444d2ad8ba h1:6rnQrD8NaLfLOPHszW1hbpviqpU8011gzdZk6wKP1xY= +github.com/smartcontractkit/chainlink-solana v1.0.3-0.20240122152632-38444d2ad8ba/go.mod h1:OZfzyayUdwsVBqxvbEMqwUntQT8HbFbgyqoudvwfVN0= +github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20240119162652-3a7274645007 h1:KwB0H2P/gxJgt823Ku1fTcFLDKMj6zsP3wbQGlBOm4U= +github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20240119162652-3a7274645007/go.mod h1:EbZAlb/2K6mKr26u3+3cLBe/caJaqCHw786On94C43g= +github.com/smartcontractkit/chainlink-testing-framework v1.23.1 h1:3Ev/twUcnhoe/l3ZreSoR6fx/GKKlIHxdCT3449U2hI= +github.com/smartcontractkit/chainlink-testing-framework v1.23.1/go.mod h1:StIOdxvwd8AMO6xuBtmD6FQfJXktEn/mJJEr7728BTc= github.com/smartcontractkit/chainlink-vrf v0.0.0-20231120191722-fef03814f868 h1:FFdvEzlYwcuVHkdZ8YnZR/XomeMGbz5E2F2HZI3I3w8= github.com/smartcontractkit/chainlink-vrf v0.0.0-20231120191722-fef03814f868/go.mod h1:Kn1Hape05UzFZ7bOUnm3GVsHzP0TNrVmpfXYNHdqGGs= 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-20231130143053-c5102a9c0fb7 h1:AA7vf29c6lFsZm+MtIEtXtg6VUOQV6waJo5MUuHfRjQ= -github.com/smartcontractkit/libocr v0.0.0-20231130143053-c5102a9c0fb7/go.mod h1:WcuWFMskcGK0MYZuH5hEhGJOzdJRUFeNEM4PAKlejI4= +github.com/smartcontractkit/libocr v0.0.0-20240112202000-6359502d2ff1 h1:3y9WsXkZ5lxFrmfH7DQHs/q308lylKId5l/3VC0QAdM= +github.com/smartcontractkit/libocr v0.0.0-20240112202000-6359502d2ff1/go.mod h1:kC0qmVPUaVkFqGiZMNhmRmjdphuUmeyLEdlWFOQzFWI= github.com/smartcontractkit/tdh2/go/ocr2/decryptionplugin v0.0.0-20230906073235-9e478e5e19f1 h1:yiKnypAqP8l0OX0P3klzZ7SCcBUxy5KqTAKZmQOvSQE= github.com/smartcontractkit/tdh2/go/ocr2/decryptionplugin v0.0.0-20230906073235-9e478e5e19f1/go.mod h1:q6f4fe39oZPdsh1i57WznEZgxd8siidMaSFq3wdPmVg= github.com/smartcontractkit/tdh2/go/tdh2 v0.0.0-20230906073235-9e478e5e19f1 h1:Dai1bn+Q5cpeGMQwRdjOdVjG8mmFFROVkSKuUgBErRQ= github.com/smartcontractkit/tdh2/go/tdh2 v0.0.0-20230906073235-9e478e5e19f1/go.mod h1:G5Sd/yzHWf26rQ+X0nG9E0buKPqRGPMJAfk2gwCzOOw= -github.com/smartcontractkit/wasp v0.4.0 h1:N8yPxlBvoJiyE6HaDkTkwRbuOHkGgQFGEHbw36oh4jA= -github.com/smartcontractkit/wasp v0.4.0/go.mod h1:3qiofyI3pkbrc48a3CVshbMfgl74SiuPL/tm30d9Wb4= +github.com/smartcontractkit/wasp v0.4.1 h1:qgIx2s+eCwH0OaBKaHEAHUQ1Z47bAgDu+ICS9IOqvGQ= +github.com/smartcontractkit/wasp v0.4.1/go.mod h1:3qiofyI3pkbrc48a3CVshbMfgl74SiuPL/tm30d9Wb4= github.com/smartcontractkit/wsrpc v0.7.2 h1:iBXzMeg7vc5YoezIQBq896y25BARw7OKbhrb6vPbtRQ= github.com/smartcontractkit/wsrpc v0.7.2/go.mod h1:sj7QX2NQibhkhxTfs3KOhAj/5xwgqMipTvJVSssT9i0= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= @@ -1712,6 +1731,9 @@ go.opentelemetry.io/collector/pdata v1.0.0-rcv0016 h1:qCPXSQCoD3qeWFb1RuIks8fw9A go.opentelemetry.io/collector/pdata v1.0.0-rcv0016/go.mod h1:OdN0alYOlYhHXu6BDlGehrZWgtBuiDsz/rlNeJeXiNg= go.opentelemetry.io/collector/semconv v0.87.0 h1:BsG1jdLLRCBRlvUujk4QA86af7r/ZXnizczQpEs/gg8= go.opentelemetry.io/collector/semconv v0.87.0/go.mod h1:j/8THcqVxFna1FpvA2zYIsUperEtOaRaqoLYIN4doWw= +go.opentelemetry.io/contrib v0.20.0 h1:ubFQUn0VCZ0gPwIoJfBJVpeBlyRMxu8Mm/huKWYd9p0= +go.opentelemetry.io/contrib/instrumentation/github.com/gin-gonic/gin/otelgin v0.46.1 h1:mMv2jG58h6ZI5t5S9QCVGdzCmAsTakMa3oxVgpSD44g= +go.opentelemetry.io/contrib/instrumentation/github.com/gin-gonic/gin/otelgin v0.46.1/go.mod h1:oqRuNKG0upTaDPbLVCG8AD0G2ETrfDtmh7jViy7ox6M= go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.46.1 h1:SpGay3w+nEwMpfVnbqOLH5gY52/foP8RE8UzTZ1pdSE= go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.46.1/go.mod h1:4UoMYEZOC0yN/sPGH76KPkkU7zgiEWYWL9vwmbnTJPE= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.45.0 h1:x8Z78aZx8cOF0+Kkazoc7lwUNMGy0LrzEMxTm4BbTxg= @@ -2021,7 +2043,6 @@ golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220209214540-3681064d5158/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220310020820-b874c991c1a5/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220405052023-b1e9470b6e64/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -2179,8 +2200,8 @@ google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz513 google.golang.org/api v0.35.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg= google.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34qYtE= google.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8= -google.golang.org/api v0.147.0 h1:Can3FaQo9LlVqxJCodNmeZW/ib3/qKAY3rFeXiHo5gc= -google.golang.org/api v0.147.0/go.mod h1:pQ/9j83DcmPd/5C9e2nFOdjjNkDZ1G+zkbK2uvdkJMs= +google.golang.org/api v0.132.0 h1:8t2/+qZ26kAOGSmOiHwVycqVaDg7q3JDILrNi/Z6rvc= +google.golang.org/api v0.132.0/go.mod h1:AeTBC6GpJnJSRJjktDcPX0QwtS8pGYZOV6MSuSCusw0= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= @@ -2312,8 +2333,6 @@ gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/mgo.v2 v2.0.0-20180705113604-9856a29383ce/go.mod h1:yeKp02qBN3iKW1OzL3MGk2IdtZzaj7SFntXj72NppTA= gopkg.in/natefinch/lumberjack.v2 v2.2.1 h1:bBRl1b0OH9s/DuPhuXpNl+VtCaJXFZ5/uEFST95x9zc= gopkg.in/natefinch/lumberjack.v2 v2.2.1/go.mod h1:YD8tP3GAjkrDg1eZH7EGmyESg/lsYskCTPBJVb9jqSc= -gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce h1:+JknDZhAj8YMt7GC73Ei8pv4MzjDUNPHgQWJdtMAaDU= -gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce/go.mod h1:5AcXVHNjg+BDxry382+8OKon8SEWiKktQR07RKPsv1c= gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= diff --git a/integration-tests/k8s/connect.go b/integration-tests/k8s/connect.go index 34eafc42e2..db9ccecb17 100644 --- a/integration-tests/k8s/connect.go +++ b/integration-tests/k8s/connect.go @@ -54,7 +54,7 @@ func ConnectRemote(l zerolog.Logger) (blockchain.EVMClient, *client2.MockserverC URLs: []string{cfg.NetworkWSURL}, HTTPURLs: []string{cfg.NetworkHTTPURL}, ChainlinkTransactionLimit: 500000, - Timeout: blockchain.JSONStrDuration{Duration: 2 * time.Minute}, + Timeout: blockchain.StrDuration{Duration: 2 * time.Minute}, MinimumConfirmations: 1, GasEstimationBuffer: 10000, } diff --git a/integration-tests/load/automationv2_1/automationv2_1_test.go b/integration-tests/load/automationv2_1/automationv2_1_test.go index d2bca2e670..4975847776 100644 --- a/integration-tests/load/automationv2_1/automationv2_1_test.go +++ b/integration-tests/load/automationv2_1/automationv2_1_test.go @@ -2,11 +2,9 @@ package automationv2_1 import ( "context" - "encoding/base64" "fmt" "math" "math/big" - "os" "strconv" "strings" "testing" @@ -26,18 +24,21 @@ import ( "github.com/smartcontractkit/chainlink-common/pkg/utils/tests" "github.com/smartcontractkit/chainlink-testing-framework/blockchain" - "github.com/smartcontractkit/chainlink-testing-framework/k8s/config" "github.com/smartcontractkit/chainlink-testing-framework/k8s/environment" "github.com/smartcontractkit/chainlink-testing-framework/k8s/pkg/helm/chainlink" "github.com/smartcontractkit/chainlink-testing-framework/k8s/pkg/helm/ethereum" "github.com/smartcontractkit/chainlink-testing-framework/logging" "github.com/smartcontractkit/chainlink-testing-framework/networks" + ctf_config "github.com/smartcontractkit/chainlink-testing-framework/config" + "github.com/smartcontractkit/chainlink/integration-tests/actions" "github.com/smartcontractkit/chainlink/integration-tests/actions/automationv2" "github.com/smartcontractkit/chainlink/integration-tests/client" "github.com/smartcontractkit/chainlink/integration-tests/contracts" contractseth "github.com/smartcontractkit/chainlink/integration-tests/contracts/ethereum" + tc "github.com/smartcontractkit/chainlink/integration-tests/testconfig" + a_config "github.com/smartcontractkit/chainlink/integration-tests/testconfig/automation" "github.com/smartcontractkit/chainlink/integration-tests/testreporters" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/automation_utils_2_1" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/log_emitter" @@ -117,105 +118,50 @@ ListenAddresses = ["0.0.0.0:6690"]` } ) -var ( - numberofNodes, _ = strconv.Atoi(getEnv("NUMBEROFNODES", "6")) // Number of nodes in the DON - duration, _ = strconv.Atoi(getEnv("DURATION", "900")) // Test duration in seconds - blockTime, _ = strconv.Atoi(getEnv("BLOCKTIME", "1")) // Block time in seconds for geth simulated dev network - nodeFunding, _ = strconv.ParseFloat(getEnv("NODEFUNDING", "100"), 64) // Amount of native to fund each node with - - specType = getEnv("SPECTYPE", "minimum") // minimum, recommended, local specs for the test - logLevel = getEnv("LOGLEVEL", "info") // log level for the chainlink nodes - pyroscope, _ = strconv.ParseBool(getEnv("PYROSCOPE", "false")) // enable pyroscope for the chainlink nodes - prometheus, _ = strconv.ParseBool(getEnv("PROMETHEUS", "false")) // enable prometheus for the chainlink nodes - configOverride = os.Getenv("CONFIG_OVERRIDE") // config overrides for the load config -) - -type Load struct { - NumberOfEvents int64 `toml:",omitempty"` - NumberOfSpamMatchingEvents int64 `toml:",omitempty"` - NumberOfSpamNonMatchingEvents int64 `toml:",omitempty"` - CheckBurnAmount *big.Int `toml:",omitempty"` - PerformBurnAmount *big.Int `toml:",omitempty"` - UpkeepGasLimit uint32 `toml:",omitempty"` - NumberOfUpkeeps int `toml:",omitempty"` - SharedTrigger bool `toml:",omitempty"` -} - -type LoadConfig struct { - Load []Load `toml:",omitempty"` -} - -var defaultLoadConfig = LoadConfig{ - Load: []Load{ - { - NumberOfEvents: 1, - NumberOfSpamMatchingEvents: 1, - NumberOfSpamNonMatchingEvents: 0, - CheckBurnAmount: big.NewInt(0), - PerformBurnAmount: big.NewInt(0), - UpkeepGasLimit: 1_000_000, - NumberOfUpkeeps: 5, - SharedTrigger: false, - }, - { - NumberOfEvents: 1, - NumberOfSpamMatchingEvents: 0, - NumberOfSpamNonMatchingEvents: 1, - CheckBurnAmount: big.NewInt(0), - PerformBurnAmount: big.NewInt(0), - UpkeepGasLimit: 1_000_000, - NumberOfUpkeeps: 5, - SharedTrigger: true, - }}, -} - func TestLogTrigger(t *testing.T) { ctx := tests.Context(t) l := logging.GetTestLogger(t) - loadConfig := &LoadConfig{} - if configOverride != "" { - d, err := base64.StdEncoding.DecodeString(configOverride) - require.NoError(t, err, "Error decoding config override") - l.Info().Str("CONFIG_OVERRIDE", configOverride).Bytes("Decoded value", d).Msg("Decoding config override") - err = toml.Unmarshal(d, &loadConfig) - require.NoError(t, err, "Error unmarshalling config override") - } else { - loadConfig = &defaultLoadConfig + loadedTestConfig, err := tc.GetConfig("Load", tc.Automation) + if err != nil { + t.Fatal(err) } - loadConfigBytes, err := toml.Marshal(loadConfig) - require.NoError(t, err, "Error marshalling load config") + version := *loadedTestConfig.ChainlinkImage.Version + image := *loadedTestConfig.ChainlinkImage.Image l.Info().Msg("Starting automation v2.1 log trigger load test") - l.Info().Str("TEST_INPUTS", os.Getenv("TEST_INPUTS")).Int("Number of Nodes", numberofNodes). - Int("Duration", duration). - Int("Block Time", blockTime). - Str("Spec Type", specType). - Str("Log Level", logLevel). - Str("Image", os.Getenv(config.EnvVarCLImage)). - Str("Tag", os.Getenv(config.EnvVarCLTag)). - Bytes("Load Config", loadConfigBytes). + l.Info(). + Int("Number of Nodes", *loadedTestConfig.Automation.General.NumberOfNodes). + Int("Duration", *loadedTestConfig.Automation.General.Duration). + Int("Block Time", *loadedTestConfig.Automation.General.BlockTime). + Str("Spec Type", *loadedTestConfig.Automation.General.SpecType). + Str("Log Level", *loadedTestConfig.Automation.General.ChainlinkNodeLogLevel). + Str("Image", image). + Str("Tag", version). Msg("Test Config") testConfigFormat := `Number of Nodes: %d -Duration: %d -Block Time: %d -Spec Type: %s -Log Level: %s -Image: %s -Tag: %s - -Load Config: -%s` - - testConfig := fmt.Sprintf(testConfigFormat, numberofNodes, duration, - blockTime, specType, logLevel, os.Getenv(config.EnvVarCLImage), os.Getenv(config.EnvVarCLTag), string(loadConfigBytes)) + Duration: %d + Block Time: %d + Spec Type: %s + Log Level: %s + Image: %s + Tag: %s + + Load Config: + %s` + + prettyLoadConfig, err := toml.Marshal(loadedTestConfig.Automation.Load) + require.NoError(t, err, "Error marshalling load config") + + testConfig := fmt.Sprintf(testConfigFormat, *loadedTestConfig.Automation.General.NumberOfNodes, *loadedTestConfig.Automation.General.Duration, + *loadedTestConfig.Automation.General.BlockTime, *loadedTestConfig.Automation.General.SpecType, *loadedTestConfig.Automation.General.ChainlinkNodeLogLevel, image, version, string(prettyLoadConfig)) l.Info().Str("testConfig", testConfig).Msg("Test Config") - testNetwork := networks.MustGetSelectedNetworksFromEnv()[0] + testNetwork := networks.MustGetSelectedNetworkConfig(loadedTestConfig.Network)[0] testType := "load" - loadDuration := time.Duration(duration) * time.Second + loadDuration := time.Duration(*loadedTestConfig.Automation.General.Duration) * time.Second automationDefaultLinkFunds := big.NewInt(0).Mul(big.NewInt(1e18), big.NewInt(int64(10000))) //10000 LINK registrySettings := &contracts.KeeperRegistrySettings{ @@ -245,28 +191,6 @@ Load Config: PreventPodEviction: true, }) - if testEnvironment.WillUseRemoteRunner() { - key := "TEST_INPUTS" - err := os.Setenv(fmt.Sprintf("TEST_%s", key), os.Getenv(key)) - require.NoError(t, err, "failed to set the environment variable TEST_INPUTS for remote runner") - - key = config.EnvVarPyroscopeServer - err = os.Setenv(fmt.Sprintf("TEST_%s", key), os.Getenv(key)) - require.NoError(t, err, "failed to set the environment variable PYROSCOPE_SERVER for remote runner") - - key = config.EnvVarPyroscopeKey - err = os.Setenv(fmt.Sprintf("TEST_%s", key), os.Getenv(key)) - require.NoError(t, err, "failed to set the environment variable PYROSCOPE_KEY for remote runner") - - key = "GRAFANA_DASHBOARD_URL" - err = os.Setenv(fmt.Sprintf("TEST_%s", key), getEnv(key, "")) - require.NoError(t, err, "failed to set the environment variable GRAFANA_DASHBOARD_URL for remote runner") - - key = "CONFIG_OVERRIDE" - err = os.Setenv(fmt.Sprintf("TEST_%s", key), os.Getenv(key)) - require.NoError(t, err, "failed to set the environment variable CONFIG_OVERRIDE for remote runner") - } - testEnvironment. AddHelm(ethereum.New(ðereum.Props{ NetworkName: testNetwork.Name, @@ -275,7 +199,7 @@ Load Config: Values: map[string]interface{}{ "resources": gethNodeSpec, "geth": map[string]interface{}{ - "blocktime": blockTime, + "blocktime": *loadedTestConfig.Automation.General.BlockTime, "capacity": "20Gi", }, }, @@ -293,7 +217,7 @@ Load Config: dbSpec = minimumDbSpec ) - switch specType { + switch *loadedTestConfig.Automation.General.SpecType { case "recommended": nodeSpec = recNodeSpec dbSpec = recDbSpec @@ -305,28 +229,34 @@ Load Config: } - if !pyroscope { - err = os.Setenv(config.EnvVarPyroscopeServer, "") - require.NoError(t, err, "Error setting pyroscope server env var") + if *loadedTestConfig.Pyroscope.Enabled { + loadedTestConfig.Pyroscope.Environment = &testEnvironment.Cfg.Namespace } - err = os.Setenv(config.EnvVarPyroscopeEnvironment, testEnvironment.Cfg.Namespace) - require.NoError(t, err, "Error setting pyroscope environment env var") + numberOfUpkeeps := *loadedTestConfig.Automation.General.NumberOfNodes - for i := 0; i < numberofNodes+1; i++ { // +1 for the OCR boot node + for i := 0; i < numberOfUpkeeps+1; i++ { // +1 for the OCR boot node var nodeTOML string if i == 1 || i == 3 { - nodeTOML = fmt.Sprintf("%s\n\n[Log]\nLevel = \"%s\"", baseTOML, logLevel) + nodeTOML = fmt.Sprintf("%s\n\n[Log]\nLevel = \"%s\"", baseTOML, *loadedTestConfig.Automation.General.ChainlinkNodeLogLevel) } else { nodeTOML = fmt.Sprintf("%s\n\n[Log]\nLevel = \"info\"", baseTOML) } - nodeTOML = networks.AddNetworksConfig(nodeTOML, testNetwork) - testEnvironment.AddHelm(chainlink.New(i, map[string]any{ + nodeTOML = networks.AddNetworksConfig(nodeTOML, loadedTestConfig.Pyroscope, testNetwork) + + var overrideFn = func(_ interface{}, target interface{}) { + ctf_config.MustConfigOverrideChainlinkVersion(loadedTestConfig.ChainlinkImage, target) + ctf_config.MightConfigOverridePyroscopeKey(loadedTestConfig.Pyroscope, target) + } + + cd := chainlink.NewWithOverride(i, map[string]any{ "toml": nodeTOML, "chainlink": nodeSpec, "db": dbSpec, - "prometheus": prometheus, - })) + "prometheus": *loadedTestConfig.Automation.General.UsePrometheus, + }, loadedTestConfig.ChainlinkImage, overrideFn) + + testEnvironment.AddHelm(cd) } err = testEnvironment.Run() @@ -383,7 +313,7 @@ Load Config: a.SetupAutomationDeployment(t) - err = actions.FundChainlinkNodesAddress(chainlinkNodes[1:], chainClient, big.NewFloat(nodeFunding), 0) + err = actions.FundChainlinkNodesAddress(chainlinkNodes[1:], chainClient, big.NewFloat(*loadedTestConfig.Common.ChainlinkNodeFunding), 0) require.NoError(t, err, "Error funding chainlink nodes") consumerContracts := make([]contracts.KeeperConsumer, 0) @@ -406,21 +336,22 @@ Load Config: } upkeepConfigs := make([]automationv2.UpkeepConfig, 0) - loadConfigs := make([]Load, 0) + loadConfigs := make([]a_config.Load, 0) cEVMClient, err := blockchain.ConcurrentEVMClient(testNetwork, testEnvironment, chainClient, l) require.NoError(t, err, "Error building concurrent chain client") - for _, u := range loadConfig.Load { - for i := 0; i < u.NumberOfUpkeeps; i++ { + for _, u := range loadedTestConfig.Automation.Load { + for i := 0; i < *u.NumberOfUpkeeps; i++ { consumerContract, err := contractDeployer.DeployAutomationSimpleLogTriggerConsumer() require.NoError(t, err, "Error deploying automation consumer contract") consumerContracts = append(consumerContracts, consumerContract) l.Debug(). Str("Contract Address", consumerContract.Address()). Int("Number", i+1). - Int("Out Of", u.NumberOfUpkeeps). + Int("Out Of", *u.NumberOfUpkeeps). Msg("Deployed Automation Log Trigger Consumer Contract") - loadCfg := Load{ + + loadCfg := a_config.Load{ NumberOfEvents: u.NumberOfEvents, NumberOfSpamMatchingEvents: u.NumberOfSpamMatchingEvents, NumberOfSpamNonMatchingEvents: u.NumberOfSpamNonMatchingEvents, @@ -429,9 +360,10 @@ Load Config: UpkeepGasLimit: u.UpkeepGasLimit, SharedTrigger: u.SharedTrigger, } + loadConfigs = append(loadConfigs, loadCfg) - if u.SharedTrigger && i > 0 { + if *u.SharedTrigger && i > 0 { triggerAddresses = append(triggerAddresses, triggerAddresses[len(triggerAddresses)-1]) continue } @@ -442,7 +374,7 @@ Load Config: l.Debug(). Str("Contract Address", triggerContract.Address().Hex()). Int("Number", i+1). - Int("Out Of", u.NumberOfUpkeeps). + Int("Out Of", *u.NumberOfUpkeeps). Msg("Deployed Automation Log Trigger Emitter Contract") } err = chainClient.WaitForEvents() @@ -476,7 +408,7 @@ Load Config: UpkeepName: fmt.Sprintf("LogTriggerUpkeep-%d", i), EncryptedEmail: []byte("test@mail.com"), UpkeepContract: common.HexToAddress(consumerContract.Address()), - GasLimit: loadConfigs[i].UpkeepGasLimit, + GasLimit: *loadConfigs[i].UpkeepGasLimit, AdminAddress: common.HexToAddress(chainClient.GetDefaultWallet().Address()), TriggerType: uint8(1), CheckData: encodedCheckDataStruct, @@ -514,11 +446,11 @@ Load Config: for i, triggerContract := range triggerContracts { c := LogTriggerConfig{ Address: triggerContract.Address().String(), - NumberOfEvents: loadConfigs[i].NumberOfEvents, - NumberOfSpamMatchingEvents: loadConfigs[i].NumberOfSpamMatchingEvents, - NumberOfSpamNonMatchingEvents: loadConfigs[i].NumberOfSpamNonMatchingEvents, + NumberOfEvents: int64(*loadConfigs[i].NumberOfEvents), + NumberOfSpamMatchingEvents: int64(*loadConfigs[i].NumberOfSpamMatchingEvents), + NumberOfSpamNonMatchingEvents: int64(*loadConfigs[i].NumberOfSpamNonMatchingEvents), } - numberOfEventsEmittedPerSec = numberOfEventsEmittedPerSec + loadConfigs[i].NumberOfEvents + numberOfEventsEmittedPerSec = numberOfEventsEmittedPerSec + int64(*loadConfigs[i].NumberOfEvents) configs = append(configs, c) } @@ -529,7 +461,7 @@ Load Config: Str("Duration", testSetupDuration.String()). Msg("Test setup ended") - ts, err := sendSlackNotification("Started", l, testEnvironment.Cfg.Namespace, strconv.Itoa(numberofNodes), + ts, err := sendSlackNotification("Started", l, &loadedTestConfig, testEnvironment.Cfg.Namespace, strconv.Itoa(*loadedTestConfig.Automation.General.NumberOfNodes), strconv.FormatInt(startTimeTestSetup.UnixMilli(), 10), "now", []slack.Block{extraBlockWithText("\bTest Config\b\n```" + testConfig + "```")}, slack.MsgOptionBlocks()) if err != nil { @@ -770,7 +702,7 @@ Test Duration: %s` avgR, medianR, ninetyPctR, ninetyNinePctR, maximumR, len(allUpkeepDelays), len(allUpkeepDelaysFast), len(allUpkeepDelaysRecovery), numberOfEventsEmitted, eventsMissed, percentMissed, testExDuration.String()) - _, err = sendSlackNotification("Finished", l, testEnvironment.Cfg.Namespace, strconv.Itoa(numberofNodes), + _, err = sendSlackNotification("Finished", l, &loadedTestConfig, testEnvironment.Cfg.Namespace, strconv.Itoa(*loadedTestConfig.Automation.General.NumberOfNodes), strconv.FormatInt(startTimeTestSetup.UnixMilli(), 10), strconv.FormatInt(time.Now().UnixMilli(), 10), []slack.Block{extraBlockWithText("\bTest Report\b\n```" + testReport + "```")}, slack.MsgOptionTS(ts)) if err != nil { @@ -778,7 +710,7 @@ Test Duration: %s` } t.Cleanup(func() { - if err = actions.TeardownRemoteSuite(t, testEnvironment.Cfg.Namespace, chainlinkNodes, nil, chainClient); err != nil { + if err = actions.TeardownRemoteSuite(t, testEnvironment.Cfg.Namespace, chainlinkNodes, nil, &loadedTestConfig, chainClient); err != nil { l.Error().Err(err).Msg("Error when tearing down remote suite") } }) diff --git a/integration-tests/load/automationv2_1/helpers.go b/integration-tests/load/automationv2_1/helpers.go index 68ac909af9..bd5bfe5866 100644 --- a/integration-tests/load/automationv2_1/helpers.go +++ b/integration-tests/load/automationv2_1/helpers.go @@ -2,47 +2,37 @@ package automationv2_1 import ( "fmt" - "os" - "strings" "github.com/rs/zerolog" "github.com/slack-go/slack" - "github.com/smartcontractkit/chainlink-testing-framework/k8s/config" reportModel "github.com/smartcontractkit/chainlink-testing-framework/testreporters" - "github.com/smartcontractkit/chainlink/integration-tests/testreporters" + tc "github.com/smartcontractkit/chainlink/integration-tests/testconfig" ) -func getEnv(key, fallback string) string { - if inputs, ok := os.LookupEnv("TEST_INPUTS"); ok { - values := strings.Split(inputs, ",") - for _, value := range values { - if strings.Contains(value, key) { - return strings.Split(value, "=")[1] - } - } - } - return fallback -} - func extraBlockWithText(text string) slack.Block { return slack.NewSectionBlock(slack.NewTextBlockObject( "mrkdwn", text, false, false), nil, nil) } -func sendSlackNotification(header string, l zerolog.Logger, namespace string, numberOfNodes, +func sendSlackNotification(header string, l zerolog.Logger, config *tc.TestConfig, namespace string, numberOfNodes, startingTime string, endingTime string, extraBlocks []slack.Block, msgOption slack.MsgOption) (string, error) { slackClient := slack.New(reportModel.SlackAPIKey) headerText := ":chainlink-keepers: Automation Load Test " + header + " :white_check_mark:" - formattedDashboardUrl := fmt.Sprintf("%s?orgId=1&from=%s&to=%s&var-namespace=%s&var-number_of_nodes=%s", testreporters.DashboardUrl, startingTime, endingTime, namespace, numberOfNodes) - l.Info().Str("Dashboard", formattedDashboardUrl).Msg("Dashboard URL") + grafanaUrl, err := config.GetGrafanaBaseURL() + if err != nil { + return "", err + } - pyroscopeServer := os.Getenv(config.EnvVarPyroscopeServer) - pyroscopeEnvironment := os.Getenv(config.EnvVarPyroscopeEnvironment) + dashboardUrl, err := config.GetGrafanaDashboardURL() + if err != nil { + return "", err + } - formattedPyroscopeUrl := fmt.Sprintf("%s/?query=chainlink-node.cpu{Environment=\"%s\"}&from=%s&to=%s", pyroscopeServer, pyroscopeEnvironment, startingTime, endingTime) + formattedDashboardUrl := fmt.Sprintf("%s%s?orgId=1&from=%s&to=%s&var-namespace=%s&var-number_of_nodes=%s", grafanaUrl, dashboardUrl, startingTime, endingTime, namespace, numberOfNodes) + l.Info().Str("Dashboard", formattedDashboardUrl).Msg("Dashboard URL") var notificationBlocks []slack.Block @@ -51,7 +41,11 @@ func sendSlackNotification(header string, l zerolog.Logger, namespace string, nu notificationBlocks = append(notificationBlocks, slack.NewContextBlock("context_block", slack.NewTextBlockObject("plain_text", namespace, false, false))) notificationBlocks = append(notificationBlocks, slack.NewDividerBlock()) - if pyroscopeServer != "" { + if *config.Pyroscope.Enabled { + pyroscopeServer := *config.Pyroscope.ServerUrl + pyroscopeEnvironment := *config.Pyroscope.Environment + + formattedPyroscopeUrl := fmt.Sprintf("%s/?query=chainlink-node.cpu{Environment=\"%s\"}&from=%s&to=%s", pyroscopeServer, pyroscopeEnvironment, startingTime, endingTime) l.Info().Str("Pyroscope", formattedPyroscopeUrl).Msg("Dashboard URL") notificationBlocks = append(notificationBlocks, slack.NewSectionBlock(slack.NewTextBlockObject("mrkdwn", fmt.Sprintf("<%s|Pyroscope>", diff --git a/integration-tests/load/functions/config.go b/integration-tests/load/functions/config.go deleted file mode 100644 index d34e8a9f1e..0000000000 --- a/integration-tests/load/functions/config.go +++ /dev/null @@ -1,125 +0,0 @@ -package loadfunctions - -import ( - "fmt" - "math/big" - "os" - - "github.com/pelletier/go-toml/v2" - "github.com/rs/zerolog/log" - - commonconfig "github.com/smartcontractkit/chainlink-common/pkg/config" -) - -const ( - DefaultConfigFilename = "config.toml" - - ErrReadPerfConfig = "failed to read TOML config for performance tests" - ErrUnmarshalPerfConfig = "failed to unmarshal TOML config for performance tests" -) - -type PerformanceConfig struct { - Soak *Soak `toml:"Soak"` - SecretsSoak *SecretsSoak `toml:"SecretsSoak"` - RealSoak *RealSoak `toml:"RealSoak"` - Stress *Stress `toml:"Stress"` - SecretsStress *SecretsStress `toml:"SecretsStress"` - RealStress *RealStress `toml:"RealStress"` - GatewayListSoak *GatewayListSoak `toml:"GatewayListSoak"` - GatewaySetSoak *GatewaySetSoak `toml:"GatewaySetSoak"` - Common *Common `toml:"Common"` - MumbaiPrivateKey string -} - -type Common struct { - Funding - LINKTokenAddr string `toml:"link_token_addr"` - Coordinator string `toml:"coordinator_addr"` - Router string `toml:"router_addr"` - LoadTestClient string `toml:"client_addr"` - SubscriptionID uint64 `toml:"subscription_id"` - DONID string `toml:"don_id"` - GatewayURL string `toml:"gateway_url"` - Receiver string `toml:"receiver"` - FunctionsCallPayloadHTTP string `toml:"functions_call_payload_http"` - FunctionsCallPayloadWithSecrets string `toml:"functions_call_payload_with_secrets"` - FunctionsCallPayloadReal string `toml:"functions_call_payload_real"` - SecretsSlotID uint8 `toml:"secrets_slot_id"` - SecretsVersionID uint64 `toml:"secrets_version_id"` - // Secrets these are for CI secrets - Secrets string `toml:"secrets"` -} - -type Funding struct { - NodeFunds *big.Float `toml:"node_funds"` - SubFunds *big.Int `toml:"sub_funds"` -} - -type Soak struct { - RPS int64 `toml:"rps"` - RequestsPerCall uint32 `toml:"requests_per_call"` - Duration *commonconfig.Duration `toml:"duration"` -} - -type SecretsSoak struct { - RPS int64 `toml:"rps"` - RequestsPerCall uint32 `toml:"requests_per_call"` - Duration *commonconfig.Duration `toml:"duration"` -} - -type RealSoak struct { - RPS int64 `toml:"rps"` - RequestsPerCall uint32 `toml:"requests_per_call"` - Duration *commonconfig.Duration `toml:"duration"` -} - -type Stress struct { - RPS int64 `toml:"rps"` - RequestsPerCall uint32 `toml:"requests_per_call"` - Duration *commonconfig.Duration `toml:"duration"` -} - -type SecretsStress struct { - RPS int64 `toml:"rps"` - RequestsPerCall uint32 `toml:"requests_per_call"` - Duration *commonconfig.Duration `toml:"duration"` -} - -type RealStress struct { - RPS int64 `toml:"rps"` - RequestsPerCall uint32 `toml:"requests_per_call"` - Duration *commonconfig.Duration `toml:"duration"` -} - -type GatewayListSoak struct { - RPS int64 `toml:"rps"` - Duration *commonconfig.Duration `toml:"duration"` -} - -type GatewaySetSoak struct { - RPS int64 `toml:"rps"` - Duration *commonconfig.Duration `toml:"duration"` -} - -func ReadConfig() (*PerformanceConfig, error) { - var cfg *PerformanceConfig - d, err := os.ReadFile(DefaultConfigFilename) - if err != nil { - return nil, fmt.Errorf("%s, err: %w", ErrReadPerfConfig, err) - } - err = toml.Unmarshal(d, &cfg) - if err != nil { - return nil, fmt.Errorf("%s, err: %w", ErrUnmarshalPerfConfig, err) - } - log.Debug().Interface("PerformanceConfig", cfg).Msg("Parsed performance config") - mpk := os.Getenv("MUMBAI_KEYS") - murls := os.Getenv("MUMBAI_URLS") - snet := os.Getenv("SELECTED_NETWORKS") - if mpk == "" || murls == "" || snet == "" { - return nil, fmt.Errorf( - "ensure variables are set:\nMUMBAI_KEYS variable, private keys, comma separated\nSELECTED_NETWORKS=MUMBAI\nMUMBAI_URLS variable, websocket urls, comma separated", - ) - } - cfg.MumbaiPrivateKey = mpk - return cfg, nil -} diff --git a/integration-tests/load/functions/functions_test.go b/integration-tests/load/functions/functions_test.go index dc52846d3c..d3b82cde33 100644 --- a/integration-tests/load/functions/functions_test.go +++ b/integration-tests/load/functions/functions_test.go @@ -6,12 +6,15 @@ import ( "github.com/smartcontractkit/wasp" "github.com/stretchr/testify/require" + + tc "github.com/smartcontractkit/chainlink/integration-tests/testconfig" ) func TestFunctionsLoad(t *testing.T) { - cfg, err := ReadConfig() - require.NoError(t, err) - ft, err := SetupLocalLoadTestEnv(cfg) + generalConfig, err := tc.GetConfig(tc.NoKey, tc.Functions) + require.NoError(t, err, "failed to get config") + + ft, err := SetupLocalLoadTestEnv(&generalConfig, &generalConfig) require.NoError(t, err) ft.EVMClient.ParallelTransactions(false) @@ -20,10 +23,14 @@ func TestFunctionsLoad(t *testing.T) { "commit": "functions_healthcheck", } - MonitorLoadStats(t, ft, labels) + MonitorLoadStats(t, ft, labels, &generalConfig) t.Run("mumbai functions soak test http", func(t *testing.T) { - _, err := wasp.NewProfile(). + config, err := tc.GetConfig("Soak", tc.Functions) + require.NoError(t, err, "failed to get config") + cfg := config.Functions + cfgl := config.Logging.Loki + _, err = wasp.NewProfile(). Add(wasp.NewGenerator(&wasp.Config{ T: t, LoadType: wasp.RPS, @@ -31,28 +38,32 @@ func TestFunctionsLoad(t *testing.T) { RateLimitUnitDuration: 5 * time.Second, CallTimeout: 3 * time.Minute, Schedule: wasp.Plain( - cfg.Soak.RPS, - cfg.Soak.Duration.Duration(), + *cfg.Performance.RPS, + cfg.Performance.Duration.Duration, ), Gun: NewSingleFunctionCallGun( ft, ModeHTTPPayload, - cfg.Soak.RequestsPerCall, - cfg.Common.FunctionsCallPayloadHTTP, - cfg.Common.SecretsSlotID, - cfg.Common.SecretsVersionID, + *cfg.Performance.RequestsPerCall, + *cfg.Common.FunctionsCallPayloadHTTP, + *cfg.Common.SecretsSlotID, + *cfg.Common.SecretsVersionID, []string{}, - cfg.Common.SubscriptionID, - StringToByte32(cfg.Common.DONID), + *cfg.Common.SubscriptionID, + StringToByte32(*cfg.Common.DONID), ), Labels: labels, - LokiConfig: wasp.NewEnvLokiConfig(), + LokiConfig: wasp.NewLokiConfig(cfgl.Endpoint, cfgl.TenantId, cfgl.BasicAuth, cfgl.BearerToken), })). Run(true) require.NoError(t, err) }) t.Run("mumbai functions stress test http", func(t *testing.T) { + config, err := tc.GetConfig("Stress", tc.Functions) + require.NoError(t, err, "failed to get config") + cfg := config.Functions + cfgl := config.Logging.Loki _, err = wasp.NewProfile(). Add(wasp.NewGenerator(&wasp.Config{ T: t, @@ -61,29 +72,33 @@ func TestFunctionsLoad(t *testing.T) { RateLimitUnitDuration: 5 * time.Second, CallTimeout: 3 * time.Minute, Schedule: wasp.Plain( - cfg.Stress.RPS, - cfg.Stress.Duration.Duration(), + *cfg.Performance.RPS, + cfg.Performance.Duration.Duration, ), Gun: NewSingleFunctionCallGun( ft, ModeHTTPPayload, - cfg.Stress.RequestsPerCall, - cfg.Common.FunctionsCallPayloadHTTP, - cfg.Common.SecretsSlotID, - cfg.Common.SecretsVersionID, + *cfg.Performance.RequestsPerCall, + *cfg.Common.FunctionsCallPayloadHTTP, + *cfg.Common.SecretsSlotID, + *cfg.Common.SecretsVersionID, []string{}, - cfg.Common.SubscriptionID, - StringToByte32(cfg.Common.DONID), + *cfg.Common.SubscriptionID, + StringToByte32(*cfg.Common.DONID), ), Labels: labels, - LokiConfig: wasp.NewEnvLokiConfig(), + LokiConfig: wasp.NewLokiConfig(cfgl.Endpoint, cfgl.TenantId, cfgl.BasicAuth, cfgl.BearerToken), })). Run(true) require.NoError(t, err) }) t.Run("mumbai functions soak test only secrets", func(t *testing.T) { - _, err := wasp.NewProfile(). + config, err := tc.GetConfig("SecretsSoak", tc.Functions) + require.NoError(t, err, "failed to get config") + cfg := config.Functions + cfgl := config.Logging.Loki + _, err = wasp.NewProfile(). Add(wasp.NewGenerator(&wasp.Config{ T: t, LoadType: wasp.RPS, @@ -91,28 +106,32 @@ func TestFunctionsLoad(t *testing.T) { RateLimitUnitDuration: 5 * time.Second, CallTimeout: 3 * time.Minute, Schedule: wasp.Plain( - cfg.SecretsSoak.RPS, - cfg.SecretsSoak.Duration.Duration(), + *cfg.Performance.RPS, + cfg.Performance.Duration.Duration, ), Gun: NewSingleFunctionCallGun( ft, ModeSecretsOnlyPayload, - cfg.SecretsSoak.RequestsPerCall, - cfg.Common.FunctionsCallPayloadWithSecrets, - cfg.Common.SecretsSlotID, - cfg.Common.SecretsVersionID, + *cfg.Performance.RequestsPerCall, + *cfg.Common.FunctionsCallPayloadWithSecrets, + *cfg.Common.SecretsSlotID, + *cfg.Common.SecretsVersionID, []string{}, - cfg.Common.SubscriptionID, - StringToByte32(cfg.Common.DONID), + *cfg.Common.SubscriptionID, + StringToByte32(*cfg.Common.DONID), ), Labels: labels, - LokiConfig: wasp.NewEnvLokiConfig(), + LokiConfig: wasp.NewLokiConfig(cfgl.Endpoint, cfgl.TenantId, cfgl.BasicAuth, cfgl.BearerToken), })). Run(true) require.NoError(t, err) }) t.Run("mumbai functions stress test only secrets", func(t *testing.T) { + config, err := tc.GetConfig("SecretsStress", tc.Functions) + require.NoError(t, err, "failed to get config") + cfg := config.Functions + cfgl := config.Logging.Loki _, err = wasp.NewProfile(). Add(wasp.NewGenerator(&wasp.Config{ T: t, @@ -121,29 +140,33 @@ func TestFunctionsLoad(t *testing.T) { RateLimitUnitDuration: 5 * time.Second, CallTimeout: 3 * time.Minute, Schedule: wasp.Plain( - cfg.SecretsStress.RPS, - cfg.SecretsStress.Duration.Duration(), + *cfg.Performance.RPS, + cfg.Performance.Duration.Duration, ), Gun: NewSingleFunctionCallGun( ft, ModeSecretsOnlyPayload, - cfg.SecretsStress.RequestsPerCall, - cfg.Common.FunctionsCallPayloadWithSecrets, - cfg.Common.SecretsSlotID, - cfg.Common.SecretsVersionID, + *cfg.Performance.RequestsPerCall, + *cfg.Common.FunctionsCallPayloadWithSecrets, + *cfg.Common.SecretsSlotID, + *cfg.Common.SecretsVersionID, []string{}, - cfg.Common.SubscriptionID, - StringToByte32(cfg.Common.DONID), + *cfg.Common.SubscriptionID, + StringToByte32(*cfg.Common.DONID), ), Labels: labels, - LokiConfig: wasp.NewEnvLokiConfig(), + LokiConfig: wasp.NewLokiConfig(cfgl.Endpoint, cfgl.TenantId, cfgl.BasicAuth, cfgl.BearerToken), })). Run(true) require.NoError(t, err) }) t.Run("mumbai functions soak test real", func(t *testing.T) { - _, err := wasp.NewProfile(). + config, err := tc.GetConfig("RealSoak", tc.Functions) + require.NoError(t, err, "failed to get config") + cfg := config.Functions + cfgl := config.Logging.Loki + _, err = wasp.NewProfile(). Add(wasp.NewGenerator(&wasp.Config{ T: t, LoadType: wasp.RPS, @@ -151,28 +174,32 @@ func TestFunctionsLoad(t *testing.T) { RateLimitUnitDuration: 5 * time.Second, CallTimeout: 3 * time.Minute, Schedule: wasp.Plain( - cfg.RealSoak.RPS, - cfg.RealSoak.Duration.Duration(), + *cfg.Performance.RPS, + cfg.Performance.Duration.Duration, ), Gun: NewSingleFunctionCallGun( ft, ModeReal, - cfg.RealSoak.RequestsPerCall, - cfg.Common.FunctionsCallPayloadReal, - cfg.Common.SecretsSlotID, - cfg.Common.SecretsVersionID, + *cfg.Performance.RequestsPerCall, + *cfg.Common.FunctionsCallPayloadReal, + *cfg.Common.SecretsSlotID, + *cfg.Common.SecretsVersionID, []string{"1", "2", "3", "4"}, - cfg.Common.SubscriptionID, - StringToByte32(cfg.Common.DONID), + *cfg.Common.SubscriptionID, + StringToByte32(*cfg.Common.DONID), ), Labels: labels, - LokiConfig: wasp.NewEnvLokiConfig(), + LokiConfig: wasp.NewLokiConfig(cfgl.Endpoint, cfgl.TenantId, cfgl.BasicAuth, cfgl.BearerToken), })). Run(true) require.NoError(t, err) }) t.Run("mumbai functions stress test real", func(t *testing.T) { + config, err := tc.GetConfig("RealStress", tc.Functions) + require.NoError(t, err, "failed to get config") + cfg := config.Functions + cfgl := config.Logging.Loki _, err = wasp.NewProfile(). Add(wasp.NewGenerator(&wasp.Config{ T: t, @@ -181,22 +208,22 @@ func TestFunctionsLoad(t *testing.T) { RateLimitUnitDuration: 5 * time.Second, CallTimeout: 3 * time.Minute, Schedule: wasp.Plain( - cfg.RealStress.RPS, - cfg.RealStress.Duration.Duration(), + *cfg.Performance.RPS, + cfg.Performance.Duration.Duration, ), Gun: NewSingleFunctionCallGun( ft, ModeReal, - cfg.RealStress.RequestsPerCall, - cfg.Common.FunctionsCallPayloadReal, - cfg.Common.SecretsSlotID, - cfg.Common.SecretsVersionID, + *cfg.Performance.RequestsPerCall, + *cfg.Common.FunctionsCallPayloadReal, + *cfg.Common.SecretsSlotID, + *cfg.Common.SecretsVersionID, []string{"1", "2", "3", "4"}, - cfg.Common.SubscriptionID, - StringToByte32(cfg.Common.DONID), + *cfg.Common.SubscriptionID, + StringToByte32(*cfg.Common.DONID), ), Labels: labels, - LokiConfig: wasp.NewEnvLokiConfig(), + LokiConfig: wasp.NewLokiConfig(cfgl.Endpoint, cfgl.TenantId, cfgl.BasicAuth, cfgl.BearerToken), })). Run(true) require.NoError(t, err) diff --git a/integration-tests/load/functions/gateway_gun.go b/integration-tests/load/functions/gateway_gun.go index 62fe80ed02..cc6132e94e 100644 --- a/integration-tests/load/functions/gateway_gun.go +++ b/integration-tests/load/functions/gateway_gun.go @@ -4,7 +4,6 @@ import ( "crypto/ecdsa" "fmt" "math/rand" - "os" "strconv" "time" @@ -12,12 +11,14 @@ import ( "github.com/rs/zerolog/log" "github.com/smartcontractkit/tdh2/go/tdh2/tdh2easy" "github.com/smartcontractkit/wasp" + + "github.com/smartcontractkit/chainlink/integration-tests/types" ) /* SingleFunctionCallGun is a gun that constantly requests randomness for one feed */ type GatewaySecretsSetGun struct { - Cfg *PerformanceConfig + Cfg types.FunctionsTestConfig Resty *resty.Client SlotID uint Method string @@ -26,7 +27,7 @@ type GatewaySecretsSetGun struct { DONPublicKey []byte } -func NewGatewaySecretsSetGun(cfg *PerformanceConfig, method string, pKey *ecdsa.PrivateKey, tdh2PubKey *tdh2easy.PublicKey, donPubKey []byte) *GatewaySecretsSetGun { +func NewGatewaySecretsSetGun(cfg types.FunctionsTestConfig, method string, pKey *ecdsa.PrivateKey, tdh2PubKey *tdh2easy.PublicKey, donPubKey []byte) *GatewaySecretsSetGun { return &GatewaySecretsSetGun{ Cfg: cfg, Resty: resty.New(), @@ -59,12 +60,18 @@ func callSecretsSet(m *GatewaySecretsSetGun) *wasp.Response { if err != nil { return &wasp.Response{Error: err.Error(), Failed: true} } + network := m.Cfg.GetNetworkConfig().SelectedNetworks[0] + if len(m.Cfg.GetNetworkConfig().WalletKeys[network]) < 1 { + panic(fmt.Sprintf("no wallet keys found for %s", network)) + } + + cfg := m.Cfg.GetFunctionsConfig() _, _, err = UploadS4Secrets(m.Resty, &S4SecretsCfg{ - GatewayURL: m.Cfg.Common.GatewayURL, - PrivateKey: os.Getenv("MUMBAI_KEYS"), + GatewayURL: *cfg.Common.GatewayURL, + PrivateKey: m.Cfg.GetNetworkConfig().WalletKeys[network][0], MessageID: randNum, Method: "secrets_set", - DonID: m.Cfg.Common.DONID, + DonID: *cfg.Common.DONID, S4SetSlotID: randSlot, S4SetVersion: version, S4SetExpirationPeriod: expiration, @@ -81,13 +88,18 @@ func callSecretsList(m *GatewaySecretsSetGun) *wasp.Response { randSlot := uint(rand.Intn(5)) version := uint64(time.Now().UnixNano()) expiration := int64(60 * 60 * 1000) + network := m.Cfg.GetNetworkConfig().SelectedNetworks[0] + if len(m.Cfg.GetNetworkConfig().WalletKeys[network]) < 1 { + panic(fmt.Sprintf("no wallet keys found for %s", network)) + } + cfg := m.Cfg.GetFunctionsConfig() if err := ListS4Secrets(m.Resty, &S4SecretsCfg{ - GatewayURL: fmt.Sprintf(m.Cfg.Common.GatewayURL), - RecieverAddr: m.Cfg.Common.Receiver, - PrivateKey: os.Getenv("MUMBAI_KEYS"), + GatewayURL: *cfg.Common.GatewayURL, + RecieverAddr: *cfg.Common.Receiver, + PrivateKey: m.Cfg.GetNetworkConfig().WalletKeys[network][0], MessageID: randNum, Method: m.Method, - DonID: m.Cfg.Common.DONID, + DonID: *cfg.Common.DONID, S4SetSlotID: randSlot, S4SetVersion: version, S4SetExpirationPeriod: expiration, diff --git a/integration-tests/load/functions/gateway_test.go b/integration-tests/load/functions/gateway_test.go index c8e63f92f2..be5d148386 100644 --- a/integration-tests/load/functions/gateway_test.go +++ b/integration-tests/load/functions/gateway_test.go @@ -6,13 +6,17 @@ import ( "github.com/smartcontractkit/wasp" "github.com/stretchr/testify/require" + tc "github.com/smartcontractkit/chainlink/integration-tests/testconfig" "github.com/smartcontractkit/chainlink/v2/core/services/gateway/handlers/functions" ) func TestGatewayLoad(t *testing.T) { - cfg, err := ReadConfig() + listConfig, err := tc.GetConfig("GatewayList", tc.Functions) require.NoError(t, err) - ft, err := SetupLocalLoadTestEnv(cfg) + cfgl := listConfig.Logging.Loki + + require.NoError(t, err) + ft, err := SetupLocalLoadTestEnv(&listConfig, &listConfig) require.NoError(t, err) ft.EVMClient.ParallelTransactions(false) @@ -25,36 +29,39 @@ func TestGatewayLoad(t *testing.T) { LoadType: wasp.RPS, GenName: functions.MethodSecretsList, Schedule: wasp.Plain( - cfg.GatewayListSoak.RPS, - cfg.GatewayListSoak.Duration.Duration(), + *listConfig.Functions.Performance.RPS, + listConfig.Functions.Performance.Duration.Duration, ), Gun: NewGatewaySecretsSetGun( - cfg, + &listConfig, functions.MethodSecretsList, ft.EthereumPrivateKey, ft.ThresholdPublicKey, ft.DONPublicKey, ), Labels: labels, - LokiConfig: wasp.NewEnvLokiConfig(), + LokiConfig: wasp.NewLokiConfig(cfgl.Endpoint, cfgl.TenantId, cfgl.BasicAuth, cfgl.BearerToken), } + setConfig, err := tc.GetConfig("GatewaySet", tc.Functions) + require.NoError(t, err) + secretsSetCfg := &wasp.Config{ LoadType: wasp.RPS, GenName: functions.MethodSecretsSet, Schedule: wasp.Plain( - cfg.GatewaySetSoak.RPS, - cfg.GatewaySetSoak.Duration.Duration(), + *setConfig.Functions.Performance.RPS, + setConfig.Functions.Performance.Duration.Duration, ), Gun: NewGatewaySecretsSetGun( - cfg, + &setConfig, functions.MethodSecretsSet, ft.EthereumPrivateKey, ft.ThresholdPublicKey, ft.DONPublicKey, ), Labels: labels, - LokiConfig: wasp.NewEnvLokiConfig(), + LokiConfig: wasp.NewLokiConfig(cfgl.Endpoint, cfgl.TenantId, cfgl.BasicAuth, cfgl.BearerToken), } t.Run("gateway secrets list soak test", func(t *testing.T) { diff --git a/integration-tests/load/functions/onchain_monitoring.go b/integration-tests/load/functions/onchain_monitoring.go index c4b4bdb78c..12a10ce004 100644 --- a/integration-tests/load/functions/onchain_monitoring.go +++ b/integration-tests/load/functions/onchain_monitoring.go @@ -6,6 +6,8 @@ import ( "github.com/rs/zerolog/log" "github.com/smartcontractkit/wasp" + + tc "github.com/smartcontractkit/chainlink/integration-tests/testconfig" ) /* Monitors on-chain stats of LoadConsumer and pushes them to Loki every second */ @@ -23,7 +25,7 @@ type LoadStats struct { Empty uint32 } -func MonitorLoadStats(t *testing.T, ft *FunctionsTest, labels map[string]string) { +func MonitorLoadStats(t *testing.T, ft *FunctionsTest, labels map[string]string, config tc.GlobalTestConfig) { go func() { updatedLabels := make(map[string]string) for k, v := range labels { @@ -32,7 +34,9 @@ func MonitorLoadStats(t *testing.T, ft *FunctionsTest, labels map[string]string) updatedLabels["type"] = LokiTypeLabel updatedLabels["go_test_name"] = t.Name() updatedLabels["gen_name"] = "performance" - lc, err := wasp.NewLokiClient(wasp.NewEnvLokiConfig()) + cfgl := config.GetLoggingConfig().Loki + lokiConfig := wasp.NewLokiConfig(cfgl.Endpoint, cfgl.TenantId, cfgl.BasicAuth, cfgl.BearerToken) + lc, err := wasp.NewLokiClient(lokiConfig) if err != nil { log.Error().Err(err).Msg(ErrLokiClient) return @@ -46,16 +50,20 @@ func MonitorLoadStats(t *testing.T, ft *FunctionsTest, labels map[string]string) if err != nil { log.Error().Err(err).Msg(ErrMetrics) } - log.Info(). - Hex("LastReqID", []byte(stats.LastRequestID)). - Str("LastResponse", stats.LastResponse). - Str("LastError", stats.LastError). - Uint32("Total", stats.Total). - Uint32("Succeeded", stats.Succeeded). - Uint32("Errored", stats.Errored). - Uint32("Empty", stats.Empty).Msg("On-chain stats for load test client") - if err := lc.HandleStruct(wasp.LabelsMapToModel(updatedLabels), time.Now(), stats); err != nil { - log.Error().Err(err).Msg(ErrLokiPush) + if stats != nil { + log.Info(). + Hex("LastReqID", []byte(stats.LastRequestID)). + Str("LastResponse", stats.LastResponse). + Str("LastError", stats.LastError). + Uint32("Total", stats.Total). + Uint32("Succeeded", stats.Succeeded). + Uint32("Errored", stats.Errored). + Uint32("Empty", stats.Empty).Msg("On-chain stats for load test client") + if err := lc.HandleStruct(wasp.LabelsMapToModel(updatedLabels), time.Now(), stats); err != nil { + log.Error().Err(err).Msg(ErrLokiPush) + } + } else { + log.Warn().Msg("No stats to push to Loki") } } }() diff --git a/integration-tests/load/functions/setup.go b/integration-tests/load/functions/setup.go index e96eac3cf8..e671190759 100644 --- a/integration-tests/load/functions/setup.go +++ b/integration-tests/load/functions/setup.go @@ -5,7 +5,6 @@ import ( "fmt" "math/big" mrand "math/rand" - "os" "strconv" "time" @@ -18,6 +17,8 @@ import ( "github.com/smartcontractkit/chainlink-testing-framework/networks" "github.com/smartcontractkit/chainlink/integration-tests/contracts" + tc "github.com/smartcontractkit/chainlink/integration-tests/testconfig" + "github.com/smartcontractkit/chainlink/integration-tests/types" chainlinkutils "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils" ) @@ -50,8 +51,9 @@ type S4SecretsCfg struct { S4SetPayload string } -func SetupLocalLoadTestEnv(cfg *PerformanceConfig) (*FunctionsTest, error) { - bc, err := blockchain.NewEVMClientFromNetwork(networks.MustGetSelectedNetworksFromEnv()[0], log.Logger) +func SetupLocalLoadTestEnv(globalConfig tc.GlobalTestConfig, functionsConfig types.FunctionsTestConfig) (*FunctionsTest, error) { + selectedNetwork := networks.MustGetSelectedNetworkConfig(globalConfig.GetNetworkConfig())[0] + bc, err := blockchain.NewEVMClientFromNetwork(selectedNetwork, log.Logger) if err != nil { return nil, err } @@ -67,28 +69,31 @@ func SetupLocalLoadTestEnv(cfg *PerformanceConfig) (*FunctionsTest, error) { if err != nil { return nil, err } - lt, err := cl.LoadLINKToken(cfg.Common.LINKTokenAddr) + + cfg := functionsConfig.GetFunctionsConfig() + + lt, err := cl.LoadLINKToken(*cfg.Common.LINKTokenAddr) if err != nil { return nil, err } - coord, err := cl.LoadFunctionsCoordinator(cfg.Common.Coordinator) + coord, err := cl.LoadFunctionsCoordinator(*cfg.Common.Coordinator) if err != nil { return nil, err } - router, err := cl.LoadFunctionsRouter(cfg.Common.Router) + router, err := cl.LoadFunctionsRouter(*cfg.Common.Router) if err != nil { return nil, err } var loadTestClient contracts.FunctionsLoadTestClient - if cfg.Common.LoadTestClient != "" { - loadTestClient, err = cl.LoadFunctionsLoadTestClient(cfg.Common.LoadTestClient) + if cfg.Common.LoadTestClient != nil && *cfg.Common.LoadTestClient != "" { + loadTestClient, err = cl.LoadFunctionsLoadTestClient(*cfg.Common.LoadTestClient) } else { - loadTestClient, err = cd.DeployFunctionsLoadTestClient(cfg.Common.Router) + loadTestClient, err = cd.DeployFunctionsLoadTestClient(*cfg.Common.Router) } if err != nil { return nil, err } - if cfg.Common.SubscriptionID == 0 { + if cfg.Common.SubscriptionID == nil { log.Info().Msg("Creating new subscription") subID, err := router.CreateSubscriptionWithConsumer(loadTestClient.Address()) if err != nil { @@ -98,13 +103,13 @@ func SetupLocalLoadTestEnv(cfg *PerformanceConfig) (*FunctionsTest, error) { if err != nil { return nil, fmt.Errorf("failed to encode subscription ID for funding: %w", err) } - _, err = lt.TransferAndCall(router.Address(), big.NewInt(0).Mul(cfg.Common.Funding.SubFunds, big.NewInt(1e18)), encodedSubId) + _, err = lt.TransferAndCall(router.Address(), big.NewInt(0).Mul(cfg.Common.SubFunds, big.NewInt(1e18)), encodedSubId) if err != nil { return nil, fmt.Errorf("failed to transferAndCall router, LINK funding: %w", err) } - cfg.Common.SubscriptionID = subID + cfg.Common.SubscriptionID = &subID } - pKey, pubKey, err := parseEthereumPrivateKey(os.Getenv("MUMBAI_KEYS")) + pKey, pubKey, err := parseEthereumPrivateKey(selectedNetwork.PrivateKeys[0]) if err != nil { return nil, fmt.Errorf("failed to load Ethereum private key: %w", err) } @@ -123,17 +128,17 @@ func SetupLocalLoadTestEnv(cfg *PerformanceConfig) (*FunctionsTest, error) { return nil, fmt.Errorf("failed to unmarshal tdh2 public key: %w", err) } var encryptedSecrets string - if cfg.Common.Secrets != "" { - encryptedSecrets, err = EncryptS4Secrets(pKey, tdh2pk, donPubKey, cfg.Common.Secrets) + if cfg.Common.Secrets != nil && *cfg.Common.Secrets != "" { + encryptedSecrets, err = EncryptS4Secrets(pKey, tdh2pk, donPubKey, *cfg.Common.Secrets) if err != nil { return nil, fmt.Errorf("failed to generate tdh2 secrets: %w", err) } slotID, slotVersion, err := UploadS4Secrets(resty.New(), &S4SecretsCfg{ - GatewayURL: cfg.Common.GatewayURL, - PrivateKey: cfg.MumbaiPrivateKey, + GatewayURL: *cfg.Common.GatewayURL, + PrivateKey: selectedNetwork.PrivateKeys[0], MessageID: strconv.Itoa(mrand.Intn(100000-1) + 1), Method: "secrets_set", - DonID: cfg.Common.DONID, + DonID: *cfg.Common.DONID, S4SetSlotID: uint(mrand.Intn(5)), S4SetVersion: uint64(time.Now().UnixNano()), S4SetExpirationPeriod: 60 * 60 * 1000, @@ -142,8 +147,8 @@ func SetupLocalLoadTestEnv(cfg *PerformanceConfig) (*FunctionsTest, error) { if err != nil { return nil, fmt.Errorf("failed to upload secrets to S4: %w", err) } - cfg.Common.SecretsSlotID = slotID - cfg.Common.SecretsVersionID = slotVersion + cfg.Common.SecretsSlotID = &slotID + cfg.Common.SecretsVersionID = &slotVersion log.Info(). Uint8("SlotID", slotID). Uint64("SlotVersion", slotVersion). diff --git a/integration-tests/load/log_poller/config.toml b/integration-tests/load/log_poller/config.toml deleted file mode 100644 index 2e32800194..0000000000 --- a/integration-tests/load/log_poller/config.toml +++ /dev/null @@ -1,22 +0,0 @@ -[general] -generator = "looped" -contracts = 10 -events_per_tx = 10 - -[chaos] -experiment_count = 10 - -[looped] -[looped.contract] -execution_count = 300 - -[looped.fuzz] -min_emit_wait_time_ms = 100 -max_emit_wait_time_ms = 500 - -[wasp] -[wasp.load] -call_timeout = "3m" -rate_limit_unit_duration = "2s" -LPS = 30 -duration = "1m" \ No newline at end of file diff --git a/integration-tests/load/log_poller/log_poller_test.go b/integration-tests/load/log_poller/log_poller_test.go deleted file mode 100644 index 04366848f0..0000000000 --- a/integration-tests/load/log_poller/log_poller_test.go +++ /dev/null @@ -1,25 +0,0 @@ -package logpoller - -import ( - "testing" - - "github.com/ethereum/go-ethereum/accounts/abi" - - "github.com/stretchr/testify/require" - - lp_helpers "github.com/smartcontractkit/chainlink/integration-tests/universal/log_poller" -) - -func TestLoadTestLogPoller(t *testing.T) { - cfg, err := lp_helpers.ReadConfig(lp_helpers.DefaultConfigFilename) - require.NoError(t, err) - - eventsToEmit := []abi.Event{} - for _, event := range lp_helpers.EmitterABI.Events { - eventsToEmit = append(eventsToEmit, event) - } - - cfg.General.EventsToEmit = eventsToEmit - - lp_helpers.ExecuteBasicLogPollerTest(t, cfg) -} diff --git a/integration-tests/load/ocr/config.go b/integration-tests/load/ocr/config.go deleted file mode 100644 index 4b324210b0..0000000000 --- a/integration-tests/load/ocr/config.go +++ /dev/null @@ -1,72 +0,0 @@ -package ocr - -import ( - "encoding/base64" - "fmt" - "os" - - "github.com/pelletier/go-toml/v2" - "github.com/rs/zerolog/log" - - commonconfig "github.com/smartcontractkit/chainlink-common/pkg/config" -) - -const ( - DefaultConfigFilename = "config.toml" - ErrReadPerfConfig = "failed to read TOML config for performance tests" - ErrUnmarshalPerfConfig = "failed to unmarshal TOML config for performance tests" -) - -type PerformanceConfig struct { - Load *Load `toml:"Load"` - Volume *Volume `toml:"Volume"` - Common *Common `toml:"Common"` -} - -type Common struct { - ETHFunds int `toml:"eth_funds"` -} - -type Load struct { - TestDuration *commonconfig.Duration `toml:"test_duration"` - Rate int64 `toml:"rate"` - RateLimitUnitDuration *commonconfig.Duration `toml:"rate_limit_unit_duration"` - VerificationInterval *commonconfig.Duration `toml:"verification_interval"` - VerificationTimeout *commonconfig.Duration `toml:"verification_timeout"` - EAChangeInterval *commonconfig.Duration `toml:"ea_change_interval"` -} - -type Volume struct { - TestDuration *commonconfig.Duration `toml:"test_duration"` - Rate int64 `toml:"rate"` - VURequestsPerUnit int `toml:"vu_requests_per_unit"` - RateLimitUnitDuration *commonconfig.Duration `toml:"rate_limit_unit_duration"` - VerificationInterval *commonconfig.Duration `toml:"verification_interval"` - VerificationTimeout *commonconfig.Duration `toml:"verification_timeout"` - EAChangeInterval *commonconfig.Duration `toml:"ea_change_interval"` -} - -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, fmt.Errorf("%s, err: %w", ErrReadPerfConfig, err) - } - } else { - d, err = base64.StdEncoding.DecodeString(rawConfig) - if err != nil { - return nil, fmt.Errorf("%s, err: %w", ErrReadPerfConfig, err) - } - } - err = toml.Unmarshal(d, &cfg) - if err != nil { - return nil, fmt.Errorf("%s, err: %w", ErrUnmarshalPerfConfig, err) - } - - log.Debug().Interface("Config", cfg).Msg("Parsed config") - return cfg, nil -} diff --git a/integration-tests/load/ocr/config.toml b/integration-tests/load/ocr/config.toml deleted file mode 100644 index df8364b3ee..0000000000 --- a/integration-tests/load/ocr/config.toml +++ /dev/null @@ -1,20 +0,0 @@ -[Load] -test_duration = "3m" -rate_limit_unit_duration = "1m" -rate = 3 -verification_interval = "5s" -verification_timeout = "3m" -ea_change_interval = "5s" - -[Volume] -test_duration = "3m" -rate_limit_unit_duration = "1m" -vu_requests_per_unit = 10 -rate = 1 -verification_interval = "5s" -verification_timeout = "3m" - -ea_change_interval = "5s" - -[Common] -eth_funds = 3 \ No newline at end of file diff --git a/integration-tests/load/ocr/ocr_test.go b/integration-tests/load/ocr/ocr_test.go index 49e624ecd8..c6edf9122b 100644 --- a/integration-tests/load/ocr/ocr_test.go +++ b/integration-tests/load/ocr/ocr_test.go @@ -8,6 +8,7 @@ import ( "github.com/smartcontractkit/wasp" "github.com/smartcontractkit/chainlink-testing-framework/logging" + tc "github.com/smartcontractkit/chainlink/integration-tests/testconfig" "github.com/smartcontractkit/chainlink/integration-tests/k8s" ) @@ -27,21 +28,25 @@ func TestOCRLoad(t *testing.T) { require.NoError(t, err) ocrInstances, err := SetupFeed(cc, msClient, cd, bootstrapNode, workerNodes, lt) require.NoError(t, err) - cfg, err := ReadConfig() + + config, err := tc.GetConfig("Load", tc.OCR) require.NoError(t, err) - SimulateEAActivity(l, cfg.Load.EAChangeInterval.Duration(), ocrInstances, workerNodes, msClient) + + cfg := config.OCR + cfgl := config.Logging.Loki + SimulateEAActivity(l, cfg.Load.EAChangeInterval.Duration, ocrInstances, workerNodes, msClient) p := wasp.NewProfile() p.Add(wasp.NewGenerator(&wasp.Config{ T: t, GenName: "ocr", LoadType: wasp.RPS, - CallTimeout: cfg.Load.VerificationTimeout.Duration(), - RateLimitUnitDuration: cfg.Load.RateLimitUnitDuration.Duration(), - Schedule: wasp.Plain(cfg.Load.Rate, cfg.Load.TestDuration.Duration()), + CallTimeout: cfg.Load.VerificationTimeout.Duration, + RateLimitUnitDuration: cfg.Load.RateLimitUnitDuration.Duration, + Schedule: wasp.Plain(*cfg.Load.Rate, cfg.Load.TestDuration.Duration), Gun: NewGun(l, cc, ocrInstances), Labels: CommonTestLabels, - LokiConfig: wasp.NewEnvLokiConfig(), + LokiConfig: wasp.NewLokiConfig(cfgl.Endpoint, cfgl.TenantId, cfgl.BasicAuth, cfgl.BearerToken), })) _, err = p.Run(true) require.NoError(t, err) @@ -53,19 +58,22 @@ func TestOCRVolume(t *testing.T) { require.NoError(t, err) lt, err := SetupCluster(cc, cd, workerNodes) require.NoError(t, err) - cfg, err := ReadConfig() + config, err := tc.GetConfig("Volume", tc.OCR) require.NoError(t, err) + cfg := config.OCR + cfgl := config.Logging.Loki + p := wasp.NewProfile() p.Add(wasp.NewGenerator(&wasp.Config{ T: t, GenName: "ocr", LoadType: wasp.VU, - CallTimeout: cfg.Volume.VerificationTimeout.Duration(), - Schedule: wasp.Plain(cfg.Volume.Rate, cfg.Volume.TestDuration.Duration()), - VU: NewVU(l, cfg.Volume.VURequestsPerUnit, cfg.Volume.RateLimitUnitDuration.Duration(), cc, lt, cd, bootstrapNode, workerNodes, msClient), + CallTimeout: cfg.Volume.VerificationTimeout.Duration, + Schedule: wasp.Plain(*cfg.Volume.Rate, cfg.Volume.TestDuration.Duration), + VU: NewVU(l, *cfg.Volume.VURequestsPerUnit, cfg.Volume.RateLimitUnitDuration.Duration, cc, lt, cd, bootstrapNode, workerNodes, msClient), Labels: CommonTestLabels, - LokiConfig: wasp.NewEnvLokiConfig(), + LokiConfig: wasp.NewLokiConfig(cfgl.Endpoint, cfgl.TenantId, cfgl.BasicAuth, cfgl.BearerToken), })) _, err = p.Run(true) require.NoError(t, err) diff --git a/integration-tests/load/vrfv2/cmd/dashboard.go b/integration-tests/load/vrfv2/cmd/dashboard.go index 0fb7be2b78..2536b4caed 100644 --- a/integration-tests/load/vrfv2/cmd/dashboard.go +++ b/integration-tests/load/vrfv2/cmd/dashboard.go @@ -13,6 +13,7 @@ import ( ) func main() { + //TODO switch to TOML too? lokiDS := os.Getenv("DATA_SOURCE_NAME") d, err := wasp.NewDashboard(nil, []dashboard.Option{ diff --git a/integration-tests/load/vrfv2/config.go b/integration-tests/load/vrfv2/config.go deleted file mode 100644 index e97ac6a964..0000000000 --- a/integration-tests/load/vrfv2/config.go +++ /dev/null @@ -1,151 +0,0 @@ -package loadvrfv2 - -import ( - "encoding/base64" - "fmt" - "os" - - "github.com/smartcontractkit/chainlink/integration-tests/actions/vrfv2_actions/vrfv2_config" - - "github.com/pelletier/go-toml/v2" - "github.com/rs/zerolog/log" - - commonconfig "github.com/smartcontractkit/chainlink-common/pkg/config" -) - -const ( - DefaultConfigFilename = "config.toml" - SoakTestType = "Soak" - LoadTestType = "Load" - StressTestType = "Stress" - SpikeTestType = "Spike" - - 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"` - LinkAddress string `toml:"link_address"` - SubID uint64 `toml:"sub_id"` - KeyHash string `toml:"key_hash"` - Funding - CreateFundSubsAndAddConsumers bool `toml:"create_fund_subs_and_add_consumers"` - NodeSendingKeys []string `toml:"node_sending_keys"` -} - -type NewEnvConfig struct { - Funding -} - -type Common struct { - MinimumConfirmations uint16 `toml:"minimum_confirmations"` - CancelSubsAfterTestRun bool `toml:"cancel_subs_after_test_run"` -} - -type Funding struct { - SubFunding - NodeSendingKeyFunding float64 `toml:"node_sending_key_funding"` - NodeSendingKeyFundingMin float64 `toml:"node_sending_key_funding_min"` -} - -type SubFunding struct { - SubFundsLink float64 `toml:"sub_funds_link"` -} - -type Soak struct { - PerformanceTestConfig -} - -type Load struct { - PerformanceTestConfig -} - -type Stress struct { - PerformanceTestConfig -} - -type Spike struct { - PerformanceTestConfig -} - -type PerformanceTestConfig struct { - NumberOfSubToCreate int `toml:"number_of_sub_to_create"` - - RPS int64 `toml:"rps"` - //Duration *commonconfig.Duration `toml:"duration"` - RateLimitUnitDuration *commonconfig.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, fmt.Errorf("%s, err: %w", ErrReadPerfConfig, err) - } - } else { - d, err = base64.StdEncoding.DecodeString(rawConfig) - if err != nil { - return nil, fmt.Errorf("%s, err: %w", ErrReadPerfConfig, err) - } - } - err = toml.Unmarshal(d, &cfg) - if err != nil { - return nil, fmt.Errorf("%s, err: %w", ErrUnmarshalPerfConfig, err) - } - - if cfg.Soak.RandomnessRequestCountPerRequest <= cfg.Soak.RandomnessRequestCountPerRequestDeviation { - return nil, fmt.Errorf("%s, err: %w", ErrDeviationShouldBeLessThanOriginal, err) - } - - log.Debug().Interface("Config", cfg).Msg("Parsed config") - return cfg, nil -} - -func SetPerformanceTestConfig(testType string, vrfv2Config *vrfv2_config.VRFV2Config, cfg *PerformanceConfig) { - switch testType { - case SoakTestType: - vrfv2Config.NumberOfSubToCreate = cfg.Soak.NumberOfSubToCreate - vrfv2Config.RPS = cfg.Soak.RPS - vrfv2Config.RateLimitUnitDuration = cfg.Soak.RateLimitUnitDuration.Duration() - vrfv2Config.RandomnessRequestCountPerRequest = cfg.Soak.RandomnessRequestCountPerRequest - vrfv2Config.RandomnessRequestCountPerRequestDeviation = cfg.Soak.RandomnessRequestCountPerRequestDeviation - case LoadTestType: - vrfv2Config.NumberOfSubToCreate = cfg.Load.NumberOfSubToCreate - vrfv2Config.RPS = cfg.Load.RPS - vrfv2Config.RateLimitUnitDuration = cfg.Load.RateLimitUnitDuration.Duration() - vrfv2Config.RandomnessRequestCountPerRequest = cfg.Load.RandomnessRequestCountPerRequest - vrfv2Config.RandomnessRequestCountPerRequestDeviation = cfg.Load.RandomnessRequestCountPerRequestDeviation - case StressTestType: - vrfv2Config.NumberOfSubToCreate = cfg.Stress.NumberOfSubToCreate - vrfv2Config.RPS = cfg.Stress.RPS - vrfv2Config.RateLimitUnitDuration = cfg.Stress.RateLimitUnitDuration.Duration() - vrfv2Config.RandomnessRequestCountPerRequest = cfg.Stress.RandomnessRequestCountPerRequest - vrfv2Config.RandomnessRequestCountPerRequestDeviation = cfg.Stress.RandomnessRequestCountPerRequestDeviation - case SpikeTestType: - vrfv2Config.NumberOfSubToCreate = cfg.Spike.NumberOfSubToCreate - vrfv2Config.RPS = cfg.Spike.RPS - vrfv2Config.RateLimitUnitDuration = cfg.Spike.RateLimitUnitDuration.Duration() - vrfv2Config.RandomnessRequestCountPerRequest = cfg.Spike.RandomnessRequestCountPerRequest - vrfv2Config.RandomnessRequestCountPerRequestDeviation = cfg.Spike.RandomnessRequestCountPerRequestDeviation - } -} diff --git a/integration-tests/load/vrfv2/config.toml b/integration-tests/load/vrfv2/config.toml deleted file mode 100644 index 6f54d1ec99..0000000000 --- a/integration-tests/load/vrfv2/config.toml +++ /dev/null @@ -1,58 +0,0 @@ - -[Common] -minimum_confirmations = 3 -cancel_subs_after_test_run = true - -[NewEnvConfig] -sub_funds_link = 1000 -node_sending_key_funding = 1000 - -[ExistingEnvConfig] -coordinator_address = "" -consumer_address = "" -sub_id = 1 -key_hash = "" -create_fund_subs_and_add_consumers = true -link_address = "" -sub_funds_link = 10 -node_sending_key_funding_min = 1 -node_sending_keys = [ - "", - "", - "", - "", - "", - "", -] - -# 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 -number_of_sub_to_create = 1 - -# approx 60 RPM - 1 tx request with 3 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 -number_of_sub_to_create = 1 - -# approx 540 RPM - 3 tx requests per second with 4 rand requests in each tx -[Stress] -rate_limit_unit_duration = "1s" -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 -number_of_sub_to_create = 1 - -# 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 -number_of_sub_to_create = 1 diff --git a/integration-tests/load/vrfv2/gun.go b/integration-tests/load/vrfv2/gun.go index fd8cb6195e..bd1dc96fad 100644 --- a/integration-tests/load/vrfv2/gun.go +++ b/integration-tests/load/vrfv2/gun.go @@ -4,36 +4,35 @@ import ( "math/rand" "github.com/rs/zerolog" - "github.com/smartcontractkit/wasp" "github.com/smartcontractkit/chainlink/integration-tests/actions/vrfv2_actions" - "github.com/smartcontractkit/chainlink/integration-tests/actions/vrfv2_actions/vrfv2_config" + "github.com/smartcontractkit/chainlink/integration-tests/types" ) /* SingleHashGun is a gun that constantly requests randomness for one feed */ type SingleHashGun struct { - contracts *vrfv2_actions.VRFV2Contracts - keyHash [32]byte - subIDs []uint64 - vrfv2Config vrfv2_config.VRFV2Config - logger zerolog.Logger + contracts *vrfv2_actions.VRFV2Contracts + keyHash [32]byte + subIDs []uint64 + testConfig types.VRFv2TestConfig + logger zerolog.Logger } func NewSingleHashGun( contracts *vrfv2_actions.VRFV2Contracts, keyHash [32]byte, subIDs []uint64, - vrfv2Config vrfv2_config.VRFV2Config, + testConfig types.VRFv2TestConfig, logger zerolog.Logger, ) *SingleHashGun { return &SingleHashGun{ - contracts: contracts, - keyHash: keyHash, - subIDs: subIDs, - vrfv2Config: vrfv2Config, - logger: logger, + contracts: contracts, + keyHash: keyHash, + subIDs: subIDs, + testConfig: testConfig, + logger: logger, } } @@ -41,19 +40,23 @@ func NewSingleHashGun( func (m *SingleHashGun) Call(_ *wasp.Generator) *wasp.Response { //todo - should work with multiple consumers and consumers having different keyhashes and wallets + vrfv2Config := m.testConfig.GetVRFv2Config().General //randomly increase/decrease randomness request count per TX - randomnessRequestCountPerRequest := deviateValue(m.vrfv2Config.RandomnessRequestCountPerRequest, m.vrfv2Config.RandomnessRequestCountPerRequestDeviation) + randomnessRequestCountPerRequest := deviateValue(*vrfv2Config.RandomnessRequestCountPerRequest, *vrfv2Config.RandomnessRequestCountPerRequestDeviation) _, err := vrfv2_actions.RequestRandomnessAndWaitForFulfillment( + m.logger, //the same consumer is used for all requests and in all subs m.contracts.LoadTestConsumers[0], m.contracts.Coordinator, - &vrfv2_actions.VRFV2Data{VRFV2KeyData: vrfv2_actions.VRFV2KeyData{KeyHash: m.keyHash}}, //randomly pick a subID from pool of subIDs m.subIDs[randInRange(0, len(m.subIDs)-1)], + &vrfv2_actions.VRFV2Data{VRFV2KeyData: vrfv2_actions.VRFV2KeyData{KeyHash: m.keyHash}}, + *vrfv2Config.MinimumConfirmations, + *vrfv2Config.CallbackGasLimit, + *vrfv2Config.NumberOfWords, randomnessRequestCountPerRequest, - m.vrfv2Config, - m.vrfv2Config.RandomWordsFulfilledEventTimeout, - m.logger, + *vrfv2Config.RandomnessRequestCountPerRequestDeviation, + vrfv2Config.RandomWordsFulfilledEventTimeout.Duration, ) if err != nil { return &wasp.Response{Error: err.Error(), Failed: true} diff --git a/integration-tests/load/vrfv2/vrfv2_test.go b/integration-tests/load/vrfv2/vrfv2_test.go index c48f348859..142764b171 100644 --- a/integration-tests/load/vrfv2/vrfv2_test.go +++ b/integration-tests/load/vrfv2/vrfv2_test.go @@ -3,13 +3,11 @@ package loadvrfv2 import ( "context" "math/big" - "os" "sync" "testing" "time" "github.com/ethereum/go-ethereum/common" - "github.com/kelseyhightower/envconfig" "github.com/rs/zerolog" "github.com/rs/zerolog/log" "github.com/smartcontractkit/wasp" @@ -18,7 +16,7 @@ import ( "github.com/smartcontractkit/chainlink-testing-framework/logging" "github.com/smartcontractkit/chainlink-testing-framework/utils/conversions" "github.com/smartcontractkit/chainlink/integration-tests/actions" - "github.com/smartcontractkit/chainlink/integration-tests/actions/vrfv2_actions/vrfv2_config" + "github.com/smartcontractkit/chainlink/integration-tests/contracts" "github.com/smartcontractkit/chainlink/integration-tests/docker/test_env" "github.com/smartcontractkit/chainlink/integration-tests/testreporters" @@ -26,6 +24,7 @@ import ( "github.com/stretchr/testify/require" "github.com/smartcontractkit/chainlink/integration-tests/actions/vrfv2_actions" + tc "github.com/smartcontractkit/chainlink/integration-tests/testconfig" ) var ( @@ -39,26 +38,21 @@ var ( "branch": "vrfv2_healthcheck", "commit": "vrfv2_healthcheck", } - - testType = os.Getenv("TEST_TYPE") ) func TestVRFV2Performance(t *testing.T) { - cfg, err := ReadConfig() + l := logging.GetTestLogger(t) + + testType, err := tc.GetConfigurationNameFromEnv() require.NoError(t, err) - var vrfv2Config vrfv2_config.VRFV2Config - err = envconfig.Process("VRFV2", &vrfv2Config) + testConfig, err := tc.GetConfig(testType, tc.VRFv2) require.NoError(t, err) testReporter := &testreporters.VRFV2TestReporter{} + vrfv2Config := testConfig.VRFv2 - SetPerformanceTestConfig(testType, &vrfv2Config, cfg) - - l := logging.GetTestLogger(t) - //todo: temporary solution with envconfig and toml config until VRF-662 is implemented - vrfv2Config.MinimumConfirmations = cfg.Common.MinimumConfirmations - - lokiConfig := wasp.NewEnvLokiConfig() + cfgl := testConfig.Logging.Loki + lokiConfig := wasp.NewLokiConfig(cfgl.Endpoint, cfgl.TenantId, cfgl.BasicAuth, cfgl.BearerToken) lc, err := wasp.NewLokiClient(lokiConfig) if err != nil { l.Error().Err(err).Msg(ErrLokiClient) @@ -68,35 +62,38 @@ func TestVRFV2Performance(t *testing.T) { updatedLabels := UpdateLabels(labels, t) l.Info(). - Str("Test Type", testType). - Str("Test Duration", vrfv2Config.TestDuration.Truncate(time.Second).String()). - Int64("RPS", vrfv2Config.RPS). - Str("RateLimitUnitDuration", vrfv2Config.RateLimitUnitDuration.String()). - Uint16("RandomnessRequestCountPerRequest", vrfv2Config.RandomnessRequestCountPerRequest). - Uint16("RandomnessRequestCountPerRequestDeviation", vrfv2Config.RandomnessRequestCountPerRequestDeviation). - Bool("UseExistingEnv", vrfv2Config.UseExistingEnv). + Str("Test Type", string(testType)). + Str("Test Duration", vrfv2Config.Performance.TestDuration.Duration.Truncate(time.Second).String()). + Int64("RPS", *vrfv2Config.Performance.RPS). + Str("RateLimitUnitDuration", vrfv2Config.Performance.RateLimitUnitDuration.String()). + Uint16("RandomnessRequestCountPerRequest", *vrfv2Config.General.RandomnessRequestCountPerRequest). + Uint16("RandomnessRequestCountPerRequestDeviation", *vrfv2Config.General.RandomnessRequestCountPerRequestDeviation). + Bool("UseExistingEnv", *vrfv2Config.Performance.UseExistingEnv). Msg("Performance Test Configuration") - if vrfv2Config.UseExistingEnv { + if *vrfv2Config.Performance.UseExistingEnv { //todo: temporary solution with envconfig and toml config until VRF-662 is implemented - vrfv2Config.CoordinatorAddress = cfg.ExistingEnvConfig.CoordinatorAddress - vrfv2Config.ConsumerAddress = cfg.ExistingEnvConfig.ConsumerAddress - vrfv2Config.LinkAddress = cfg.ExistingEnvConfig.LinkAddress - vrfv2Config.SubscriptionFundingAmountLink = cfg.ExistingEnvConfig.SubFunding.SubFundsLink - vrfv2Config.SubID = cfg.ExistingEnvConfig.SubID - vrfv2Config.KeyHash = cfg.ExistingEnvConfig.KeyHash + cfg := testConfig.VRFv2 + + vrfv2Config.Performance.CoordinatorAddress = cfg.ExistingEnvConfig.CoordinatorAddress + vrfv2Config.Performance.ConsumerAddress = cfg.ExistingEnvConfig.ConsumerAddress + vrfv2Config.Performance.LinkAddress = cfg.ExistingEnvConfig.LinkAddress + vrfv2Config.General.SubscriptionFundingAmountLink = cfg.ExistingEnvConfig.SubFunding.SubFundsLink + vrfv2Config.Performance.SubID = cfg.ExistingEnvConfig.SubID + vrfv2Config.Performance.KeyHash = cfg.ExistingEnvConfig.KeyHash env, err = test_env.NewCLTestEnvBuilder(). WithTestInstance(t). + WithTestConfig(&testConfig). WithCustomCleanup( func() { - teardown(t, vrfv2Contracts.LoadTestConsumers[0], lc, updatedLabels, testReporter, testType, vrfv2Config) + teardown(t, vrfv2Contracts.LoadTestConsumers[0], lc, updatedLabels, testReporter, string(testType), &testConfig) if env.EVMClient.NetworkSimulated() { l.Info(). Str("Network Name", env.EVMClient.GetNetworkName()). Msg("Network is a simulated network. Skipping fund return for Coordinator Subscriptions.") } else { - if cfg.Common.CancelSubsAfterTestRun { + if *vrfv2Config.Common.CancelSubsAfterTestRun { //cancel subs and return funds to sub owner cancelSubsAndReturnFunds(subIDs, l) } @@ -106,38 +103,38 @@ func TestVRFV2Performance(t *testing.T) { require.NoError(t, err, "error creating test env") - coordinator, err := env.ContractLoader.LoadVRFCoordinatorV2(vrfv2Config.CoordinatorAddress) + coordinator, err := env.ContractLoader.LoadVRFCoordinatorV2(*vrfv2Config.Performance.CoordinatorAddress) require.NoError(t, err) var consumers []contracts.VRFv2LoadTestConsumer - if cfg.ExistingEnvConfig.CreateFundSubsAndAddConsumers { - linkToken, err := env.ContractLoader.LoadLINKToken(vrfv2Config.LinkAddress) + if *cfg.ExistingEnvConfig.CreateFundSubsAndAddConsumers { + linkToken, err := env.ContractLoader.LoadLINKToken(*vrfv2Config.Performance.LinkAddress) require.NoError(t, err) - consumers, err = vrfv2_actions.DeployVRFV2Consumers(env.ContractDeployer, coordinator, 1) + consumers, err = vrfv2_actions.DeployVRFV2Consumers(env.ContractDeployer, coordinator.Address(), 1) require.NoError(t, err) err = env.EVMClient.WaitForEvents() require.NoError(t, err, vrfv2_actions.ErrWaitTXsComplete) l.Info(). - Str("Coordinator", cfg.ExistingEnvConfig.CoordinatorAddress). - Int("Number of Subs to create", vrfv2Config.NumberOfSubToCreate). + Str("Coordinator", *cfg.ExistingEnvConfig.CoordinatorAddress). + Int("Number of Subs to create", *vrfv2Config.General.NumberOfSubToCreate). Msg("Creating and funding subscriptions, deploying and adding consumers to subs") subIDs, err = vrfv2_actions.CreateFundSubsAndAddConsumers( env, - vrfv2Config, + big.NewFloat(*cfg.General.SubscriptionFundingAmountLink), linkToken, coordinator, consumers, - vrfv2Config.NumberOfSubToCreate, + *vrfv2Config.General.NumberOfSubToCreate, ) require.NoError(t, err) } else { - consumer, err := env.ContractLoader.LoadVRFv2LoadTestConsumer(vrfv2Config.ConsumerAddress) + consumer, err := env.ContractLoader.LoadVRFv2LoadTestConsumer(*vrfv2Config.Performance.ConsumerAddress) require.NoError(t, err) consumers = append(consumers, consumer) - subIDs = append(subIDs, vrfv2Config.SubID) + subIDs = append(subIDs, *vrfv2Config.Performance.SubID) } - err = FundNodesIfNeeded(cfg, env.EVMClient, l) + err = FundNodesIfNeeded(&testConfig, env.EVMClient, l) require.NoError(t, err) vrfv2Contracts = &vrfv2_actions.VRFV2Contracts{ @@ -150,7 +147,7 @@ func TestVRFV2Performance(t *testing.T) { VRFV2KeyData: vrfv2_actions.VRFV2KeyData{ VRFKey: nil, EncodedProvingKey: [2]*big.Int{}, - KeyHash: common.HexToHash(vrfv2Config.KeyHash), + KeyHash: common.HexToHash(*vrfv2Config.Performance.KeyHash), }, VRFJob: nil, PrimaryEthAddress: "", @@ -159,23 +156,27 @@ func TestVRFV2Performance(t *testing.T) { } else { //todo: temporary solution with envconfig and toml config until VRF-662 is implemented - vrfv2Config.ChainlinkNodeFunding = cfg.NewEnvConfig.NodeSendingKeyFunding - vrfv2Config.SubscriptionFundingAmountLink = cfg.NewEnvConfig.Funding.SubFundsLink + testConfig.Common.ChainlinkNodeFunding = testConfig.VRFv2.NewEnvConfig.NodeSendingKeyFunding + vrfv2Config.General.SubscriptionFundingAmountLink = testConfig.VRFv2.NewEnvConfig.Funding.SubFundsLink + + network, err := actions.EthereumNetworkConfigFromConfig(l, &testConfig) + require.NoError(t, err, "Error building ethereum network config") env, err = test_env.NewCLTestEnvBuilder(). WithTestInstance(t). - WithGeth(). + WithTestConfig(&testConfig). + WithPrivateEthereumNetwork(network). WithCLNodes(1). - WithFunding(big.NewFloat(vrfv2Config.ChainlinkNodeFunding)). + WithFunding(big.NewFloat(*testConfig.Common.ChainlinkNodeFunding)). WithCustomCleanup( func() { - teardown(t, vrfv2Contracts.LoadTestConsumers[0], lc, updatedLabels, testReporter, testType, vrfv2Config) + teardown(t, vrfv2Contracts.LoadTestConsumers[0], lc, updatedLabels, testReporter, string(testType), &testConfig) if env.EVMClient.NetworkSimulated() { l.Info(). Str("Network Name", env.EVMClient.GetNetworkName()). Msg("Network is a simulated network. Skipping fund return for Coordinator Subscriptions.") } else { - if cfg.Common.CancelSubsAfterTestRun { + if *testConfig.VRFv2.Common.CancelSubsAfterTestRun { //cancel subs and return funds to sub owner cancelSubsAndReturnFunds(subIDs, l) } @@ -190,22 +191,27 @@ func TestVRFV2Performance(t *testing.T) { env.ParallelTransactions(true) - mockETHLinkFeed, err := actions.DeployMockETHLinkFeed(env.ContractDeployer, big.NewInt(vrfv2Config.LinkNativeFeedResponse)) + mockETHLinkFeed, err := actions.DeployMockETHLinkFeed(env.ContractDeployer, big.NewInt(*vrfv2Config.General.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") + useVRFOwner := true + useTestCoordinator := true + vrfv2Contracts, subIDs, vrfv2Data, err = vrfv2_actions.SetupVRFV2Environment( env, - vrfv2Config, + &testConfig, + useVRFOwner, + useTestCoordinator, linkToken, mockETHLinkFeed, //register proving key against EOA address in order to return funds to this address env.EVMClient.GetDefaultWallet().Address(), 0, 1, - vrfv2Config.NumberOfSubToCreate, + *vrfv2Config.General.NumberOfSubToCreate, l, ) require.NoError(t, err, "error setting up VRF v2 env") @@ -223,12 +229,12 @@ func TestVRFV2Performance(t *testing.T) { T: t, LoadType: wasp.RPS, GenName: "gun", - RateLimitUnitDuration: vrfv2Config.RateLimitUnitDuration, + RateLimitUnitDuration: vrfv2Config.Performance.RateLimitUnitDuration.Duration, Gun: NewSingleHashGun( vrfv2Contracts, vrfv2Data.KeyHash, subIDs, - vrfv2Config, + &testConfig, l, ), Labels: labels, @@ -245,8 +251,8 @@ func TestVRFV2Performance(t *testing.T) { t.Run("vrfv2 performance test", func(t *testing.T) { singleFeedConfig.Schedule = wasp.Plain( - vrfv2Config.RPS, - vrfv2Config.TestDuration, + *vrfv2Config.Performance.RPS, + vrfv2Config.Performance.TestDuration.Duration, ) _, err = wasp.NewProfile(). Add(wasp.NewGenerator(singleFeedConfig)). @@ -289,15 +295,16 @@ func cancelSubsAndReturnFunds(subIDs []uint64, l zerolog.Logger) { } } -func FundNodesIfNeeded(cfg *PerformanceConfig, client blockchain.EVMClient, l zerolog.Logger) error { - if cfg.ExistingEnvConfig.NodeSendingKeyFundingMin > 0 { +func FundNodesIfNeeded(vrfv2TestConfig tc.VRFv2TestConfig, client blockchain.EVMClient, l zerolog.Logger) error { + cfg := vrfv2TestConfig.GetVRFv2Config() + if cfg.ExistingEnvConfig.NodeSendingKeyFundingMin != nil && *cfg.ExistingEnvConfig.NodeSendingKeyFundingMin > 0 { for _, sendingKey := range cfg.ExistingEnvConfig.NodeSendingKeys { address := common.HexToAddress(sendingKey) sendingKeyBalance, err := client.BalanceAt(context.Background(), address) if err != nil { return err } - fundingAtLeast := conversions.EtherToWei(big.NewFloat(cfg.ExistingEnvConfig.NodeSendingKeyFundingMin)) + fundingAtLeast := conversions.EtherToWei(big.NewFloat(*cfg.ExistingEnvConfig.NodeSendingKeyFundingMin)) fundingToSendWei := new(big.Int).Sub(fundingAtLeast, sendingKeyBalance) fundingToSendEth := conversions.WeiToEther(fundingToSendWei) if fundingToSendWei.Cmp(big.NewInt(0)) == 1 { @@ -330,7 +337,7 @@ func teardown( updatedLabels map[string]string, testReporter *testreporters.VRFV2TestReporter, testType string, - vrfv2Config vrfv2_config.VRFV2Config, + testConfig *tc.TestConfig, ) { //send final results to Loki metrics := GetLoadTestMetrics(consumer) @@ -343,7 +350,7 @@ func teardown( metrics.AverageFulfillmentInMillions, metrics.SlowestFulfillment, metrics.FastestFulfillment, - vrfv2Config, + testConfig, ) // send Slack notification diff --git a/integration-tests/load/vrfv2plus/cmd/dashboard.go b/integration-tests/load/vrfv2plus/cmd/dashboard.go index 049ee9ff2e..2be0e26504 100644 --- a/integration-tests/load/vrfv2plus/cmd/dashboard.go +++ b/integration-tests/load/vrfv2plus/cmd/dashboard.go @@ -13,6 +13,7 @@ import ( ) func main() { + //TODO switch to TOML too? lokiDS := os.Getenv("DATA_SOURCE_NAME") d, err := wasp.NewDashboard(nil, []dashboard.Option{ diff --git a/integration-tests/load/vrfv2plus/config.go b/integration-tests/load/vrfv2plus/config.go deleted file mode 100644 index 2fc6b6a4c7..0000000000 --- a/integration-tests/load/vrfv2plus/config.go +++ /dev/null @@ -1,151 +0,0 @@ -package loadvrfv2plus - -import ( - "encoding/base64" - "fmt" - "os" - - "github.com/pelletier/go-toml/v2" - "github.com/rs/zerolog/log" - - commonconfig "github.com/smartcontractkit/chainlink-common/pkg/config" - "github.com/smartcontractkit/chainlink/integration-tests/actions/vrfv2plus/vrfv2plus_config" -) - -const ( - DefaultConfigFilename = "config.toml" - SoakTestType = "Soak" - LoadTestType = "Load" - StressTestType = "Stress" - SpikeTestType = "Spike" - - 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"` - LinkAddress string `toml:"link_address"` - SubID string `toml:"sub_id"` - KeyHash string `toml:"key_hash"` - Funding - CreateFundSubsAndAddConsumers bool `toml:"create_fund_subs_and_add_consumers"` - NodeSendingKeys []string `toml:"node_sending_keys"` -} - -type NewEnvConfig struct { - Funding -} - -type Common struct { - MinimumConfirmations uint16 `toml:"minimum_confirmations"` - CancelSubsAfterTestRun bool `toml:"cancel_subs_after_test_run"` -} - -type Funding struct { - SubFunding - NodeSendingKeyFunding float64 `toml:"node_sending_key_funding"` - NodeSendingKeyFundingMin float64 `toml:"node_sending_key_funding_min"` -} - -type SubFunding struct { - SubFundsLink float64 `toml:"sub_funds_link"` - SubFundsNative float64 `toml:"sub_funds_native"` -} - -type Soak struct { - PerformanceTestConfig -} - -type Load struct { - PerformanceTestConfig -} - -type Stress struct { - PerformanceTestConfig -} - -type Spike struct { - PerformanceTestConfig -} - -type PerformanceTestConfig struct { - NumberOfSubToCreate int `toml:"number_of_sub_to_create"` - - RPS int64 `toml:"rps"` - //Duration *commonconfig.Duration `toml:"duration"` - RateLimitUnitDuration *commonconfig.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, fmt.Errorf("%s, err: %w", ErrReadPerfConfig, err) - } - } else { - d, err = base64.StdEncoding.DecodeString(rawConfig) - if err != nil { - return nil, fmt.Errorf("%s, err: %w", ErrReadPerfConfig, err) - } - } - err = toml.Unmarshal(d, &cfg) - if err != nil { - return nil, fmt.Errorf("%s, err: %w", ErrUnmarshalPerfConfig, err) - } - - if cfg.Soak.RandomnessRequestCountPerRequest <= cfg.Soak.RandomnessRequestCountPerRequestDeviation { - return nil, fmt.Errorf("%s, err: %w", ErrDeviationShouldBeLessThanOriginal, err) - } - - log.Debug().Interface("Config", cfg).Msg("Parsed config") - return cfg, nil -} - -func SetPerformanceTestConfig(testType string, vrfv2PlusConfig *vrfv2plus_config.VRFV2PlusConfig, cfg *PerformanceConfig) { - switch testType { - case SoakTestType: - vrfv2PlusConfig.NumberOfSubToCreate = cfg.Soak.NumberOfSubToCreate - vrfv2PlusConfig.RPS = cfg.Soak.RPS - vrfv2PlusConfig.RateLimitUnitDuration = cfg.Soak.RateLimitUnitDuration.Duration() - vrfv2PlusConfig.RandomnessRequestCountPerRequest = cfg.Soak.RandomnessRequestCountPerRequest - vrfv2PlusConfig.RandomnessRequestCountPerRequestDeviation = cfg.Soak.RandomnessRequestCountPerRequestDeviation - case LoadTestType: - vrfv2PlusConfig.NumberOfSubToCreate = cfg.Load.NumberOfSubToCreate - vrfv2PlusConfig.RPS = cfg.Load.RPS - vrfv2PlusConfig.RateLimitUnitDuration = cfg.Load.RateLimitUnitDuration.Duration() - vrfv2PlusConfig.RandomnessRequestCountPerRequest = cfg.Load.RandomnessRequestCountPerRequest - vrfv2PlusConfig.RandomnessRequestCountPerRequestDeviation = cfg.Load.RandomnessRequestCountPerRequestDeviation - case StressTestType: - vrfv2PlusConfig.NumberOfSubToCreate = cfg.Stress.NumberOfSubToCreate - vrfv2PlusConfig.RPS = cfg.Stress.RPS - vrfv2PlusConfig.RateLimitUnitDuration = cfg.Stress.RateLimitUnitDuration.Duration() - vrfv2PlusConfig.RandomnessRequestCountPerRequest = cfg.Stress.RandomnessRequestCountPerRequest - vrfv2PlusConfig.RandomnessRequestCountPerRequestDeviation = cfg.Stress.RandomnessRequestCountPerRequestDeviation - case SpikeTestType: - vrfv2PlusConfig.NumberOfSubToCreate = cfg.Spike.NumberOfSubToCreate - 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 deleted file mode 100644 index 8ccf60c6d8..0000000000 --- a/integration-tests/load/vrfv2plus/config.toml +++ /dev/null @@ -1,60 +0,0 @@ - -[Common] -minimum_confirmations = 3 -cancel_subs_after_test_run = true - -[NewEnvConfig] -sub_funds_link = 1 -sub_funds_native = 1 -node_funds = 10 -node_sending_key_funding = 1000 - -[ExistingEnvConfig] -coordinator_address = "" -consumer_address = "" -sub_id = 1 -key_hash = "" -create_fund_subs_and_add_consumers = true -link_address = "" -sub_funds_link = 10 -node_sending_key_funding_min = 1 -node_sending_keys = [ - "", - "", - "", - "", - "", - "", -] - -# 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 -number_of_sub_to_create = 1 - -# approx 60 RPM - 1 tx request with 3 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 -number_of_sub_to_create = 1 - -# approx 540 RPM - 3 tx requests per second with 4 rand requests in each tx -[Stress] -rate_limit_unit_duration = "1s" -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 -number_of_sub_to_create = 1 - -# 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 -number_of_sub_to_create = 1 diff --git a/integration-tests/load/vrfv2plus/gun.go b/integration-tests/load/vrfv2plus/gun.go index 77b60e3000..bfa56d5f3d 100644 --- a/integration-tests/load/vrfv2plus/gun.go +++ b/integration-tests/load/vrfv2plus/gun.go @@ -1,6 +1,7 @@ package loadvrfv2plus import ( + "fmt" "math/big" "math/rand" @@ -8,32 +9,33 @@ import ( "github.com/smartcontractkit/wasp" "github.com/smartcontractkit/chainlink/integration-tests/actions/vrfv2plus" - "github.com/smartcontractkit/chainlink/integration-tests/actions/vrfv2plus/vrfv2plus_config" + vrfv2plus_config "github.com/smartcontractkit/chainlink/integration-tests/testconfig/vrfv2plus" + "github.com/smartcontractkit/chainlink/integration-tests/types" ) /* 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 + contracts *vrfv2plus.VRFV2_5Contracts + keyHash [32]byte + subIDs []*big.Int + testConfig types.VRFv2PlusTestConfig + logger zerolog.Logger } func NewSingleHashGun( contracts *vrfv2plus.VRFV2_5Contracts, keyHash [32]byte, subIDs []*big.Int, - vrfv2PlusConfig vrfv2plus_config.VRFV2PlusConfig, + testConfig types.VRFv2PlusTestConfig, logger zerolog.Logger, ) *SingleHashGun { return &SingleHashGun{ - contracts: contracts, - keyHash: keyHash, - subIDs: subIDs, - vrfv2PlusConfig: vrfv2PlusConfig, - logger: logger, + contracts: contracts, + keyHash: keyHash, + subIDs: subIDs, + testConfig: testConfig, + logger: logger, } } @@ -41,9 +43,14 @@ func NewSingleHashGun( func (m *SingleHashGun) Call(_ *wasp.Generator) *wasp.Response { //todo - should work with multiple consumers and consumers having different keyhashes and wallets + billingType, err := selectBillingType(*m.testConfig.GetVRFv2PlusConfig().General.SubscriptionBillingType) + if err != nil { + return &wasp.Response{Error: err.Error(), Failed: true} + } + //randomly increase/decrease randomness request count per TX - randomnessRequestCountPerRequest := deviateValue(m.vrfv2PlusConfig.RandomnessRequestCountPerRequest, m.vrfv2PlusConfig.RandomnessRequestCountPerRequestDeviation) - _, err := vrfv2plus.RequestRandomnessAndWaitForFulfillment( + randomnessRequestCountPerRequest := deviateValue(*m.testConfig.GetVRFv2PlusConfig().General.RandomnessRequestCountPerRequest, *m.testConfig.GetVRFv2PlusConfig().General.RandomnessRequestCountPerRequestDeviation) + _, err = vrfv2plus.RequestRandomnessAndWaitForFulfillment( //the same consumer is used for all requests and in all subs m.contracts.LoadTestConsumers[0], m.contracts.Coordinator, @@ -51,10 +58,13 @@ func (m *SingleHashGun) Call(_ *wasp.Generator) *wasp.Response { //randomly pick a subID from pool of subIDs m.subIDs[randInRange(0, len(m.subIDs)-1)], //randomly pick payment type - randBool(), + billingType, + *m.testConfig.GetVRFv2PlusConfig().General.MinimumConfirmations, + *m.testConfig.GetVRFv2PlusConfig().General.CallbackGasLimit, + *m.testConfig.GetVRFv2PlusConfig().General.NumberOfWords, randomnessRequestCountPerRequest, - m.vrfv2PlusConfig, - m.vrfv2PlusConfig.RandomWordsFulfilledEventTimeout, + *m.testConfig.GetVRFv2PlusConfig().General.RandomnessRequestCountPerRequestDeviation, + m.testConfig.GetVRFv2PlusConfig().General.RandomWordsFulfilledEventTimeout.Duration, m.logger, ) if err != nil { @@ -78,3 +88,16 @@ func randBool() bool { func randInRange(min int, max int) int { return rand.Intn(max-min+1) + min } + +func selectBillingType(billingType string) (bool, error) { + switch vrfv2plus_config.BillingType(billingType) { + case vrfv2plus_config.BillingType_Link: + return false, nil + case vrfv2plus_config.BillingType_Native: + return true, nil + case vrfv2plus_config.BillingType_Link_and_Native: + return randBool(), nil + default: + return false, fmt.Errorf("invalid billing type: %s", billingType) + } +} diff --git a/integration-tests/load/vrfv2plus/vrfv2plus_test.go b/integration-tests/load/vrfv2plus/vrfv2plus_test.go index 74be537c75..b32d40e983 100644 --- a/integration-tests/load/vrfv2plus/vrfv2plus_test.go +++ b/integration-tests/load/vrfv2plus/vrfv2plus_test.go @@ -3,13 +3,11 @@ package loadvrfv2plus import ( "context" "math/big" - "os" "sync" "testing" "time" "github.com/ethereum/go-ethereum/common" - "github.com/kelseyhightower/envconfig" "github.com/rs/zerolog" "github.com/rs/zerolog/log" "github.com/smartcontractkit/wasp" @@ -23,9 +21,11 @@ import ( "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" + + tc "github.com/smartcontractkit/chainlink/integration-tests/testconfig" + vrfv2plus_config "github.com/smartcontractkit/chainlink/integration-tests/testconfig/vrfv2plus" ) var ( @@ -39,27 +39,21 @@ var ( "branch": "vrfv2Plus_healthcheck", "commit": "vrfv2Plus_healthcheck", } - - testType = os.Getenv("TEST_TYPE") ) func TestVRFV2PlusPerformance(t *testing.T) { - cfg, err := ReadConfig() + l := logging.GetTestLogger(t) + + testType, err := tc.GetConfigurationNameFromEnv() require.NoError(t, err) - var vrfv2PlusConfig vrfv2plus_config.VRFV2PlusConfig - err = envconfig.Process("VRFV2PLUS", &vrfv2PlusConfig) + testConfig, err := tc.GetConfig(testType, tc.VRFv2Plus) require.NoError(t, err) + cfgl := testConfig.Logging.Loki + vrfv2PlusConfig := testConfig.VRFv2Plus testReporter := &testreporters.VRFV2PlusTestReporter{} - SetPerformanceTestConfig(testType, &vrfv2PlusConfig, cfg) - - l := logging.GetTestLogger(t) - //todo: temporary solution with envconfig and toml config until VRF-662 is implemented - vrfv2PlusConfig.MinimumConfirmations = cfg.Common.MinimumConfirmations - - lokiConfig := wasp.NewEnvLokiConfig() - lc, err := wasp.NewLokiClient(lokiConfig) + lc, err := wasp.NewLokiClient(wasp.NewLokiConfig(cfgl.Endpoint, cfgl.TenantId, cfgl.BasicAuth, cfgl.BearerToken)) if err != nil { l.Error().Err(err).Msg(ErrLokiClient) return @@ -68,36 +62,37 @@ func TestVRFV2PlusPerformance(t *testing.T) { updatedLabels := UpdateLabels(labels, t) l.Info(). - Str("Test Type", testType). - 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). + Str("Test Type", string(testType)). + Str("Test Duration", vrfv2PlusConfig.Performance.TestDuration.Duration.Truncate(time.Second).String()). + Int64("RPS", *vrfv2PlusConfig.Performance.RPS). + Str("RateLimitUnitDuration", vrfv2PlusConfig.Performance.RateLimitUnitDuration.String()). + Uint16("RandomnessRequestCountPerRequest", *vrfv2PlusConfig.General.RandomnessRequestCountPerRequest). + Uint16("RandomnessRequestCountPerRequestDeviation", *vrfv2PlusConfig.General.RandomnessRequestCountPerRequestDeviation). + Bool("UseExistingEnv", *vrfv2PlusConfig.Performance.UseExistingEnv). Msg("Performance Test Configuration") - if vrfv2PlusConfig.UseExistingEnv { + if *vrfv2PlusConfig.Performance.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.LinkAddress = cfg.ExistingEnvConfig.LinkAddress - vrfv2PlusConfig.SubscriptionFundingAmountLink = cfg.ExistingEnvConfig.SubFunding.SubFundsLink - vrfv2PlusConfig.SubscriptionFundingAmountNative = cfg.ExistingEnvConfig.SubFunding.SubFundsNative - vrfv2PlusConfig.SubID = cfg.ExistingEnvConfig.SubID - vrfv2PlusConfig.KeyHash = cfg.ExistingEnvConfig.KeyHash + vrfv2PlusConfig.Performance.CoordinatorAddress = testConfig.VRFv2Plus.ExistingEnvConfig.CoordinatorAddress + vrfv2PlusConfig.Performance.ConsumerAddress = testConfig.VRFv2Plus.ExistingEnvConfig.ConsumerAddress + vrfv2PlusConfig.Performance.LinkAddress = testConfig.VRFv2Plus.ExistingEnvConfig.LinkAddress + vrfv2PlusConfig.General.SubscriptionFundingAmountLink = testConfig.VRFv2Plus.ExistingEnvConfig.SubFunding.SubFundsLink + vrfv2PlusConfig.General.SubscriptionFundingAmountNative = testConfig.VRFv2Plus.ExistingEnvConfig.SubFunding.SubFundsNative + vrfv2PlusConfig.Performance.SubID = testConfig.VRFv2Plus.ExistingEnvConfig.SubID + vrfv2PlusConfig.Performance.KeyHash = testConfig.VRFv2Plus.ExistingEnvConfig.KeyHash env, err = test_env.NewCLTestEnvBuilder(). WithTestInstance(t). + WithTestConfig(&testConfig). WithCustomCleanup( func() { - teardown(t, vrfv2PlusContracts.LoadTestConsumers[0], lc, updatedLabels, testReporter, testType, vrfv2PlusConfig) + teardown(t, vrfv2PlusContracts.LoadTestConsumers[0], lc, updatedLabels, testReporter, string(testType), &testConfig) if env.EVMClient.NetworkSimulated() { l.Info(). Str("Network Name", env.EVMClient.GetNetworkName()). Msg("Network is a simulated network. Skipping fund return for Coordinator Subscriptions.") } else { - if cfg.Common.CancelSubsAfterTestRun { + if *testConfig.VRFv2Plus.Common.CancelSubsAfterTestRun { //cancel subs and return funds to sub owner cancelSubsAndReturnFunds(subIDs, l) } @@ -107,41 +102,43 @@ func TestVRFV2PlusPerformance(t *testing.T) { require.NoError(t, err, "error creating test env") - coordinator, err := env.ContractLoader.LoadVRFCoordinatorV2_5(vrfv2PlusConfig.CoordinatorAddress) + coordinator, err := env.ContractLoader.LoadVRFCoordinatorV2_5(*vrfv2PlusConfig.Performance.CoordinatorAddress) require.NoError(t, err) var consumers []contracts.VRFv2PlusLoadTestConsumer - if cfg.ExistingEnvConfig.CreateFundSubsAndAddConsumers { - linkToken, err := env.ContractLoader.LoadLINKToken(vrfv2PlusConfig.LinkAddress) + if *testConfig.VRFv2Plus.ExistingEnvConfig.CreateFundSubsAndAddConsumers { + linkToken, err := env.ContractLoader.LoadLINKToken(*vrfv2PlusConfig.Performance.LinkAddress) require.NoError(t, err) consumers, err = vrfv2plus.DeployVRFV2PlusConsumers(env.ContractDeployer, coordinator, 1) require.NoError(t, err) err = env.EVMClient.WaitForEvents() require.NoError(t, err, vrfv2plus.ErrWaitTXsComplete) l.Info(). - Str("Coordinator", cfg.ExistingEnvConfig.CoordinatorAddress). - Int("Number of Subs to create", vrfv2PlusConfig.NumberOfSubToCreate). + Str("Coordinator", *vrfv2PlusConfig.Performance.CoordinatorAddress). + Int("Number of Subs to create", *vrfv2PlusConfig.General.NumberOfSubToCreate). Msg("Creating and funding subscriptions, deploying and adding consumers to subs") subIDs, err = vrfv2plus.CreateFundSubsAndAddConsumers( env, - vrfv2PlusConfig, + big.NewFloat(*testConfig.GetVRFv2PlusConfig().General.SubscriptionFundingAmountNative), + big.NewFloat(*testConfig.GetVRFv2PlusConfig().General.SubscriptionFundingAmountLink), linkToken, coordinator, consumers, - vrfv2PlusConfig.NumberOfSubToCreate, + *vrfv2PlusConfig.General.NumberOfSubToCreate, + vrfv2plus_config.BillingType(*vrfv2PlusConfig.General.SubscriptionBillingType), ) require.NoError(t, err) } else { - consumer, err := env.ContractLoader.LoadVRFv2PlusLoadTestConsumer(vrfv2PlusConfig.ConsumerAddress) + consumer, err := env.ContractLoader.LoadVRFv2PlusLoadTestConsumer(*vrfv2PlusConfig.Performance.ConsumerAddress) require.NoError(t, err) consumers = append(consumers, consumer) var ok bool - subID, ok := new(big.Int).SetString(vrfv2PlusConfig.SubID, 10) + subID := big.NewInt(int64(*vrfv2PlusConfig.Performance.SubID)) require.True(t, ok) subIDs = append(subIDs, subID) } - err = FundNodesIfNeeded(cfg, env.EVMClient, l) + err = FundNodesIfNeeded(&testConfig, env.EVMClient, l) require.NoError(t, err) vrfv2PlusContracts = &vrfv2plus.VRFV2_5Contracts{ @@ -154,7 +151,7 @@ func TestVRFV2PlusPerformance(t *testing.T) { VRFV2PlusKeyData: vrfv2plus.VRFV2PlusKeyData{ VRFKey: nil, EncodedProvingKey: [2]*big.Int{}, - KeyHash: common.HexToHash(vrfv2PlusConfig.KeyHash), + KeyHash: common.HexToHash(*vrfv2PlusConfig.Performance.KeyHash), }, VRFJob: nil, PrimaryEthAddress: "", @@ -163,24 +160,28 @@ func TestVRFV2PlusPerformance(t *testing.T) { } else { //todo: temporary solution with envconfig and toml config until VRF-662 is implemented - vrfv2PlusConfig.ChainlinkNodeFunding = cfg.NewEnvConfig.NodeSendingKeyFunding - vrfv2PlusConfig.SubscriptionFundingAmountLink = cfg.NewEnvConfig.Funding.SubFundsLink - vrfv2PlusConfig.SubscriptionFundingAmountNative = cfg.NewEnvConfig.Funding.SubFundsNative + testConfig.Common.ChainlinkNodeFunding = testConfig.VRFv2.NewEnvConfig.NodeSendingKeyFunding + vrfv2PlusConfig.General.SubscriptionFundingAmountLink = testConfig.VRFv2Plus.NewEnvConfig.Funding.SubFundsLink + vrfv2PlusConfig.General.SubscriptionFundingAmountNative = testConfig.VRFv2Plus.NewEnvConfig.Funding.SubFundsNative + + network, err := actions.EthereumNetworkConfigFromConfig(l, &testConfig) + require.NoError(t, err, "Error building ethereum network config") env, err = test_env.NewCLTestEnvBuilder(). WithTestInstance(t). - WithGeth(). + WithTestConfig(&testConfig). + WithPrivateEthereumNetwork(network). WithCLNodes(1). - WithFunding(big.NewFloat(vrfv2PlusConfig.ChainlinkNodeFunding)). + WithFunding(big.NewFloat(*testConfig.Common.ChainlinkNodeFunding)). WithCustomCleanup( func() { - teardown(t, vrfv2PlusContracts.LoadTestConsumers[0], lc, updatedLabels, testReporter, testType, vrfv2PlusConfig) + teardown(t, vrfv2PlusContracts.LoadTestConsumers[0], lc, updatedLabels, testReporter, string(testType), &testConfig) if env.EVMClient.NetworkSimulated() { l.Info(). Str("Network Name", env.EVMClient.GetNetworkName()). Msg("Network is a simulated network. Skipping fund return for Coordinator Subscriptions.") } else { - if cfg.Common.CancelSubsAfterTestRun { + if *testConfig.VRFv2Plus.Common.CancelSubsAfterTestRun { //cancel subs and return funds to sub owner cancelSubsAndReturnFunds(subIDs, l) } @@ -195,7 +196,7 @@ func TestVRFV2PlusPerformance(t *testing.T) { env.ParallelTransactions(true) - mockETHLinkFeed, err := actions.DeployMockETHLinkFeed(env.ContractDeployer, big.NewInt(vrfv2PlusConfig.LinkNativeFeedResponse)) + mockETHLinkFeed, err := actions.DeployMockETHLinkFeed(env.ContractDeployer, big.NewInt(*vrfv2PlusConfig.General.LinkNativeFeedResponse)) require.NoError(t, err, "error deploying mock ETH/LINK feed") linkToken, err := actions.DeployLINKToken(env.ContractDeployer) @@ -203,12 +204,12 @@ func TestVRFV2PlusPerformance(t *testing.T) { vrfv2PlusContracts, subIDs, vrfv2PlusData, err = vrfv2plus.SetupVRFV2_5Environment( env, - vrfv2PlusConfig, + &testConfig, linkToken, mockETHLinkFeed, 0, 1, - vrfv2PlusConfig.NumberOfSubToCreate, + *vrfv2PlusConfig.General.NumberOfSubToCreate, l, ) require.NoError(t, err, "error setting up VRF v2_5 env") @@ -226,16 +227,16 @@ func TestVRFV2PlusPerformance(t *testing.T) { T: t, LoadType: wasp.RPS, GenName: "gun", - RateLimitUnitDuration: vrfv2PlusConfig.RateLimitUnitDuration, + RateLimitUnitDuration: vrfv2PlusConfig.Performance.RateLimitUnitDuration.Duration, Gun: NewSingleHashGun( vrfv2PlusContracts, vrfv2PlusData.KeyHash, subIDs, - vrfv2PlusConfig, + &testConfig, l, ), Labels: labels, - LokiConfig: lokiConfig, + LokiConfig: wasp.NewLokiConfig(cfgl.Endpoint, cfgl.TenantId, cfgl.BasicAuth, cfgl.BearerToken), CallTimeout: 2 * time.Minute, } require.Len(t, vrfv2PlusContracts.LoadTestConsumers, 1, "only one consumer should be created for Load Test") @@ -246,10 +247,9 @@ func TestVRFV2PlusPerformance(t *testing.T) { // is our "job" stable at all, no memory leaks, no flaking performance under some RPS? t.Run("vrfv2plus performance test", func(t *testing.T) { - singleFeedConfig.Schedule = wasp.Plain( - vrfv2PlusConfig.RPS, - vrfv2PlusConfig.TestDuration, + *vrfv2PlusConfig.Performance.RPS, + vrfv2PlusConfig.Performance.TestDuration.Duration, ) _, err = wasp.NewProfile(). Add(wasp.NewGenerator(singleFeedConfig)). @@ -292,15 +292,16 @@ func cancelSubsAndReturnFunds(subIDs []*big.Int, l zerolog.Logger) { } } -func FundNodesIfNeeded(cfg *PerformanceConfig, client blockchain.EVMClient, l zerolog.Logger) error { - if cfg.ExistingEnvConfig.NodeSendingKeyFundingMin > 0 { +func FundNodesIfNeeded(vrfv2plusTestConfig tc.VRFv2PlusTestConfig, client blockchain.EVMClient, l zerolog.Logger) error { + cfg := vrfv2plusTestConfig.GetVRFv2PlusConfig() + if *cfg.ExistingEnvConfig.NodeSendingKeyFundingMin > 0 { for _, sendingKey := range cfg.ExistingEnvConfig.NodeSendingKeys { address := common.HexToAddress(sendingKey) sendingKeyBalance, err := client.BalanceAt(context.Background(), address) if err != nil { return err } - fundingAtLeast := conversions.EtherToWei(big.NewFloat(cfg.ExistingEnvConfig.NodeSendingKeyFundingMin)) + fundingAtLeast := conversions.EtherToWei(big.NewFloat(*cfg.ExistingEnvConfig.NodeSendingKeyFundingMin)) fundingToSendWei := new(big.Int).Sub(fundingAtLeast, sendingKeyBalance) fundingToSendEth := conversions.WeiToEther(fundingToSendWei) if fundingToSendWei.Cmp(big.NewInt(0)) == 1 { @@ -333,7 +334,7 @@ func teardown( updatedLabels map[string]string, testReporter *testreporters.VRFV2PlusTestReporter, testType string, - vrfv2PlusConfig vrfv2plus_config.VRFV2PlusConfig, + testConfig *tc.TestConfig, ) { //send final results to Loki metrics := GetLoadTestMetrics(consumer) @@ -346,11 +347,11 @@ func teardown( metrics.AverageFulfillmentInMillions, metrics.SlowestFulfillment, metrics.FastestFulfillment, - vrfv2PlusConfig, + testConfig, ) // send Slack notification - err := testReporter.SendSlackNotification(t, nil) + err := testReporter.SendSlackNotification(t, nil, testConfig) if err != nil { log.Warn().Err(err).Msg("Error sending Slack notification") } diff --git a/integration-tests/migration/upgrade_version_test.go b/integration-tests/migration/upgrade_version_test.go index 6603fc1685..584a9fbc75 100644 --- a/integration-tests/migration/upgrade_version_test.go +++ b/integration-tests/migration/upgrade_version_test.go @@ -5,30 +5,37 @@ import ( "github.com/stretchr/testify/require" - "github.com/smartcontractkit/chainlink-testing-framework/utils/osutil" - "github.com/smartcontractkit/chainlink/integration-tests/docker/test_env" + + tc "github.com/smartcontractkit/chainlink/integration-tests/testconfig" ) func TestVersionUpgrade(t *testing.T) { t.Parallel() + + config, err := tc.GetConfig("Migration", tc.Node) + require.NoError(t, err, "Error getting config") + + err = config.ChainlinkUpgradeImage.Validate() + require.NoError(t, err, "Error validating upgrade image") + env, err := test_env.NewCLTestEnvBuilder(). + WithTestConfig(&config). WithTestInstance(t). WithStandardCleanup(). WithGeth(). WithCLNodes(1). + WithStandardCleanup(). Build() require.NoError(t, err) - upgradeImage, err := osutil.GetEnv("UPGRADE_IMAGE") - require.NoError(t, err, "Error getting upgrade image") - upgradeVersion, err := osutil.GetEnv("UPGRADE_VERSION") - require.NoError(t, err, "Error getting upgrade version") + // just restarting CL container with the same name, DB is still the same + // // [Database] // MigrateOnStartup = true // // by default - err = env.ClCluster.Nodes[0].UpgradeVersion(upgradeImage, upgradeVersion) + err = env.ClCluster.Nodes[0].UpgradeVersion(*config.ChainlinkUpgradeImage.Image, *config.ChainlinkUpgradeImage.Version) require.NoError(t, err) } diff --git a/integration-tests/performance/cron_test.go b/integration-tests/performance/cron_test.go deleted file mode 100644 index 38d861cee0..0000000000 --- a/integration-tests/performance/cron_test.go +++ /dev/null @@ -1,139 +0,0 @@ -package performance - -import ( - "fmt" - "os" - "strings" - "testing" - "time" - - "github.com/google/uuid" - "github.com/onsi/gomega" - "github.com/stretchr/testify/require" - "go.uber.org/zap/zapcore" - - "github.com/smartcontractkit/chainlink-testing-framework/blockchain" - ctfClient "github.com/smartcontractkit/chainlink-testing-framework/client" - "github.com/smartcontractkit/chainlink-testing-framework/k8s/environment" - "github.com/smartcontractkit/chainlink-testing-framework/k8s/pkg/helm/chainlink" - "github.com/smartcontractkit/chainlink-testing-framework/k8s/pkg/helm/ethereum" - "github.com/smartcontractkit/chainlink-testing-framework/k8s/pkg/helm/mockserver" - mockservercfg "github.com/smartcontractkit/chainlink-testing-framework/k8s/pkg/helm/mockserver-cfg" - "github.com/smartcontractkit/chainlink-testing-framework/logging" - - "github.com/smartcontractkit/chainlink-testing-framework/networks" - - "github.com/smartcontractkit/chainlink/integration-tests/actions" - "github.com/smartcontractkit/chainlink/integration-tests/client" - "github.com/smartcontractkit/chainlink/integration-tests/testreporters" - "github.com/smartcontractkit/chainlink/integration-tests/testsetups" -) - -func TestMain(m *testing.M) { - os.Exit(m.Run()) -} - -func CleanupPerformanceTest( - t *testing.T, - testEnvironment *environment.Environment, - chainlinkNodes []*client.ChainlinkK8sClient, - testReporter testreporters.ChainlinkProfileTestReporter, - chainClient blockchain.EVMClient, -) { - if chainClient != nil { - chainClient.GasStats().PrintStats() - } - err := actions.TeardownSuite(t, testEnvironment, chainlinkNodes, &testReporter, zapcore.PanicLevel, chainClient) - require.NoError(t, err, "Error tearing down environment") -} - -func TestCronPerformance(t *testing.T) { - testEnvironment := setupCronTest(t) - if testEnvironment.WillUseRemoteRunner() { - return - } - - chainlinkNodes, err := client.ConnectChainlinkNodes(testEnvironment) - require.NoError(t, err, "Connecting to chainlink nodes shouldn't fail") - mockServer, err := ctfClient.ConnectMockServer(testEnvironment) - require.NoError(t, err, "Creating mockserver client shouldn't fail") - chainlinkNode := chainlinkNodes[0] - err = mockServer.SetValuePath("/variable", 5) - require.NoError(t, err, "Setting value path in mockserver shouldn't fail") - - profileFunction := func(chainlinkNode *client.ChainlinkClient) { - if chainlinkNode != chainlinkNodes[len(chainlinkNodes)-1].ChainlinkClient { - // Not the last node, hence not all nodes started profiling yet. - return - } - bta := &client.BridgeTypeAttributes{ - Name: fmt.Sprintf("variable-%s", uuid.New().String()), - URL: fmt.Sprintf("%s/variable", mockServer.Config.ClusterURL), - RequestData: "{}", - } - err = chainlinkNode.MustCreateBridge(bta) - require.NoError(t, err, "Creating bridge in chainlink node shouldn't fail") - - job, err := chainlinkNode.MustCreateJob(&client.CronJobSpec{ - Schedule: "CRON_TZ=UTC * * * * * *", - ObservationSource: client.ObservationSourceSpecBridge(bta), - }) - require.NoError(t, err, "Creating Cron Job in chainlink node shouldn't fail") - - gom := gomega.NewGomegaWithT(t) - gom.Eventually(func(g gomega.Gomega) { - jobRuns, err := chainlinkNode.MustReadRunsByJob(job.Data.ID) - 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)) - - for _, jr := range jobRuns.Data { - g.Expect(jr.Attributes.Errors).Should(gomega.Equal([]interface{}{nil}), "Job run %s shouldn't have errors", jr.ID) - } - }, "2m", "1s").Should(gomega.Succeed()) - } - - profileTest := testsetups.NewChainlinkProfileTest(testsetups.ChainlinkProfileTestInputs{ - ProfileFunction: profileFunction, - ProfileDuration: 30 * time.Second, - ChainlinkNodes: []*client.ChainlinkK8sClient{chainlinkNode}, - }) - // Register cleanup for any test - t.Cleanup(func() { - CleanupPerformanceTest(t, testEnvironment, chainlinkNodes, profileTest.TestReporter, nil) - }) - profileTest.Setup(testEnvironment) - profileTest.Run() -} - -func setupCronTest(t *testing.T) (testEnvironment *environment.Environment) { - logging.Init() - network := networks.MustGetSelectedNetworksFromEnv()[0] - evmConfig := ethereum.New(nil) - if !network.Simulated { - evmConfig = ethereum.New(ðereum.Props{ - NetworkName: network.Name, - Simulated: network.Simulated, - WsURLs: network.URLs, - }) - } - baseTOML := `[WebServer] -HTTPWriteTimout = '300s'` - cd := chainlink.New(0, map[string]interface{}{ - "replicas": 1, - "toml": networks.AddNetworksConfig(baseTOML, network), - }) - - testEnvironment = environment.New(&environment.Config{ - 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). - 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 deleted file mode 100644 index 0fe1ca37e1..0000000000 --- a/integration-tests/performance/directrequest_test.go +++ /dev/null @@ -1,160 +0,0 @@ -package performance - -import ( - "fmt" - "math/big" - "strings" - "testing" - "time" - - "github.com/onsi/gomega" - "github.com/stretchr/testify/require" - - "github.com/smartcontractkit/chainlink-testing-framework/blockchain" - ctfClient "github.com/smartcontractkit/chainlink-testing-framework/client" - "github.com/smartcontractkit/chainlink-testing-framework/k8s/environment" - "github.com/smartcontractkit/chainlink-testing-framework/k8s/pkg/helm/chainlink" - "github.com/smartcontractkit/chainlink-testing-framework/k8s/pkg/helm/ethereum" - "github.com/smartcontractkit/chainlink-testing-framework/k8s/pkg/helm/mockserver" - mockservercfg "github.com/smartcontractkit/chainlink-testing-framework/k8s/pkg/helm/mockserver-cfg" - "github.com/smartcontractkit/chainlink-testing-framework/logging" - "github.com/smartcontractkit/chainlink-testing-framework/networks" - "github.com/smartcontractkit/chainlink-testing-framework/utils/testcontext" - - "github.com/smartcontractkit/chainlink/integration-tests/actions" - "github.com/smartcontractkit/chainlink/integration-tests/client" - "github.com/smartcontractkit/chainlink/integration-tests/contracts" - "github.com/smartcontractkit/chainlink/integration-tests/testsetups" - - "github.com/google/uuid" -) - -func TestDirectRequestPerformance(t *testing.T) { - l := logging.GetTestLogger(t) - testEnvironment := setupDirectRequestTest(t) - if testEnvironment.WillUseRemoteRunner() { - return - } - - chainClient, err := blockchain.NewEVMClient(blockchain.SimulatedEVMNetwork, testEnvironment, l) - require.NoError(t, err, "Connecting to blockchain nodes shouldn't fail") - contractDeployer, err := contracts.NewContractDeployer(chainClient, l) - require.NoError(t, err, "Deploying contracts shouldn't fail") - chainlinkNodes, err := client.ConnectChainlinkNodes(testEnvironment) - require.NoError(t, err, "Connecting to chainlink nodes shouldn't fail") - mockServerClient, err := ctfClient.ConnectMockServer(testEnvironment) - require.NoError(t, err, "Error connecting to mock server") - - err = actions.FundChainlinkNodes(chainlinkNodes, chainClient, big.NewFloat(.01)) - require.NoError(t, err, "Funding chainlink nodes with ETH shouldn't fail") - - lt, err := contractDeployer.DeployLinkTokenContract() - require.NoError(t, err, "Deploying Link Token Contract shouldn't fail") - oracle, err := contractDeployer.DeployOracle(lt.Address()) - require.NoError(t, err, "Deploying Oracle Contract shouldn't fail") - consumer, err := contractDeployer.DeployAPIConsumer(lt.Address()) - require.NoError(t, err, "Deploying Consumer Contract shouldn't fail") - err = chainClient.SetDefaultWallet(0) - require.NoError(t, err, "Setting default wallet shouldn't fail") - err = lt.Transfer(consumer.Address(), big.NewInt(2e18)) - require.NoError(t, err, "Transferring %d to consumer contract shouldn't fail", big.NewInt(2e18)) - - err = mockServerClient.SetValuePath("/variable", 5) - require.NoError(t, err, "Setting mockserver value path shouldn't fail") - - jobUUID := uuid.New() - - bta := client.BridgeTypeAttributes{ - Name: fmt.Sprintf("five-%s", jobUUID.String()), - URL: fmt.Sprintf("%s/variable", mockServerClient.Config.ClusterURL), - } - err = chainlinkNodes[0].MustCreateBridge(&bta) - require.NoError(t, err, "Creating bridge shouldn't fail") - - os := &client.DirectRequestTxPipelineSpec{ - BridgeTypeAttributes: bta, - DataPath: "data,result", - } - ost, err := os.String() - require.NoError(t, err, "Building observation source spec shouldn't fail") - - _, err = chainlinkNodes[0].MustCreateJob(&client.DirectRequestJobSpec{ - Name: "direct_request", - MinIncomingConfirmations: "1", - ContractAddress: oracle.Address(), - EVMChainID: chainClient.GetChainID().String(), - ExternalJobID: jobUUID.String(), - ObservationSource: ost, - }) - require.NoError(t, err, "Creating direct_request job shouldn't fail") - - profileFunction := func(chainlinkNode *client.ChainlinkClient) { - if chainlinkNode != chainlinkNodes[len(chainlinkNodes)-1].ChainlinkClient { - // Not the last node, hence not all nodes started profiling yet. - return - } - jobUUIDReplaces := strings.Replace(jobUUID.String(), "-", "", 4) - var jobID [32]byte - copy(jobID[:], jobUUIDReplaces) - err = consumer.CreateRequestTo( - oracle.Address(), - jobID, - big.NewInt(1e18), - fmt.Sprintf("%s/variable", mockServerClient.Config.ClusterURL), - "data,result", - big.NewInt(100), - ) - require.NoError(t, err, "Calling oracle contract shouldn't fail") - - gom := gomega.NewGomegaWithT(t) - gom.Eventually(func(g gomega.Gomega) { - d, err := consumer.Data(testcontext.Get(t)) - g.Expect(err).ShouldNot(gomega.HaveOccurred(), "Getting data from consumer contract shouldn't fail") - g.Expect(d).ShouldNot(gomega.BeNil(), "Expected the initial on chain data to be nil") - l.Debug().Int64("Data", d.Int64()).Msg("Found on chain") - g.Expect(d.Int64()).Should(gomega.BeNumerically("==", 5), "Expected the on-chain data to be 5, but found %d", d.Int64()) - }, "2m", "1s").Should(gomega.Succeed()) - } - - profileTest := testsetups.NewChainlinkProfileTest(testsetups.ChainlinkProfileTestInputs{ - ProfileFunction: profileFunction, - ProfileDuration: 30 * time.Second, - ChainlinkNodes: chainlinkNodes, - }) - profileTest.Setup(testEnvironment) - t.Cleanup(func() { - CleanupPerformanceTest(t, testEnvironment, chainlinkNodes, profileTest.TestReporter, chainClient) - }) - profileTest.Run() -} - -func setupDirectRequestTest(t *testing.T) (testEnvironment *environment.Environment) { - network := networks.MustGetSelectedNetworksFromEnv()[0] - evmConfig := ethereum.New(nil) - if !network.Simulated { - evmConfig = ethereum.New(ðereum.Props{ - NetworkName: network.Name, - Simulated: network.Simulated, - WsURLs: network.URLs, - }) - } - baseTOML := `[WebServer] -HTTPWriteTimout = '300s'` - cd := chainlink.New(0, map[string]interface{}{ - "replicas": 1, - "toml": networks.AddNetworksConfig(baseTOML, network), - }) - - testEnvironment = environment.New(&environment.Config{ - 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). - 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 deleted file mode 100644 index 5fa31b626a..0000000000 --- a/integration-tests/performance/flux_test.go +++ /dev/null @@ -1,207 +0,0 @@ -package performance - -import ( - "fmt" - "math/big" - "strings" - "testing" - "time" - - "github.com/ethereum/go-ethereum/common" - "github.com/google/uuid" - "github.com/stretchr/testify/require" - - "github.com/smartcontractkit/chainlink-testing-framework/blockchain" - ctfClient "github.com/smartcontractkit/chainlink-testing-framework/client" - "github.com/smartcontractkit/chainlink-testing-framework/k8s/environment" - "github.com/smartcontractkit/chainlink-testing-framework/k8s/pkg/helm/chainlink" - "github.com/smartcontractkit/chainlink-testing-framework/k8s/pkg/helm/ethereum" - "github.com/smartcontractkit/chainlink-testing-framework/k8s/pkg/helm/mockserver" - mockservercfg "github.com/smartcontractkit/chainlink-testing-framework/k8s/pkg/helm/mockserver-cfg" - "github.com/smartcontractkit/chainlink-testing-framework/logging" - "github.com/smartcontractkit/chainlink-testing-framework/networks" - "github.com/smartcontractkit/chainlink-testing-framework/utils/testcontext" - - "github.com/smartcontractkit/chainlink/integration-tests/actions" - "github.com/smartcontractkit/chainlink/integration-tests/client" - "github.com/smartcontractkit/chainlink/integration-tests/contracts" - "github.com/smartcontractkit/chainlink/integration-tests/testsetups" -) - -func TestFluxPerformance(t *testing.T) { - l := logging.GetTestLogger(t) - testEnvironment, testNetwork := setupFluxTest(t) - if testEnvironment.WillUseRemoteRunner() { - return - } - - chainClient, err := blockchain.NewEVMClient(testNetwork, testEnvironment, l) - require.NoError(t, err, "Connecting to blockchain nodes shouldn't fail") - contractDeployer, err := contracts.NewContractDeployer(chainClient, l) - require.NoError(t, err, "Deploying contracts shouldn't fail") - chainlinkNodes, err := client.ConnectChainlinkNodes(testEnvironment) - require.NoError(t, err, "Connecting to chainlink nodes shouldn't fail") - nodeAddresses, err := actions.ChainlinkNodeAddresses(chainlinkNodes) - require.NoError(t, err, "Retreiving on-chain wallet addresses for chainlink nodes shouldn't fail") - mockServer, err := ctfClient.ConnectMockServer(testEnvironment) - require.NoError(t, err, "Creating mock server client shouldn't fail") - - chainClient.ParallelTransactions(true) - - adapterUUID := uuid.New().String() - adapterPath := fmt.Sprintf("/variable-%s", adapterUUID) - err = mockServer.SetValuePath(adapterPath, 1e5) - require.NoError(t, err, "Setting mockserver value path shouldn't fail") - - linkToken, err := contractDeployer.DeployLinkTokenContract() - require.NoError(t, err, "Deploying Link Token Contract shouldn't fail") - fluxInstance, err := contractDeployer.DeployFluxAggregatorContract(linkToken.Address(), contracts.DefaultFluxAggregatorOptions()) - require.NoError(t, err, "Deploying Flux Aggregator Contract shouldn't fail") - err = chainClient.WaitForEvents() - require.NoError(t, err, "Failed waiting for deployment of flux aggregator contract") - - err = linkToken.Transfer(fluxInstance.Address(), big.NewInt(1e18)) - require.NoError(t, err, "Funding Flux Aggregator Contract shouldn't fail") - err = chainClient.WaitForEvents() - require.NoError(t, err, "Failed waiting for funding of flux aggregator contract") - - err = fluxInstance.UpdateAvailableFunds() - require.NoError(t, err, "Updating the available funds on the Flux Aggregator Contract shouldn't fail") - - err = actions.FundChainlinkNodes(chainlinkNodes, chainClient, big.NewFloat(.02)) - require.NoError(t, err, "Funding chainlink nodes with ETH shouldn't fail") - - err = fluxInstance.SetOracles( - contracts.FluxAggregatorSetOraclesOptions{ - AddList: nodeAddresses, - RemoveList: []common.Address{}, - AdminList: nodeAddresses, - MinSubmissions: 3, - MaxSubmissions: 3, - RestartDelayRounds: 0, - }) - require.NoError(t, err, "Setting oracle options in the Flux Aggregator contract shouldn't fail") - err = chainClient.WaitForEvents() - require.NoError(t, err, "Waiting for event subscriptions in nodes shouldn't fail") - oracles, err := fluxInstance.GetOracles(testcontext.Get(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", mockServer.Config.ClusterURL, adapterPath) - bta := &client.BridgeTypeAttributes{ - Name: fmt.Sprintf("variable-%s", adapterUUID), - URL: adapterFullURL, - } - for i, n := range chainlinkNodes { - err = n.MustCreateBridge(bta) - require.NoError(t, err, "Creating bridge shouldn't fail for node %d", i+1) - - fluxSpec := &client.FluxMonitorJobSpec{ - Name: fmt.Sprintf("flux-monitor-%s", adapterUUID), - ContractAddress: fluxInstance.Address(), - EVMChainID: chainClient.GetChainID().String(), - Threshold: 0, - AbsoluteThreshold: 0, - PollTimerPeriod: 15 * time.Second, // min 15s - IdleTimerDisabled: true, - ObservationSource: client.ObservationSourceSpecBridge(bta), - } - _, err = n.MustCreateJob(fluxSpec) - require.NoError(t, err, "Creating flux job shouldn't fail for node %d", i+1) - } - - profileFunction := func(chainlinkNode *client.ChainlinkClient) { - if chainlinkNode != chainlinkNodes[len(chainlinkNodes)-1].ChainlinkClient { - // Not the last node, hence not all nodes started profiling yet. - return - } - fluxRoundTimeout := 2 * time.Minute - fluxRound := contracts.NewFluxAggregatorRoundConfirmer(fluxInstance, big.NewInt(1), fluxRoundTimeout, l) - chainClient.AddHeaderEventSubscription(fluxInstance.Address(), fluxRound) - err = chainClient.WaitForEvents() - require.NoError(t, err, "Waiting for event subscriptions in nodes shouldn't fail") - data, err := fluxInstance.GetContractData(testcontext.Get(t)) - require.NoError(t, err, "Getting contract data from flux aggregator contract shouldn't fail") - l.Info().Interface("Data", data).Msg("Round data") - require.Equal(t, int64(1e5), data.LatestRoundData.Answer.Int64(), - "Expected latest round answer to be %d, but found %d", int64(1e5), data.LatestRoundData.Answer.Int64()) - require.Equal(t, int64(1), data.LatestRoundData.RoundId.Int64(), - "Expected latest round id to be %d, but found %d", int64(1), data.LatestRoundData.RoundId.Int64()) - require.Equal(t, int64(1), data.LatestRoundData.AnsweredInRound.Int64(), - "Expected latest round's answered in round to be %d, but found %d", int64(1), data.LatestRoundData.AnsweredInRound.Int64()) - require.Equal(t, int64(999999999999999997), data.AvailableFunds.Int64(), - "Expected available funds to be %d, but found %d", int64(999999999999999997), data.AvailableFunds.Int64()) - require.Equal(t, int64(3), data.AllocatedFunds.Int64(), - "Expected allocated funds to be %d, but found %d", int64(3), data.AllocatedFunds.Int64()) - - fluxRound = contracts.NewFluxAggregatorRoundConfirmer(fluxInstance, big.NewInt(2), fluxRoundTimeout, l) - chainClient.AddHeaderEventSubscription(fluxInstance.Address(), fluxRound) - err = mockServer.SetValuePath(adapterPath, 1e10) - require.NoError(t, err, "Setting value path in mock server shouldn't fail") - err = chainClient.WaitForEvents() - require.NoError(t, err, "Waiting for event subscriptions in nodes shouldn't fail") - data, err = fluxInstance.GetContractData(testcontext.Get(t)) - require.NoError(t, err, "Getting contract data from flux aggregator contract shouldn't fail") - require.Equal(t, int64(1e10), data.LatestRoundData.Answer.Int64(), - "Expected latest round answer to be %d, but found %d", int64(1e10), data.LatestRoundData.Answer.Int64()) - require.Equal(t, int64(2), data.LatestRoundData.RoundId.Int64(), - "Expected latest round id to be %d, but found %d", int64(2), data.LatestRoundData.RoundId.Int64()) - require.Equal(t, int64(999999999999999994), data.AvailableFunds.Int64(), - "Expected available funds to be %d, but found %d", int64(999999999999999994), data.AvailableFunds.Int64()) - require.Equal(t, int64(6), data.AllocatedFunds.Int64(), - "Expected allocated funds to be %d, but found %d", int64(6), data.AllocatedFunds.Int64()) - l.Info().Interface("data", data).Msg("Round data") - - for _, oracleAddr := range nodeAddresses { - payment, _ := fluxInstance.WithdrawablePayment(testcontext.Get(t), oracleAddr) - require.Equal(t, int64(2), payment.Int64(), - "Expected flux aggregator contract's withdrawable payment to be %d, but found %d", int64(2), payment.Int64()) - } - } - - profileTest := testsetups.NewChainlinkProfileTest(testsetups.ChainlinkProfileTestInputs{ - ProfileFunction: profileFunction, - ProfileDuration: 30 * time.Second, - ChainlinkNodes: chainlinkNodes, - }) - // Register cleanup - t.Cleanup(func() { - CleanupPerformanceTest(t, testEnvironment, chainlinkNodes, profileTest.TestReporter, chainClient) - }) - profileTest.Setup(testEnvironment) - profileTest.Run() -} - -func setupFluxTest(t *testing.T) (testEnvironment *environment.Environment, testNetwork blockchain.EVMNetwork) { - testNetwork = networks.MustGetSelectedNetworksFromEnv()[0] - evmConf := ethereum.New(nil) - if !testNetwork.Simulated { - evmConf = ethereum.New(ðereum.Props{ - NetworkName: testNetwork.Name, - Simulated: testNetwork.Simulated, - WsURLs: testNetwork.URLs, - }) - } - baseTOML := `[WebServer] -HTTPWriteTimout = '300s' - -[OCR] -Enabled = true` - cd := chainlink.New(0, map[string]interface{}{ - "replicas": 3, - "toml": networks.AddNetworksConfig(baseTOML, testNetwork), - }) - - testEnvironment = environment.New(&environment.Config{ - 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). - 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 deleted file mode 100644 index ac6e9e6a57..0000000000 --- a/integration-tests/performance/keeper_test.go +++ /dev/null @@ -1,194 +0,0 @@ -package performance - -//revive:disable:dot-imports -import ( - "fmt" - "math/big" - "strings" - "testing" - "time" - - "github.com/onsi/gomega" - "github.com/stretchr/testify/require" - - "github.com/smartcontractkit/chainlink-testing-framework/blockchain" - "github.com/smartcontractkit/chainlink-testing-framework/k8s/environment" - "github.com/smartcontractkit/chainlink-testing-framework/k8s/pkg/helm/chainlink" - eth "github.com/smartcontractkit/chainlink-testing-framework/k8s/pkg/helm/ethereum" - "github.com/smartcontractkit/chainlink-testing-framework/k8s/pkg/helm/mockserver" - mockservercfg "github.com/smartcontractkit/chainlink-testing-framework/k8s/pkg/helm/mockserver-cfg" - "github.com/smartcontractkit/chainlink-testing-framework/logging" - "github.com/smartcontractkit/chainlink-testing-framework/networks" - "github.com/smartcontractkit/chainlink-testing-framework/utils/testcontext" - - "github.com/smartcontractkit/chainlink/integration-tests/actions" - "github.com/smartcontractkit/chainlink/integration-tests/client" - "github.com/smartcontractkit/chainlink/integration-tests/contracts" - "github.com/smartcontractkit/chainlink/integration-tests/contracts/ethereum" - "github.com/smartcontractkit/chainlink/integration-tests/testsetups" -) - -var keeperDefaultRegistryConfig = contracts.KeeperRegistrySettings{ - PaymentPremiumPPB: uint32(200000000), - FlatFeeMicroLINK: uint32(0), - BlockCountPerTurn: big.NewInt(10), - CheckGasLimit: uint32(2500000), - StalenessSeconds: big.NewInt(90000), - GasCeilingMultiplier: uint16(1), - MinUpkeepSpend: big.NewInt(0), - MaxPerformGas: uint32(5000000), - FallbackGasPrice: big.NewInt(2e11), - FallbackLinkPrice: big.NewInt(2e18), - MaxCheckDataSize: uint32(5000), - MaxPerformDataSize: uint32(5000), -} - -func TestKeeperPerformance(t *testing.T) { - l := logging.GetTestLogger(t) - testEnvironment, chainClient, chainlinkNodes, contractDeployer, linkToken := setupKeeperTest(t, "basic-smoke") - if testEnvironment.WillUseRemoteRunner() { - return - } - registry, _, consumers, upkeepIDs := actions.DeployKeeperContracts( - t, - ethereum.RegistryVersion_1_1, - keeperDefaultRegistryConfig, - 1, - uint32(2500000), - linkToken, - contractDeployer, - chainClient, - big.NewInt(9e18), - ) - gom := gomega.NewGomegaWithT(t) - - profileFunction := func(chainlinkNode *client.ChainlinkClient) { - if chainlinkNode != chainlinkNodes[len(chainlinkNodes)-1].ChainlinkClient { - // Not the last node, hence not all nodes started profiling yet. - return - } - actions.CreateKeeperJobs(t, chainlinkNodes, registry, contracts.OCRv2Config{}, chainClient.GetChainID().String()) - err := chainClient.WaitForEvents() - require.NoError(t, err, "Error creating keeper jobs") - - gom.Eventually(func(g gomega.Gomega) { - // Check if the upkeeps are performing multiple times by analysing their counters and checking they are greater than 10 - for i := 0; i < len(upkeepIDs); i++ { - counter, err := consumers[i].Counter(testcontext.Get(t)) - g.Expect(err).ShouldNot(gomega.HaveOccurred(), "Failed to retrieve consumer counter for upkeep at index %d", i) - g.Expect(counter.Int64()).Should(gomega.BeNumerically(">", int64(10)), - "Expected consumer counter to be greater than 10, but got %d", counter.Int64()) - l.Info().Int64("Upkeep counter", counter.Int64()).Msg("Number of upkeeps performed") - } - }, "5m", "1s").Should(gomega.Succeed()) - - // Cancel all the registered upkeeps via the registry - for i := 0; i < len(upkeepIDs); i++ { - err = registry.CancelUpkeep(upkeepIDs[i]) - require.NoError(t, err, "Could not cancel upkeep at index %d", i) - } - - err = chainClient.WaitForEvents() - require.NoError(t, err, "Error waiting for upkeeps to be cancelled") - - var countersAfterCancellation = make([]*big.Int, len(upkeepIDs)) - - for i := 0; i < len(upkeepIDs); i++ { - // Obtain the amount of times the upkeep has been executed so far - countersAfterCancellation[i], err = consumers[i].Counter(testcontext.Get(t)) - require.NoError(t, err, "Failed to retrieve consumer counter for upkeep at index %d", i) - l.Info().Int("Index", i).Int64("Upkeeps Performed", countersAfterCancellation[i].Int64()).Msg("Cancelled Upkeep") - } - - gom.Consistently(func(g gomega.Gomega) { - for i := 0; i < len(upkeepIDs); i++ { - // Expect the counter to remain constant because the upkeep was cancelled, so it shouldn't increase anymore - latestCounter, err := consumers[i].Counter(testcontext.Get(t)) - require.NoError(t, err, "Failed to retrieve consumer counter for upkeep at index %d", i) - g.Expect(latestCounter.Int64()).Should(gomega.Equal(countersAfterCancellation[i].Int64()), - "Expected consumer counter to remain constant at %d, but got %d", - countersAfterCancellation[i].Int64(), latestCounter.Int64()) - } - }, "1m", "1s").Should(gomega.Succeed()) - } - profileTest := testsetups.NewChainlinkProfileTest(testsetups.ChainlinkProfileTestInputs{ - ProfileFunction: profileFunction, - ProfileDuration: 10 * time.Second, - ChainlinkNodes: chainlinkNodes, - }) - // Register cleanup - t.Cleanup(func() { - CleanupPerformanceTest(t, testEnvironment, chainlinkNodes, profileTest.TestReporter, chainClient) - }) - profileTest.Setup(testEnvironment) - profileTest.Run() -} - -func setupKeeperTest( - t *testing.T, - testName string, -) ( - *environment.Environment, - blockchain.EVMClient, - []*client.ChainlinkK8sClient, - contracts.ContractDeployer, - contracts.LinkToken, -) { - network := networks.MustGetSelectedNetworksFromEnv()[0] - evmConfig := eth.New(nil) - if !network.Simulated { - evmConfig = eth.New(ð.Props{ - NetworkName: network.Name, - Simulated: network.Simulated, - WsURLs: network.URLs, - }) - } - baseTOML := `[WebServer] -HTTPWriteTimout = '300s' - -[Keeper] -TurnLookBack = 0 - -[Keeper.Registry] -SyncInterval = '5s' -PerformGasOverhead = 150_000` - networkName := strings.ReplaceAll(strings.ToLower(network.Name), " ", "-") - cd := chainlink.New(0, map[string]interface{}{ - "replicas": 5, - "toml": networks.AddNetworksConfig(baseTOML, network), - }) - - testEnvironment := environment.New( - &environment.Config{ - NamespacePrefix: fmt.Sprintf("performance-keeper-%s-%s", testName, networkName), - Test: t, - PreventPodEviction: true, - }, - ). - AddHelm(mockservercfg.New(nil)). - AddHelm(mockserver.New(nil)). - AddHelm(evmConfig). - AddHelm(cd) - err := testEnvironment.Run() - require.NoError(t, err, "Error deploying test environment") - if testEnvironment.WillUseRemoteRunner() { - return testEnvironment, nil, nil, nil, nil - } - - l := logging.GetTestLogger(t) - chainClient, err := blockchain.NewEVMClient(network, testEnvironment, l) - require.NoError(t, err, "Connecting to blockchain nodes shouldn't fail") - contractDeployer, err := contracts.NewContractDeployer(chainClient, l) - require.NoError(t, err, "Deploying contracts shouldn't fail") - chainlinkNodes, err := client.ConnectChainlinkNodes(testEnvironment) - require.NoError(t, err, "Connecting to chainlink nodes shouldn't fail") - chainClient.ParallelTransactions(true) - - err = actions.FundChainlinkNodes(chainlinkNodes, chainClient, big.NewFloat(.5)) - require.NoError(t, err, "Funding Chainlink nodes shouldn't fail") - - linkToken, err := contractDeployer.DeployLinkTokenContract() - require.NoError(t, err, "Deploying Link Token Contract shouldn't fail") - - return testEnvironment, chainClient, chainlinkNodes, contractDeployer, linkToken -} diff --git a/integration-tests/performance/ocr_test.go b/integration-tests/performance/ocr_test.go deleted file mode 100644 index 7e0ed0111d..0000000000 --- a/integration-tests/performance/ocr_test.go +++ /dev/null @@ -1,126 +0,0 @@ -package performance - -import ( - "fmt" - "math/big" - "strings" - "testing" - "time" - - "github.com/stretchr/testify/require" - - "github.com/smartcontractkit/chainlink-testing-framework/blockchain" - ctfClient "github.com/smartcontractkit/chainlink-testing-framework/client" - "github.com/smartcontractkit/chainlink-testing-framework/k8s/environment" - "github.com/smartcontractkit/chainlink-testing-framework/k8s/pkg/helm/chainlink" - "github.com/smartcontractkit/chainlink-testing-framework/k8s/pkg/helm/ethereum" - "github.com/smartcontractkit/chainlink-testing-framework/k8s/pkg/helm/mockserver" - mockservercfg "github.com/smartcontractkit/chainlink-testing-framework/k8s/pkg/helm/mockserver-cfg" - "github.com/smartcontractkit/chainlink-testing-framework/logging" - "github.com/smartcontractkit/chainlink-testing-framework/networks" - "github.com/smartcontractkit/chainlink-testing-framework/utils/testcontext" - - "github.com/smartcontractkit/chainlink/integration-tests/actions" - "github.com/smartcontractkit/chainlink/integration-tests/client" - "github.com/smartcontractkit/chainlink/integration-tests/contracts" - "github.com/smartcontractkit/chainlink/integration-tests/testsetups" -) - -func TestOCRBasic(t *testing.T) { - t.Parallel() - testEnvironment, testNetwork := setupOCRTest(t) - if testEnvironment.WillUseRemoteRunner() { - return - } - l := logging.GetTestLogger(t) - chainClient, err := blockchain.NewEVMClient(testNetwork, testEnvironment, l) - require.NoError(t, err, "Connecting to blockchain nodes shouldn't fail") - contractDeployer, err := contracts.NewContractDeployer(chainClient, l) - require.NoError(t, err, "Deploying contracts shouldn't fail") - - chainlinkNodes, err := client.ConnectChainlinkNodes(testEnvironment) - require.NoError(t, err, "Connecting to chainlink nodes shouldn't fail") - bootstrapNode, workerNodes := chainlinkNodes[0], chainlinkNodes[1:] - mockServer, err := ctfClient.ConnectMockServer(testEnvironment) - require.NoError(t, err, "Creating mockserver clients shouldn't fail") - - chainClient.ParallelTransactions(true) - - linkTokenContract, err := contractDeployer.DeployLinkTokenContract() - require.NoError(t, err, "Deploying Link Token Contract shouldn't fail") - - err = actions.FundChainlinkNodes(chainlinkNodes, chainClient, big.NewFloat(.05)) - require.NoError(t, err, "Error funding Chainlink nodes") - - ocrInstances, err := actions.DeployOCRContracts(1, linkTokenContract, contractDeployer, workerNodes, chainClient) - require.NoError(t, err) - err = chainClient.WaitForEvents() - require.NoError(t, err, "Error waiting for events") - - profileFunction := func(chainlinkNode *client.ChainlinkClient) { - err = actions.CreateOCRJobs(ocrInstances, bootstrapNode, workerNodes, 5, mockServer, chainClient.GetChainID().String()) - require.NoError(t, err) - err = actions.StartNewRound(1, ocrInstances, chainClient, l) - require.NoError(t, err) - - answer, err := ocrInstances[0].GetLatestAnswer(testcontext.Get(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 = mockServer.SetValuePath("ocr", 10) - require.NoError(t, err) - err = actions.StartNewRound(2, ocrInstances, chainClient, l) - require.NoError(t, err) - - answer, err = ocrInstances[0].GetLatestAnswer(testcontext.Get(t)) - require.NoError(t, err, "Error getting latest OCR answer") - require.Equal(t, int64(10), answer.Int64(), "Expected latest answer from OCR contract to be 10 but got %d", answer.Int64()) - } - profileTest := testsetups.NewChainlinkProfileTest(testsetups.ChainlinkProfileTestInputs{ - ProfileFunction: profileFunction, - ProfileDuration: time.Minute, - ChainlinkNodes: chainlinkNodes, - }) - t.Cleanup(func() { - CleanupPerformanceTest(t, testEnvironment, chainlinkNodes, profileTest.TestReporter, chainClient) - }) - profileTest.Setup(testEnvironment) - profileTest.Run() -} - -func setupOCRTest(t *testing.T) (testEnvironment *environment.Environment, testNetwork blockchain.EVMNetwork) { - testNetwork = networks.MustGetSelectedNetworksFromEnv()[0] - evmConfig := ethereum.New(nil) - if !testNetwork.Simulated { - evmConfig = ethereum.New(ðereum.Props{ - NetworkName: testNetwork.Name, - Simulated: testNetwork.Simulated, - WsURLs: testNetwork.URLs, - }) - } - baseTOML := `[OCR] -Enabled = true - -[P2P] -[P2P.V2] -AnnounceAddresses = ["0.0.0.0:6690"] -ListenAddresses = ["0.0.0.0:6690"]` - - cd := chainlink.New(0, map[string]interface{}{ - "replicas": 6, - "toml": networks.AddNetworksConfig(baseTOML, testNetwork), - }) - - testEnvironment = environment.New(&environment.Config{ - 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). - 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 deleted file mode 100644 index cad4ea5eeb..0000000000 --- a/integration-tests/performance/vrf_test.go +++ /dev/null @@ -1,163 +0,0 @@ -package performance - -import ( - "fmt" - "math/big" - "strings" - "testing" - "time" - - "github.com/google/uuid" - "github.com/onsi/gomega" - "github.com/stretchr/testify/require" - - "github.com/smartcontractkit/chainlink-testing-framework/blockchain" - "github.com/smartcontractkit/chainlink-testing-framework/k8s/environment" - "github.com/smartcontractkit/chainlink-testing-framework/k8s/pkg/helm/chainlink" - "github.com/smartcontractkit/chainlink-testing-framework/k8s/pkg/helm/ethereum" - "github.com/smartcontractkit/chainlink-testing-framework/logging" - "github.com/smartcontractkit/chainlink-testing-framework/networks" - "github.com/smartcontractkit/chainlink-testing-framework/utils/testcontext" - - "github.com/smartcontractkit/chainlink/integration-tests/actions" - "github.com/smartcontractkit/chainlink/integration-tests/client" - "github.com/smartcontractkit/chainlink/integration-tests/contracts" - "github.com/smartcontractkit/chainlink/integration-tests/testsetups" -) - -func TestVRFBasic(t *testing.T) { - t.Parallel() - l := logging.GetTestLogger(t) - testEnvironment, testNetwork := setupVRFTest(t) - if testEnvironment.WillUseRemoteRunner() { - return - } - - chainClient, err := blockchain.NewEVMClient(testNetwork, testEnvironment, l) - require.NoError(t, err, "Connecting client shouldn't fail") - cd, err := contracts.NewContractDeployer(chainClient, l) - require.NoError(t, err, "Deploying contracts shouldn't fail") - chainlinkNodes, err := client.ConnectChainlinkNodes(testEnvironment) - require.NoError(t, err, "Connecting to chainlink nodes shouldn't fail") - chainClient.ParallelTransactions(true) - - err = actions.FundChainlinkNodes(chainlinkNodes, chainClient, big.NewFloat(.01)) - require.NoError(t, err, "Funding chainlink nodes with ETH shouldn't fail") - - lt, err := cd.DeployLinkTokenContract() - require.NoError(t, err, "Deploying Link Token Contract shouldn't fail") - bhs, err := cd.DeployBlockhashStore() - require.NoError(t, err, "Deploying Blockhash store shouldn't fail") - coordinator, err := cd.DeployVRFCoordinator(lt.Address(), bhs.Address()) - require.NoError(t, err, "Deploying VRF coordinator shouldn't fail") - consumer, err := cd.DeployVRFConsumer(lt.Address(), coordinator.Address()) - require.NoError(t, err, "Deploying VRF consumer contract shouldn't fail") - err = chainClient.WaitForEvents() - require.NoError(t, err, "Failed to wait for VRF setup contracts to deploy") - - err = lt.Transfer(consumer.Address(), big.NewInt(2e18)) - require.NoError(t, err, "Funding consumer contract shouldn't fail") - _, err = cd.DeployVRFContract() - require.NoError(t, err, "Deploying VRF contract shouldn't fail") - err = chainClient.WaitForEvents() - require.NoError(t, err, "Waiting for event subscriptions in nodes shouldn't fail") - - profileFunction := func(chainlinkNode *client.ChainlinkClient) { - nodeKey, err := chainlinkNode.MustCreateVRFKey() - require.NoError(t, err, "Creating VRF key shouldn't fail") - l.Debug().Interface("Key JSON", nodeKey).Msg("Created proving key") - pubKeyCompressed := nodeKey.Data.ID - jobUUID := uuid.New() - os := &client.VRFTxPipelineSpec{ - Address: coordinator.Address(), - } - ost, err := os.String() - require.NoError(t, err, "Building observation source spec shouldn't fail") - job, err := chainlinkNode.MustCreateJob(&client.VRFJobSpec{ - Name: fmt.Sprintf("vrf-%s", jobUUID), - CoordinatorAddress: coordinator.Address(), - MinIncomingConfirmations: 1, - PublicKey: pubKeyCompressed, - ExternalJobID: jobUUID.String(), - ObservationSource: ost, - }) - require.NoError(t, err, "Creating VRF Job shouldn't fail") - - oracleAddr, err := chainlinkNode.PrimaryEthAddress() - require.NoError(t, err, "Getting primary ETH address of chainlink node shouldn't fail") - provingKey, err := actions.EncodeOnChainVRFProvingKey(*nodeKey) - require.NoError(t, err, "Encoding on-chain VRF Proving key shouldn't fail") - err = coordinator.RegisterProvingKey( - big.NewInt(1), - oracleAddr, - provingKey, - actions.EncodeOnChainExternalJobID(jobUUID), - ) - require.NoError(t, err, "Registering the on-chain VRF Proving key shouldn't fail") - encodedProvingKeys := make([][2]*big.Int, 0) - encodedProvingKeys = append(encodedProvingKeys, provingKey) - - requestHash, err := coordinator.HashOfKey(testcontext.Get(t), encodedProvingKeys[0]) - require.NoError(t, err, "Getting Hash of encoded proving keys shouldn't fail") - err = consumer.RequestRandomness(requestHash, big.NewInt(1)) - require.NoError(t, err, "Requesting randomness shouldn't fail") - - gom := gomega.NewGomegaWithT(t) - timeout := time.Minute * 2 - gom.Eventually(func(g gomega.Gomega) { - jobRuns, err := chainlinkNodes[0].MustReadRunsByJob(job.Data.ID) - g.Expect(err).ShouldNot(gomega.HaveOccurred(), "Job execution shouldn't fail") - - out, err := consumer.RandomnessOutput(testcontext.Get(t)) - g.Expect(err).ShouldNot(gomega.HaveOccurred(), "Getting the randomness output of the consumer shouldn't fail") - // Checks that the job has actually run - g.Expect(len(jobRuns.Data)).Should(gomega.BeNumerically(">=", 1), - fmt.Sprintf("Expected the VRF job to run once or more after %s", timeout)) - - // TODO: This is an imperfect check, given it's a random number, it CAN be 0, but chances are unlikely. - // So we're just checking that the answer has changed to something other than the default (0) - // There's a better formula to ensure that VRF response is as expected, detailed under Technical Walkthrough. - // https://blog.chain.link/chainlink-vrf-on-chain-verifiable-randomness/ - g.Expect(out.Uint64()).ShouldNot(gomega.BeNumerically("==", 0), "Expected the VRF job give an answer other than 0") - l.Debug().Uint64("Output", out.Uint64()).Msg("Randomness fulfilled") - }, timeout, "1s").Should(gomega.Succeed()) - } - profileTest := testsetups.NewChainlinkProfileTest(testsetups.ChainlinkProfileTestInputs{ - ProfileFunction: profileFunction, - ProfileDuration: 30 * time.Second, - ChainlinkNodes: chainlinkNodes, - }) - t.Cleanup(func() { - CleanupPerformanceTest(t, testEnvironment, chainlinkNodes, profileTest.TestReporter, chainClient) - }) - profileTest.Setup(testEnvironment) - profileTest.Run() -} - -func setupVRFTest(t *testing.T) (testEnvironment *environment.Environment, testNetwork blockchain.EVMNetwork) { - testNetwork = networks.MustGetSelectedNetworksFromEnv()[0] - evmConfig := ethereum.New(nil) - if !testNetwork.Simulated { - evmConfig = ethereum.New(ðereum.Props{ - NetworkName: testNetwork.Name, - Simulated: testNetwork.Simulated, - WsURLs: testNetwork.URLs, - }) - } - baseTOML := `[WebServer] -HTTPWriteTimout = '300s'` - cd := chainlink.New(0, map[string]interface{}{ - "toml": networks.AddNetworksConfig(baseTOML, testNetwork), - }) - - testEnvironment = environment.New(&environment.Config{ - NamespacePrefix: fmt.Sprintf("smoke-vrf-%s", strings.ReplaceAll(strings.ToLower(testNetwork.Name), " ", "-")), - Test: t, - PreventPodEviction: true, - }). - AddHelm(evmConfig). - 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 dae977d3ee..36b5d3eb98 100644 --- a/integration-tests/reorg/automation_reorg_test.go +++ b/integration-tests/reorg/automation_reorg_test.go @@ -12,6 +12,7 @@ import ( "go.uber.org/zap/zapcore" "github.com/smartcontractkit/chainlink-testing-framework/blockchain" + ctf_config "github.com/smartcontractkit/chainlink-testing-framework/config" "github.com/smartcontractkit/chainlink-testing-framework/k8s/environment" "github.com/smartcontractkit/chainlink-testing-framework/k8s/pkg/cdk8s/blockscout" "github.com/smartcontractkit/chainlink-testing-framework/k8s/pkg/helm/chainlink" @@ -24,6 +25,8 @@ import ( "github.com/smartcontractkit/chainlink/integration-tests/client" "github.com/smartcontractkit/chainlink/integration-tests/contracts" "github.com/smartcontractkit/chainlink/integration-tests/contracts/ethereum" + + tc "github.com/smartcontractkit/chainlink/integration-tests/testconfig" ) var ( @@ -47,9 +50,9 @@ HistoryDepth = 400 [EVM.GasEstimator] Mode = 'FixedPrice' LimitDefault = 5_000_000` - activeEVMNetwork = networks.MustGetSelectedNetworksFromEnv()[0] + defaultAutomationSettings = map[string]interface{}{ - "toml": networks.AddNetworkDetailedConfig(baseTOML, networkTOML, activeEVMNetwork), + "toml": "", "db": map[string]interface{}{ "stateful": false, "capacity": "1Gi", @@ -67,7 +70,7 @@ LimitDefault = 5_000_000` } defaultReorgEthereumSettings = &reorg.Props{ - NetworkName: activeEVMNetwork.Name, + NetworkName: "", NetworkType: "geth-reorg", Values: map[string]interface{}{ "geth": map[string]interface{}{ @@ -126,9 +129,9 @@ func TestAutomationReorg(t *testing.T) { l := logging.GetTestLogger(t) 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, } for name, registryVersion := range registryVersions { @@ -136,22 +139,38 @@ func TestAutomationReorg(t *testing.T) { registryVersion := registryVersion t.Run(name, func(t *testing.T) { t.Parallel() - network := networks.MustGetSelectedNetworksFromEnv()[0] + config, err := tc.GetConfig("Reorg", tc.Automation) + if err != nil { + t.Fatal(err) + } + + network := networks.MustGetSelectedNetworkConfig(config.Network)[0] defaultAutomationSettings["replicas"] = numberOfNodes - cd := chainlink.New(0, defaultAutomationSettings) + defaultAutomationSettings["toml"] = networks.AddNetworkDetailedConfig(baseTOML, config.Pyroscope, networkTOML, network) + + var overrideFn = func(_ interface{}, target interface{}) { + ctf_config.MustConfigOverrideChainlinkVersion(config.ChainlinkImage, target) + ctf_config.MightConfigOverridePyroscopeKey(config.Pyroscope, target) + } + + cd := chainlink.NewWithOverride(0, defaultAutomationSettings, config.ChainlinkImage, overrideFn) + + ethSetting := defaultReorgEthereumSettings + ethSetting.NetworkName = network.Name + testEnvironment := environment. New(&environment.Config{ NamespacePrefix: fmt.Sprintf("automation-reorg-%d", automationReorgBlocks), TTL: time.Hour * 1, Test: t}). - AddHelm(reorg.New(defaultReorgEthereumSettings)). + AddHelm(reorg.New(ethSetting)). AddChart(blockscout.New(&blockscout.Props{ Name: "geth-blockscout", - WsURL: activeEVMNetwork.URL, - HttpURL: activeEVMNetwork.HTTPURLs[0]})). + WsURL: network.URL, + HttpURL: network.HTTPURLs[0]})). AddHelm(cd) - err := testEnvironment.Run() + err = testEnvironment.Run() require.NoError(t, err, "Error setting up test environment") if testEnvironment.WillUseRemoteRunner() { @@ -168,7 +187,7 @@ func TestAutomationReorg(t *testing.T) { // Register cleanup for any test t.Cleanup(func() { - err := actions.TeardownSuite(t, testEnvironment, chainlinkNodes, nil, zapcore.PanicLevel, chainClient) + err := actions.TeardownSuite(t, testEnvironment, chainlinkNodes, nil, zapcore.PanicLevel, &config, chainClient) require.NoError(t, err, "Error tearing down environment") }) diff --git a/integration-tests/reorg/log_poller_maybe_reorg_test.go b/integration-tests/reorg/log_poller_maybe_reorg_test.go deleted file mode 100644 index d319e39aa2..0000000000 --- a/integration-tests/reorg/log_poller_maybe_reorg_test.go +++ /dev/null @@ -1,43 +0,0 @@ -package reorg - -import ( - "testing" - - "github.com/ethereum/go-ethereum/accounts/abi" - - logpoller "github.com/smartcontractkit/chainlink/integration-tests/universal/log_poller" -) - -func TestLogPollerFromEnv(t *testing.T) { - cfg := logpoller.Config{ - General: &logpoller.General{ - Generator: logpoller.GeneratorType_Looped, - Contracts: 2, - EventsPerTx: 100, - UseFinalityTag: true, - }, - LoopedConfig: &logpoller.LoopedConfig{ - ContractConfig: logpoller.ContractConfig{ - ExecutionCount: 100, - }, - FuzzConfig: logpoller.FuzzConfig{ - MinEmitWaitTimeMs: 400, - MaxEmitWaitTimeMs: 600, - }, - }, - } - - eventsToEmit := []abi.Event{} - for _, event := range logpoller.EmitterABI.Events { - eventsToEmit = append(eventsToEmit, event) - } - - cfg.General.EventsToEmit = eventsToEmit - err := cfg.OverrideFromEnv() - if err != nil { - t.Errorf("failed to override config from env: %v", err) - t.FailNow() - } - - logpoller.ExecuteCILogPollerTest(t, &cfg) -} diff --git a/integration-tests/reorg/reorg_test.go b/integration-tests/reorg/reorg_test.go deleted file mode 100644 index fc35047d0e..0000000000 --- a/integration-tests/reorg/reorg_test.go +++ /dev/null @@ -1,228 +0,0 @@ -package reorg - -import ( - "fmt" - "math/big" - "os" - "strings" - "testing" - "time" - - "github.com/google/uuid" - "github.com/onsi/gomega" - "github.com/rs/zerolog/log" - "github.com/stretchr/testify/require" - "go.uber.org/zap/zapcore" - - "github.com/smartcontractkit/chainlink-testing-framework/blockchain" - ctfClient "github.com/smartcontractkit/chainlink-testing-framework/client" - "github.com/smartcontractkit/chainlink-testing-framework/k8s/environment" - "github.com/smartcontractkit/chainlink-testing-framework/k8s/pkg/cdk8s/blockscout" - "github.com/smartcontractkit/chainlink-testing-framework/k8s/pkg/helm/chainlink" - "github.com/smartcontractkit/chainlink-testing-framework/k8s/pkg/helm/mockserver" - mockservercfg "github.com/smartcontractkit/chainlink-testing-framework/k8s/pkg/helm/mockserver-cfg" - "github.com/smartcontractkit/chainlink-testing-framework/k8s/pkg/helm/reorg" - "github.com/smartcontractkit/chainlink-testing-framework/logging" - "github.com/smartcontractkit/chainlink-testing-framework/networks" - "github.com/smartcontractkit/chainlink-testing-framework/utils/testcontext" - - "github.com/smartcontractkit/chainlink/integration-tests/actions" - "github.com/smartcontractkit/chainlink/integration-tests/client" - "github.com/smartcontractkit/chainlink/integration-tests/contracts" -) - -const ( - baseDRTOML = ` -[Feature] -LogPoller = true -` - networkDRTOML = ` -Enabled = true -FinalityDepth = %s -LogPollInterval = '1s' - -[EVM.HeadTracker] -HistoryDepth = %s -` -) - -const ( - EVMFinalityDepth = "200" - EVMTrackerHistoryDepth = "400" - reorgBlocks = 10 - minIncomingConfirmations = "200" - timeout = "15m" - interval = "2s" -) - -var ( - networkSettings = blockchain.EVMNetwork{ - Name: "geth", - Simulated: true, - ChainID: 1337, - PrivateKeys: []string{ - "ac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80", - }, - ChainlinkTransactionLimit: 500000, - Timeout: blockchain.JSONStrDuration{Duration: 2 * time.Minute}, - MinimumConfirmations: 1, - GasEstimationBuffer: 10000, - } -) - -func TestMain(m *testing.M) { - os.Exit(m.Run()) -} - -func CleanupReorgTest( - t *testing.T, - testEnvironment *environment.Environment, - chainlinkNodes []*client.ChainlinkK8sClient, - chainClient blockchain.EVMClient, -) { - if chainClient != nil { - chainClient.GasStats().PrintStats() - } - err := actions.TeardownSuite(t, testEnvironment, chainlinkNodes, nil, zapcore.PanicLevel, chainClient) - require.NoError(t, err, "Error tearing down environment") -} - -func TestDirectRequestReorg(t *testing.T) { - logging.Init() - l := logging.GetTestLogger(t) - testEnvironment := environment.New(&environment.Config{ - TTL: 1 * time.Hour, - Test: t, - }) - err := testEnvironment. - AddHelm(mockservercfg.New(nil)). - AddHelm(mockserver.New(nil)). - AddChart(blockscout.New(&blockscout.Props{ - WsURL: "ws://geth-ethereum-geth:8546", - HttpURL: "http://geth-ethereum-geth:8544", - })). - AddHelm(reorg.New(&reorg.Props{ - NetworkName: "geth", - NetworkType: "geth-reorg", - Values: map[string]interface{}{ - "geth": map[string]interface{}{ - "genesis": map[string]interface{}{ - "networkId": "1337", - }, - }, - }, - })). - Run() - require.NoError(t, err, "Error deploying test environment") - if testEnvironment.WillUseRemoteRunner() { - return - } - - // related https://app.shortcut.com/chainlinklabs/story/38295/creating-an-evm-chain-via-cli-or-api-immediately-polling-the-nodes-and-returning-an-error - // node must work and reconnect even if network is not working - time.Sleep(90 * time.Second) - activeEVMNetwork = networks.SimulatedEVMNonDev - netCfg := fmt.Sprintf(networkDRTOML, EVMFinalityDepth, EVMTrackerHistoryDepth) - chainlinkDeployment := chainlink.New(0, map[string]interface{}{ - "replicas": 1, - "toml": networks.AddNetworkDetailedConfig(baseDRTOML, netCfg, activeEVMNetwork), - }) - - err = testEnvironment.AddHelm(chainlinkDeployment).Run() - require.NoError(t, err, "Error adding to test environment") - - chainClient, err := blockchain.NewEVMClient(networkSettings, testEnvironment, l) - require.NoError(t, err, "Error connecting to blockchain") - cd, 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") - ms, err := ctfClient.ConnectMockServer(testEnvironment) - require.NoError(t, err, "Error connecting to Mockserver") - - t.Cleanup(func() { - CleanupReorgTest(t, testEnvironment, chainlinkNodes, chainClient) - }) - - err = actions.FundChainlinkNodes(chainlinkNodes, chainClient, big.NewFloat(10)) - require.NoError(t, err, "Error funding Chainlink nodes") - - lt, err := cd.DeployLinkTokenContract() - require.NoError(t, err, "Deploying Link Token Contract shouldn't fail") - oracle, err := cd.DeployOracle(lt.Address()) - require.NoError(t, err, "Deploying Oracle Contract shouldn't fail") - consumer, err := cd.DeployAPIConsumer(lt.Address()) - require.NoError(t, err, "Deploying Consumer Contract shouldn't fail") - err = chainClient.SetDefaultWallet(0) - require.NoError(t, err, "Setting default wallet shouldn't fail") - err = lt.Transfer(consumer.Address(), big.NewInt(2e18)) - require.NoError(t, err, "Transferring %d to consumer contract shouldn't fail", big.NewInt(2e18)) - - err = ms.SetValuePath("/variable", 5) - require.NoError(t, err, "Setting mockserver value path shouldn't fail") - - jobUUID := uuid.New() - - bta := client.BridgeTypeAttributes{ - Name: fmt.Sprintf("five-%s", jobUUID.String()), - URL: fmt.Sprintf("%s/variable", ms.Config.ClusterURL), - } - err = chainlinkNodes[0].MustCreateBridge(&bta) - require.NoError(t, err, "Creating bridge shouldn't fail") - - drps := &client.DirectRequestTxPipelineSpec{ - BridgeTypeAttributes: bta, - DataPath: "data,result", - } - ost, err := drps.String() - require.NoError(t, err, "Building observation source spec shouldn't fail") - - _, err = chainlinkNodes[0].MustCreateJob(&client.DirectRequestJobSpec{ - Name: "direct_request", - MinIncomingConfirmations: minIncomingConfirmations, - ContractAddress: oracle.Address(), - EVMChainID: chainClient.GetChainID().String(), - ExternalJobID: jobUUID.String(), - ObservationSource: ost, - }) - require.NoError(t, err, "Creating direct_request job shouldn't fail") - - 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(reorgBlocks) - rc.WaitReorgStarted() - - jobUUIDReplaces := strings.Replace(jobUUID.String(), "-", "", 4) - var jobID [32]byte - copy(jobID[:], jobUUIDReplaces) - err = consumer.CreateRequestTo( - oracle.Address(), - jobID, - big.NewInt(1e18), - fmt.Sprintf("%s/variable", ms.Config.ClusterURL), - "data,result", - big.NewInt(100), - ) - require.NoError(t, err, "Calling oracle contract shouldn't fail") - - err = rc.WaitDepthReached() - require.NoError(t, err, "Error waiting for depth to be reached") - - gom := gomega.NewGomegaWithT(t) - gom.Eventually(func(g gomega.Gomega) { - d, err := consumer.Data(testcontext.Get(t)) - g.Expect(err).ShouldNot(gomega.HaveOccurred(), "Getting data from consumer contract shouldn't fail") - g.Expect(d).ShouldNot(gomega.BeNil(), "Expected the initial on chain data to be nil") - log.Debug().Int64("Data", d.Int64()).Msg("Found on chain") - g.Expect(d.Int64()).Should(gomega.BeNumerically("==", 5), "Expected the on-chain data to be 5, but found %d", d.Int64()) - }, timeout, interval).Should(gomega.Succeed()) -} diff --git a/integration-tests/scripts/buildTests b/integration-tests/scripts/buildTests index edf4043ce1..749bb54511 100755 --- a/integration-tests/scripts/buildTests +++ b/integration-tests/scripts/buildTests @@ -21,6 +21,6 @@ OIFS=$IFS IFS=' ' for x in $tosplit do - go test -c ./"${x}" + go test -c -tags embed ./"${x}" done IFS=$OIFS diff --git a/integration-tests/scripts/entrypoint b/integration-tests/scripts/entrypoint index baa6f44b34..315d8cee95 100755 --- a/integration-tests/scripts/entrypoint +++ b/integration-tests/scripts/entrypoint @@ -26,6 +26,9 @@ echo "Test exit code: ${exit_code}" if [ $exit_code -eq 3 ]; then echo "Test was interrupted, exiting with 1 exit code to trigger K8s to restart" exit 1 # Exiting with non-zero status to trigger pod restart +else + echo "Test either panicked or had some sort of failure. We're exiting with a non-zero exit code so that K8s doesn't restart the pod." + echo "TEST_FAILED" fi # Sleep for the amount of time provided by the POST_RUN_SLEEP env var diff --git a/integration-tests/scripts/search_and_delete.sh b/integration-tests/scripts/search_and_delete.sh new file mode 100755 index 0000000000..ae1f8a6e70 --- /dev/null +++ b/integration-tests/scripts/search_and_delete.sh @@ -0,0 +1,41 @@ +#!/bin/bash + +if [ $# -eq 0 ]; then + read -p "Enter the comma-separated list of filenames to search for: " filenames +else + filenames=$@ +fi + +IFS=',' read -ra filenames_arr <<< "$filenames" + +# Start search from the current working directory +current_dir=$(pwd) + +echo "Searching for files in $current_dir..." +found_files=() +for filename in "${filenames_arr[@]}"; do + while IFS= read -r file; do + found_files+=("$file") + done < <(find "$current_dir" -type f -name "$filename" 2>/dev/null) +done + +if [[ ${#found_files[@]} -eq 0 ]]; then + echo "No files found." + exit 0 +fi + +echo "Found files:" +for file in "${found_files[@]}"; do + echo "$file" +done + +read -p "Do you want to remove all these files? (y/n): " confirm + +if [[ $confirm == "yes" ]] || [[ $confirm == "y" ]]; then + for file in "${found_files[@]}"; do + rm "$file" + done + echo "Files removed." +else + echo "Files not removed." +fi \ No newline at end of file diff --git a/integration-tests/smoke/README.md b/integration-tests/smoke/README.md index 1dedc4e384..266720c7bc 100644 --- a/integration-tests/smoke/README.md +++ b/integration-tests/smoke/README.md @@ -52,18 +52,32 @@ Here is an example for 3 nodes cluster ``` ### Running against Live Testnets +1. Prepare your `overrides.toml` file with selected network and CL image name and version and save anywhere inside `integration-tests` folder. +```toml +[ChainlinkImage] +image="your-image" +version="your-version" +[Network] +selected_networks=["polygon_mumbai"] + +[Network.RpcHttpUrls] +polygon_mumbai=["https://http.endpoint.com"] + +[Network.RpcWsUrls] +polygon_mumbai=["wss://ws.endpoint.com"] + +[Network.WalletKeys] +polygon_mumbai=["my_so_private_key"] ``` -SELECTED_NETWORKS= \ -_KEYS= \ -_URLS= \ -_HTTP_URLS= \ +Then execute: +```bash go test -v -run ${TestName} ``` ### Debugging CL client API calls -``` +```bash export CL_CLIENT_DEBUG=true ``` \ No newline at end of file diff --git a/integration-tests/smoke/automation_test.go b/integration-tests/smoke/automation_test.go index 0bdb6cf1f4..07f5c907b2 100644 --- a/integration-tests/smoke/automation_test.go +++ b/integration-tests/smoke/automation_test.go @@ -17,8 +17,8 @@ import ( ocr2keepers30config "github.com/smartcontractkit/chainlink-automation/pkg/v3/config" "github.com/smartcontractkit/chainlink/integration-tests/actions/automationv2" - - "github.com/kelseyhightower/envconfig" + tc "github.com/smartcontractkit/chainlink/integration-tests/testconfig" + "github.com/smartcontractkit/chainlink/integration-tests/types" "github.com/ethereum/go-ethereum/common" "github.com/onsi/gomega" @@ -30,6 +30,7 @@ import ( "github.com/smartcontractkit/chainlink-testing-framework/utils/testcontext" commonconfig "github.com/smartcontractkit/chainlink-common/pkg/config" + "github.com/smartcontractkit/chainlink/integration-tests/actions" "github.com/smartcontractkit/chainlink/integration-tests/contracts" "github.com/smartcontractkit/chainlink/integration-tests/contracts/ethereum" @@ -68,18 +69,27 @@ var ( func TestMain(m *testing.M) { logging.Init() - fmt.Printf("Running Smoke Test on %s\n", networks.MustGetSelectedNetworksFromEnv()[0].Name) // Print to get around disabled logging - fmt.Printf("Chainlink Image %s\n", os.Getenv("CHAINLINK_IMAGE")) // Print to get around disabled logging - fmt.Printf("Chainlink Version %s\n", os.Getenv("CHAINLINK_VERSION")) // Print to get around disabled logging + // config, err := tc.GetConfig(tc.NoTest, tc.Smoke, tc.Automation) + // if err != nil { + // panic(err) + // } + // fmt.Printf("Running Smoke Test on %s\n", networks.MustGetSelectedNetworkConfig(config.Network)[0].Name) // Print to get around disabled logging + // fmt.Printf("Chainlink Image %v\n", config.ChainlinkImage.Image) // Print to get around disabled logging + // fmt.Printf("Chainlink Version %v\n", config.ChainlinkImage.Version) // Print to get around disabled logging os.Exit(m.Run()) } func TestAutomationBasic(t *testing.T) { - SetupAutomationBasic(t, false) + config, err := tc.GetConfig("Smoke", tc.Automation) + if err != nil { + t.Fatal(err) + } + SetupAutomationBasic(t, false, &config) } -func SetupAutomationBasic(t *testing.T, nodeUpgrade bool) { +func SetupAutomationBasic(t *testing.T, nodeUpgrade bool, automationTestConfig types.AutomationTestConfig) { t.Parallel() + registryVersions := map[string]ethereum.KeeperRegistryVersion{ "registry_2_0": ethereum.RegistryVersion_2_0, "registry_2_1_conditional": ethereum.RegistryVersion_2_1, @@ -93,19 +103,14 @@ func SetupAutomationBasic(t *testing.T, nodeUpgrade bool) { name := name registryVersion := registryVersion t.Run(name, func(t *testing.T) { + cfg := tc.MustCopy(automationTestConfig) t.Parallel() l := logging.GetTestLogger(t) - var ( - upgradeImage string - upgradeVersion string - err error - ) + var err error if nodeUpgrade { - 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") + if cfg.GetChainlinkUpgradeImageConfig() == nil { + t.Fatal("[ChainlinkUpgradeImage] must be set in TOML config to upgrade nodes") } } @@ -116,7 +121,7 @@ func SetupAutomationBasic(t *testing.T, nodeUpgrade bool) { isMercury := isMercuryV02 || isMercuryV03 a := setupAutomationTestDocker( - t, registryVersion, automationDefaultRegistryConfig, isMercuryV02, isMercuryV03, + t, registryVersion, automationDefaultRegistryConfig, isMercuryV02, isMercuryV03, automationTestConfig, ) consumers, upkeepIDs := actions.DeployConsumers( @@ -172,10 +177,11 @@ func SetupAutomationBasic(t *testing.T, nodeUpgrade bool) { l.Info().Msgf("Total time taken to get 5 performs for each upkeep: %s", time.Since(startTime)) if nodeUpgrade { + require.NotNil(t, cfg.GetChainlinkImageConfig(), "unable to upgrade node version, [ChainlinkUpgradeImage] was not set, must both a new image or a new version") expect := 5 // Upgrade the nodes one at a time and check that the upkeeps are still being performed for i := 0; i < 5; i++ { - err = actions.UpgradeChainlinkNodeVersionsLocal(upgradeImage, upgradeVersion, a.DockerEnv.ClCluster.Nodes[i]) + err = actions.UpgradeChainlinkNodeVersionsLocal(*cfg.GetChainlinkImageConfig().Image, *cfg.GetChainlinkImageConfig().Version, a.DockerEnv.ClCluster.Nodes[i]) require.NoError(t, err, "Error when upgrading node %d", i) time.Sleep(time.Second * 10) expect = expect + 5 @@ -229,8 +235,13 @@ func TestSetUpkeepTriggerConfig(t *testing.T) { t.Parallel() l := logging.GetTestLogger(t) + config, err := tc.GetConfig("Smoke", tc.Automation) + if err != nil { + t.Fatal(err) + } + a := setupAutomationTestDocker( - t, ethereum.RegistryVersion_2_1, automationDefaultRegistryConfig, false, false, + t, ethereum.RegistryVersion_2_1, automationDefaultRegistryConfig, false, false, &config, ) consumers, upkeepIDs := actions.DeployConsumers( @@ -308,7 +319,7 @@ func TestSetUpkeepTriggerConfig(t *testing.T) { require.NoError(t, err, "Could not set upkeep trigger config at index %d", i) } - err := a.ChainClient.WaitForEvents() + err = a.ChainClient.WaitForEvents() require.NoError(t, err, "Error encountered when waiting for setting trigger config for upkeeps") var countersAfterSetNoMatch = make([]*big.Int, len(upkeepIDs)) @@ -404,8 +415,12 @@ func TestAutomationAddFunds(t *testing.T) { registryVersion := registryVersion t.Run(name, func(t *testing.T) { t.Parallel() + config, err := tc.GetConfig("Smoke", tc.Automation) + if err != nil { + t.Fatal(err) + } a := setupAutomationTestDocker( - t, registryVersion, automationDefaultRegistryConfig, false, false, + t, registryVersion, automationDefaultRegistryConfig, false, false, &config, ) consumers, upkeepIDs := actions.DeployConsumers( @@ -432,7 +447,7 @@ func TestAutomationAddFunds(t *testing.T) { }, "2m", "1s").Should(gomega.Succeed()) // ~1m for setup, 1m assertion // Grant permission to the registry to fund the upkeep - err := a.LinkToken.Approve(a.Registry.Address(), big.NewInt(9e18)) + err = a.LinkToken.Approve(a.Registry.Address(), big.NewInt(9e18)) require.NoError(t, err, "Could not approve permissions for the registry on the link token contract") err = a.ChainClient.WaitForEvents() require.NoError(t, err, "Error waiting for events") @@ -467,8 +482,12 @@ func TestAutomationPauseUnPause(t *testing.T) { t.Run(name, func(t *testing.T) { t.Parallel() l := logging.GetTestLogger(t) + config, err := tc.GetConfig("Smoke", tc.Automation) + if err != nil { + t.Fatal(err) + } a := setupAutomationTestDocker( - t, registryVersion, automationDefaultRegistryConfig, false, false, + t, registryVersion, automationDefaultRegistryConfig, false, false, &config, ) consumers, upkeepIDs := actions.DeployConsumers( @@ -503,7 +522,7 @@ func TestAutomationPauseUnPause(t *testing.T) { require.NoError(t, err, "Could not pause upkeep at index %d", i) } - err := a.ChainClient.WaitForEvents() + err = a.ChainClient.WaitForEvents() require.NoError(t, err, "Error waiting for upkeeps to be paused") var countersAfterPause = make([]*big.Int, len(upkeepIDs)) @@ -562,8 +581,12 @@ func TestAutomationRegisterUpkeep(t *testing.T) { t.Run(name, func(t *testing.T) { t.Parallel() l := logging.GetTestLogger(t) + config, err := tc.GetConfig("Smoke", tc.Automation) + if err != nil { + t.Fatal(err) + } a := setupAutomationTestDocker( - t, registryVersion, automationDefaultRegistryConfig, false, false, + t, registryVersion, automationDefaultRegistryConfig, false, false, &config, ) consumers, upkeepIDs := actions.DeployConsumers( @@ -645,8 +668,12 @@ func TestAutomationPauseRegistry(t *testing.T) { registryVersion := registryVersion t.Run(name, func(t *testing.T) { t.Parallel() + config, err := tc.GetConfig("Smoke", tc.Automation) + if err != nil { + t.Fatal(err) + } a := setupAutomationTestDocker( - t, registryVersion, automationDefaultRegistryConfig, false, false, + t, registryVersion, automationDefaultRegistryConfig, false, false, &config, ) consumers, upkeepIDs := actions.DeployConsumers( @@ -675,7 +702,7 @@ func TestAutomationPauseRegistry(t *testing.T) { }, "4m", "1s").Should(gomega.Succeed()) // ~1m for cluster setup, ~1m for performing each upkeep once, ~2m buffer // Pause the registry - err := a.Registry.Pause() + err = a.Registry.Pause() require.NoError(t, err, "Error pausing registry") err = a.ChainClient.WaitForEvents() require.NoError(t, err, "Error waiting for registry to pause") @@ -715,8 +742,12 @@ func TestAutomationKeeperNodesDown(t *testing.T) { t.Run(name, func(t *testing.T) { t.Parallel() l := logging.GetTestLogger(t) + config, err := tc.GetConfig("Smoke", tc.Automation) + if err != nil { + t.Fatal(err) + } a := setupAutomationTestDocker( - t, registryVersion, automationDefaultRegistryConfig, false, false, + t, registryVersion, automationDefaultRegistryConfig, false, false, &config, ) consumers, upkeepIDs := actions.DeployConsumers( @@ -750,7 +781,7 @@ func TestAutomationKeeperNodesDown(t *testing.T) { }, "4m", "1s").Should(gomega.Succeed()) // ~1m for cluster setup, ~1m for performing each upkeep once, ~2m buffer // Take down 1 node. Currently, using 4 nodes so f=1 and is the max nodes that can go down. - err := nodesWithoutBootstrap[0].MustDeleteJob("1") + err = nodesWithoutBootstrap[0].MustDeleteJob("1") require.NoError(t, err, "Error deleting job from Chainlink node") err = a.ChainClient.WaitForEvents() require.NoError(t, err, "Error waiting for blockchain events") @@ -814,8 +845,12 @@ func TestAutomationPerformSimulation(t *testing.T) { registryVersion := registryVersion t.Run(name, func(t *testing.T) { t.Parallel() + config, err := tc.GetConfig("Smoke", tc.Automation) + if err != nil { + t.Fatal(err) + } a := setupAutomationTestDocker( - t, registryVersion, automationDefaultRegistryConfig, false, false, + t, registryVersion, automationDefaultRegistryConfig, false, false, &config, ) consumersPerformance, _ := actions.DeployPerformanceConsumers( @@ -848,7 +883,7 @@ func TestAutomationPerformSimulation(t *testing.T) { }, "2m", "1s").Should(gomega.Succeed()) // ~1m for setup, 1m assertion // Set performGas on consumer to be low, so that performUpkeep starts becoming successful - err := consumerPerformance.SetPerformGasToBurn(testcontext.Get(t), big.NewInt(100000)) + err = consumerPerformance.SetPerformGasToBurn(testcontext.Get(t), big.NewInt(100000)) require.NoError(t, err, "Perform gas should be set successfully on consumer") err = a.ChainClient.WaitForEvents() require.NoError(t, err, "Error waiting for set perform gas tx") @@ -878,8 +913,12 @@ func TestAutomationCheckPerformGasLimit(t *testing.T) { t.Run(name, func(t *testing.T) { t.Parallel() l := logging.GetTestLogger(t) + config, err := tc.GetConfig("Smoke", tc.Automation) + if err != nil { + t.Fatal(err) + } a := setupAutomationTestDocker( - t, registryVersion, automationDefaultRegistryConfig, false, false, + t, registryVersion, automationDefaultRegistryConfig, false, false, &config, ) consumersPerformance, upkeepIDs := actions.DeployPerformanceConsumers( @@ -914,7 +953,7 @@ func TestAutomationCheckPerformGasLimit(t *testing.T) { }, "2m", "1s").Should(gomega.Succeed()) // ~1m for setup, 1m assertion // Increase gas limit for the upkeep, higher than the performGasBurn - err := a.Registry.SetUpkeepGasLimit(upkeepID, uint32(4500000)) + err = a.Registry.SetUpkeepGasLimit(upkeepID, uint32(4500000)) require.NoError(t, err, "Error setting upkeep gas limit") err = a.ChainClient.WaitForEvents() require.NoError(t, err, "Error waiting for SetUpkeepGasLimit tx") @@ -992,8 +1031,13 @@ func TestUpdateCheckData(t *testing.T) { t.Run(name, func(t *testing.T) { t.Parallel() l := logging.GetTestLogger(t) + config, err := tc.GetConfig("Smoke", tc.Automation) + if err != nil { + t.Fatal(err) + } + a := setupAutomationTestDocker( - t, registryVersion, automationDefaultRegistryConfig, false, false, + t, registryVersion, automationDefaultRegistryConfig, false, false, &config, ) performDataChecker, upkeepIDs := actions.DeployPerformDataCheckerConsumers( @@ -1027,7 +1071,7 @@ func TestUpdateCheckData(t *testing.T) { require.NoError(t, err, "Could not update check data for upkeep at index %d", i) } - err := a.ChainClient.WaitForEvents() + err = a.ChainClient.WaitForEvents() require.NoError(t, err, "Error while waiting for check data update") // retrieve new check data for all upkeeps @@ -1052,23 +1096,20 @@ func TestUpdateCheckData(t *testing.T) { } } -type TestConfig struct { - ChainlinkNodeFunding float64 `envconfig:"CHAINLINK_NODE_FUNDING" default:"1"` -} - func setupAutomationTestDocker( t *testing.T, registryVersion ethereum.KeeperRegistryVersion, registryConfig contracts.KeeperRegistrySettings, isMercuryV02 bool, isMercuryV03 bool, + automationTestConfig types.AutomationTestConfig, ) automationv2.AutomationTest { 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 - network := networks.MustGetSelectedNetworksFromEnv()[0] + network := networks.MustGetSelectedNetworkConfig(automationTestConfig.GetNetworkConfig())[0] // build the node config clNodeConfig := node.NewConfig(node.NewBaseConfig()) @@ -1084,17 +1125,16 @@ func setupAutomationTestDocker( //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) + l.Debug().Msgf("Funding amount: %f", *automationTestConfig.GetCommonConfig().ChainlinkNodeFunding) clNodesCount := 5 if isMercuryV02 || isMercuryV03 { env, err = test_env.NewCLTestEnvBuilder(). WithTestInstance(t). + WithTestConfig(automationTestConfig). WithGeth(). WithMockAdapter(). - WithFunding(big.NewFloat(testConfig.ChainlinkNodeFunding)). + WithFunding(big.NewFloat(*automationTestConfig.GetCommonConfig().ChainlinkNodeFunding)). WithStandardCleanup(). Build() require.NoError(t, err, "Error deploying test environment for Mercury") @@ -1120,19 +1160,20 @@ func setupAutomationTestDocker( node.SetChainConfig(clNodeConfig, wsUrls, httpUrls, network, false) - err = env.StartClCluster(clNodeConfig, clNodesCount, secretsConfig) + err = env.StartClCluster(clNodeConfig, clNodesCount, secretsConfig, automationTestConfig) require.NoError(t, err, "Error starting CL nodes test environment for Mercury") - err = env.FundChainlinkNodes(big.NewFloat(testConfig.ChainlinkNodeFunding)) + err = env.FundChainlinkNodes(big.NewFloat(*automationTestConfig.GetCommonConfig().ChainlinkNodeFunding)) require.NoError(t, err, "Error funding CL nodes") } else { env, err = test_env.NewCLTestEnvBuilder(). WithTestInstance(t). + WithTestConfig(automationTestConfig). WithGeth(). WithMockAdapter(). WithCLNodes(clNodesCount). WithCLNodeConfig(clNodeConfig). - WithFunding(big.NewFloat(testConfig.ChainlinkNodeFunding)). + WithFunding(big.NewFloat(*automationTestConfig.GetCommonConfig().ChainlinkNodeFunding)). WithStandardCleanup(). Build() require.NoError(t, err, "Error deploying test environment") diff --git a/integration-tests/smoke/automation_upgrade_test.go b/integration-tests/smoke/automation_upgrade_test.go index 2828554362..6601457de8 100644 --- a/integration-tests/smoke/automation_upgrade_test.go +++ b/integration-tests/smoke/automation_upgrade_test.go @@ -2,8 +2,14 @@ package smoke import ( "testing" + + tc "github.com/smartcontractkit/chainlink/integration-tests/testconfig" ) func TestAutomationNodeUpgrade(t *testing.T) { - SetupAutomationBasic(t, true) + config, err := tc.GetConfig(t.Name(), tc.Automation) + if err != nil { + t.Fatal(err, "Error getting config") + } + SetupAutomationBasic(t, true, &config) } diff --git a/integration-tests/smoke/cron_test.go b/integration-tests/smoke/cron_test.go index df1b85882e..b6e04612ac 100644 --- a/integration-tests/smoke/cron_test.go +++ b/integration-tests/smoke/cron_test.go @@ -13,14 +13,21 @@ import ( "github.com/smartcontractkit/chainlink/integration-tests/client" "github.com/smartcontractkit/chainlink/integration-tests/docker/test_env" + tc "github.com/smartcontractkit/chainlink/integration-tests/testconfig" ) func TestCronBasic(t *testing.T) { t.Parallel() l := logging.GetTestLogger(t) + config, err := tc.GetConfig("Smoke", tc.Cron) + if err != nil { + t.Fatal(err) + } + env, err := test_env.NewCLTestEnvBuilder(). WithTestInstance(t). + WithTestConfig(&config). WithGeth(). WithMockAdapter(). WithCLNodes(1). @@ -65,8 +72,14 @@ func TestCronJobReplacement(t *testing.T) { t.Parallel() l := logging.GetTestLogger(t) + config, err := tc.GetConfig("Smoke", tc.Cron) + if err != nil { + t.Fatal(err) + } + env, err := test_env.NewCLTestEnvBuilder(). WithTestInstance(t). + WithTestConfig(&config). WithGeth(). WithMockAdapter(). WithCLNodes(1). diff --git a/integration-tests/smoke/flux_test.go b/integration-tests/smoke/flux_test.go index 345971e892..c8cec4e385 100644 --- a/integration-tests/smoke/flux_test.go +++ b/integration-tests/smoke/flux_test.go @@ -19,14 +19,21 @@ import ( "github.com/smartcontractkit/chainlink/integration-tests/client" "github.com/smartcontractkit/chainlink/integration-tests/contracts" "github.com/smartcontractkit/chainlink/integration-tests/docker/test_env" + tc "github.com/smartcontractkit/chainlink/integration-tests/testconfig" ) func TestFluxBasic(t *testing.T) { t.Parallel() l := logging.GetTestLogger(t) + config, err := tc.GetConfig("Smoke", tc.Flux) + if err != nil { + t.Fatal(err) + } + env, err := test_env.NewCLTestEnvBuilder(). WithTestInstance(t). + WithTestConfig(&config). WithGeth(). WithMockAdapter(). WithCLNodes(3). diff --git a/integration-tests/smoke/forwarder_ocr_test.go b/integration-tests/smoke/forwarder_ocr_test.go index fd8dfc780a..5c603c5b08 100644 --- a/integration-tests/smoke/forwarder_ocr_test.go +++ b/integration-tests/smoke/forwarder_ocr_test.go @@ -12,14 +12,21 @@ import ( "github.com/smartcontractkit/chainlink/integration-tests/actions" "github.com/smartcontractkit/chainlink/integration-tests/docker/test_env" + tc "github.com/smartcontractkit/chainlink/integration-tests/testconfig" ) func TestForwarderOCRBasic(t *testing.T) { t.Parallel() l := logging.GetTestLogger(t) + config, err := tc.GetConfig("Smoke", tc.ForwarderOcr) + if err != nil { + t.Fatal(err) + } + env, err := test_env.NewCLTestEnvBuilder(). WithTestInstance(t). + WithTestConfig(&config). WithGeth(). WithMockAdapter(). WithForwarders(). diff --git a/integration-tests/smoke/forwarders_ocr2_test.go b/integration-tests/smoke/forwarders_ocr2_test.go index 90dc20a389..9385fb4f9a 100644 --- a/integration-tests/smoke/forwarders_ocr2_test.go +++ b/integration-tests/smoke/forwarders_ocr2_test.go @@ -17,14 +17,22 @@ import ( "github.com/smartcontractkit/chainlink/integration-tests/contracts" "github.com/smartcontractkit/chainlink/integration-tests/docker/test_env" "github.com/smartcontractkit/chainlink/integration-tests/types/config/node" + + tc "github.com/smartcontractkit/chainlink/integration-tests/testconfig" ) func TestForwarderOCR2Basic(t *testing.T) { t.Parallel() l := logging.GetTestLogger(t) + config, err := tc.GetConfig("Smoke", tc.ForwarderOcr2) + if err != nil { + t.Fatal(err) + } + env, err := test_env.NewCLTestEnvBuilder(). WithTestInstance(t). + WithTestConfig(&config). WithGeth(). WithMockAdapter(). WithCLNodeConfig(node.NewConfig(node.NewBaseConfig(), @@ -77,7 +85,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.MockAdapter, "ocr2", 5, env.EVMClient.GetChainID().Uint64(), true) + err = actions.CreateOCRv2JobsLocal(ocrInstances, bootstrapNode, workerNodes, env.MockAdapter, "ocr2", 5, env.EVMClient.GetChainID().Uint64(), true, false) require.NoError(t, err, "Error creating OCRv2 jobs with forwarders") err = env.EVMClient.WaitForEvents() require.NoError(t, err, "Error waiting for events") diff --git a/integration-tests/smoke/keeper_test.go b/integration-tests/smoke/keeper_test.go index cac5aa93d3..0ebbc1e083 100644 --- a/integration-tests/smoke/keeper_test.go +++ b/integration-tests/smoke/keeper_test.go @@ -22,6 +22,8 @@ import ( "github.com/smartcontractkit/chainlink/integration-tests/contracts/ethereum" "github.com/smartcontractkit/chainlink/integration-tests/docker/test_env" "github.com/smartcontractkit/chainlink/integration-tests/types/config/node" + + tc "github.com/smartcontractkit/chainlink/integration-tests/testconfig" ) const ( @@ -86,7 +88,12 @@ func TestKeeperBasicSmoke(t *testing.T) { t.Run(fmt.Sprintf("registry_1_%d", registryVersion), func(t *testing.T) { t.Parallel() l := logging.GetTestLogger(t) - chainClient, chainlinkNodes, contractDeployer, linkToken, _ := setupKeeperTest(t) + config, err := tc.GetConfig("Smoke", tc.Keeper) + if err != nil { + t.Fatal(err) + } + + chainClient, chainlinkNodes, contractDeployer, linkToken, _ := setupKeeperTest(t, &config) registry, _, consumers, upkeepIDs := actions.DeployKeeperContracts( t, registryVersion, @@ -100,7 +107,7 @@ func TestKeeperBasicSmoke(t *testing.T) { ) gom := gomega.NewGomegaWithT(t) - _, err := actions.CreateKeeperJobsLocal(l, chainlinkNodes, registry, contracts.OCRv2Config{}, chainClient.GetChainID().String()) + _, err = actions.CreateKeeperJobsLocal(l, chainlinkNodes, registry, contracts.OCRv2Config{}, chainClient.GetChainID().String()) require.NoError(t, err, "Error creating keeper jobs") err = chainClient.WaitForEvents() require.NoError(t, err, "Error creating keeper jobs") @@ -162,7 +169,12 @@ func TestKeeperBlockCountPerTurn(t *testing.T) { t.Run(fmt.Sprintf("registry_1_%d", registryVersion), func(t *testing.T) { t.Parallel() l := logging.GetTestLogger(t) - chainClient, chainlinkNodes, contractDeployer, linkToken, _ := setupKeeperTest(t) + config, err := tc.GetConfig("Smoke", tc.Keeper) + if err != nil { + t.Fatal(err) + } + + chainClient, chainlinkNodes, contractDeployer, linkToken, _ := setupKeeperTest(t, &config) registry, _, consumers, upkeepIDs := actions.DeployKeeperContracts( t, registryVersion, @@ -176,7 +188,7 @@ func TestKeeperBlockCountPerTurn(t *testing.T) { ) gom := gomega.NewGomegaWithT(t) - _, err := actions.CreateKeeperJobsLocal(l, chainlinkNodes, registry, contracts.OCRv2Config{}, chainClient.GetChainID().String()) + _, err = actions.CreateKeeperJobsLocal(l, chainlinkNodes, registry, contracts.OCRv2Config{}, chainClient.GetChainID().String()) require.NoError(t, err, "Error creating keeper jobs") err = chainClient.WaitForEvents() require.NoError(t, err, "Error creating keeper jobs") @@ -266,7 +278,12 @@ func TestKeeperSimulation(t *testing.T) { t.Run(fmt.Sprintf("registry_1_%d", registryVersion), func(t *testing.T) { t.Parallel() l := logging.GetTestLogger(t) - chainClient, chainlinkNodes, contractDeployer, linkToken, _ := setupKeeperTest(t) + config, err := tc.GetConfig("Smoke", tc.Keeper) + if err != nil { + t.Fatal(err) + } + + chainClient, chainlinkNodes, contractDeployer, linkToken, _ := setupKeeperTest(t, &config) registry, _, consumersPerformance, upkeepIDs := actions.DeployPerformanceKeeperContracts( t, registryVersion, @@ -284,7 +301,7 @@ func TestKeeperSimulation(t *testing.T) { ) gom := gomega.NewGomegaWithT(t) - _, err := actions.CreateKeeperJobsLocal(l, chainlinkNodes, registry, contracts.OCRv2Config{}, chainClient.GetChainID().String()) + _, err = actions.CreateKeeperJobsLocal(l, chainlinkNodes, registry, contracts.OCRv2Config{}, chainClient.GetChainID().String()) require.NoError(t, err, "Error creating keeper jobs") err = chainClient.WaitForEvents() require.NoError(t, err, "Error creating keeper jobs") @@ -339,7 +356,11 @@ func TestKeeperCheckPerformGasLimit(t *testing.T) { t.Run(fmt.Sprintf("registry_1_%d", registryVersion), func(t *testing.T) { t.Parallel() l := logging.GetTestLogger(t) - chainClient, chainlinkNodes, contractDeployer, linkToken, _ := setupKeeperTest(t) + config, err := tc.GetConfig("Smoke", tc.Keeper) + if err != nil { + t.Fatal(err) + } + chainClient, chainlinkNodes, contractDeployer, linkToken, _ := setupKeeperTest(t, &config) registry, _, consumersPerformance, upkeepIDs := actions.DeployPerformanceKeeperContracts( t, registryVersion, @@ -357,7 +378,7 @@ func TestKeeperCheckPerformGasLimit(t *testing.T) { ) gom := gomega.NewGomegaWithT(t) - _, err := actions.CreateKeeperJobsLocal(l, chainlinkNodes, registry, contracts.OCRv2Config{}, chainClient.GetChainID().String()) + _, err = actions.CreateKeeperJobsLocal(l, chainlinkNodes, registry, contracts.OCRv2Config{}, chainClient.GetChainID().String()) require.NoError(t, err, "Error creating keeper jobs") err = chainClient.WaitForEvents() require.NoError(t, err, "Error creating keeper jobs") @@ -452,7 +473,11 @@ func TestKeeperRegisterUpkeep(t *testing.T) { t.Run(fmt.Sprintf("registry_1_%d", registryVersion), func(t *testing.T) { t.Parallel() l := logging.GetTestLogger(t) - chainClient, chainlinkNodes, contractDeployer, linkToken, _ := setupKeeperTest(t) + config, err := tc.GetConfig("Smoke", tc.Keeper) + if err != nil { + t.Fatal(err) + } + chainClient, chainlinkNodes, contractDeployer, linkToken, _ := setupKeeperTest(t, &config) registry, registrar, consumers, upkeepIDs := actions.DeployKeeperContracts( t, registryVersion, @@ -466,7 +491,7 @@ func TestKeeperRegisterUpkeep(t *testing.T) { ) gom := gomega.NewGomegaWithT(t) - _, err := actions.CreateKeeperJobsLocal(l, chainlinkNodes, registry, contracts.OCRv2Config{}, chainClient.GetChainID().String()) + _, err = actions.CreateKeeperJobsLocal(l, chainlinkNodes, registry, contracts.OCRv2Config{}, chainClient.GetChainID().String()) require.NoError(t, err, "Error creating keeper jobs") err = chainClient.WaitForEvents() require.NoError(t, err, "Error creating keeper jobs") @@ -541,7 +566,11 @@ func TestKeeperAddFunds(t *testing.T) { t.Run(fmt.Sprintf("registry_1_%d", registryVersion), func(t *testing.T) { t.Parallel() l := logging.GetTestLogger(t) - chainClient, chainlinkNodes, contractDeployer, linkToken, _ := setupKeeperTest(t) + config, err := tc.GetConfig("Smoke", tc.Keeper) + if err != nil { + t.Fatal(err) + } + chainClient, chainlinkNodes, contractDeployer, linkToken, _ := setupKeeperTest(t, &config) registry, _, consumers, upkeepIDs := actions.DeployKeeperContracts( t, registryVersion, @@ -555,7 +584,7 @@ func TestKeeperAddFunds(t *testing.T) { ) gom := gomega.NewGomegaWithT(t) - _, err := actions.CreateKeeperJobsLocal(l, chainlinkNodes, registry, contracts.OCRv2Config{}, chainClient.GetChainID().String()) + _, err = actions.CreateKeeperJobsLocal(l, chainlinkNodes, registry, contracts.OCRv2Config{}, chainClient.GetChainID().String()) require.NoError(t, err, "Error creating keeper jobs") err = chainClient.WaitForEvents() require.NoError(t, err, "Error creating keeper jobs") @@ -604,7 +633,11 @@ func TestKeeperRemove(t *testing.T) { t.Run(fmt.Sprintf("registry_1_%d", registryVersion), func(t *testing.T) { t.Parallel() l := logging.GetTestLogger(t) - chainClient, chainlinkNodes, contractDeployer, linkToken, _ := setupKeeperTest(t) + config, err := tc.GetConfig("Smoke", tc.Keeper) + if err != nil { + t.Fatal(err) + } + chainClient, chainlinkNodes, contractDeployer, linkToken, _ := setupKeeperTest(t, &config) registry, _, consumers, upkeepIDs := actions.DeployKeeperContracts( t, registryVersion, @@ -618,7 +651,7 @@ func TestKeeperRemove(t *testing.T) { ) gom := gomega.NewGomegaWithT(t) - _, err := actions.CreateKeeperJobsLocal(l, chainlinkNodes, registry, contracts.OCRv2Config{}, chainClient.GetChainID().String()) + _, err = actions.CreateKeeperJobsLocal(l, chainlinkNodes, registry, contracts.OCRv2Config{}, chainClient.GetChainID().String()) require.NoError(t, err, "Error creating keeper jobs") err = chainClient.WaitForEvents() require.NoError(t, err, "Error creating keeper jobs") @@ -682,7 +715,11 @@ func TestKeeperPauseRegistry(t *testing.T) { t.Run(fmt.Sprintf("registry_1_%d", registryVersion), func(t *testing.T) { t.Parallel() l := logging.GetTestLogger(t) - chainClient, chainlinkNodes, contractDeployer, linkToken, _ := setupKeeperTest(t) + config, err := tc.GetConfig("Smoke", tc.Keeper) + if err != nil { + t.Fatal(err) + } + chainClient, chainlinkNodes, contractDeployer, linkToken, _ := setupKeeperTest(t, &config) registry, _, consumers, upkeepIDs := actions.DeployKeeperContracts( t, registryVersion, @@ -696,7 +733,7 @@ func TestKeeperPauseRegistry(t *testing.T) { ) gom := gomega.NewGomegaWithT(t) - _, err := actions.CreateKeeperJobsLocal(l, chainlinkNodes, registry, contracts.OCRv2Config{}, chainClient.GetChainID().String()) + _, err = actions.CreateKeeperJobsLocal(l, chainlinkNodes, registry, contracts.OCRv2Config{}, chainClient.GetChainID().String()) require.NoError(t, err, "Error creating keeper jobs") err = chainClient.WaitForEvents() require.NoError(t, err, "Error creating keeper jobs") @@ -743,7 +780,11 @@ func TestKeeperPauseRegistry(t *testing.T) { func TestKeeperMigrateRegistry(t *testing.T) { t.Parallel() l := logging.GetTestLogger(t) - chainClient, chainlinkNodes, contractDeployer, linkToken, _ := setupKeeperTest(t) + config, err := tc.GetConfig("Smoke", tc.Keeper) + if err != nil { + t.Fatal(err) + } + chainClient, chainlinkNodes, contractDeployer, linkToken, _ := setupKeeperTest(t, &config) registry, _, consumers, upkeepIDs := actions.DeployKeeperContracts( t, ethereum.RegistryVersion_1_2, @@ -757,7 +798,7 @@ func TestKeeperMigrateRegistry(t *testing.T) { ) gom := gomega.NewGomegaWithT(t) - _, err := actions.CreateKeeperJobsLocal(l, chainlinkNodes, registry, contracts.OCRv2Config{}, chainClient.GetChainID().String()) + _, err = actions.CreateKeeperJobsLocal(l, chainlinkNodes, registry, contracts.OCRv2Config{}, chainClient.GetChainID().String()) require.NoError(t, err, "Error creating keeper jobs") err = chainClient.WaitForEvents() require.NoError(t, err, "Error creating keeper jobs") @@ -835,7 +876,11 @@ func TestKeeperNodeDown(t *testing.T) { t.Run(fmt.Sprintf("registry_1_%d", registryVersion), func(t *testing.T) { t.Parallel() l := logging.GetTestLogger(t) - chainClient, chainlinkNodes, contractDeployer, linkToken, _ := setupKeeperTest(t) + config, err := tc.GetConfig("Smoke", tc.Keeper) + if err != nil { + t.Fatal(err) + } + chainClient, chainlinkNodes, contractDeployer, linkToken, _ := setupKeeperTest(t, &config) registry, _, consumers, upkeepIDs := actions.DeployKeeperContracts( t, registryVersion, @@ -941,7 +986,11 @@ type nodeAndJob struct { func TestKeeperPauseUnPauseUpkeep(t *testing.T) { t.Parallel() l := logging.GetTestLogger(t) - chainClient, chainlinkNodes, contractDeployer, linkToken, _ := setupKeeperTest(t) + config, err := tc.GetConfig("Smoke", tc.Keeper) + if err != nil { + t.Fatal(err) + } + chainClient, chainlinkNodes, contractDeployer, linkToken, _ := setupKeeperTest(t, &config) registry, _, consumers, upkeepIDs := actions.DeployKeeperContracts( t, ethereum.RegistryVersion_1_3, @@ -955,7 +1004,7 @@ func TestKeeperPauseUnPauseUpkeep(t *testing.T) { ) gom := gomega.NewGomegaWithT(t) - _, err := actions.CreateKeeperJobsLocal(l, chainlinkNodes, registry, contracts.OCRv2Config{}, chainClient.GetChainID().String()) + _, err = actions.CreateKeeperJobsLocal(l, chainlinkNodes, registry, contracts.OCRv2Config{}, chainClient.GetChainID().String()) require.NoError(t, err, "Error creating keeper jobs") err = chainClient.WaitForEvents() require.NoError(t, err, "Error creating keeper jobs") @@ -1031,7 +1080,11 @@ func TestKeeperPauseUnPauseUpkeep(t *testing.T) { func TestKeeperUpdateCheckData(t *testing.T) { t.Parallel() l := logging.GetTestLogger(t) - chainClient, chainlinkNodes, contractDeployer, linkToken, _ := setupKeeperTest(t) + config, err := tc.GetConfig("Smoke", tc.Keeper) + if err != nil { + t.Fatal(err) + } + chainClient, chainlinkNodes, contractDeployer, linkToken, _ := setupKeeperTest(t, &config) registry, _, performDataChecker, upkeepIDs := actions.DeployPerformDataCheckerContracts( t, ethereum.RegistryVersion_1_3, @@ -1046,7 +1099,7 @@ func TestKeeperUpdateCheckData(t *testing.T) { ) gom := gomega.NewGomegaWithT(t) - _, err := actions.CreateKeeperJobsLocal(l, chainlinkNodes, registry, contracts.OCRv2Config{}, chainClient.GetChainID().String()) + _, err = actions.CreateKeeperJobsLocal(l, chainlinkNodes, registry, contracts.OCRv2Config{}, chainClient.GetChainID().String()) require.NoError(t, err, "Error creating keeper jobs") err = chainClient.WaitForEvents() require.NoError(t, err, "Error creating keeper jobs") @@ -1090,7 +1143,7 @@ func TestKeeperUpdateCheckData(t *testing.T) { }, "3m", "1s").Should(gomega.Succeed()) } -func setupKeeperTest(t *testing.T) ( +func setupKeeperTest(t *testing.T, config *tc.TestConfig) ( blockchain.EVMClient, []*client.ChainlinkClient, contracts.ContractDeployer, @@ -1107,6 +1160,7 @@ func setupKeeperTest(t *testing.T) ( env, err := test_env.NewCLTestEnvBuilder(). WithTestInstance(t). + WithTestConfig(config). WithGeth(). WithCLNodes(5). WithCLNodeConfig(clNodeConfig). @@ -1128,10 +1182,14 @@ func setupKeeperTest(t *testing.T) ( func TestKeeperJobReplacement(t *testing.T) { t.Parallel() + l := logging.GetTestLogger(t) registryVersion := ethereum.RegistryVersion_1_3 + config, err := tc.GetConfig("Smoke", tc.Keeper) + if err != nil { + t.Fatal(err) + } - l := logging.GetTestLogger(t) - chainClient, chainlinkNodes, contractDeployer, linkToken, _ := setupKeeperTest(t) + chainClient, chainlinkNodes, contractDeployer, linkToken, _ := setupKeeperTest(t, &config) registry, _, consumers, upkeepIDs := actions.DeployKeeperContracts( t, registryVersion, @@ -1145,7 +1203,7 @@ func TestKeeperJobReplacement(t *testing.T) { ) gom := gomega.NewGomegaWithT(t) - _, err := actions.CreateKeeperJobsLocal(l, chainlinkNodes, registry, contracts.OCRv2Config{}, chainClient.GetChainID().String()) + _, err = actions.CreateKeeperJobsLocal(l, chainlinkNodes, registry, contracts.OCRv2Config{}, chainClient.GetChainID().String()) require.NoError(t, err, "Error creating keeper jobs") err = chainClient.WaitForEvents() require.NoError(t, err, "Error creating keeper jobs") diff --git a/integration-tests/smoke/log_poller_test.go b/integration-tests/smoke/log_poller_test.go index 03a287ee6b..593b4eb879 100644 --- a/integration-tests/smoke/log_poller_test.go +++ b/integration-tests/smoke/log_poller_test.go @@ -1,261 +1,395 @@ package smoke import ( + "fmt" + "math/big" "testing" + "time" "github.com/ethereum/go-ethereum/accounts/abi" - + "github.com/onsi/gomega" + "github.com/rs/zerolog" + "github.com/stretchr/testify/require" + + "github.com/smartcontractkit/chainlink-testing-framework/logging" + "github.com/smartcontractkit/chainlink-testing-framework/utils/testcontext" + "github.com/smartcontractkit/chainlink/integration-tests/actions" + "github.com/smartcontractkit/chainlink/integration-tests/contracts" + "github.com/smartcontractkit/chainlink/integration-tests/contracts/ethereum" + "github.com/smartcontractkit/chainlink/integration-tests/docker/test_env" + tc "github.com/smartcontractkit/chainlink/integration-tests/testconfig" + lp_config "github.com/smartcontractkit/chainlink/integration-tests/testconfig/log_poller" logpoller "github.com/smartcontractkit/chainlink/integration-tests/universal/log_poller" + + core_logger "github.com/smartcontractkit/chainlink/v2/core/logger" ) // consistency test with no network disruptions with approximate emission of 1500-1600 logs per second for ~110-120 seconds // 6 filters are registered func TestLogPollerFewFiltersFixedDepth(t *testing.T) { - cfg := logpoller.Config{ - General: &logpoller.General{ - Generator: logpoller.GeneratorType_Looped, - Contracts: 2, - EventsPerTx: 4, - UseFinalityTag: false, - }, - LoopedConfig: &logpoller.LoopedConfig{ - ContractConfig: logpoller.ContractConfig{ - ExecutionCount: 100, - }, - FuzzConfig: logpoller.FuzzConfig{ - MinEmitWaitTimeMs: 200, - MaxEmitWaitTimeMs: 500, - }, - }, - } + executeBasicLogPollerTest(t) +} - eventsToEmit := []abi.Event{} - for _, event := range logpoller.EmitterABI.Events { - eventsToEmit = append(eventsToEmit, event) - } +func TestLogPollerFewFiltersFinalityTag(t *testing.T) { + executeBasicLogPollerTest(t) +} - cfg.General.EventsToEmit = eventsToEmit +// consistency test with no network disruptions with approximate emission of 1000-1100 logs per second for ~110-120 seconds +// 900 filters are registered +func TestLogPollerManyFiltersFixedDepth(t *testing.T) { + t.Skip("Execute manually, when needed as it runs for a long time") + executeBasicLogPollerTest(t) +} - logpoller.ExecuteBasicLogPollerTest(t, &cfg) +func TestLogPollerManyFiltersFinalityTag(t *testing.T) { + t.Skip("Execute manually, when needed as it runs for a long time") + executeBasicLogPollerTest(t) } -func TestLogPollerFewFiltersFinalityTag(t *testing.T) { - cfg := logpoller.Config{ - General: &logpoller.General{ - Generator: logpoller.GeneratorType_Looped, - Contracts: 2, - EventsPerTx: 4, - UseFinalityTag: true, - }, - LoopedConfig: &logpoller.LoopedConfig{ - ContractConfig: logpoller.ContractConfig{ - ExecutionCount: 100, - }, - FuzzConfig: logpoller.FuzzConfig{ - MinEmitWaitTimeMs: 200, - MaxEmitWaitTimeMs: 500, - }, - }, - } +// consistency test that introduces random distruptions by pausing either Chainlink or Postgres containers for random interval of 5-20 seconds +// with approximate emission of 520-550 logs per second for ~110 seconds +// 6 filters are registered +func TestLogPollerWithChaosFixedDepth(t *testing.T) { + executeBasicLogPollerTest(t) +} - eventsToEmit := []abi.Event{} - for _, event := range logpoller.EmitterABI.Events { - eventsToEmit = append(eventsToEmit, event) - } +func TestLogPollerWithChaosFinalityTag(t *testing.T) { + executeBasicLogPollerTest(t) +} - cfg.General.EventsToEmit = eventsToEmit +func TestLogPollerWithChaosPostgresFixedDepth(t *testing.T) { + executeBasicLogPollerTest(t) +} - logpoller.ExecuteBasicLogPollerTest(t, &cfg) +func TestLogPollerWithChaosPostgresFinalityTag(t *testing.T) { + executeBasicLogPollerTest(t) } -// consistency test with no network disruptions with approximate emission of 1000-1100 logs per second for ~110-120 seconds -// 900 filters are registered -func TestLogManyFiltersPollerFixedDepth(t *testing.T) { - cfg := logpoller.Config{ - General: &logpoller.General{ - Generator: logpoller.GeneratorType_Looped, - Contracts: 300, - EventsPerTx: 3, - UseFinalityTag: false, - }, - LoopedConfig: &logpoller.LoopedConfig{ - ContractConfig: logpoller.ContractConfig{ - ExecutionCount: 30, - }, - FuzzConfig: logpoller.FuzzConfig{ - MinEmitWaitTimeMs: 200, - MaxEmitWaitTimeMs: 500, - }, - }, - } +// consistency test that registers filters after events were emitted and then triggers replay via API +// unfortunately there is no way to make sure that logs that are indexed are only picked up by replay +// and not by backup poller +// with approximate emission of 24 logs per second for ~110 seconds +// 6 filters are registered +func TestLogPollerReplayFixedDepth(t *testing.T) { + executeLogPollerReplay(t, "5m") +} + +func TestLogPollerReplayFinalityTag(t *testing.T) { + executeLogPollerReplay(t, "5m") +} + +// HELPER FUNCTIONS +func executeBasicLogPollerTest(t *testing.T) { + testConfig, err := tc.GetConfig(t.Name(), tc.LogPoller) + require.NoError(t, err, "Error getting config") eventsToEmit := []abi.Event{} for _, event := range logpoller.EmitterABI.Events { eventsToEmit = append(eventsToEmit, event) } + cfg := testConfig.LogPoller cfg.General.EventsToEmit = eventsToEmit - logpoller.ExecuteBasicLogPollerTest(t, &cfg) -} + l := logging.GetTestLogger(t) + coreLogger := core_logger.TestLogger(t) //needed by ORM ¯\_(ツ)_/¯ -func TestLogManyFiltersPollerFinalityTag(t *testing.T) { - cfg := logpoller.Config{ - General: &logpoller.General{ - Generator: logpoller.GeneratorType_Looped, - Contracts: 300, - EventsPerTx: 3, - UseFinalityTag: true, - }, - LoopedConfig: &logpoller.LoopedConfig{ - ContractConfig: logpoller.ContractConfig{ - ExecutionCount: 30, - }, - FuzzConfig: logpoller.FuzzConfig{ - MinEmitWaitTimeMs: 200, - MaxEmitWaitTimeMs: 500, - }, - }, - } + lpTestEnv := prepareEnvironment(l, t, &testConfig) + testEnv := lpTestEnv.testEnv - eventsToEmit := []abi.Event{} - for _, event := range logpoller.EmitterABI.Events { - eventsToEmit = append(eventsToEmit, event) - } + // Register log triggered upkeep for each combination of log emitter contract and event signature (topic) + // We need to register a separate upkeep for each event signature, because log trigger doesn't support multiple topics (even if log poller does) + err = logpoller.RegisterFiltersAndAssertUniquness(l, lpTestEnv.registry, lpTestEnv.upkeepIDs, lpTestEnv.logEmitters, cfg, lpTestEnv.upKeepsNeeded) + require.NoError(t, err, "Error registering filters") - cfg.General.EventsToEmit = eventsToEmit + l.Info().Msg("No duplicate filters found. OK!") - logpoller.ExecuteBasicLogPollerTest(t, &cfg) -} + err = testEnv.EVMClient.WaitForEvents() + require.NoError(t, err, "Error encountered when waiting for setting trigger config for upkeeps") -// consistency test that introduces random distruptions by pausing either Chainlink or Postgres containers for random interval of 5-20 seconds -// with approximate emission of 520-550 logs per second for ~110 seconds -// 6 filters are registered -func TestLogPollerWithChaosFixedDepth(t *testing.T) { - cfg := logpoller.Config{ - General: &logpoller.General{ - Generator: logpoller.GeneratorType_Looped, - Contracts: 2, - EventsPerTx: 100, - UseFinalityTag: false, - }, - LoopedConfig: &logpoller.LoopedConfig{ - ContractConfig: logpoller.ContractConfig{ - ExecutionCount: 100, - }, - FuzzConfig: logpoller.FuzzConfig{ - MinEmitWaitTimeMs: 200, - MaxEmitWaitTimeMs: 500, - }, - }, - ChaosConfig: &logpoller.ChaosConfig{ - ExperimentCount: 10, - }, - } + expectedFilters := logpoller.GetExpectedFilters(lpTestEnv.logEmitters, cfg) + waitForAllNodesToHaveExpectedFiltersRegisteredOrFail(l, coreLogger, t, testEnv, expectedFilters) - eventsToEmit := []abi.Event{} - for _, event := range logpoller.EmitterABI.Events { - eventsToEmit = append(eventsToEmit, event) - } + // Save block number before starting to emit events, so that we can later use it when querying logs + sb, err := testEnv.EVMClient.LatestBlockNumber(testcontext.Get(t)) + require.NoError(t, err, "Error getting latest block number") + startBlock := int64(sb) - cfg.General.EventsToEmit = eventsToEmit + l.Info().Int64("Starting Block", startBlock).Msg("STARTING EVENT EMISSION") + startTime := time.Now() - logpoller.ExecuteBasicLogPollerTest(t, &cfg) -} + // Start chaos experimnents by randomly pausing random containers (Chainlink nodes or their DBs) + chaosDoneCh := make(chan error, 1) + go func() { + logpoller.ExecuteChaosExperiment(l, testEnv, cfg, chaosDoneCh) + }() -func TestLogPollerWithChaosFinalityTag(t *testing.T) { - cfg := logpoller.Config{ - General: &logpoller.General{ - Generator: logpoller.GeneratorType_Looped, - Contracts: 2, - EventsPerTx: 100, - UseFinalityTag: true, - }, - LoopedConfig: &logpoller.LoopedConfig{ - ContractConfig: logpoller.ContractConfig{ - ExecutionCount: 100, - }, - FuzzConfig: logpoller.FuzzConfig{ - MinEmitWaitTimeMs: 200, - MaxEmitWaitTimeMs: 500, - }, - }, - ChaosConfig: &logpoller.ChaosConfig{ - ExperimentCount: 10, - }, - } + totalLogsEmitted, err := logpoller.ExecuteGenerator(t, cfg, lpTestEnv.logEmitters) + endTime := time.Now() + require.NoError(t, err, "Error executing event generator") - eventsToEmit := []abi.Event{} - for _, event := range logpoller.EmitterABI.Events { - eventsToEmit = append(eventsToEmit, event) - } + expectedLogsEmitted := logpoller.GetExpectedLogCount(cfg) + duration := int(endTime.Sub(startTime).Seconds()) - cfg.General.EventsToEmit = eventsToEmit + eb, err := testEnv.EVMClient.LatestBlockNumber(testcontext.Get(t)) + require.NoError(t, err, "Error getting latest block number") + + l.Info(). + Int("Total logs emitted", totalLogsEmitted). + Uint64("Probable last block with logs", eb). + Int64("Expected total logs emitted", expectedLogsEmitted). + Str("Duration", fmt.Sprintf("%d sec", duration)). + Str("LPS", fmt.Sprintf("~%d/sec", totalLogsEmitted/duration)). + Msg("FINISHED EVENT EMISSION") + + l.Info().Msg("Waiting before proceeding with test until all chaos experiments finish") + chaosError := <-chaosDoneCh + require.NoError(t, chaosError, "Error encountered during chaos experiment") + + // use ridciuously high end block so that we don't have to find out the block number of the last block in which logs were emitted + // as that's not trivial to do (i.e. just because chain was at block X when log emission ended it doesn't mean all events made it to that block) + endBlock := int64(eb) + 10000 - logpoller.ExecuteBasicLogPollerTest(t, &cfg) + // logCountWaitDuration, err := time.ParseDuration("5m") + // require.NoError(t, err, "Error parsing log count wait duration") + allNodesLogCountMatches, err := logpoller.FluentlyCheckIfAllNodesHaveLogCount("5m", startBlock, endBlock, totalLogsEmitted, expectedFilters, l, coreLogger, testEnv) + require.NoError(t, err, "Error checking if CL nodes have expected log count") + + conditionallyWaitUntilNodesHaveTheSameLogsAsEvm(l, coreLogger, t, allNodesLogCountMatches, lpTestEnv, cfg, startBlock, endBlock, "5m") } -// consistency test that registers filters after events were emitted and then triggers replay via API -// unfortunately there is no way to make sure that logs that are indexed are only picked up by replay -// and not by backup poller -// with approximate emission of 24 logs per second for ~110 seconds -// 6 filters are registered -func TestLogPollerReplayFixedDepth(t *testing.T) { - cfg := logpoller.Config{ - General: &logpoller.General{ - Generator: logpoller.GeneratorType_Looped, - Contracts: 2, - EventsPerTx: 4, - UseFinalityTag: false, - }, - LoopedConfig: &logpoller.LoopedConfig{ - ContractConfig: logpoller.ContractConfig{ - ExecutionCount: 100, - }, - FuzzConfig: logpoller.FuzzConfig{ - MinEmitWaitTimeMs: 200, - MaxEmitWaitTimeMs: 500, - }, - }, - } +func executeLogPollerReplay(t *testing.T, consistencyTimeout string) { + testConfig, err := tc.GetConfig(t.Name(), tc.LogPoller) + require.NoError(t, err, "Error getting config") eventsToEmit := []abi.Event{} for _, event := range logpoller.EmitterABI.Events { eventsToEmit = append(eventsToEmit, event) } + cfg := testConfig.LogPoller cfg.General.EventsToEmit = eventsToEmit - consistencyTimeout := "5m" - logpoller.ExecuteLogPollerReplay(t, &cfg, consistencyTimeout) + l := logging.GetTestLogger(t) + coreLogger := core_logger.TestLogger(t) //needed by ORM ¯\_(ツ)_/¯ + + lpTestEnv := prepareEnvironment(l, t, &testConfig) + testEnv := lpTestEnv.testEnv + + // Save block number before starting to emit events, so that we can later use it when querying logs + sb, err := testEnv.EVMClient.LatestBlockNumber(testcontext.Get(t)) + require.NoError(t, err, "Error getting latest block number") + startBlock := int64(sb) + + l.Info().Int64("Starting Block", startBlock).Msg("STARTING EVENT EMISSION") + startTime := time.Now() + totalLogsEmitted, err := logpoller.ExecuteGenerator(t, cfg, lpTestEnv.logEmitters) + endTime := time.Now() + require.NoError(t, err, "Error executing event generator") + expectedLogsEmitted := logpoller.GetExpectedLogCount(cfg) + duration := int(endTime.Sub(startTime).Seconds()) + + // Save block number after finishing to emit events, so that we can later use it when querying logs + eb, err := testEnv.EVMClient.LatestBlockNumber(testcontext.Get(t)) + require.NoError(t, err, "Error getting latest block number") + + endBlock, err := logpoller.GetEndBlockToWaitFor(int64(eb), testEnv.EVMClient.GetChainID().Int64(), cfg) + require.NoError(t, err, "Error getting end block to wait for") + + l.Info().Int64("Ending Block", endBlock).Int("Total logs emitted", totalLogsEmitted).Int64("Expected total logs emitted", expectedLogsEmitted).Str("Duration", fmt.Sprintf("%d sec", duration)).Str("LPS", fmt.Sprintf("%d/sec", totalLogsEmitted/duration)).Msg("FINISHED EVENT EMISSION") + + // Lets make sure no logs are in DB yet + expectedFilters := logpoller.GetExpectedFilters(lpTestEnv.logEmitters, cfg) + logCountMatches, err := logpoller.ClNodesHaveExpectedLogCount(startBlock, endBlock, testEnv.EVMClient.GetChainID(), 0, expectedFilters, l, coreLogger, testEnv.ClCluster) + require.NoError(t, err, "Error checking if CL nodes have expected log count") + require.True(t, logCountMatches, "Some CL nodes already had logs in DB") + l.Info().Msg("No logs were saved by CL nodes yet, as expected. Proceeding.") + + // Register log triggered upkeep for each combination of log emitter contract and event signature (topic) + // We need to register a separate upkeep for each event signature, because log trigger doesn't support multiple topics (even if log poller does) + err = logpoller.RegisterFiltersAndAssertUniquness(l, lpTestEnv.registry, lpTestEnv.upkeepIDs, lpTestEnv.logEmitters, cfg, lpTestEnv.upKeepsNeeded) + require.NoError(t, err, "Error registering filters") + + err = testEnv.EVMClient.WaitForEvents() + require.NoError(t, err, "Error encountered when waiting for setting trigger config for upkeeps") + + waitForAllNodesToHaveExpectedFiltersRegisteredOrFail(l, coreLogger, t, testEnv, expectedFilters) + + blockFinalisationWaitDuration := "5m" + l.Warn().Str("Duration", blockFinalisationWaitDuration).Msg("Waiting for all CL nodes to have end block finalised") + gom := gomega.NewGomegaWithT(t) + gom.Eventually(func(g gomega.Gomega) { + hasFinalised, err := logpoller.LogPollerHasFinalisedEndBlock(endBlock, testEnv.EVMClient.GetChainID(), l, coreLogger, testEnv.ClCluster) + if err != nil { + l.Warn().Err(err).Msg("Error checking if nodes have finalised end block. Retrying...") + } + g.Expect(hasFinalised).To(gomega.BeTrue(), "Some nodes have not finalised end block") + }, blockFinalisationWaitDuration, "10s").Should(gomega.Succeed()) + + // Trigger replay + l.Info().Msg("Triggering log poller's replay") + for i := 1; i < len(testEnv.ClCluster.Nodes); i++ { + nodeName := testEnv.ClCluster.Nodes[i].ContainerName + response, _, err := testEnv.ClCluster.Nodes[i].API.ReplayLogPollerFromBlock(startBlock, testEnv.EVMClient.GetChainID().Int64()) + require.NoError(t, err, "Error triggering log poller's replay on node %s", nodeName) + require.Equal(t, "Replay started", response.Data.Attributes.Message, "Unexpected response message from log poller's replay") + } + + // so that we don't have to look for block number of the last block in which logs were emitted as that's not trivial to do + endBlock = endBlock + 10000 + l.Warn().Str("Duration", consistencyTimeout).Msg("Waiting for replay logs to be processed by all nodes") + + // logCountWaitDuration, err := time.ParseDuration("5m") + allNodesLogCountMatches, err := logpoller.FluentlyCheckIfAllNodesHaveLogCount("5m", startBlock, endBlock, totalLogsEmitted, expectedFilters, l, coreLogger, testEnv) + require.NoError(t, err, "Error checking if CL nodes have expected log count") + + conditionallyWaitUntilNodesHaveTheSameLogsAsEvm(l, coreLogger, t, allNodesLogCountMatches, lpTestEnv, cfg, startBlock, endBlock, "5m") } -func TestLogPollerReplayFinalityTag(t *testing.T) { - cfg := logpoller.Config{ - General: &logpoller.General{ - Generator: logpoller.GeneratorType_Looped, - Contracts: 2, - EventsPerTx: 4, - UseFinalityTag: false, - }, - LoopedConfig: &logpoller.LoopedConfig{ - ContractConfig: logpoller.ContractConfig{ - ExecutionCount: 100, - }, - FuzzConfig: logpoller.FuzzConfig{ - MinEmitWaitTimeMs: 200, - MaxEmitWaitTimeMs: 500, - }, - }, +type logPollerEnvironment struct { + logEmitters []*contracts.LogEmitter + testEnv *test_env.CLClusterTestEnv + registry contracts.KeeperRegistry + upkeepIDs []*big.Int + upKeepsNeeded int +} + +// prepareEnvironment prepares environment for log poller tests by starting DON, private Ethereum network, +// deploying registry and log emitter contracts and registering log triggered upkeeps +func prepareEnvironment(l zerolog.Logger, t *testing.T, testConfig *tc.TestConfig) logPollerEnvironment { + cfg := testConfig.LogPoller + if cfg.General.EventsToEmit == nil || len(cfg.General.EventsToEmit) == 0 { + l.Warn().Msg("No events to emit specified, using all events from log emitter contract") + for _, event := range logpoller.EmitterABI.Events { + cfg.General.EventsToEmit = append(cfg.General.EventsToEmit, event) + } } - eventsToEmit := []abi.Event{} - for _, event := range logpoller.EmitterABI.Events { - eventsToEmit = append(eventsToEmit, event) + l.Info().Msg("Starting basic log poller test") + + var ( + err error + upKeepsNeeded = *cfg.General.Contracts * len(cfg.General.EventsToEmit) + ) + + chainClient, _, contractDeployer, linkToken, registry, registrar, testEnv := logpoller.SetupLogPollerTestDocker( + t, + ethereum.RegistryVersion_2_1, + logpoller.DefaultOCRRegistryConfig, + upKeepsNeeded, + time.Duration(500*time.Millisecond), + *cfg.General.UseFinalityTag, + testConfig, + ) + + _, upkeepIDs := actions.DeployConsumers( + t, + registry, + registrar, + linkToken, + contractDeployer, + chainClient, + upKeepsNeeded, + big.NewInt(int64(9e18)), + uint32(2500000), + true, + false, + ) + + err = logpoller.AssertUpkeepIdsUniqueness(upkeepIDs) + require.NoError(t, err, "Error asserting upkeep ids uniqueness") + l.Info().Msg("No duplicate upkeep IDs found. OK!") + + // Deploy Log Emitter contracts + logEmitters := logpoller.UploadLogEmitterContractsAndWaitForFinalisation(l, t, testEnv, cfg) + err = logpoller.AssertContractAddressUniquneness(logEmitters) + require.NoError(t, err, "Error asserting contract addresses uniqueness") + l.Info().Msg("No duplicate contract addresses found. OK!") + + return logPollerEnvironment{ + logEmitters: logEmitters, + registry: registry, + upkeepIDs: upkeepIDs, + upKeepsNeeded: upKeepsNeeded, + testEnv: testEnv, } +} - cfg.General.EventsToEmit = eventsToEmit - consistencyTimeout := "5m" +// waitForAllNodesToHaveExpectedFiltersRegisteredOrFail waits until all nodes have expected filters registered until timeout +func waitForAllNodesToHaveExpectedFiltersRegisteredOrFail(l zerolog.Logger, coreLogger core_logger.SugaredLogger, t *testing.T, testEnv *test_env.CLClusterTestEnv, expectedFilters []logpoller.ExpectedFilter) { + // Make sure that all nodes have expected filters registered before starting to emit events + gom := gomega.NewGomegaWithT(t) + gom.Eventually(func(g gomega.Gomega) { + hasFilters := false + for i := 1; i < len(testEnv.ClCluster.Nodes); i++ { + nodeName := testEnv.ClCluster.Nodes[i].ContainerName + l.Info(). + Str("Node name", nodeName). + Msg("Fetching filters from log poller's DB") + var message string + var err error + + hasFilters, message, err = logpoller.NodeHasExpectedFilters(expectedFilters, coreLogger, testEnv.EVMClient.GetChainID(), testEnv.ClCluster.Nodes[i].PostgresDb) + if !hasFilters || err != nil { + l.Warn(). + Str("Details", message). + Msg("Some filters were missing, but we will retry") + break + } + } + g.Expect(hasFilters).To(gomega.BeTrue(), "Not all expected filters were found in the DB") + }, "5m", "10s").Should(gomega.Succeed()) + + l.Info(). + Msg("All nodes have expected filters registered") + l.Info(). + Int("Count", len(expectedFilters)). + Msg("Expected filters count") +} - logpoller.ExecuteLogPollerReplay(t, &cfg, consistencyTimeout) +// conditionallyWaitUntilNodesHaveTheSameLogsAsEvm checks whether all CL nodes have the same number of logs as EVM node +// if not, then it prints missing logs and wait for some time and checks again +func conditionallyWaitUntilNodesHaveTheSameLogsAsEvm(l zerolog.Logger, coreLogger core_logger.SugaredLogger, t *testing.T, allNodesLogCountMatches bool, lpTestEnv logPollerEnvironment, cfg *lp_config.Config, startBlock, endBlock int64, waitDuration string) { + logCountWaitDuration, err := time.ParseDuration(waitDuration) + require.NoError(t, err, "Error parsing log count wait duration") + + allNodesHaveAllExpectedLogs := false + if !allNodesLogCountMatches { + missingLogs, err := logpoller.GetMissingLogs(startBlock, endBlock, lpTestEnv.logEmitters, lpTestEnv.testEnv.EVMClient, lpTestEnv.testEnv.ClCluster, l, coreLogger, cfg) + if err == nil { + if !missingLogs.IsEmpty() { + logpoller.PrintMissingLogsInfo(missingLogs, l, cfg) + } else { + allNodesHaveAllExpectedLogs = true + l.Info().Msg("All CL nodes have all the logs that EVM node has") + } + } + } + + require.True(t, allNodesLogCountMatches, "Not all CL nodes had expected log count afer %s", logCountWaitDuration) + + // Wait until all CL nodes have exactly the same logs emitted by test contracts as the EVM node has + // but only in the rare case that first attempt to do it failed (basically here want to know not only + // if log count matches, but whether details of every single log match) + if !allNodesHaveAllExpectedLogs { + logConsistencyWaitDuration := "5m" + l.Info(). + Str("Duration", logConsistencyWaitDuration). + Msg("Waiting for CL nodes to have all the logs that EVM node has") + + gom := gomega.NewGomegaWithT(t) + gom.Eventually(func(g gomega.Gomega) { + missingLogs, err := logpoller.GetMissingLogs(startBlock, endBlock, lpTestEnv.logEmitters, lpTestEnv.testEnv.EVMClient, lpTestEnv.testEnv.ClCluster, l, coreLogger, cfg) + if err != nil { + l.Warn(). + Err(err). + Msg("Error getting missing logs. Retrying...") + } + + if !missingLogs.IsEmpty() { + logpoller.PrintMissingLogsInfo(missingLogs, l, cfg) + } + g.Expect(missingLogs.IsEmpty()).To(gomega.BeTrue(), "Some CL nodes were missing logs") + }, logConsistencyWaitDuration, "10s").Should(gomega.Succeed()) + } } diff --git a/integration-tests/smoke/log_poller_test.go_test_list.json b/integration-tests/smoke/log_poller_test.go_test_list.json new file mode 100644 index 0000000000..2159654e28 --- /dev/null +++ b/integration-tests/smoke/log_poller_test.go_test_list.json @@ -0,0 +1,44 @@ +{ + "tests": [ + { + "name": "TestLogPollerFewFiltersFixedDepth", + "label": "ubuntu-latest" + }, + { + "name": "TestLogPollerFewFiltersFinalityTag", + "label": "ubuntu-latest" + }, + { + "name": "TestLogPollerWithChaosFixedDepth", + "label": "ubuntu-latest" + }, + { + "name": "TestLogPollerWithChaosFinalityTag", + "label": "ubuntu-latest" + }, + { + "name": "TestLogPollerWithChaosPostgresFinalityTag", + "label": "ubuntu-latest" + }, + { + "name": "TestLogPollerWithChaosPostgresFixedDepth", + "label": "ubuntu-latest" + }, + { + "name": "TestLogPollerReplayFixedDepth", + "label": "ubuntu-latest" + }, + { + "name": "TestLogPollerReplayFinalityTag", + "label": "ubuntu-latest" + }, + { + "name": "TestLogPollerManyFiltersFixedDepth", + "label": "ubuntu-latest" + }, + { + "name": "TestLogPollerManyFiltersFinalityTag", + "label": "ubuntu-latest" + } + ] +} \ No newline at end of file diff --git a/integration-tests/smoke/ocr2_test.go b/integration-tests/smoke/ocr2_test.go index 2603b6e9e6..89dcfc187d 100644 --- a/integration-tests/smoke/ocr2_test.go +++ b/integration-tests/smoke/ocr2_test.go @@ -11,24 +11,30 @@ import ( "github.com/smartcontractkit/chainlink-testing-framework/logging" "github.com/smartcontractkit/chainlink-testing-framework/utils/testcontext" + "github.com/smartcontractkit/chainlink/v2/core/config/env" "github.com/smartcontractkit/chainlink/integration-tests/actions" "github.com/smartcontractkit/chainlink/integration-tests/contracts" "github.com/smartcontractkit/chainlink/integration-tests/docker/test_env" + tc "github.com/smartcontractkit/chainlink/integration-tests/testconfig" "github.com/smartcontractkit/chainlink/integration-tests/types/config/node" - "github.com/smartcontractkit/chainlink/v2/core/config/env" ) // Tests a basic OCRv2 median feed func TestOCRv2Basic(t *testing.T) { t.Parallel() + noMedianPlugin := map[string]string{string(env.MedianPlugin.Cmd): ""} + medianPlugin := map[string]string{string(env.MedianPlugin.Cmd): "chainlink-feeds"} for _, test := range []struct { - name string - env map[string]string + name string + env map[string]string + chainReaderAndCodec bool }{ - {"legacy", map[string]string{string(env.MedianPluginCmd): ""}}, - {"plugins", map[string]string{string(env.MedianPluginCmd): "chainlink-feeds"}}, + {"legacy", noMedianPlugin, false}, + {"legacy-chain-reader", noMedianPlugin, true}, + {"plugins", medianPlugin, false}, + {"plugins-chain-reader", medianPlugin, true}, } { test := test t.Run(test.name, func(t *testing.T) { @@ -36,11 +42,17 @@ func TestOCRv2Basic(t *testing.T) { l := logging.GetTestLogger(t) - network, err := actions.EthereumNetworkConfigFromEnvOrDefault(l) + config, err := tc.GetConfig("Smoke", tc.OCR2) + if err != nil { + t.Fatal(err) + } + + network, err := actions.EthereumNetworkConfigFromConfig(l, &config) require.NoError(t, err, "Error building ethereum network config") env, err := test_env.NewCLTestEnvBuilder(). WithTestInstance(t). + WithTestConfig(&config). WithPrivateEthereumNetwork(network). WithMockAdapter(). WithCLNodeConfig(node.NewConfig(node.NewBaseConfig(), @@ -80,7 +92,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.MockAdapter, "ocr2", 5, env.EVMClient.GetChainID().Uint64(), false) + err = actions.CreateOCRv2JobsLocal(aggregatorContracts, bootstrapNode, workerNodes, env.MockAdapter, "ocr2", 5, env.EVMClient.GetChainID().Uint64(), false, test.chainReaderAndCodec) require.NoError(t, err, "Error creating OCRv2 jobs") ocrv2Config, err := actions.BuildMedianOCR2ConfigLocal(workerNodes, ocrOffchainOptions) @@ -90,7 +102,7 @@ func TestOCRv2Basic(t *testing.T) { require.NoError(t, err, "Error configuring OCRv2 aggregator contracts") err = actions.WatchNewOCR2Round(1, aggregatorContracts, env.EVMClient, time.Minute*5, l) - require.NoError(t, err, "Error starting new OCR2 round") + require.NoError(t, err, "Error watching for new OCR2 round") roundData, err := aggregatorContracts[0].GetRound(testcontext.Get(t), big.NewInt(1)) require.NoError(t, err, "Getting latest answer from OCR contract shouldn't fail") require.Equal(t, int64(5), roundData.Answer.Int64(), @@ -118,11 +130,17 @@ func TestOCRv2Request(t *testing.T) { t.Parallel() l := logging.GetTestLogger(t) - network, err := actions.EthereumNetworkConfigFromEnvOrDefault(l) + config, err := tc.GetConfig("Smoke", tc.ForwarderOcr) + if err != nil { + t.Fatal(err) + } + + network, err := actions.EthereumNetworkConfigFromConfig(l, &config) require.NoError(t, err, "Error building ethereum network config") env, err := test_env.NewCLTestEnvBuilder(). WithTestInstance(t). + WithTestConfig(&config). WithPrivateEthereumNetwork(network). WithMockAdapter(). WithCLNodeConfig(node.NewConfig(node.NewBaseConfig(), @@ -161,7 +179,7 @@ func TestOCRv2Request(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.MockAdapter, "ocr2", 5, env.EVMClient.GetChainID().Uint64(), false) + err = actions.CreateOCRv2JobsLocal(aggregatorContracts, bootstrapNode, workerNodes, env.MockAdapter, "ocr2", 5, env.EVMClient.GetChainID().Uint64(), false, false) require.NoError(t, err, "Error creating OCRv2 jobs") ocrv2Config, err := actions.BuildMedianOCR2ConfigLocal(workerNodes, ocrOffchainOptions) @@ -171,7 +189,7 @@ func TestOCRv2Request(t *testing.T) { require.NoError(t, err, "Error configuring OCRv2 aggregator contracts") err = actions.WatchNewOCR2Round(1, aggregatorContracts, env.EVMClient, time.Minute*5, l) - require.NoError(t, err, "Error starting new OCR2 round") + require.NoError(t, err, "Error watching for new OCR2 round") roundData, err := aggregatorContracts[0].GetRound(testcontext.Get(t), big.NewInt(1)) require.NoError(t, err, "Getting latest answer from OCR contract shouldn't fail") require.Equal(t, int64(5), roundData.Answer.Int64(), @@ -193,11 +211,19 @@ func TestOCRv2Request(t *testing.T) { } } +// TestOCRv2JobReplacement tests that a func TestOCRv2JobReplacement(t *testing.T) { + t.Parallel() l := logging.GetTestLogger(t) + config, err := tc.GetConfig("Smoke", tc.OCR2) + if err != nil { + t.Fatal(err) + } + env, err := test_env.NewCLTestEnvBuilder(). WithTestInstance(t). + WithTestConfig(&config). WithGeth(). WithMockAdapter(). WithCLNodeConfig(node.NewConfig(node.NewBaseConfig(), @@ -236,7 +262,7 @@ func TestOCRv2JobReplacement(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.MockAdapter, "ocr2", 5, env.EVMClient.GetChainID().Uint64(), false) + err = actions.CreateOCRv2JobsLocal(aggregatorContracts, bootstrapNode, workerNodes, env.MockAdapter, "ocr2", 5, env.EVMClient.GetChainID().Uint64(), false, false) require.NoError(t, err, "Error creating OCRv2 jobs") ocrv2Config, err := actions.BuildMedianOCR2ConfigLocal(workerNodes, ocrOffchainOptions) @@ -246,7 +272,7 @@ func TestOCRv2JobReplacement(t *testing.T) { require.NoError(t, err, "Error configuring OCRv2 aggregator contracts") err = actions.WatchNewOCR2Round(1, aggregatorContracts, env.EVMClient, time.Minute*5, l) - require.NoError(t, err, "Error starting new OCR2 round") + require.NoError(t, err, "Error watching for new OCR2 round") roundData, err := aggregatorContracts[0].GetRound(testcontext.Get(t), big.NewInt(1)) require.NoError(t, err, "Getting latest answer from OCR contract shouldn't fail") require.Equal(t, int64(5), roundData.Answer.Int64(), @@ -272,11 +298,11 @@ func TestOCRv2JobReplacement(t *testing.T) { err = actions.DeleteBridges(nodeClients) require.NoError(t, err) - err = actions.CreateOCRv2JobsLocal(aggregatorContracts, bootstrapNode, workerNodes, env.MockAdapter, "ocr2", 15, env.EVMClient.GetChainID().Uint64(), false) + err = actions.CreateOCRv2JobsLocal(aggregatorContracts, bootstrapNode, workerNodes, env.MockAdapter, "ocr2", 15, env.EVMClient.GetChainID().Uint64(), false, false) require.NoError(t, err, "Error creating OCRv2 jobs") err = actions.WatchNewOCR2Round(3, aggregatorContracts, env.EVMClient, time.Minute*3, l) - require.NoError(t, err, "Error starting new OCR2 round") + require.NoError(t, err, "Error watching for new OCR2 round") roundData, err = aggregatorContracts[0].GetRound(testcontext.Get(t), big.NewInt(3)) require.NoError(t, err, "Getting latest answer from OCR contract shouldn't fail") require.Equal(t, int64(15), roundData.Answer.Int64(), diff --git a/integration-tests/smoke/ocr2vrf_test.go b/integration-tests/smoke/ocr2vrf_test.go index 773476826c..c01ac46fbb 100644 --- a/integration-tests/smoke/ocr2vrf_test.go +++ b/integration-tests/smoke/ocr2vrf_test.go @@ -10,6 +10,7 @@ import ( "go.uber.org/zap/zapcore" "github.com/smartcontractkit/chainlink-testing-framework/blockchain" + ctf_config "github.com/smartcontractkit/chainlink-testing-framework/config" "github.com/smartcontractkit/chainlink-testing-framework/k8s/environment" "github.com/smartcontractkit/chainlink-testing-framework/k8s/pkg/helm/chainlink" eth "github.com/smartcontractkit/chainlink-testing-framework/k8s/pkg/helm/ethereum" @@ -23,12 +24,21 @@ import ( "github.com/smartcontractkit/chainlink/integration-tests/client" "github.com/smartcontractkit/chainlink/integration-tests/config" "github.com/smartcontractkit/chainlink/integration-tests/contracts" + "github.com/smartcontractkit/chainlink/integration-tests/testconfig" + tc "github.com/smartcontractkit/chainlink/integration-tests/testconfig" ) +var ocr2vrfSmokeConfig *testconfig.TestConfig + func TestOCR2VRFRedeemModel(t *testing.T) { t.Parallel() t.Skip("VRFv3 is on pause, skipping") l := logging.GetTestLogger(t) + config, err := tc.GetConfig("Smoke", tc.OCR2) + if err != nil { + t.Fatal(err) + } + testEnvironment, testNetwork := setupOCR2VRFEnvironment(t) if testEnvironment.WillUseRemoteRunner() { return @@ -44,7 +54,7 @@ func TestOCR2VRFRedeemModel(t *testing.T) { require.NoError(t, err, "Retreiving on-chain wallet addresses for chainlink nodes shouldn't fail") t.Cleanup(func() { - err := actions.TeardownSuite(t, testEnvironment, chainlinkNodes, nil, zapcore.ErrorLevel, chainClient) + err := actions.TeardownSuite(t, testEnvironment, chainlinkNodes, nil, zapcore.ErrorLevel, &config, chainClient) require.NoError(t, err, "Error tearing down environment") }) @@ -91,6 +101,11 @@ func TestOCR2VRFFulfillmentModel(t *testing.T) { t.Parallel() t.Skip("VRFv3 is on pause, skipping") l := logging.GetTestLogger(t) + config, err := tc.GetConfig("Smoke", tc.OCR2) + if err != nil { + t.Fatal(err) + } + testEnvironment, testNetwork := setupOCR2VRFEnvironment(t) if testEnvironment.WillUseRemoteRunner() { return @@ -106,7 +121,7 @@ func TestOCR2VRFFulfillmentModel(t *testing.T) { require.NoError(t, err, "Retreiving on-chain wallet addresses for chainlink nodes shouldn't fail") t.Cleanup(func() { - err := actions.TeardownSuite(t, testEnvironment, chainlinkNodes, nil, zapcore.ErrorLevel, chainClient) + err := actions.TeardownSuite(t, testEnvironment, chainlinkNodes, nil, zapcore.ErrorLevel, &config, chainClient) require.NoError(t, err, "Error tearing down environment") }) @@ -149,7 +164,15 @@ func TestOCR2VRFFulfillmentModel(t *testing.T) { } func setupOCR2VRFEnvironment(t *testing.T) (testEnvironment *environment.Environment, testNetwork blockchain.EVMNetwork) { - testNetwork = networks.MustGetSelectedNetworksFromEnv()[0] + if ocr2vrfSmokeConfig == nil { + c, err := testconfig.GetConfig("Smoke", tc.OCR2VRF) + if err != nil { + t.Fatal(err) + } + ocr2vrfSmokeConfig = &c + } + + testNetwork = networks.MustGetSelectedNetworkConfig(ocr2vrfSmokeConfig.Network)[0] evmConfig := eth.New(nil) if !testNetwork.Simulated { evmConfig = eth.New(ð.Props{ @@ -159,14 +182,20 @@ func setupOCR2VRFEnvironment(t *testing.T) (testEnvironment *environment.Environ }) } - cd := chainlink.New(0, map[string]interface{}{ + var overrideFn = func(_ interface{}, target interface{}) { + ctf_config.MustConfigOverrideChainlinkVersion(ocr2vrfSmokeConfig.ChainlinkImage, target) + ctf_config.MightConfigOverridePyroscopeKey(ocr2vrfSmokeConfig.Pyroscope, target) + } + + cd := chainlink.NewWithOverride(0, map[string]interface{}{ "replicas": 6, "toml": networks.AddNetworkDetailedConfig( config.BaseOCR2Config, + ocr2vrfSmokeConfig.Pyroscope, config.DefaultOCR2VRFNetworkDetailTomlConfig, testNetwork, ), - }) + }, ocr2vrfSmokeConfig.ChainlinkImage, overrideFn) testEnvironment = environment.New(&environment.Config{ NamespacePrefix: fmt.Sprintf("smoke-ocr2vrf-%s", strings.ReplaceAll(strings.ToLower(testNetwork.Name), " ", "-")), diff --git a/integration-tests/smoke/ocr_test.go b/integration-tests/smoke/ocr_test.go index 5f09183589..549d6b0a63 100644 --- a/integration-tests/smoke/ocr_test.go +++ b/integration-tests/smoke/ocr_test.go @@ -11,17 +11,25 @@ import ( "github.com/smartcontractkit/chainlink/integration-tests/actions" "github.com/smartcontractkit/chainlink/integration-tests/docker/test_env" + + tc "github.com/smartcontractkit/chainlink/integration-tests/testconfig" ) func TestOCRBasic(t *testing.T) { t.Parallel() l := logging.GetTestLogger(t) - network, err := actions.EthereumNetworkConfigFromEnvOrDefault(l) + config, err := tc.GetConfig("Smoke", tc.OCR) + if err != nil { + t.Fatal(err) + } + + network, err := actions.EthereumNetworkConfigFromConfig(l, &config) require.NoError(t, err, "Error building ethereum network config") env, err := test_env.NewCLTestEnvBuilder(). WithTestInstance(t). + WithTestConfig(&config). WithPrivateEthereumNetwork(network). WithMockAdapter(). WithCLNodes(6). @@ -67,8 +75,14 @@ func TestOCRJobReplacement(t *testing.T) { t.Parallel() l := logging.GetTestLogger(t) + config, err := tc.GetConfig("Smoke", tc.OCR) + if err != nil { + t.Fatal(err) + } + env, err := test_env.NewCLTestEnvBuilder(). WithTestInstance(t). + WithTestConfig(&config). WithGeth(). WithMockAdapter(). WithCLNodes(6). diff --git a/integration-tests/smoke/runlog_test.go b/integration-tests/smoke/runlog_test.go index dc08b19b16..f7f5c54069 100644 --- a/integration-tests/smoke/runlog_test.go +++ b/integration-tests/smoke/runlog_test.go @@ -16,14 +16,22 @@ import ( "github.com/smartcontractkit/chainlink/integration-tests/client" "github.com/smartcontractkit/chainlink/integration-tests/docker/test_env" + + tc "github.com/smartcontractkit/chainlink/integration-tests/testconfig" ) func TestRunLogBasic(t *testing.T) { t.Parallel() l := logging.GetTestLogger(t) + config, err := tc.GetConfig("Smoke", tc.RunLog) + if err != nil { + t.Fatal(err) + } + env, err := test_env.NewCLTestEnvBuilder(). WithTestInstance(t). + WithTestConfig(&config). WithGeth(). WithMockAdapter(). WithCLNodes(1). diff --git a/integration-tests/smoke/vrf_test.go b/integration-tests/smoke/vrf_test.go index 51ea3828cf..c296fcd0f3 100644 --- a/integration-tests/smoke/vrf_test.go +++ b/integration-tests/smoke/vrf_test.go @@ -17,14 +17,21 @@ import ( "github.com/smartcontractkit/chainlink/integration-tests/actions/vrfv1" "github.com/smartcontractkit/chainlink/integration-tests/client" "github.com/smartcontractkit/chainlink/integration-tests/docker/test_env" + tc "github.com/smartcontractkit/chainlink/integration-tests/testconfig" ) func TestVRFBasic(t *testing.T) { t.Parallel() l := logging.GetTestLogger(t) + config, err := tc.GetConfig("Smoke", tc.VRF) + if err != nil { + t.Fatal(err) + } + env, err := test_env.NewCLTestEnvBuilder(). WithTestInstance(t). + WithTestConfig(&config). WithGeth(). WithCLNodes(1). WithFunding(big.NewFloat(.1)). @@ -111,9 +118,14 @@ func TestVRFBasic(t *testing.T) { func TestVRFJobReplacement(t *testing.T) { t.Parallel() l := logging.GetTestLogger(t) + config, err := tc.GetConfig("Smoke", tc.VRF) + if err != nil { + t.Fatal(err) + } env, err := test_env.NewCLTestEnvBuilder(). WithTestInstance(t). + WithTestConfig(&config). WithGeth(). WithCLNodes(1). WithFunding(big.NewFloat(.1)). diff --git a/integration-tests/smoke/vrfv2_test.go b/integration-tests/smoke/vrfv2_test.go index 8958480d51..0d136b62a9 100644 --- a/integration-tests/smoke/vrfv2_test.go +++ b/integration-tests/smoke/vrfv2_test.go @@ -9,44 +9,48 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/google/go-cmp/cmp" "github.com/google/go-cmp/cmp/cmpopts" - "github.com/kelseyhightower/envconfig" "github.com/stretchr/testify/require" commonassets "github.com/smartcontractkit/chainlink-common/pkg/assets" "github.com/smartcontractkit/chainlink-testing-framework/blockchain" "github.com/smartcontractkit/chainlink-testing-framework/logging" + "github.com/smartcontractkit/chainlink-testing-framework/utils/conversions" + "github.com/smartcontractkit/chainlink-testing-framework/utils/ptr" "github.com/smartcontractkit/chainlink-testing-framework/utils/testcontext" "github.com/smartcontractkit/chainlink/integration-tests/actions" "github.com/smartcontractkit/chainlink/integration-tests/actions/vrfv2_actions" - "github.com/smartcontractkit/chainlink/integration-tests/actions/vrfv2_actions/vrfv2_config" + "github.com/smartcontractkit/chainlink/integration-tests/docker/test_env" + tc "github.com/smartcontractkit/chainlink/integration-tests/testconfig" ) func TestVRFv2Basic(t *testing.T) { t.Parallel() l := logging.GetTestLogger(t) - network, err := actions.EthereumNetworkConfigFromEnvOrDefault(l) - require.NoError(t, err, "Error building ethereum network config") + config, err := tc.GetConfig("Smoke", tc.VRFv2) + require.NoError(t, err, "Error getting config") - var vrfv2Config vrfv2_config.VRFV2Config - err = envconfig.Process("VRFV2", &vrfv2Config) - require.NoError(t, err) + useVRFOwner := false + useTestCoordinator := false + network, err := actions.EthereumNetworkConfigFromConfig(l, &config) + require.NoError(t, err, "Error building ethereum network config") env, err := test_env.NewCLTestEnvBuilder(). WithTestInstance(t). + WithTestConfig(&config). WithPrivateEthereumNetwork(network). WithCLNodes(1). - WithFunding(big.NewFloat(vrfv2Config.ChainlinkNodeFunding)). + WithFunding(big.NewFloat(*config.Common.ChainlinkNodeFunding)). WithStandardCleanup(). Build() require.NoError(t, err, "error creating test env") env.ParallelTransactions(true) - mockETHLinkFeed, err := actions.DeployMockETHLinkFeed(env.ContractDeployer, big.NewInt(vrfv2Config.LinkNativeFeedResponse)) + mockETHLinkFeed, err := actions.DeployMockETHLinkFeed(env.ContractDeployer, big.NewInt(*config.VRFv2.General.LinkNativeFeedResponse)) require.NoError(t, err) linkToken, err := actions.DeployLINKToken(env.ContractDeployer) require.NoError(t, err) @@ -57,7 +61,9 @@ func TestVRFv2Basic(t *testing.T) { numberOfTxKeysToCreate := 1 vrfv2Contracts, subIDs, vrfv2Data, err := vrfv2_actions.SetupVRFV2Environment( env, - vrfv2Config, + &config, + useVRFOwner, + useTestCoordinator, linkToken, mockETHLinkFeed, defaultWalletAddress, @@ -76,7 +82,7 @@ func TestVRFv2Basic(t *testing.T) { vrfv2_actions.LogSubDetails(l, subscription, subID, vrfv2Contracts.Coordinator) t.Run("Request Randomness", func(t *testing.T) { - testConfig := vrfv2Config + configCopy := config.MustCopy().(tc.TestConfig) subBalanceBeforeRequest := subscription.Balance jobRunsBeforeTest, err := env.ClCluster.Nodes[0].API.MustReadRunsByJob(vrfv2Data.VRFJob.Data.ID) @@ -84,14 +90,17 @@ func TestVRFv2Basic(t *testing.T) { // test and assert randomWordsFulfilledEvent, err := vrfv2_actions.RequestRandomnessAndWaitForFulfillment( + l, vrfv2Contracts.LoadTestConsumers[0], vrfv2Contracts.Coordinator, - vrfv2Data, subID, - testConfig.RandomnessRequestCountPerRequest, - testConfig, - testConfig.RandomWordsFulfilledEventTimeout, - l, + vrfv2Data, + *configCopy.VRFv2.General.MinimumConfirmations, + *configCopy.VRFv2.General.CallbackGasLimit, + *configCopy.VRFv2.General.NumberOfWords, + *configCopy.VRFv2.General.RandomnessRequestCountPerRequest, + *configCopy.VRFv2.General.RandomnessRequestCountPerRequestDeviation, + configCopy.VRFv2.General.RandomWordsFulfilledEventTimeout.Duration, ) require.NoError(t, err, "error requesting randomness and waiting for fulfilment") @@ -110,7 +119,7 @@ func TestVRFv2Basic(t *testing.T) { require.True(t, status.Fulfilled) l.Debug().Bool("Fulfilment Status", status.Fulfilled).Msg("Random Words Request Fulfilment Status") - require.Equal(t, testConfig.NumberOfWords, uint32(len(status.RandomWords))) + require.Equal(t, *config.VRFv2.General.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") @@ -118,10 +127,10 @@ func TestVRFv2Basic(t *testing.T) { }) t.Run("Direct Funding (VRFV2Wrapper)", func(t *testing.T) { - testConfig := vrfv2Config + configCopy := config.MustCopy().(tc.TestConfig) wrapperContracts, wrapperSubID, err := vrfv2_actions.SetupVRFV2WrapperEnvironment( env, - testConfig, + &configCopy, linkToken, mockETHLinkFeed, vrfv2Contracts.Coordinator, @@ -140,14 +149,17 @@ func TestVRFv2Basic(t *testing.T) { // Request Randomness and wait for fulfillment event randomWordsFulfilledEvent, err := vrfv2_actions.DirectFundingRequestRandomnessAndWaitForFulfillment( + l, wrapperConsumer, vrfv2Contracts.Coordinator, - vrfv2Data, *wrapperSubID, - vrfv2Config.RandomnessRequestCountPerRequest, - vrfv2Config, - testConfig.RandomWordsFulfilledEventTimeout, - l, + vrfv2Data, + *configCopy.VRFv2.General.MinimumConfirmations, + *configCopy.VRFv2.General.CallbackGasLimit, + *configCopy.VRFv2.General.NumberOfWords, + *configCopy.VRFv2.General.RandomnessRequestCountPerRequest, + *configCopy.VRFv2.General.RandomnessRequestCountPerRequestDeviation, + configCopy.VRFv2.General.RandomWordsFulfilledEventTimeout.Duration, ) require.NoError(t, err, "Error requesting randomness and waiting for fulfilment") @@ -170,7 +182,7 @@ func TestVRFv2Basic(t *testing.T) { require.Equal(t, expectedWrapperConsumerJuelsBalance, wrapperConsumerJuelsBalanceAfterRequest) // Check random word count - require.Equal(t, testConfig.NumberOfWords, uint32(len(consumerStatus.RandomWords))) + require.Equal(t, *configCopy.VRFv2.General.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") @@ -191,10 +203,10 @@ func TestVRFv2Basic(t *testing.T) { }) t.Run("Oracle Withdraw", func(t *testing.T) { - testConfig := vrfv2Config + configCopy := config.MustCopy().(tc.TestConfig) subIDsForOracleWithDraw, err := vrfv2_actions.CreateFundSubsAndAddConsumers( env, - testConfig, + big.NewFloat(*configCopy.VRFv2.General.SubscriptionFundingAmountLink), linkToken, vrfv2Contracts.Coordinator, vrfv2Contracts.LoadTestConsumers, @@ -205,14 +217,17 @@ func TestVRFv2Basic(t *testing.T) { subIDForOracleWithdraw := subIDsForOracleWithDraw[0] fulfilledEventLink, err := vrfv2_actions.RequestRandomnessAndWaitForFulfillment( + l, vrfv2Contracts.LoadTestConsumers[0], vrfv2Contracts.Coordinator, - vrfv2Data, subIDForOracleWithdraw, - testConfig.RandomnessRequestCountPerRequest, - testConfig, - testConfig.RandomWordsFulfilledEventTimeout, - l, + vrfv2Data, + *configCopy.VRFv2.General.MinimumConfirmations, + *configCopy.VRFv2.General.CallbackGasLimit, + *configCopy.VRFv2.General.NumberOfWords, + *configCopy.VRFv2.General.RandomnessRequestCountPerRequest, + *configCopy.VRFv2.General.RandomnessRequestCountPerRequestDeviation, + configCopy.VRFv2.General.RandomWordsFulfilledEventTimeout.Duration, ) require.NoError(t, err) @@ -244,10 +259,10 @@ func TestVRFv2Basic(t *testing.T) { }) t.Run("Canceling Sub And Returning Funds", func(t *testing.T) { - testConfig := vrfv2Config + configCopy := config.MustCopy().(tc.TestConfig) subIDsForCancelling, err := vrfv2_actions.CreateFundSubsAndAddConsumers( env, - testConfig, + big.NewFloat(*configCopy.VRFv2.General.SubscriptionFundingAmountLink), linkToken, vrfv2Contracts.Coordinator, vrfv2Contracts.LoadTestConsumers, @@ -318,14 +333,13 @@ func TestVRFv2Basic(t *testing.T) { }) t.Run("Owner Canceling Sub And Returning Funds While Having Pending Requests", func(t *testing.T) { - testConfig := vrfv2Config - + configCopy := config.MustCopy().(tc.TestConfig) // Underfund subscription to force fulfillments to fail - testConfig.SubscriptionFundingAmountLink = float64(0.000000000000000001) // 1 Juel + configCopy.VRFv2.General.SubscriptionFundingAmountLink = ptr.Ptr(float64(0.000000000000000001)) // 1 Juel subIDsForCancelling, err := vrfv2_actions.CreateFundSubsAndAddConsumers( env, - testConfig, + big.NewFloat(*configCopy.VRFv2.General.SubscriptionFundingAmountLink), linkToken, vrfv2Contracts.Coordinator, vrfv2Contracts.LoadTestConsumers, @@ -349,14 +363,17 @@ func TestVRFv2Basic(t *testing.T) { // Request randomness - should fail due to underfunded subscription randomWordsFulfilledEventTimeout := 5 * time.Second _, err = vrfv2_actions.RequestRandomnessAndWaitForFulfillment( + l, vrfv2Contracts.LoadTestConsumers[0], vrfv2Contracts.Coordinator, - vrfv2Data, subIDForCancelling, - testConfig.RandomnessRequestCountPerRequest, - testConfig, + vrfv2Data, + *configCopy.VRFv2.General.MinimumConfirmations, + *configCopy.VRFv2.General.CallbackGasLimit, + *configCopy.VRFv2.General.NumberOfWords, + *configCopy.VRFv2.General.RandomnessRequestCountPerRequest, + *configCopy.VRFv2.General.RandomnessRequestCountPerRequestDeviation, randomWordsFulfilledEventTimeout, - l, ) require.Error(t, err, "Error should occur while waiting for fulfilment due to low sub balance") @@ -433,25 +450,30 @@ func TestVRFv2MultipleSendingKeys(t *testing.T) { t.Parallel() l := logging.GetTestLogger(t) - network, err := actions.EthereumNetworkConfigFromEnvOrDefault(l) - require.NoError(t, err, "Error building ethereum network config") + config, err := tc.GetConfig("Smoke", tc.VRFv2) + if err != nil { + t.Fatal(err) + } - var vrfv2Config vrfv2_config.VRFV2Config - err = envconfig.Process("VRFV2", &vrfv2Config) - require.NoError(t, err) + useVRFOwner := false + useTestCoordinator := false + + network, err := actions.EthereumNetworkConfigFromConfig(l, &config) + require.NoError(t, err, "Error building ethereum network config") env, err := test_env.NewCLTestEnvBuilder(). + WithTestConfig(&config). WithTestInstance(t). WithPrivateEthereumNetwork(network). WithCLNodes(1). - WithFunding(big.NewFloat(vrfv2Config.ChainlinkNodeFunding)). + WithFunding(big.NewFloat(*config.Common.ChainlinkNodeFunding)). WithStandardCleanup(). Build() require.NoError(t, err, "error creating test env") env.ParallelTransactions(true) - mockETHLinkFeed, err := actions.DeployMockETHLinkFeed(env.ContractDeployer, big.NewInt(vrfv2Config.LinkNativeFeedResponse)) + mockETHLinkFeed, err := actions.DeployMockETHLinkFeed(env.ContractDeployer, big.NewInt(*config.VRFv2.General.LinkNativeFeedResponse)) require.NoError(t, err) linkToken, err := actions.DeployLINKToken(env.ContractDeployer) require.NoError(t, err) @@ -462,7 +484,9 @@ func TestVRFv2MultipleSendingKeys(t *testing.T) { numberOfTxKeysToCreate := 2 vrfv2Contracts, subIDs, vrfv2Data, err := vrfv2_actions.SetupVRFV2Environment( env, - vrfv2Config, + &config, + useVRFOwner, + useTestCoordinator, linkToken, mockETHLinkFeed, defaultWalletAddress, @@ -481,7 +505,6 @@ func TestVRFv2MultipleSendingKeys(t *testing.T) { vrfv2_actions.LogSubDetails(l, subscription, subID, vrfv2Contracts.Coordinator) t.Run("Request Randomness with multiple sending keys", func(t *testing.T) { - testConfig := vrfv2Config txKeys, _, err := env.ClCluster.Nodes[0].API.ReadTxKeys("evm") require.NoError(t, err, "error reading tx keys") @@ -490,14 +513,17 @@ func TestVRFv2MultipleSendingKeys(t *testing.T) { var fulfillmentTxFromAddresses []string for i := 0; i < numberOfTxKeysToCreate+1; i++ { randomWordsFulfilledEvent, err := vrfv2_actions.RequestRandomnessAndWaitForFulfillment( + l, vrfv2Contracts.LoadTestConsumers[0], vrfv2Contracts.Coordinator, - vrfv2Data, subID, - testConfig.RandomnessRequestCountPerRequest, - testConfig, - testConfig.RandomWordsFulfilledEventTimeout, - l, + vrfv2Data, + *config.VRFv2.General.MinimumConfirmations, + *config.VRFv2.General.CallbackGasLimit, + *config.VRFv2.General.NumberOfWords, + *config.VRFv2.General.RandomnessRequestCountPerRequest, + *config.VRFv2.General.RandomnessRequestCountPerRequestDeviation, + config.VRFv2.General.RandomWordsFulfilledEventTimeout.Duration, ) require.NoError(t, err, "error requesting randomness and waiting for fulfilment") @@ -519,3 +545,135 @@ func TestVRFv2MultipleSendingKeys(t *testing.T) { require.True(t, equalIgnoreOrder) }) } + +func TestVRFOwner(t *testing.T) { + t.Parallel() + l := logging.GetTestLogger(t) + + config, err := tc.GetConfig("Smoke", tc.VRFv2) + require.NoError(t, err, "Error getting config") + + useVRFOwner := true + useTestCoordinator := true + network, err := actions.EthereumNetworkConfigFromConfig(l, &config) + require.NoError(t, err, "Error building ethereum network config") + + env, err := test_env.NewCLTestEnvBuilder(). + WithTestInstance(t). + WithTestConfig(&config). + WithPrivateEthereumNetwork(network). + WithCLNodes(1). + WithFunding(big.NewFloat(*config.Common.ChainlinkNodeFunding)). + WithStandardCleanup(). + Build() + require.NoError(t, err, "error creating test env") + + env.ParallelTransactions(true) + + mockETHLinkFeed, err := env.ContractDeployer.DeployVRFMockETHLINKFeed(big.NewInt(*config.VRFv2.General.LinkNativeFeedResponse)) + + require.NoError(t, err) + linkToken, err := actions.DeployLINKToken(env.ContractDeployer) + require.NoError(t, err) + + // register proving key against oracle address (sending key) in order to test oracleWithdraw + defaultWalletAddress := env.EVMClient.GetDefaultWallet().Address() + + numberOfTxKeysToCreate := 1 + vrfv2Contracts, subIDs, vrfv2Data, err := vrfv2_actions.SetupVRFV2Environment( + env, + &config, + useVRFOwner, + useTestCoordinator, + linkToken, + mockETHLinkFeed, + defaultWalletAddress, + numberOfTxKeysToCreate, + 1, + 1, + l, + ) + require.NoError(t, err, "error setting up VRF v2 env") + + subID := subIDs[0] + + subscription, err := vrfv2Contracts.Coordinator.GetSubscription(context.Background(), subID) + require.NoError(t, err, "error getting subscription information") + + vrfv2_actions.LogSubDetails(l, subscription, subID, vrfv2Contracts.Coordinator) + + t.Run("Request Randomness With Force-Fulfill", func(t *testing.T) { + configCopy := config.MustCopy().(tc.TestConfig) + + vrfCoordinatorOwner, err := vrfv2Contracts.Coordinator.GetOwner(testcontext.Get(t)) + require.NoError(t, err) + require.Equal(t, vrfv2Contracts.VRFOwner.Address(), vrfCoordinatorOwner.String()) + + err = linkToken.Transfer( + vrfv2Contracts.LoadTestConsumers[0].Address(), + conversions.EtherToWei(big.NewFloat(5)), + ) + require.NoError(t, err, "error transferring link to consumer contract") + + err = env.EVMClient.WaitForEvents() + require.NoError(t, err, vrfv2_actions.ErrWaitTXsComplete) + + consumerLinkBalance, err := linkToken.BalanceOf(testcontext.Get(t), vrfv2Contracts.LoadTestConsumers[0].Address()) + require.NoError(t, err, "error getting consumer link balance") + l.Info(). + Str("Balance", conversions.WeiToEther(consumerLinkBalance).String()). + Str("Consumer", vrfv2Contracts.LoadTestConsumers[0].Address()). + Msg("Consumer Link Balance") + + err = mockETHLinkFeed.SetBlockTimestampDeduction(big.NewInt(3)) + require.NoError(t, err) + err = env.EVMClient.WaitForEvents() + require.NoError(t, err, vrfv2_actions.ErrWaitTXsComplete) + + // test and assert + _, randFulfilledEvent, _, err := vrfv2_actions.RequestRandomnessWithForceFulfillAndWaitForFulfillment( + l, + vrfv2Contracts.LoadTestConsumers[0], + vrfv2Contracts.Coordinator, + vrfv2Contracts.VRFOwner, + vrfv2Data, + *configCopy.VRFv2.General.MinimumConfirmations, + *configCopy.VRFv2.General.CallbackGasLimit, + *configCopy.VRFv2.General.NumberOfWords, + *configCopy.VRFv2.General.RandomnessRequestCountPerRequest, + *configCopy.VRFv2.General.RandomnessRequestCountPerRequestDeviation, + conversions.EtherToWei(big.NewFloat(5)), + common.HexToAddress(linkToken.Address()), + time.Minute*2, + ) + require.NoError(t, err, "error requesting randomness with force-fulfillment and waiting for fulfilment") + require.Equal(t, 0, randFulfilledEvent.Payment.Cmp(big.NewInt(0)), "Forced Fulfilled Randomness's Payment should be 0") + + status, err := vrfv2Contracts.LoadTestConsumers[0].GetRequestStatus(context.Background(), randFulfilledEvent.RequestId) + require.NoError(t, err, "error getting rand request status") + require.True(t, status.Fulfilled) + l.Debug().Bool("Fulfilment Status", status.Fulfilled).Msg("Random Words Request Fulfilment Status") + + require.Equal(t, *configCopy.VRFv2.General.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") + } + + coordinatorConfig, err := vrfv2Contracts.Coordinator.GetConfig(testcontext.Get(t)) + require.NoError(t, err, "error getting coordinator config") + + coordinatorFeeConfig, err := vrfv2Contracts.Coordinator.GetFeeConfig(testcontext.Get(t)) + require.NoError(t, err, "error getting coordinator fee config") + + coordinatorFallbackWeiPerUnitLinkConfig, err := vrfv2Contracts.Coordinator.GetFallbackWeiPerUnitLink(testcontext.Get(t)) + require.NoError(t, err, "error getting coordinator FallbackWeiPerUnitLink") + + require.Equal(t, *configCopy.VRFv2.General.StalenessSeconds, coordinatorConfig.StalenessSeconds) + require.Equal(t, *configCopy.VRFv2.General.GasAfterPaymentCalculation, coordinatorConfig.GasAfterPaymentCalculation) + require.Equal(t, *configCopy.VRFv2.General.MinimumConfirmations, coordinatorConfig.MinimumRequestConfirmations) + require.Equal(t, *configCopy.VRFv2.General.FulfillmentFlatFeeLinkPPMTier1, coordinatorFeeConfig.FulfillmentFlatFeeLinkPPMTier1) + require.Equal(t, *configCopy.VRFv2.General.ReqsForTier2, coordinatorFeeConfig.ReqsForTier2.Int64()) + require.Equal(t, *configCopy.VRFv2.General.FallbackWeiPerUnitLink, coordinatorFallbackWeiPerUnitLinkConfig.Int64()) + }) +} diff --git a/integration-tests/smoke/vrfv2plus_test.go b/integration-tests/smoke/vrfv2plus_test.go index 6cc4a07237..f1f11d3e1f 100644 --- a/integration-tests/smoke/vrfv2plus_test.go +++ b/integration-tests/smoke/vrfv2plus_test.go @@ -10,18 +10,19 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/google/go-cmp/cmp" "github.com/google/go-cmp/cmp/cmpopts" - "github.com/kelseyhightower/envconfig" "github.com/stretchr/testify/require" "github.com/smartcontractkit/chainlink-testing-framework/blockchain" "github.com/smartcontractkit/chainlink-testing-framework/logging" + "github.com/smartcontractkit/chainlink-testing-framework/utils/ptr" "github.com/smartcontractkit/chainlink-testing-framework/utils/testcontext" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/vrf_v2plus_upgraded_version" "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/docker/test_env" + tc "github.com/smartcontractkit/chainlink/integration-tests/testconfig" + vrfv2plus_config "github.com/smartcontractkit/chainlink/integration-tests/testconfig/vrfv2plus" it_utils "github.com/smartcontractkit/chainlink/integration-tests/utils" ) @@ -29,25 +30,28 @@ func TestVRFv2Plus(t *testing.T) { t.Parallel() l := logging.GetTestLogger(t) - network, err := actions.EthereumNetworkConfigFromEnvOrDefault(l) - require.NoError(t, err, "Error building ethereum network config") + config, err := tc.GetConfig("Smoke", tc.VRFv2Plus) + if err != nil { + t.Fatal(err) + } - var vrfv2PlusConfig vrfv2plus_config.VRFV2PlusConfig - err = envconfig.Process("VRFV2PLUS", &vrfv2PlusConfig) - require.NoError(t, err) + network, err := actions.EthereumNetworkConfigFromConfig(l, &config) + require.NoError(t, err, "Error building ethereum network config") env, err := test_env.NewCLTestEnvBuilder(). WithTestInstance(t). + WithTestConfig(&config). WithPrivateEthereumNetwork(network). + WithGeth(). WithCLNodes(1). - WithFunding(big.NewFloat(vrfv2PlusConfig.ChainlinkNodeFunding)). + WithFunding(big.NewFloat(*config.Common.ChainlinkNodeFunding)). WithStandardCleanup(). Build() require.NoError(t, err, "error creating test env") env.ParallelTransactions(true) - mockETHLinkFeed, err := actions.DeployMockETHLinkFeed(env.ContractDeployer, big.NewInt(vrfv2PlusConfig.LinkNativeFeedResponse)) + mockETHLinkFeed, err := actions.DeployMockETHLinkFeed(env.ContractDeployer, big.NewInt(*config.VRFv2Plus.General.LinkNativeFeedResponse)) require.NoError(t, err, "error deploying mock ETH/LINK feed") linkToken, err := actions.DeployLINKToken(env.ContractDeployer) @@ -59,7 +63,7 @@ func TestVRFv2Plus(t *testing.T) { numberOfTxKeysToCreate := 2 vrfv2PlusContracts, subIDs, vrfv2PlusData, err := vrfv2plus.SetupVRFV2_5Environment( env, - vrfv2PlusConfig, + &config, linkToken, mockETHLinkFeed, numberOfTxKeysToCreate, @@ -77,7 +81,7 @@ func TestVRFv2Plus(t *testing.T) { vrfv2plus.LogSubDetails(l, subscription, subID, vrfv2PlusContracts.Coordinator) t.Run("Link Billing", func(t *testing.T) { - testConfig := vrfv2PlusConfig + configCopy := config.MustCopy().(tc.TestConfig) var isNativeBilling = false subBalanceBeforeRequest := subscription.Balance @@ -91,9 +95,12 @@ func TestVRFv2Plus(t *testing.T) { vrfv2PlusData, subID, isNativeBilling, - testConfig.RandomnessRequestCountPerRequest, - testConfig, - testConfig.RandomWordsFulfilledEventTimeout, + *configCopy.VRFv2Plus.General.MinimumConfirmations, + *configCopy.VRFv2Plus.General.CallbackGasLimit, + *configCopy.VRFv2Plus.General.NumberOfWords, + *configCopy.VRFv2Plus.General.RandomnessRequestCountPerRequest, + *configCopy.VRFv2Plus.General.RandomnessRequestCountPerRequestDeviation, + configCopy.VRFv2Plus.General.RandomWordsFulfilledEventTimeout.Duration, l, ) require.NoError(t, err, "error requesting randomness and waiting for fulfilment") @@ -113,7 +120,7 @@ func TestVRFv2Plus(t *testing.T) { require.True(t, status.Fulfilled) l.Debug().Bool("Fulfilment Status", status.Fulfilled).Msg("Random Words Request Fulfilment Status") - require.Equal(t, testConfig.NumberOfWords, uint32(len(status.RandomWords))) + require.Equal(t, *configCopy.VRFv2Plus.General.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") @@ -121,7 +128,8 @@ func TestVRFv2Plus(t *testing.T) { }) t.Run("Native Billing", func(t *testing.T) { - testConfig := vrfv2PlusConfig + configCopy := config.MustCopy().(tc.TestConfig) + testConfig := configCopy.VRFv2Plus.General var isNativeBilling = true subNativeTokenBalanceBeforeRequest := subscription.NativeBalance @@ -135,9 +143,12 @@ func TestVRFv2Plus(t *testing.T) { vrfv2PlusData, subID, isNativeBilling, - testConfig.RandomnessRequestCountPerRequest, - testConfig, - testConfig.RandomWordsFulfilledEventTimeout, + *configCopy.VRFv2Plus.General.MinimumConfirmations, + *configCopy.VRFv2Plus.General.CallbackGasLimit, + *configCopy.VRFv2Plus.General.NumberOfWords, + *configCopy.VRFv2Plus.General.RandomnessRequestCountPerRequest, + *configCopy.VRFv2Plus.General.RandomnessRequestCountPerRequestDeviation, + configCopy.VRFv2Plus.General.RandomWordsFulfilledEventTimeout.Duration, l, ) require.NoError(t, err, "error requesting randomness and waiting for fulfilment") @@ -156,17 +167,17 @@ func TestVRFv2Plus(t *testing.T) { require.True(t, status.Fulfilled) l.Debug().Bool("Fulfilment Status", status.Fulfilled).Msg("Random Words Request Fulfilment Status") - require.Equal(t, testConfig.NumberOfWords, uint32(len(status.RandomWords))) + require.Equal(t, *testConfig.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") } }) t.Run("Direct Funding (VRFV2PlusWrapper)", func(t *testing.T) { - testConfig := vrfv2PlusConfig + configCopy := config.MustCopy().(tc.TestConfig) wrapperContracts, wrapperSubID, err := vrfv2plus.SetupVRFV2PlusWrapperEnvironment( env, - testConfig, + &configCopy, linkToken, mockETHLinkFeed, vrfv2PlusContracts.Coordinator, @@ -176,7 +187,8 @@ func TestVRFv2Plus(t *testing.T) { require.NoError(t, err) t.Run("Link Billing", func(t *testing.T) { - testConfig := vrfv2PlusConfig + configCopy := config.MustCopy().(tc.TestConfig) + testConfig := configCopy.VRFv2Plus.General var isNativeBilling = false wrapperConsumerJuelsBalanceBeforeRequest, err := linkToken.BalanceOf(testcontext.Get(t), wrapperContracts.LoadTestConsumers[0].Address()) @@ -192,8 +204,12 @@ func TestVRFv2Plus(t *testing.T) { vrfv2PlusData, wrapperSubID, isNativeBilling, - testConfig, - testConfig.RandomWordsFulfilledEventTimeout, + *configCopy.VRFv2Plus.General.MinimumConfirmations, + *configCopy.VRFv2Plus.General.CallbackGasLimit, + *configCopy.VRFv2Plus.General.NumberOfWords, + *configCopy.VRFv2Plus.General.RandomnessRequestCountPerRequest, + *configCopy.VRFv2Plus.General.RandomnessRequestCountPerRequestDeviation, + configCopy.VRFv2Plus.General.RandomWordsFulfilledEventTimeout.Duration, l, ) require.NoError(t, err, "error requesting randomness and waiting for fulfilment") @@ -218,14 +234,15 @@ func TestVRFv2Plus(t *testing.T) { //require.Equal(t, 1, consumerStatus.Paid.Cmp(randomWordsFulfilledEvent.Payment), "Expected Consumer contract pay more than the Coordinator Sub") vrfv2plus.LogFulfillmentDetailsLinkBilling(l, wrapperConsumerJuelsBalanceBeforeRequest, wrapperConsumerJuelsBalanceAfterRequest, consumerStatus, randomWordsFulfilledEvent) - require.Equal(t, testConfig.NumberOfWords, uint32(len(consumerStatus.RandomWords))) + require.Equal(t, *testConfig.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") } }) t.Run("Native Billing", func(t *testing.T) { - testConfig := vrfv2PlusConfig + configCopy := config.MustCopy().(tc.TestConfig) + testConfig := configCopy.VRFv2Plus.General var isNativeBilling = true wrapperConsumerBalanceBeforeRequestWei, err := env.EVMClient.BalanceAt(testcontext.Get(t), common.HexToAddress(wrapperContracts.LoadTestConsumers[0].Address())) @@ -241,8 +258,12 @@ func TestVRFv2Plus(t *testing.T) { vrfv2PlusData, wrapperSubID, isNativeBilling, - testConfig, - testConfig.RandomWordsFulfilledEventTimeout, + *configCopy.VRFv2Plus.General.MinimumConfirmations, + *configCopy.VRFv2Plus.General.CallbackGasLimit, + *configCopy.VRFv2Plus.General.NumberOfWords, + *configCopy.VRFv2Plus.General.RandomnessRequestCountPerRequest, + *configCopy.VRFv2Plus.General.RandomnessRequestCountPerRequestDeviation, + configCopy.VRFv2Plus.General.RandomWordsFulfilledEventTimeout.Duration, l, ) require.NoError(t, err, "error requesting randomness and waiting for fulfilment") @@ -267,7 +288,7 @@ func TestVRFv2Plus(t *testing.T) { //require.Equal(t, 1, consumerStatus.Paid.Cmp(randomWordsFulfilledEvent.Payment), "Expected Consumer contract pay more than the Coordinator Sub") vrfv2plus.LogFulfillmentDetailsNativeBilling(l, wrapperConsumerBalanceBeforeRequestWei, wrapperConsumerBalanceAfterRequestWei, consumerStatus, randomWordsFulfilledEvent) - require.Equal(t, testConfig.NumberOfWords, uint32(len(consumerStatus.RandomWords))) + require.Equal(t, *testConfig.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") @@ -275,14 +296,16 @@ func TestVRFv2Plus(t *testing.T) { }) }) t.Run("Canceling Sub And Returning Funds", func(t *testing.T) { - testConfig := vrfv2PlusConfig + configCopy := config.MustCopy().(tc.TestConfig) subIDsForCancelling, err := vrfv2plus.CreateFundSubsAndAddConsumers( env, - testConfig, + big.NewFloat(*configCopy.GetVRFv2PlusConfig().General.SubscriptionFundingAmountNative), + big.NewFloat(*configCopy.GetVRFv2PlusConfig().General.SubscriptionFundingAmountLink), linkToken, vrfv2PlusContracts.Coordinator, vrfv2PlusContracts.LoadTestConsumers, 1, + vrfv2plus_config.BillingType(*configCopy.GetVRFv2PlusConfig().General.SubscriptionBillingType), ) require.NoError(t, err) subIDForCancelling := subIDsForCancelling[0] @@ -367,18 +390,22 @@ func TestVRFv2Plus(t *testing.T) { }) t.Run("Owner Canceling Sub And Returning Funds While Having Pending Requests", func(t *testing.T) { - testConfig := vrfv2PlusConfig + configCopy := config.MustCopy().(tc.TestConfig) + testConfig := configCopy.VRFv2Plus.General + //underfund subs in order rand fulfillments to fail - testConfig.SubscriptionFundingAmountNative = float64(0.000000000000000001) //1 Wei - testConfig.SubscriptionFundingAmountLink = float64(0.000000000000000001) //1 Juels + testConfig.SubscriptionFundingAmountNative = ptr.Ptr(float64(0.000000000000000001)) //1 Wei + testConfig.SubscriptionFundingAmountLink = ptr.Ptr(float64(0.000000000000000001)) //1 Juels subIDsForCancelling, err := vrfv2plus.CreateFundSubsAndAddConsumers( env, - testConfig, + big.NewFloat(*configCopy.GetVRFv2PlusConfig().General.SubscriptionFundingAmountNative), + big.NewFloat(*configCopy.GetVRFv2PlusConfig().General.SubscriptionFundingAmountLink), linkToken, vrfv2PlusContracts.Coordinator, vrfv2PlusContracts.LoadTestConsumers, 1, + vrfv2plus_config.BillingType(*configCopy.GetVRFv2PlusConfig().General.SubscriptionBillingType), ) require.NoError(t, err) @@ -405,8 +432,11 @@ func TestVRFv2Plus(t *testing.T) { vrfv2PlusData, subIDForCancelling, false, - testConfig.RandomnessRequestCountPerRequest, - testConfig, + *configCopy.VRFv2Plus.General.MinimumConfirmations, + *configCopy.VRFv2Plus.General.CallbackGasLimit, + *configCopy.VRFv2Plus.General.NumberOfWords, + *configCopy.VRFv2Plus.General.RandomnessRequestCountPerRequest, + *configCopy.VRFv2Plus.General.RandomnessRequestCountPerRequestDeviation, randomWordsFulfilledEventTimeout, l, ) @@ -419,8 +449,11 @@ func TestVRFv2Plus(t *testing.T) { vrfv2PlusData, subIDForCancelling, true, - testConfig.RandomnessRequestCountPerRequest, - testConfig, + *configCopy.VRFv2Plus.General.MinimumConfirmations, + *configCopy.VRFv2Plus.General.CallbackGasLimit, + *configCopy.VRFv2Plus.General.NumberOfWords, + *configCopy.VRFv2Plus.General.RandomnessRequestCountPerRequest, + *configCopy.VRFv2Plus.General.RandomnessRequestCountPerRequestDeviation, randomWordsFulfilledEventTimeout, l, ) @@ -523,14 +556,16 @@ func TestVRFv2Plus(t *testing.T) { }) t.Run("Owner Withdraw", func(t *testing.T) { - testConfig := vrfv2PlusConfig + configCopy := config.MustCopy().(tc.TestConfig) subIDsForWithdraw, err := vrfv2plus.CreateFundSubsAndAddConsumers( env, - testConfig, + big.NewFloat(*configCopy.GetVRFv2PlusConfig().General.SubscriptionFundingAmountNative), + big.NewFloat(*configCopy.GetVRFv2PlusConfig().General.SubscriptionFundingAmountLink), linkToken, vrfv2PlusContracts.Coordinator, vrfv2PlusContracts.LoadTestConsumers, 1, + vrfv2plus_config.BillingType(*configCopy.GetVRFv2PlusConfig().General.SubscriptionBillingType), ) require.NoError(t, err) subIDForWithdraw := subIDsForWithdraw[0] @@ -541,9 +576,12 @@ func TestVRFv2Plus(t *testing.T) { vrfv2PlusData, subIDForWithdraw, false, - testConfig.RandomnessRequestCountPerRequest, - testConfig, - testConfig.RandomWordsFulfilledEventTimeout, + *configCopy.VRFv2Plus.General.MinimumConfirmations, + *configCopy.VRFv2Plus.General.CallbackGasLimit, + *configCopy.VRFv2Plus.General.NumberOfWords, + *configCopy.VRFv2Plus.General.RandomnessRequestCountPerRequest, + *configCopy.VRFv2Plus.General.RandomnessRequestCountPerRequestDeviation, + configCopy.VRFv2Plus.General.RandomWordsFulfilledEventTimeout.Duration, l, ) require.NoError(t, err) @@ -554,9 +592,12 @@ func TestVRFv2Plus(t *testing.T) { vrfv2PlusData, subIDForWithdraw, true, - testConfig.RandomnessRequestCountPerRequest, - testConfig, - testConfig.RandomWordsFulfilledEventTimeout, + *configCopy.VRFv2Plus.General.MinimumConfirmations, + *configCopy.VRFv2Plus.General.CallbackGasLimit, + *configCopy.VRFv2Plus.General.NumberOfWords, + *configCopy.VRFv2Plus.General.RandomnessRequestCountPerRequest, + *configCopy.VRFv2Plus.General.RandomnessRequestCountPerRequestDeviation, + configCopy.VRFv2Plus.General.RandomWordsFulfilledEventTimeout.Duration, l, ) require.NoError(t, err) @@ -608,25 +649,27 @@ func TestVRFv2PlusMultipleSendingKeys(t *testing.T) { t.Parallel() l := logging.GetTestLogger(t) - network, err := actions.EthereumNetworkConfigFromEnvOrDefault(l) - require.NoError(t, err, "Error building ethereum network config") + config, err := tc.GetConfig("Smoke", tc.VRFv2Plus) + if err != nil { + t.Fatal(err) + } - var vrfv2PlusConfig vrfv2plus_config.VRFV2PlusConfig - err = envconfig.Process("VRFV2PLUS", &vrfv2PlusConfig) - require.NoError(t, err) + network, err := actions.EthereumNetworkConfigFromConfig(l, &config) + require.NoError(t, err, "Error building ethereum network config") env, err := test_env.NewCLTestEnvBuilder(). WithTestInstance(t). + WithTestConfig(&config). WithPrivateEthereumNetwork(network). WithCLNodes(1). - WithFunding(big.NewFloat(vrfv2PlusConfig.ChainlinkNodeFunding)). + WithFunding(big.NewFloat(*config.Common.ChainlinkNodeFunding)). WithStandardCleanup(). Build() require.NoError(t, err, "error creating test env") env.ParallelTransactions(true) - mockETHLinkFeed, err := actions.DeployMockETHLinkFeed(env.ContractDeployer, big.NewInt(vrfv2PlusConfig.LinkNativeFeedResponse)) + mockETHLinkFeed, err := actions.DeployMockETHLinkFeed(env.ContractDeployer, big.NewInt(*config.VRFv2Plus.General.LinkNativeFeedResponse)) require.NoError(t, err, "error deploying mock ETH/LINK feed") linkToken, err := actions.DeployLINKToken(env.ContractDeployer) @@ -635,7 +678,7 @@ func TestVRFv2PlusMultipleSendingKeys(t *testing.T) { numberOfTxKeysToCreate := 2 vrfv2PlusContracts, subIDs, vrfv2PlusData, err := vrfv2plus.SetupVRFV2_5Environment( env, - vrfv2PlusConfig, + &config, linkToken, mockETHLinkFeed, numberOfTxKeysToCreate, @@ -653,7 +696,7 @@ func TestVRFv2PlusMultipleSendingKeys(t *testing.T) { vrfv2plus.LogSubDetails(l, subscription, subID, vrfv2PlusContracts.Coordinator) t.Run("Request Randomness with multiple sending keys", func(t *testing.T) { - testConfig := vrfv2PlusConfig + configCopy := config.MustCopy().(tc.TestConfig) var isNativeBilling = false txKeys, _, err := env.ClCluster.Nodes[0].API.ReadTxKeys("evm") require.NoError(t, err, "error reading tx keys") @@ -668,9 +711,12 @@ func TestVRFv2PlusMultipleSendingKeys(t *testing.T) { vrfv2PlusData, subID, isNativeBilling, - testConfig.RandomnessRequestCountPerRequest, - testConfig, - testConfig.RandomWordsFulfilledEventTimeout, + *configCopy.VRFv2Plus.General.MinimumConfirmations, + *configCopy.VRFv2Plus.General.CallbackGasLimit, + *configCopy.VRFv2Plus.General.NumberOfWords, + *configCopy.VRFv2Plus.General.RandomnessRequestCountPerRequest, + *configCopy.VRFv2Plus.General.RandomnessRequestCountPerRequestDeviation, + configCopy.VRFv2Plus.General.RandomWordsFulfilledEventTimeout.Duration, l, ) require.NoError(t, err, "error requesting randomness and waiting for fulfilment") @@ -698,24 +744,26 @@ func TestVRFv2PlusMigration(t *testing.T) { t.Parallel() l := logging.GetTestLogger(t) - network, err := actions.EthereumNetworkConfigFromEnvOrDefault(l) - require.NoError(t, err, "Error building ethereum network config") + config, err := tc.GetConfig("Smoke", tc.VRFv2Plus) + if err != nil { + t.Fatal(err) + } - var vrfv2PlusConfig vrfv2plus_config.VRFV2PlusConfig - err = envconfig.Process("VRFV2PLUS", &vrfv2PlusConfig) - require.NoError(t, err) + network, err := actions.EthereumNetworkConfigFromConfig(l, &config) + require.NoError(t, err, "Error building ethereum network config") env, err := test_env.NewCLTestEnvBuilder(). WithTestInstance(t). + WithTestConfig(&config). WithPrivateEthereumNetwork(network). WithCLNodes(1). - WithFunding(big.NewFloat(vrfv2PlusConfig.ChainlinkNodeFunding)). + WithFunding(big.NewFloat(*config.Common.ChainlinkNodeFunding)). WithStandardCleanup(). Build() require.NoError(t, err, "error creating test env") env.ParallelTransactions(true) - mockETHLinkFeedAddress, err := actions.DeployMockETHLinkFeed(env.ContractDeployer, big.NewInt(vrfv2PlusConfig.LinkNativeFeedResponse)) + mockETHLinkFeedAddress, err := actions.DeployMockETHLinkFeed(env.ContractDeployer, big.NewInt(*config.VRFv2Plus.General.LinkNativeFeedResponse)) require.NoError(t, err, "error deploying mock ETH/LINK feed") linkAddress, err := actions.DeployLINKToken(env.ContractDeployer) @@ -723,7 +771,7 @@ func TestVRFv2PlusMigration(t *testing.T) { vrfv2PlusContracts, subIDs, vrfv2PlusData, err := vrfv2plus.SetupVRFV2_5Environment( env, - vrfv2PlusConfig, + &config, linkAddress, mockETHLinkFeedAddress, 0, @@ -758,15 +806,16 @@ func TestVRFv2PlusMigration(t *testing.T) { _, err = vrfv2plus.VRFV2PlusUpgradedVersionRegisterProvingKey(vrfv2PlusData.VRFKey, newCoordinator) require.NoError(t, err, fmt.Errorf("%s, err: %w", vrfv2plus.ErrRegisteringProvingKey, err)) + vrfv2PlusConfig := config.VRFv2Plus.General err = newCoordinator.SetConfig( - vrfv2PlusConfig.MinimumConfirmations, - vrfv2PlusConfig.MaxGasLimitCoordinatorConfig, - vrfv2PlusConfig.StalenessSeconds, - vrfv2PlusConfig.GasAfterPaymentCalculation, - big.NewInt(vrfv2PlusConfig.LinkNativeFeedResponse), + *vrfv2PlusConfig.MinimumConfirmations, + *vrfv2PlusConfig.MaxGasLimitCoordinatorConfig, + *vrfv2PlusConfig.StalenessSeconds, + *vrfv2PlusConfig.GasAfterPaymentCalculation, + big.NewInt(*vrfv2PlusConfig.LinkNativeFeedResponse), vrf_v2plus_upgraded_version.VRFCoordinatorV2PlusUpgradedVersionFeeConfig{ - FulfillmentFlatFeeLinkPPM: vrfv2PlusConfig.FulfillmentFlatFeeLinkPPM, - FulfillmentFlatFeeNativePPM: vrfv2PlusConfig.FulfillmentFlatFeeNativePPM, + FulfillmentFlatFeeLinkPPM: *vrfv2PlusConfig.FulfillmentFlatFeeLinkPPM, + FulfillmentFlatFeeNativePPM: *vrfv2PlusConfig.FulfillmentFlatFeeNativePPM, }, ) require.NoError(t, err) @@ -776,13 +825,23 @@ func TestVRFv2PlusMigration(t *testing.T) { err = env.EVMClient.WaitForEvents() require.NoError(t, err, vrfv2plus.ErrWaitTXsComplete) + vrfJobSpecConfig := vrfv2plus.VRFJobSpecConfig{ + ForwardingAllowed: false, + CoordinatorAddress: newCoordinator.Address(), + FromAddresses: []string{vrfv2PlusData.PrimaryEthAddress}, + EVMChainID: vrfv2PlusData.ChainID.String(), + MinIncomingConfirmations: int(*vrfv2PlusConfig.MinimumConfirmations), + PublicKey: vrfv2PlusData.VRFKey.Data.ID, + EstimateGasMultiplier: 1, + BatchFulfillmentEnabled: false, + BatchFulfillmentGasMultiplier: 1.15, + PollPeriod: time.Second * 1, + RequestTimeout: time.Hour * 24, + } + _, err = vrfv2plus.CreateVRFV2PlusJob( env.ClCluster.NodeAPIs()[0], - newCoordinator.Address(), - []string{vrfv2PlusData.PrimaryEthAddress}, - vrfv2PlusData.VRFKey.Data.ID, - vrfv2PlusData.ChainID.String(), - vrfv2PlusConfig.MinimumConfirmations, + vrfJobSpecConfig, ) require.NoError(t, err, vrfv2plus.ErrCreateVRFV2PlusJobs) @@ -868,7 +927,11 @@ func TestVRFv2PlusMigration(t *testing.T) { vrfv2PlusData, subID, false, - vrfv2PlusConfig, + *config.VRFv2Plus.General.MinimumConfirmations, + *config.VRFv2Plus.General.CallbackGasLimit, + *config.VRFv2Plus.General.NumberOfWords, + *config.VRFv2Plus.General.RandomnessRequestCountPerRequest, + *config.VRFv2Plus.General.RandomnessRequestCountPerRequestDeviation, l, ) require.NoError(t, err, "error requesting randomness and waiting for fulfilment") @@ -880,9 +943,12 @@ func TestVRFv2PlusMigration(t *testing.T) { vrfv2PlusData, subID, true, - vrfv2PlusConfig, + *config.VRFv2Plus.General.MinimumConfirmations, + *config.VRFv2Plus.General.CallbackGasLimit, + *config.VRFv2Plus.General.NumberOfWords, + *config.VRFv2Plus.General.RandomnessRequestCountPerRequest, + *config.VRFv2Plus.General.RandomnessRequestCountPerRequestDeviation, l, ) require.NoError(t, err, "error requesting randomness and waiting for fulfilment") - } diff --git a/integration-tests/soak/forwarder_ocr_test.go b/integration-tests/soak/forwarder_ocr_test.go index 538f5ff156..b5355a6c3f 100644 --- a/integration-tests/soak/forwarder_ocr_test.go +++ b/integration-tests/soak/forwarder_ocr_test.go @@ -8,6 +8,7 @@ import ( "github.com/smartcontractkit/chainlink-testing-framework/logging" "github.com/smartcontractkit/chainlink/integration-tests/actions" + tc "github.com/smartcontractkit/chainlink/integration-tests/testconfig" "github.com/smartcontractkit/chainlink/integration-tests/testsetups" ) @@ -21,9 +22,12 @@ ForwardersEnabled = true` // fmt.Println(networks.AddNetworkDetailedConfig(config.BaseOCRP2PV1Config, customNetworkTOML, network)) // fmt.Println("---------------------") - ocrSoakTest, err := testsetups.NewOCRSoakTest(t, true) + config, err := tc.GetConfig("Soak", tc.OCR) + require.NoError(t, err, "Error getting config") + + ocrSoakTest, err := testsetups.NewOCRSoakTest(t, &config, true) require.NoError(t, err, "Error creating soak test") - ocrSoakTest.DeployEnvironment(customNetworkTOML) + ocrSoakTest.DeployEnvironment(customNetworkTOML, &config) if ocrSoakTest.Environment().WillUseRemoteRunner() { return } @@ -32,6 +36,6 @@ ForwardersEnabled = true` l.Error().Err(err).Msg("Error tearing down environment") } }) - ocrSoakTest.Setup() + ocrSoakTest.Setup(&config) ocrSoakTest.Run() } diff --git a/integration-tests/soak/ocr_test.go b/integration-tests/soak/ocr_test.go index 4d7971d678..e25391e845 100644 --- a/integration-tests/soak/ocr_test.go +++ b/integration-tests/soak/ocr_test.go @@ -8,6 +8,7 @@ import ( "github.com/smartcontractkit/chainlink-testing-framework/logging" "github.com/smartcontractkit/chainlink/integration-tests/actions" + tc "github.com/smartcontractkit/chainlink/integration-tests/testconfig" "github.com/smartcontractkit/chainlink/integration-tests/testsetups" ) @@ -21,10 +22,13 @@ func TestOCRSoak(t *testing.T) { // fmt.Println(networks.AddNetworkDetailedConfig(config.BaseOCR1Config, customNetworkTOML, network)) // fmt.Println("---------------------") - ocrSoakTest, err := testsetups.NewOCRSoakTest(t, false) + config, err := tc.GetConfig("Soak", tc.OCR) + require.NoError(t, err, "Error getting config") + + ocrSoakTest, err := testsetups.NewOCRSoakTest(t, &config, false) require.NoError(t, err, "Error creating soak test") if !ocrSoakTest.Interrupted() { - ocrSoakTest.DeployEnvironment(customNetworkTOML) + ocrSoakTest.DeployEnvironment(customNetworkTOML, &config) } if ocrSoakTest.Environment().WillUseRemoteRunner() { return @@ -39,7 +43,7 @@ func TestOCRSoak(t *testing.T) { require.NoError(t, err, "Error loading state") ocrSoakTest.Resume() } else { - ocrSoakTest.Setup() + ocrSoakTest.Setup(&config) ocrSoakTest.Run() } } diff --git a/integration-tests/testconfig/automation/automation.toml b/integration-tests/testconfig/automation/automation.toml new file mode 100644 index 0000000000..58b95f9b4c --- /dev/null +++ b/integration-tests/testconfig/automation/automation.toml @@ -0,0 +1,49 @@ +# product defaults +[Common] +chainlink_node_funding = 0.5 + +# reorg test specific overrides +[Reorg.Automation] +[Reorg.Automation.General] +number_of_nodes=6 +duration=100 +block_time=1 +spec_type="minimum" +chainlink_node_log_level="info" +use_prometheus=false + +# load test specific overrides +[Load.Common] +chainlink_node_funding = 100 + +[Load.Automation] +[Load.Automation.General] +number_of_nodes=6 +duration=900 +block_time=1 +spec_type="minimum" +chainlink_node_log_level="info" +use_prometheus=false + +[[Load.Automation.Load]] +number_of_upkeeps=5 +number_of_events = 1 +number_of_spam_matching_events = 1 +number_of_spam_non_matching_events = 0 +check_burn_amount = 0 +perform_burn_amount = 0 +upkeep_gas_limit = 1000000 +shared_trigger = false + +[[Load.Automation.Load]] +number_of_upkeeps=5 +number_of_events = 1 +number_of_spam_matching_events = 0 +number_of_spam_non_matching_events = 1 +check_burn_amount = 0 +perform_burn_amount = 0 +upkeep_gas_limit = 1000000 +shared_trigger = true + +[Load.Pyroscope] +enabled=false \ No newline at end of file diff --git a/integration-tests/testconfig/automation/config.go b/integration-tests/testconfig/automation/config.go new file mode 100644 index 0000000000..4431a640d0 --- /dev/null +++ b/integration-tests/testconfig/automation/config.go @@ -0,0 +1,91 @@ +package automation + +import ( + "errors" + "math/big" +) + +type Config struct { + General *General `toml:"General"` + Load []Load `toml:"Load"` +} + +func (c *Config) Validate() error { + if c.General != nil { + if err := c.General.Validate(); err != nil { + return err + } + } + if len(c.Load) > 0 { + for _, load := range c.Load { + if err := load.Validate(); err != nil { + return err + } + } + } + return nil +} + +// General is a common configuration for all automation performance tests +type General struct { + NumberOfNodes *int `toml:"number_of_nodes"` + Duration *int `toml:"duration"` + BlockTime *int `toml:"block_time"` + SpecType *string `toml:"spec_type"` + ChainlinkNodeLogLevel *string `toml:"chainlink_node_log_level"` + UsePrometheus *bool `toml:"use_prometheus"` +} + +func (c *General) Validate() error { + if c.NumberOfNodes == nil || *c.NumberOfNodes < 1 { + return errors.New("number_of_nodes must be set to a positive integer") + } + if c.Duration == nil || *c.Duration < 1 { + return errors.New("duration must be set to a positive integer") + } + if c.BlockTime == nil || *c.BlockTime < 1 { + return errors.New("block_time must be set to a positive integer") + } + if c.SpecType == nil { + return errors.New("spec_type must be set") + } + if c.ChainlinkNodeLogLevel == nil { + return errors.New("chainlink_node_log_level must be set") + } + + return nil +} + +type Load struct { + NumberOfUpkeeps *int `toml:"number_of_upkeeps"` + NumberOfEvents *int `toml:"number_of_events"` + NumberOfSpamMatchingEvents *int `toml:"number_of_spam_matching_events"` + NumberOfSpamNonMatchingEvents *int `toml:"number_of_spam_non_matching_events"` + CheckBurnAmount *big.Int `toml:"check_burn_amount"` + PerformBurnAmount *big.Int `toml:"perform_burn_amount"` + SharedTrigger *bool `toml:"shared_trigger"` + UpkeepGasLimit *uint32 `toml:"upkeep_gas_limit"` +} + +func (c *Load) Validate() error { + if c.NumberOfUpkeeps == nil || *c.NumberOfUpkeeps < 1 { + return errors.New("number_of_upkeeps must be set to a positive integer") + } + if c.NumberOfEvents == nil || *c.NumberOfEvents < 0 { + return errors.New("number_of_events must be set to a non-negative integer") + } + if c.NumberOfSpamMatchingEvents == nil || *c.NumberOfSpamMatchingEvents < 0 { + return errors.New("number_of_spam_matching_events must be set to a non-negative integer") + } + if c.NumberOfSpamNonMatchingEvents == nil || *c.NumberOfSpamNonMatchingEvents < 0 { + return errors.New("number_of_spam_non_matching_events must be set to a non-negative integer") + } + if c.CheckBurnAmount == nil || c.CheckBurnAmount.Cmp(big.NewInt(0)) < 0 { + return errors.New("check_burn_amount must be set to a non-negative integer") + } + if c.PerformBurnAmount == nil || c.PerformBurnAmount.Cmp(big.NewInt(0)) < 0 { + return errors.New("perform_burn_amount must be set to a non-negative integer") + } + + return nil +} diff --git a/integration-tests/testconfig/automation/example.toml b/integration-tests/testconfig/automation/example.toml new file mode 100644 index 0000000000..a8e0510d83 --- /dev/null +++ b/integration-tests/testconfig/automation/example.toml @@ -0,0 +1,90 @@ +# Example of full config with all fields +# General part +[ChainlinkImage] +image="public.ecr.aws/chainlink/chainlink" +version="2.7.0" + +[Logging] +# if set to true will save logs even if test did not fail +test_log_collect=false + +[Logging.LogStream] +# supported targets: file, loki, in-memory. if empty no logs will be persistet +log_targets=["file"] +# context timeout for starting log producer and also time-frame for requesting logs +log_producer_timeout="10s" +# number of retries before log producer gives up and stops listening to logs +log_producer_retry_limit=10 + +[Logging.Loki] +tenant_id="tenant_id" +# full URL of Loki ingest endpoint +endpoint="https://loki.url/api/v3/push" +# currently only needed when using public instance +basic_auth="loki-basic-auth" +# only needed for cloud grafana +bearer_token="bearer_token" + +# LogStream will try to shorten Grafana URLs by default (if all 3 variables are set) +[Logging.Grafana] +# grafana url (trailing "/" will be stripped) +base_url="http://grafana.url" +# url of your grafana dashboard (prefix and suffix "/" are stirpped), example: /d/ad61652-2712-1722/my-dashboard +dashboard_url="/d/your-dashboard" +bearer_token="my-awesome-token" + +# if you want to use polygon_mumbial +[Network] +selected_networks=["polygon_mumbai"] + +[Network.RpcHttpUrls] +polygon_mumbai = ["https://my-rpc-endpoint.io"] + +[Network.RpcWsUrls] +polygon_mumbai = ["https://my-rpc-endpoint.io"] + +[Network.WalletKeys] +polygon_mumbai = ["change-me-to-your-PK"] + +[PrivateEthereumNetwork] +# pos or pow +consensus_type="pos" +# only prysm supported currently +consensus_layer="prysm" +# geth, besu, nethermind or erigon +execution_layer="geth" +# if true after env started it will wait for at least 1 epoch to be finalised before continuing +wait_for_finalization=false + +[PrivateEthereumNetwork.EthereumChainConfig] +# duration of single slot, lower => faster block production, must be >= 4 +seconds_per_slot=12 +# numer of slots in epoch, lower => faster epoch finalisation, must be >= 4 +slots_per_epoch=6 +# extra genesis gelay, no need to modify, but it should be after all validators/beacon chain starts +genesis_delay=15 +# number of validators in the network +validator_count=8 +chain_id=1337 +# list of addresses to be prefunded in genesis +addresses_to_fund=["0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266"] + +# Common +[Common] +chainlink_node_funding = 0.5 + +# Product part +[Automation] +[Automation.General] +number_of_nodes=6 +duration=100 +block_time=1 +number_of_events=1 +spec_type="minimum" +chainlink_node_log_level="info" +use_prometheus=false + +# upgrade test specific override +[TestAutomationNodeUpgrade.ChainlinkUpgradeImage] +image="public.ecr.aws/chainlink/chainlink" +version="2.8.0" \ No newline at end of file diff --git a/integration-tests/testconfig/configs_embed.go b/integration-tests/testconfig/configs_embed.go new file mode 100644 index 0000000000..67e954ff50 --- /dev/null +++ b/integration-tests/testconfig/configs_embed.go @@ -0,0 +1,21 @@ +//go:build embed +// +build embed + +package testconfig + +import "embed" + +//go:embed default.toml +//go:embed automation/automation.toml +//go:embed functions/functions.toml +//go:embed keeper/keeper.toml +//go:embed log_poller/log_poller.toml +//go:embed node/node.toml +//go:embed ocr/ocr.toml +//go:embed vrfv2/vrfv2.toml +//go:embed vrfv2plus/vrfv2plus.toml +var embeddedConfigsFs embed.FS + +func init() { + areConfigsEmbedded = true +} diff --git a/integration-tests/testconfig/configs_noembed.go b/integration-tests/testconfig/configs_noembed.go new file mode 100644 index 0000000000..95572c4a04 --- /dev/null +++ b/integration-tests/testconfig/configs_noembed.go @@ -0,0 +1,12 @@ +//go:build !embed +// +build !embed + +package testconfig + +import "embed" + +var embeddedConfigsFs embed.FS + +func init() { + areConfigsEmbedded = false +} diff --git a/integration-tests/testconfig/default.toml b/integration-tests/testconfig/default.toml new file mode 100644 index 0000000000..a65c23d70d --- /dev/null +++ b/integration-tests/testconfig/default.toml @@ -0,0 +1,22 @@ +[Logging] +test_log_collect=false + +[Logging.LogStream] +log_targets=["file"] +log_producer_timeout="10s" +log_producer_retry_limit=10 + +[Network] +selected_networks=["simulated"] + +[PrivateEthereumNetwork] +consensus_type="pow" +execution_layer="geth" + +[PrivateEthereumNetwork.EthereumChainConfig] +seconds_per_slot=3 +slots_per_epoch=2 +genesis_delay=15 +validator_count=4 +chain_id=1337 +addresses_to_fund=["0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266"] \ No newline at end of file diff --git a/integration-tests/testconfig/functions/config.go b/integration-tests/testconfig/functions/config.go new file mode 100644 index 0000000000..88c0e05295 --- /dev/null +++ b/integration-tests/testconfig/functions/config.go @@ -0,0 +1,118 @@ +package functions + +import ( + "errors" + "math/big" + + "github.com/ethereum/go-ethereum/common" + + "github.com/smartcontractkit/chainlink-testing-framework/blockchain" + "github.com/smartcontractkit/chainlink-testing-framework/utils/net" +) + +const ( + ErrReadPerfConfig = "failed to read TOML config for performance tests" + ErrUnmarshalPerfConfig = "failed to unmarshal TOML config for performance tests" +) + +type Config struct { + Performance *Performance `toml:"Performance"` + Common *Common `toml:"Common"` +} + +type Common struct { + NodeFunds *big.Float `toml:"node_funds"` + SubFunds *big.Int `toml:"sub_funds"` + LINKTokenAddr *string `toml:"link_token_addr"` + Coordinator *string `toml:"coordinator_addr"` + Router *string `toml:"router_addr"` + LoadTestClient *string `toml:"client_addr"` + SubscriptionID *uint64 `toml:"subscription_id"` + DONID *string `toml:"don_id"` + GatewayURL *string `toml:"gateway_url"` + Receiver *string `toml:"receiver"` + FunctionsCallPayloadHTTP *string `toml:"functions_call_payload_http"` + FunctionsCallPayloadWithSecrets *string `toml:"functions_call_payload_with_secrets"` + FunctionsCallPayloadReal *string `toml:"functions_call_payload_real"` + SecretsSlotID *uint8 `toml:"secrets_slot_id"` + SecretsVersionID *uint64 `toml:"secrets_version_id"` + // Secrets these are for CI secrets + Secrets *string `toml:"secrets"` +} + +func (c *Common) Validate() error { + if c.SubFunds == nil { + return errors.New("sub_funds must be set") + } + if c.LINKTokenAddr == nil || *c.LINKTokenAddr == "" { + return errors.New("link_token_addr must be set") + } + if !common.IsHexAddress(*c.LINKTokenAddr) { + return errors.New("link_token_addr must be a valid address") + } + if c.Coordinator == nil || *c.Coordinator == "" { + return errors.New("coordinator must be set") + } + if !common.IsHexAddress(*c.Coordinator) { + return errors.New("coordinator must be a valid address") + } + if c.Router == nil || *c.Router == "" { + return errors.New("router must be set") + } + if !common.IsHexAddress(*c.Router) { + return errors.New("router must be a valid address") + } + if c.DONID == nil || *c.DONID == "" { + return errors.New("don_id must be set") + } + if c.GatewayURL == nil || *c.GatewayURL == "" { + return errors.New("gateway_url must be set") + } + if !net.IsValidURL(*c.GatewayURL) { + return errors.New("gateway_url must be a valid URL") + } + if c.Receiver == nil || *c.Receiver == "" { + return errors.New("receiver must be set") + } + if !common.IsHexAddress(*c.Receiver) { + return errors.New("receiver must be a valid address") + } + return nil +} + +type Performance struct { + RPS *int64 `toml:"rps"` + RequestsPerCall *uint32 `toml:"requests_per_call"` + Duration *blockchain.StrDuration `toml:"duration"` +} + +func (c *Performance) Validate() error { + if c.RPS == nil || *c.RPS < 1 { + return errors.New("rps must be greater than 0") + } + if c.RequestsPerCall != nil && *c.RequestsPerCall < 1 { + return errors.New("requests_per_call must be greater than 0") + } + if c.Duration == nil || c.Duration.Duration < 1 { + return errors.New("duration must be greater than 0") + } + return nil +} + +func (c *Config) Validate() error { + if c == nil { + return nil + } + if c.Common != nil { + if err := c.Common.Validate(); err != nil { + return err + } + } + if c.Performance != nil { + if err := c.Performance.Validate(); err != nil { + return err + } + } + + return nil +} diff --git a/integration-tests/testconfig/functions/example.toml b/integration-tests/testconfig/functions/example.toml new file mode 100644 index 0000000000..7628fbeee3 --- /dev/null +++ b/integration-tests/testconfig/functions/example.toml @@ -0,0 +1,113 @@ +# Example of full config with all fields +# General part +[ChainlinkImage] +image="public.ecr.aws/chainlink/chainlink" +version="2.7.0" + +[Logging] +# if set to true will save logs even if test did not fail +test_log_collect=false + +[Logging.LogStream] +# supported targets: file, loki, in-memory. if empty no logs will be persistet +log_targets=["file"] +# context timeout for starting log producer and also time-frame for requesting logs +log_producer_timeout="10s" +# number of retries before log producer gives up and stops listening to logs +log_producer_retry_limit=10 + +[Logging.Loki] +tenant_id="tenant_id" +# full URL of Loki ingest endpoint +endpoint="https://loki.url/api/v3/push" +# currently only needed when using public instance +basic_auth="loki-basic-auth" +# only needed for cloud grafana +bearer_token="bearer_token" + +# LogStream will try to shorten Grafana URLs by default (if all 3 variables are set) +[Logging.Grafana] +# grafana url (trailing "/" will be stripped) +base_url="http://grafana.url" +# url of your grafana dashboard (prefix and suffix "/" are stirpped), example: /d/ad61652-2712-1722/my-dashboard +dashboard_url="/d/your-dashboard" +bearer_token="my-awesome-token" + +# if you want to use simulated network +[Network] +selected_networks=["polygon_mumbai"] + +[Network.RpcHttpUrls] +polygon_mumbai = ["https://my-rpc-endpoint.io"] + +[Network.RpcWsUrls] +polygon_mumbai = ["https://my-rpc-endpoint.io"] + +[Network.WalletKeys] +polygon_mumbai = ["change-me-to-your-PK"] + +[PrivateEthereumNetwork] +# pos or pow +consensus_type="pos" +# only prysm supported currently +consensus_layer="prysm" +# geth, besu, nethermind or erigon +execution_layer="geth" +# if true after env started it will wait for at least 1 epoch to be finalised before continuing +wait_for_finalization=false + +[PrivateEthereumNetwork.EthereumChainConfig] +# duration of single slot, lower => faster block production, must be >= 4 +seconds_per_slot=12 +# numer of slots in epoch, lower => faster epoch finalisation, must be >= 4 +slots_per_epoch=6 +# extra genesis gelay, no need to modify, but it should be after all validators/beacon chain starts +genesis_delay=15 +# number of validators in the network +validator_count=8 +chain_id=1337 +# list of addresses to be prefunded in genesis +addresses_to_fund=["0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266"] + +# Common +[Common] +chainlink_node_funding = 0.5 + +# Product part +[Functions] +[Functions.Common] +# Polygon Mumbai only for now +receiver = "0x3098B6665589959711A48a6bAe5B7F2908f6a3bE" +don_id = "fun-staging-mumbai-1" +gateway_url = "https://gateway-stg-one.main.stage.cldev.sh" +link_token_addr = "0x326C977E6efc84E512bB9C30f76E30c160eD06FB" +coordinator_addr = "0x6D6a83BB356b7242E88C1A2b290102fde26590D0" +router_addr = "0x2673266D3Cd08b53494B5a92B66DEec7F1408E7A" + +# comment "client_addr" and "subscription_id" and test will create a new pair +# get it from logs and save +client_addr = "0x89D4b58D859a536D0B888ecD5093eF5FF9e4F977" +subscription_id = 47 +sub_funds = 10 + +functions_call_payload_with_secrets = "return Functions.encodeString(JSON.stringify(secrets))" +functions_call_payload_http = """ +const response = await Functions.makeHttpRequest({ url: 'http://dummyjson.com/products/1' }); +return Functions.encodeUint256(response.data.id); +""" +functions_call_payload_real = """ +const arg1 = args[0]; +const arg2 = args[1]; +const arg3 = args[2]; +const arg4 = args[3]; + +const response = await Functions.makeHttpRequest({ url: 'http://dummyjson.com/products/${arg1}' }); +return Functions.encodeString(JSON.stringify(secrets)); +""" +secrets_slot_id = 0 +secrets_version_id = 1693945705 + +[Functions.Performance] +rps = 95 +requests_per_call = 20 +duration = "10m" \ No newline at end of file diff --git a/integration-tests/load/functions/config.toml b/integration-tests/testconfig/functions/functions.toml similarity index 63% rename from integration-tests/load/functions/config.toml rename to integration-tests/testconfig/functions/functions.toml index 2de3ba9282..a4bcb6439e 100644 --- a/integration-tests/load/functions/config.toml +++ b/integration-tests/testconfig/functions/functions.toml @@ -1,42 +1,6 @@ -[Soak] -rps = 1 -requests_per_call = 40 -duration = "10m" - -[Stress] -rps = 1 -requests_per_call = 78 -duration = "10m" - -[SecretsSoak] -rps = 1 -requests_per_call = 20 -duration = "10m" - -[SecretsStress] -rps = 1 -requests_per_call = 40 -duration = "10m" - -[RealSoak] -rps = 1 -requests_per_call = 20 -duration = "10m" - -[RealStress] -rps = 1 -requests_per_call = 40 -duration = "10m" - -[GatewayListSoak] -rps = 95 -duration = "10m" - -[GatewaySetSoak] -rps = 95 -duration = "10m" - -[Common] +# product defaults +[Functions] +[Functions.Common] # Polygon Mumbai only for now receiver = "0x3098B6665589959711A48a6bAe5B7F2908f6a3bE" don_id = "fun-staging-mumbai-1" @@ -66,8 +30,62 @@ const response = await Functions.makeHttpRequest({ url: 'http://dummyjson.com/pr return Functions.encodeString(JSON.stringify(secrets)); """ secrets_slot_id = 0 -secrets_version = 1693945705 +secrets_version_id = 1693945705 # uncomment to upload new secrets to s4 and use it in your run # TODO: not working now -#secrets = "{\"secrets\": \"secretValue\"}" \ No newline at end of file +#secrets = "{\"secrets\": \"secretValue\"}" + +# gateway-list specific test configuration +[GatewayList.Functions] +[GatewayList.Functions.Performance] +rps = 95 +duration = "10m" + +# gateway-set specific test configuration +[GatewaySet.Functions] +[GatewaySet.Functions.Performance] +rps = 95 +duration = "10m" + +# real-soak specific test configuration +[RealSoak.Functions] +[RealSoak.Functions.Performance] +rps = 1 +requests_per_call = 20 +duration = "10m" + +# real-stress specific test configuration +[RealStress.Functions] +[RealStress.Functions.Performance] +rps = 1 +requests_per_call = 40 +duration = "10m" + +# secrets-soak specific test configuration +[SecretsSoak.Functions] +[SecretsSoak.Functions.Performance] +rps = 1 +requests_per_call = 20 +duration = "10m" + +# secrets-stress specific test configuration +[SecretsStress.Functions] +[SecretsStress.Functions.Performance] +rps = 1 +requests_per_call = 40 +duration = "10m" + +# soak specific test configuration +[Soak.Functions] +[Soak.Functions.Performance] +rps = 1 +requests_per_call = 40 +duration = "10m" + +# soak specific test configuration +[Stress.Functions] +[Stress.Functions.Performance] +rps = 1 +requests_per_call = 78 +duration = "10m" \ No newline at end of file diff --git a/integration-tests/testconfig/keeper/config.go b/integration-tests/testconfig/keeper/config.go new file mode 100644 index 0000000000..da6cd7acc9 --- /dev/null +++ b/integration-tests/testconfig/keeper/config.go @@ -0,0 +1,85 @@ +package keeper + +import ( + "errors" +) + +type Config struct { + Common *Common `toml:"Common"` +} + +func (c *Config) Validate() error { + if c.Common == nil { + return nil + } + return c.Common.Validate() +} + +type Common struct { + RegistryToTest *string `toml:"registry_to_test"` + NumberOfRegistries *int `toml:"number_of_registries"` + NumberOfNodes *int `toml:"number_of_nodes"` + NumberOfUpkeeps *int `toml:"number_of_upkeeps"` + UpkeepGasLimit *int64 `toml:"upkeep_gas_limit"` + CheckGasToBurn *int64 `toml:"check_gas_to_burn"` + PerformGasToBurn *int64 `toml:"perform_gas_to_burn"` + MaxPerformGas *int64 `toml:"max_perform_gas"` + BlockRange *int64 `toml:"block_range"` + BlockInterval *int64 `toml:"block_interval"` + ForceSingleTxKey *bool `toml:"forces_single_tx_key"` + DeleteJobsOnEnd *bool `toml:"delete_jobs_on_end"` + RegistryAddress *string `toml:"registry_address"` + RegistrarAddress *string `toml:"registrar_address"` + LinkTokenAddress *string `toml:"link_token_address"` + EthFeedAddress *string `toml:"eth_feed_address"` + GasFeedAddress *string `toml:"gas_feed_address"` +} + +func (c *Common) Validate() error { + if c.RegistryToTest == nil || *c.RegistryToTest == "" { + return errors.New("registry_to_test must be set") + } + if c.NumberOfRegistries == nil || *c.NumberOfRegistries <= 0 { + return errors.New("number_of_registries must be a positive integer") + } + if c.NumberOfNodes == nil || *c.NumberOfNodes <= 0 { + return errors.New("number_of_nodes must be a positive integer") + } + if c.NumberOfUpkeeps == nil || *c.NumberOfUpkeeps <= 0 { + return errors.New("number_of_upkeeps must be a positive integer") + } + if c.UpkeepGasLimit == nil || *c.UpkeepGasLimit <= 0 { + return errors.New("upkeep_gas_limit must be a positive integer") + } + if c.CheckGasToBurn == nil || *c.CheckGasToBurn <= 0 { + return errors.New("check_gas_to_burn must be a positive integer") + } + if c.PerformGasToBurn == nil || *c.PerformGasToBurn <= 0 { + return errors.New("perform_gas_to_burn must be a positive integer") + } + if c.MaxPerformGas == nil || *c.MaxPerformGas <= 0 { + return errors.New("max_perform_gas must be a positive integer") + } + if c.BlockRange == nil || *c.BlockRange <= 0 { + return errors.New("block_range must be a positive integer") + } + if c.BlockInterval == nil || *c.BlockInterval <= 0 { + return errors.New("block_interval must be a positive integer") + } + if c.RegistryAddress == nil { + c.RegistryAddress = new(string) + } + if c.RegistrarAddress == nil { + c.RegistrarAddress = new(string) + } + if c.LinkTokenAddress == nil { + c.LinkTokenAddress = new(string) + } + if c.EthFeedAddress == nil { + c.EthFeedAddress = new(string) + } + if c.GasFeedAddress == nil { + c.GasFeedAddress = new(string) + } + return nil +} diff --git a/integration-tests/testconfig/keeper/example.toml b/integration-tests/testconfig/keeper/example.toml new file mode 100644 index 0000000000..6bdd6537bc --- /dev/null +++ b/integration-tests/testconfig/keeper/example.toml @@ -0,0 +1,88 @@ +# Example of full config with all fields +# General part +[ChainlinkImage] +image="public.ecr.aws/chainlink/chainlink" +version="2.7.0" + +[Logging] +# if set to true will save logs even if test did not fail +test_log_collect=false + +[Logging.LogStream] +# supported targets: file, loki, in-memory. if empty no logs will be persistet +log_targets=["file"] +# context timeout for starting log producer and also time-frame for requesting logs +log_producer_timeout="10s" +# number of retries before log producer gives up and stops listening to logs +log_producer_retry_limit=10 + +[Logging.Loki] +tenant_id="tenant_id" +# full URL of Loki ingest endpoint +endpoint="https://loki.url/api/v3/push" +# currently only needed when using public instance +basic_auth="loki-basic-auth" +# only needed for cloud grafana +bearer_token="bearer_token" + +# LogStream will try to shorten Grafana URLs by default (if all 3 variables are set) +[Logging.Grafana] +# grafana url (trailing "/" will be stripped) +base_url="http://grafana.url" +# url of your grafana dashboard (prefix and suffix "/" are stirpped), example: /d/ad61652-2712-1722/my-dashboard +dashboard_url="/d/your-dashboard" +bearer_token="my-awesome-token" + +# if you want to use polygon_mumbial +[Network] +selected_networks=["polygon_mumbai"] + +[Network.RpcHttpUrls] +polygon_mumbai = ["https://my-rpc-endpoint.io"] + +[Network.RpcWsUrls] +polygon_mumbai = ["https://my-rpc-endpoint.io"] + +[Network.WalletKeys] +polygon_mumbai = ["change-me-to-your-PK"] + +[PrivateEthereumNetwork] +# pos or pow +consensus_type="pos" +# only prysm supported currently +consensus_layer="prysm" +# geth, besu, nethermind or erigon +execution_layer="geth" +# if true after env started it will wait for at least 1 epoch to be finalised before continuing +wait_for_finalization=false + +[PrivateEthereumNetwork.EthereumChainConfig] +# duration of single slot, lower => faster block production, must be >= 4 +seconds_per_slot=12 +# numer of slots in epoch, lower => faster epoch finalisation, must be >= 4 +slots_per_epoch=6 +# extra genesis gelay, no need to modify, but it should be after all validators/beacon chain starts +genesis_delay=15 +# number of validators in the network +validator_count=8 +chain_id=1337 +# list of addresses to be prefunded in genesis +addresses_to_fund=["0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266"] + +# Product part +[Common] +chainlink_node_funding = 0.5 + +[Keeper.Common] +registry_to_test = "2_1" +number_of_registries = 1 +number_of_nodes = 6 +number_of_upkeeps = 500 +upkeep_gas_limit = 150000 +check_gas_to_burn = 100000 +perform_gas_to_burn = 50000 +max_perform_gas = 5000000 +block_range = 3600 +block_interval = 20 +forces_single_tx_key = false +delete_jobs_on_end = true \ No newline at end of file diff --git a/integration-tests/testconfig/keeper/keeper.toml b/integration-tests/testconfig/keeper/keeper.toml new file mode 100644 index 0000000000..516dbb35a6 --- /dev/null +++ b/integration-tests/testconfig/keeper/keeper.toml @@ -0,0 +1,17 @@ +# product defaults +[Common] +chainlink_node_funding = 0.5 + +[Keeper.Common] +registry_to_test = "2_1" +number_of_registries = 1 +number_of_nodes = 6 +number_of_upkeeps = 500 +upkeep_gas_limit = 1500000 +check_gas_to_burn = 100000 +perform_gas_to_burn = 50000 +max_perform_gas = 5000000 +block_range = 3600 +block_interval = 20 +forces_single_tx_key = false +delete_jobs_on_end = true \ No newline at end of file diff --git a/integration-tests/testconfig/log_poller/config.go b/integration-tests/testconfig/log_poller/config.go new file mode 100644 index 0000000000..96c3b55c27 --- /dev/null +++ b/integration-tests/testconfig/log_poller/config.go @@ -0,0 +1,158 @@ +package logpoller + +import ( + "fmt" + + "github.com/ethereum/go-ethereum/accounts/abi" + + "github.com/smartcontractkit/chainlink-testing-framework/blockchain" +) + +const ( + ErrReadPerfConfig = "failed to read TOML config for performance tests" + ErrUnmarshalPerfConfig = "failed to unmarshal TOML config for performance tests" +) + +type GeneratorType = string + +const ( + GeneratorType_WASP = "wasp" + GeneratorType_Looped = "looped" +) + +type Config struct { + General *General `toml:"General"` + ChaosConfig *ChaosConfig `toml:"Chaos"` + Wasp *WaspConfig `toml:"Wasp"` + LoopedConfig *LoopedConfig `toml:"Looped"` +} + +func (c *Config) Validate() error { + if c.General == nil { + return fmt.Errorf("General config must be set") + } + + err := c.General.Validate() + if err != nil { + return fmt.Errorf("General config validation failed: %w", err) + } + + switch *c.General.Generator { + case GeneratorType_WASP: + if c.Wasp == nil { + return fmt.Errorf("wasp config is nil") + } + err = c.Wasp.Validate() + if err != nil { + return fmt.Errorf("wasp config validation failed: %w", err) + } + case GeneratorType_Looped: + if c.LoopedConfig == nil { + return fmt.Errorf("looped config is nil") + } + err = c.LoopedConfig.Validate() + if err != nil { + return fmt.Errorf("looped config validation failed: %w", err) + } + default: + return fmt.Errorf("unknown generator type: %s", *c.General.Generator) + } + + if c.ChaosConfig != nil { + if err := c.ChaosConfig.Validate(); err != nil { + return fmt.Errorf("chaos config validation failed: %w", err) + } + } + + return nil +} + +type LoopedConfig struct { + ExecutionCount *int `toml:"execution_count"` + MinEmitWaitTimeMs *int `toml:"min_emit_wait_time_ms"` + MaxEmitWaitTimeMs *int `toml:"max_emit_wait_time_ms"` +} + +func (l *LoopedConfig) Validate() error { + if l.ExecutionCount == nil || *l.ExecutionCount == 0 { + return fmt.Errorf("execution_count must be set and > 0") + } + + if l.MinEmitWaitTimeMs == nil || *l.MinEmitWaitTimeMs == 0 { + return fmt.Errorf("min_emit_wait_time_ms must be set and > 0") + } + + if l.MaxEmitWaitTimeMs == nil || *l.MaxEmitWaitTimeMs == 0 { + return fmt.Errorf("max_emit_wait_time_ms must be set and > 0") + } + + return nil +} + +type General struct { + Generator *string `toml:"generator"` + EventsToEmit []abi.Event `toml:"-"` + Contracts *int `toml:"contracts"` + EventsPerTx *int `toml:"events_per_tx"` + UseFinalityTag *bool `toml:"use_finality_tag"` +} + +func (g *General) Validate() error { + if g.Generator == nil || *g.Generator == "" { + return fmt.Errorf("generator is empty") + } + + if g.Contracts == nil || *g.Contracts == 0 { + return fmt.Errorf("contracts is 0, but must be > 0") + } + + if g.EventsPerTx == nil || *g.EventsPerTx == 0 { + return fmt.Errorf("events_per_tx is 0, but must be > 0") + } + + return nil +} + +type ChaosConfig struct { + ExperimentCount *int `toml:"experiment_count"` + TargetComponent *string `toml:"target_component"` +} + +func (c *ChaosConfig) Validate() error { + if c.ExperimentCount != nil && *c.ExperimentCount == 0 { + return fmt.Errorf("experiment_count must be > 0") + } + + return nil +} + +type WaspConfig struct { + RPS *int64 `toml:"rps"` + LPS *int64 `toml:"lps"` + RateLimitUnitDuration *blockchain.StrDuration `toml:"rate_limit_unit_duration"` + Duration *blockchain.StrDuration `toml:"duration"` + CallTimeout *blockchain.StrDuration `toml:"call_timeout"` +} + +func (w *WaspConfig) Validate() error { + if w.RPS == nil && w.LPS == nil { + return fmt.Errorf("either RPS or LPS needs to be set") + } + if *w.RPS == 0 && *w.LPS == 0 { + return fmt.Errorf("either RPS or LPS needs to be a positive integer") + } + if *w.RPS != 0 && *w.LPS != 0 { + return fmt.Errorf("only one of RPS or LPS can be set") + } + if w.Duration == nil || w.Duration.Duration == 0 { + return fmt.Errorf("duration must be set and > 0") + } + if w.CallTimeout == nil || w.CallTimeout.Duration == 0 { + return fmt.Errorf("call_timeout must be set and > 0") + } + if w.RateLimitUnitDuration == nil || w.RateLimitUnitDuration.Duration == 0 { + return fmt.Errorf("rate_limit_unit_duration must be set and > 0") + } + + return nil +} diff --git a/integration-tests/testconfig/log_poller/example.toml b/integration-tests/testconfig/log_poller/example.toml new file mode 100644 index 0000000000..90ec89a3ed --- /dev/null +++ b/integration-tests/testconfig/log_poller/example.toml @@ -0,0 +1,87 @@ +# Example of full config with all fields +# General part +[ChainlinkImage] +image="public.ecr.aws/chainlink/chainlink" +version="2.7.0" + +[Logging] +# if set to true will save logs even if test did not fail +test_log_collect=false + +[Logging.LogStream] +# supported targets: file, loki, in-memory. if empty no logs will be persistet +log_targets=["file"] +# context timeout for starting log producer and also time-frame for requesting logs +log_producer_timeout="10s" +# number of retries before log producer gives up and stops listening to logs +log_producer_retry_limit=10 + +[Logging.Loki] +tenant_id="tenant_id" +# full URL of Loki ingest endpoint +endpoint="https://loki.url/api/v3/push" +# currently only needed when using public instance +basic_auth="loki-basic-auth" +# only needed for cloud grafana +bearer_token="bearer_token" + +# LogStream will try to shorten Grafana URLs by default (if all 3 variables are set) +[Logging.Grafana] +# grafana url (trailing "/" will be stripped) +base_url="http://grafana.url" +# url of your grafana dashboard (prefix and suffix "/" are stirpped), example: /d/ad61652-2712-1722/my-dashboard +dashboard_url="/d/your-dashboard" +bearer_token="my-awesome-token" + +# if you want to use polygon_mumbial +[Network] +selected_networks=["polygon_mumbai"] + +[Network.RpcHttpUrls] +polygon_mumbai = ["https://my-rpc-endpoint.io"] + +[Network.RpcWsUrls] +polygon_mumbai = ["https://my-rpc-endpoint.io"] + +[Network.WalletKeys] +polygon_mumbai = ["change-me-to-your-PK"] + +[PrivateEthereumNetwork] +# pos or pow +consensus_type="pos" +# only prysm supported currently +consensus_layer="prysm" +# geth, besu, nethermind or erigon +execution_layer="geth" +# if true after env started it will wait for at least 1 epoch to be finalised before continuing +wait_for_finalization=false + +[PrivateEthereumNetwork.EthereumChainConfig] +# duration of single slot, lower => faster block production, must be >= 4 +seconds_per_slot=12 +# numer of slots in epoch, lower => faster epoch finalisation, must be >= 4 +slots_per_epoch=6 +# extra genesis gelay, no need to modify, but it should be after all validators/beacon chain starts +genesis_delay=15 +# number of validators in the network +validator_count=8 +chain_id=1337 +# list of addresses to be prefunded in genesis +addresses_to_fund=["0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266"] + +# Common +[Common] +chainlink_node_funding = 0.5 + +# Product part +[LogPoller] +[LogPoller.General] +generator = "looped" +contracts = 2 +events_per_tx = 4 +use_finality_tag = true + +[LogPoller.Looped] +execution_count = 100 +min_emit_wait_time_ms = 200 +max_emit_wait_time_ms = 500 \ No newline at end of file diff --git a/integration-tests/testconfig/log_poller/log_poller.toml b/integration-tests/testconfig/log_poller/log_poller.toml new file mode 100644 index 0000000000..2f46ebf11c --- /dev/null +++ b/integration-tests/testconfig/log_poller/log_poller.toml @@ -0,0 +1,61 @@ +# product defaults +[LogPoller] +[LogPoller.General] +generator = "looped" +contracts = 2 +events_per_tx = 4 +use_finality_tag = true + +[LogPoller.Looped] +execution_count = 100 +min_emit_wait_time_ms = 200 +max_emit_wait_time_ms = 500 + +# test-specific +[TestLogPollerFewFiltersFixedDepth.LogPoller.General] +use_finality_tag = false + +[TestLogManyFiltersPollerFinalityTag.LogPoller.General] +contracts = 300 +events_per_tx = 3 + +[TestLogManyFiltersPollerFinalityTag.LogPoller.Looped] +execution_count = 30 + +[TestLogManyFiltersPollerFixedDepth.LogPoller.General] +use_finality_tag = false +contracts = 300 +events_per_tx = 3 + +[TestLogManyFiltersPollerFixedDepth.LogPoller.Looped] +execution_count = 30 + +[TestLogPollerWithChaosFinalityTag.LogPoller.General] +execution_count = 30 +[TestLogPollerWithChaosFinalityTag.LogPoller.Chaos] +experiment_count = 4 +target_component = "chainlink" + +[TestLogPollerWithChaosFixedDepth.LogPoller.General] +execution_count = 30 +use_finality_tag = false +[TestLogPollerWithChaosFixedDepth.LogPoller.Chaos] +experiment_count = 4 +target_component = "chainlink" + +[TestLogPollerWithChaosPostgresFinalityTag.LogPoller.General] +execution_count = 30 +[TestLogPollerWithChaosPostgresFinalityTag.LogPoller.Chaos] +experiment_count = 4 +target_component = "postgres" + +[TestLogPollerWithChaosPostgresFixedDepth.LogPoller.General] +execution_count = 30 +use_finality_tag = false +[TestLogPollerWithChaosPostgresFixedDepth.LogPoller.Chaos] +experiment_count = 4 +target_component = "postgres" + +[TestLogPollerReplayFixedDepth.LogPoller.General] +use_finality_tag = false + diff --git a/integration-tests/testconfig/node/example.toml b/integration-tests/testconfig/node/example.toml new file mode 100644 index 0000000000..55ee1ffccf --- /dev/null +++ b/integration-tests/testconfig/node/example.toml @@ -0,0 +1,79 @@ +# Example of full config with all fields +# General part +[ChainlinkImage] +image="public.ecr.aws/chainlink/chainlink" +version="2.7.0" + +[Logging] +# if set to true will save logs even if test did not fail +test_log_collect=false + +[Logging.LogStream] +# supported targets: file, loki, in-memory. if empty no logs will be persistet +log_targets=["file"] +# context timeout for starting log producer and also time-frame for requesting logs +log_producer_timeout="10s" +# number of retries before log producer gives up and stops listening to logs +log_producer_retry_limit=10 + +[Logging.Loki] +tenant_id="tenant_id" +# full URL of Loki ingest endpoint +endpoint="https://loki.url/api/v3/push" +# currently only needed when using public instance +basic_auth="loki-basic-auth" +# only needed for cloud grafana +bearer_token="bearer_token" + +# LogStream will try to shorten Grafana URLs by default (if all 3 variables are set) +[Logging.Grafana] +# grafana url (trailing "/" will be stripped) +base_url="http://grafana.url" +# url of your grafana dashboard (prefix and suffix "/" are stirpped), example: /d/ad61652-2712-1722/my-dashboard +dashboard_url="/d/your-dashboard" +bearer_token="my-awesome-token" + +# if you want to use polygon_mumbial +[Network] +selected_networks=["polygon_mumbai"] + +[Network.RpcHttpUrls] +polygon_mumbai = ["https://my-rpc-endpoint.io"] + +[Network.RpcWsUrls] +polygon_mumbai = ["https://my-rpc-endpoint.io"] + +[Network.WalletKeys] +polygon_mumbai = ["change-me-to-your-PK"] + +[PrivateEthereumNetwork] +# pos or pow +consensus_type="pos" +# only prysm supported currently +consensus_layer="prysm" +# geth, besu, nethermind or erigon +execution_layer="geth" +# if true after env started it will wait for at least 1 epoch to be finalised before continuing +wait_for_finalization=false + +[PrivateEthereumNetwork.EthereumChainConfig] +# duration of single slot, lower => faster block production, must be >= 4 +seconds_per_slot=12 +# numer of slots in epoch, lower => faster epoch finalisation, must be >= 4 +slots_per_epoch=6 +# extra genesis gelay, no need to modify, but it should be after all validators/beacon chain starts +genesis_delay=15 +# number of validators in the network +validator_count=8 +chain_id=1337 +# list of addresses to be prefunded in genesis +addresses_to_fund=["0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266"] + +# Common +[Common] +chainlink_node_funding = 0.5 + +# Test-specific part +[ChainlinkUpgradeImage] +image="public.ecr.aws/chainlink/chainlink" +version="2.8.0" \ No newline at end of file diff --git a/integration-tests/testconfig/node/node.toml b/integration-tests/testconfig/node/node.toml new file mode 100644 index 0000000000..683b55a35a --- /dev/null +++ b/integration-tests/testconfig/node/node.toml @@ -0,0 +1,5 @@ +# original image +[ChainlinkImage] + +# image to upgrade to +[ChainlinkUpgradeImage] \ No newline at end of file diff --git a/integration-tests/testconfig/ocr/example.toml b/integration-tests/testconfig/ocr/example.toml new file mode 100644 index 0000000000..6cbdbef155 --- /dev/null +++ b/integration-tests/testconfig/ocr/example.toml @@ -0,0 +1,96 @@ +# Example of full config with all fields +# General part +[ChainlinkImage] +image="public.ecr.aws/chainlink/chainlink" +version="2.7.0" + +[Logging] +# if set to true will save logs even if test did not fail +test_log_collect=false + +[Logging.LogStream] +# supported targets: file, loki, in-memory. if empty no logs will be persistet +log_targets=["file"] +# context timeout for starting log producer and also time-frame for requesting logs +log_producer_timeout="10s" +# number of retries before log producer gives up and stops listening to logs +log_producer_retry_limit=10 + +[Logging.Loki] +tenant_id="tenant_id" +# full URL of Loki ingest endpoint +endpoint="https://loki.url/api/v3/push" +# currently only needed when using public instance +basic_auth="loki-basic-auth" +# only needed for cloud grafana +bearer_token="bearer_token" + +# LogStream will try to shorten Grafana URLs by default (if all 3 variables are set) +[Logging.Grafana] +# grafana url (trailing "/" will be stripped) +base_url="http://grafana.url" +# url of your grafana dashboard (prefix and suffix "/" are stirpped), example: /d/ad61652-2712-1722/my-dashboard +dashboard_url="/d/your-dashboard" +bearer_token="my-awesome-token" + +# if you want to use polygon_mumbial +[Network] +selected_networks=["polygon_mumbai"] + +[Network.RpcHttpUrls] +polygon_mumbai = ["https://my-rpc-endpoint.io"] + +[Network.RpcWsUrls] +polygon_mumbai = ["https://my-rpc-endpoint.io"] + +[Network.WalletKeys] +polygon_mumbai = ["change-me-to-your-PK"] + +[PrivateEthereumNetwork] +# pos or pow +consensus_type="pos" +# only prysm supported currently +consensus_layer="prysm" +# geth, besu, nethermind or erigon +execution_layer="geth" +# if true after env started it will wait for at least 1 epoch to be finalised before continuing +wait_for_finalization=false + +[PrivateEthereumNetwork.EthereumChainConfig] +# duration of single slot, lower => faster block production, must be >= 4 +seconds_per_slot=12 +# numer of slots in epoch, lower => faster epoch finalisation, must be >= 4 +slots_per_epoch=6 +# extra genesis gelay, no need to modify, but it should be after all validators/beacon chain starts +genesis_delay=15 +# number of validators in the network +validator_count=8 +chain_id=1337 +# list of addresses to be prefunded in genesis +addresses_to_fund=["0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266"] + +# load test specific configuration +[Load.OCR] +[Load.OCR.Common] +eth_funds = 3 + +[Load.OCR.Load] +test_duration = "3m" +rate_limit_unit_duration = "1m" +rate = 3 +verification_interval = "5s" +verification_timeout = "3m" +ea_change_interval = "5s" + +# soak test specific configuration +[Soak.Common] +chainlink_node_funding = 100 + +[Soak.OCR] +[Soak.OCR.Common] +test_duration="15m" + +[Soak.OCR.Soak] +ocr_version="1" +number_of_contracts=2 +time_between_rounds="1m" \ No newline at end of file diff --git a/integration-tests/testconfig/ocr/ocr.go b/integration-tests/testconfig/ocr/ocr.go new file mode 100644 index 0000000000..0fd995a96f --- /dev/null +++ b/integration-tests/testconfig/ocr/ocr.go @@ -0,0 +1,136 @@ +package ocr + +import ( + "errors" + + "github.com/smartcontractkit/chainlink-testing-framework/blockchain" +) + +type Config struct { + Soak *SoakConfig `toml:"Soak"` + Load *Load `toml:"Load"` + Volume *Volume `toml:"Volume"` + Common *Common `toml:"Common"` +} + +func (o *Config) Validate() error { + if o.Common != nil { + if err := o.Common.Validate(); err != nil { + return err + } + } + if o.Soak != nil { + if err := o.Soak.Validate(); err != nil { + return err + } + } + if o.Volume != nil { + if err := o.Volume.Validate(); err != nil { + return err + } + } + return nil +} + +type Common struct { + ETHFunds *int `toml:"eth_funds"` + TestDuration *blockchain.StrDuration `toml:"test_duration"` +} + +func (o *Common) Validate() error { + if o.ETHFunds != nil && *o.ETHFunds < 0 { + return errors.New("eth_funds must be set and cannot be negative") + } + return nil +} + +type Load struct { + Rate *int64 `toml:"rate"` + RequestsPerUnit *int `toml:"requests_per_unit"` + RateLimitUnitDuration *blockchain.StrDuration `toml:"rate_limit_unit_duration"` + VerificationInterval *blockchain.StrDuration `toml:"verification_interval"` + VerificationTimeout *blockchain.StrDuration `toml:"verification_timeout"` + EAChangeInterval *blockchain.StrDuration `toml:"ea_change_interval"` + TestDuration *blockchain.StrDuration `toml:"test_duration"` +} + +func (o *Load) Validate() error { + if o.TestDuration == nil { + return errors.New("load test duration must be set") + } + if o.Rate == nil || *o.Rate <= 0 { + return errors.New("rate must be set and be a positive integer") + } + if o.RequestsPerUnit == nil || *o.RequestsPerUnit <= 0 { + return errors.New("vu_requests_per_unit must be set and be a positive integer") + } + if o.RateLimitUnitDuration == nil || o.RateLimitUnitDuration.Duration == 0 { + return errors.New("rate_limit_unit_duration must be set and be a positive integer") + } + if o.VerificationInterval == nil || o.VerificationInterval.Duration == 0 { + return errors.New("verification_interval must be set and be a positive integer") + } + if o.VerificationTimeout == nil || o.VerificationTimeout.Duration == 0 { + return errors.New("verification_timeout must be set and be a positive integer") + } + if o.EAChangeInterval == nil || o.EAChangeInterval.Duration == 0 { + return errors.New("ea_change_interval must be set and be a positive integer") + } + + return nil +} + +type Volume struct { + Rate *int64 `toml:"rate"` + VURequestsPerUnit *int `toml:"vu_requests_per_unit"` + RateLimitUnitDuration *blockchain.StrDuration `toml:"rate_limit_unit_duration"` + VerificationInterval *blockchain.StrDuration `toml:"verification_interval"` + VerificationTimeout *blockchain.StrDuration `toml:"verification_timeout"` + EAChangeInterval *blockchain.StrDuration `toml:"ea_change_interval"` + TestDuration *blockchain.StrDuration `toml:"test_duration"` +} + +func (o *Volume) Validate() error { + if o.TestDuration == nil { + return errors.New("volume test duration must be set") + } + if o.Rate == nil || *o.Rate <= 0 { + return errors.New("rate must be set and be a positive integer") + } + if o.VURequestsPerUnit == nil || *o.VURequestsPerUnit <= 0 { + return errors.New("vu_requests_per_unit must be set and be a positive integer") + } + if o.RateLimitUnitDuration == nil || o.RateLimitUnitDuration.Duration == 0 { + return errors.New("rate_limit_unit_duration must be set and be a positive integer") + } + if o.VerificationInterval == nil || o.VerificationInterval.Duration == 0 { + return errors.New("verification_interval must be set and be a positive integer") + } + if o.VerificationTimeout == nil || o.VerificationTimeout.Duration == 0 { + return errors.New("verification_timeout must be set and be a positive integer") + } + if o.EAChangeInterval == nil || o.EAChangeInterval.Duration == 0 { + return errors.New("ea_change_interval must be set and be a positive integer") + } + + return nil +} + +type SoakConfig struct { + OCRVersion *string `toml:"ocr_version"` + NumberOfContracts *int `toml:"number_of_contracts"` + TimeBetweenRounds *blockchain.StrDuration `toml:"time_between_rounds"` +} + +func (o *SoakConfig) Validate() error { + if o.OCRVersion == nil || *o.OCRVersion == "" { + return errors.New("ocr_version must be set to either 1 or 2") + } + if o.NumberOfContracts == nil || *o.NumberOfContracts <= 1 { + return errors.New("number_of_contracts must be set and be greater than 1") + } + if o.TimeBetweenRounds == nil || o.TimeBetweenRounds.Duration == 0 { + return errors.New("time_between_rounds must be set and be a positive integer") + } + return nil +} diff --git a/integration-tests/testconfig/ocr/ocr.toml b/integration-tests/testconfig/ocr/ocr.toml new file mode 100644 index 0000000000..8d3c73ca76 --- /dev/null +++ b/integration-tests/testconfig/ocr/ocr.toml @@ -0,0 +1,43 @@ +# product defaults +[Common] +chainlink_node_funding = 0.5 + +# load test specific configuration +[Load.OCR] +[Load.OCR.Common] +eth_funds = 3 + +[Load.OCR.Load] +test_duration = "3m" +rate_limit_unit_duration = "1m" +rate = 3 +verification_interval = "5s" +verification_timeout = "3m" +ea_change_interval = "5s" + +# volume test specific configuration +[Volume.OCR] +[Volume.OCR.Common] +eth_funds = 3 + +[Volume.OCR.Volume] +test_duration = "3m" +rate_limit_unit_duration = "1m" +vu_requests_per_unit = 10 +rate = 1 +verification_interval = "5s" +verification_timeout = "3m" +ea_change_interval = "5s" + +# soak test specific configuration +[Soak.Common] +chainlink_node_funding = 100 + +[Soak.OCR] +[Soak.OCR.Common] +test_duration="15m" + +[Soak.OCR.Soak] +ocr_version="1" +number_of_contracts=2 +time_between_rounds="1m" \ No newline at end of file diff --git a/integration-tests/testconfig/testconfig.go b/integration-tests/testconfig/testconfig.go new file mode 100644 index 0000000000..28eddb24e6 --- /dev/null +++ b/integration-tests/testconfig/testconfig.go @@ -0,0 +1,541 @@ +package testconfig + +import ( + "embed" + "encoding/base64" + "fmt" + "os" + "slices" + "strings" + + "github.com/barkimedes/go-deepcopy" + "github.com/google/uuid" + "github.com/pelletier/go-toml/v2" + "github.com/pkg/errors" + "github.com/rs/zerolog" + "golang.org/x/text/cases" + "golang.org/x/text/language" + + ctf_config "github.com/smartcontractkit/chainlink-testing-framework/config" + "github.com/smartcontractkit/chainlink-testing-framework/docker/test_env" + ctf_test_env "github.com/smartcontractkit/chainlink-testing-framework/docker/test_env" + k8s_config "github.com/smartcontractkit/chainlink-testing-framework/k8s/config" + "github.com/smartcontractkit/chainlink-testing-framework/logging" + "github.com/smartcontractkit/chainlink-testing-framework/utils/osutil" + + a_config "github.com/smartcontractkit/chainlink/integration-tests/testconfig/automation" + f_config "github.com/smartcontractkit/chainlink/integration-tests/testconfig/functions" + keeper_config "github.com/smartcontractkit/chainlink/integration-tests/testconfig/keeper" + lp_config "github.com/smartcontractkit/chainlink/integration-tests/testconfig/log_poller" + ocr_config "github.com/smartcontractkit/chainlink/integration-tests/testconfig/ocr" + vrf_config "github.com/smartcontractkit/chainlink/integration-tests/testconfig/vrf" + vrfv2_config "github.com/smartcontractkit/chainlink/integration-tests/testconfig/vrfv2" + vrfv2plus_config "github.com/smartcontractkit/chainlink/integration-tests/testconfig/vrfv2plus" +) + +type GlobalTestConfig interface { + GetChainlinkImageConfig() *ctf_config.ChainlinkImageConfig + GetLoggingConfig() *ctf_config.LoggingConfig + GetNetworkConfig() *ctf_config.NetworkConfig + GetPrivateEthereumNetworkConfig() *test_env.EthereumNetwork + GetPyroscopeConfig() *ctf_config.PyroscopeConfig +} + +type UpgradeableChainlinkTestConfig interface { + GetChainlinkUpgradeImageConfig() *ctf_config.ChainlinkImageConfig +} + +type CommonTestConfig interface { + GetCommonConfig() *Common +} + +type VRFv2TestConfig interface { + GetVRFv2Config() *vrfv2_config.Config +} + +type VRFv2PlusTestConfig interface { + GetVRFv2PlusConfig() *vrfv2plus_config.Config +} + +type FunctionsTestConfig interface { + GetFunctionsConfig() *f_config.Config +} + +type KeeperTestConfig interface { + GetKeeperConfig() *keeper_config.Config +} + +type OcrTestConfig interface { + GetOCRConfig() *ocr_config.Config +} + +type NamedConfiguration interface { + GetConfigurationName() string +} + +type TestConfig struct { + ChainlinkImage *ctf_config.ChainlinkImageConfig `toml:"ChainlinkImage"` + ChainlinkUpgradeImage *ctf_config.ChainlinkImageConfig `toml:"ChainlinkUpgradeImage"` + Logging *ctf_config.LoggingConfig `toml:"Logging"` + Network *ctf_config.NetworkConfig `toml:"Network"` + Pyroscope *ctf_config.PyroscopeConfig `toml:"Pyroscope"` + PrivateEthereumNetwork *ctf_test_env.EthereumNetwork `toml:"PrivateEthereumNetwork"` + + Common *Common `toml:"Common"` + Automation *a_config.Config `toml:"Automation"` + Functions *f_config.Config `toml:"Functions"` + Keeper *keeper_config.Config `toml:"Keeper"` + LogPoller *lp_config.Config `toml:"LogPoller"` + OCR *ocr_config.Config `toml:"OCR"` + VRF *vrf_config.Config `toml:"VRF"` + VRFv2 *vrfv2_config.Config `toml:"VRFv2"` + VRFv2Plus *vrfv2plus_config.Config `toml:"VRFv2Plus"` + + ConfigurationName string `toml:"-"` +} + +var embeddedConfigs embed.FS +var areConfigsEmbedded bool + +func init() { + embeddedConfigs = embeddedConfigsFs +} + +// Returns Grafana URL from Logging config +func (c *TestConfig) GetGrafanaBaseURL() (string, error) { + if c.Logging.Grafana == nil || c.Logging.Grafana.BaseUrl == nil { + return "", errors.New("grafana base url not set") + } + + return strings.TrimSuffix(*c.Logging.Grafana.BaseUrl, "/"), nil +} + +// Returns Grafana Dashboard URL from Logging config +func (c *TestConfig) GetGrafanaDashboardURL() (string, error) { + if c.Logging.Grafana == nil || c.Logging.Grafana.DashboardUrl == nil { + return "", errors.New("grafana dashboard url not set") + } + + url := *c.Logging.Grafana.DashboardUrl + if !strings.HasPrefix(url, "/") { + url = "/" + url + } + + return url, nil +} + +// Saves Test Config to a local file +func (c *TestConfig) Save() (string, error) { + filePath := fmt.Sprintf("test_config-%s.toml", uuid.New()) + + content, err := toml.Marshal(*c) + if err != nil { + return "", errors.Wrapf(err, "error marshaling test config") + } + + err = os.WriteFile(filePath, content, 0600) + if err != nil { + return "", errors.Wrapf(err, "error writing test config") + } + + return filePath, nil +} + +// MustCopy Returns a deep copy of the Test Config or panics on error +func (c TestConfig) MustCopy() any { + return deepcopy.MustAnything(c).(TestConfig) +} + +// MustCopy Returns a deep copy of struct passed to it and returns a typed copy (or panics on error) +func MustCopy[T any](c T) T { + return deepcopy.MustAnything(c).(T) +} + +func (c *TestConfig) GetLoggingConfig() *ctf_config.LoggingConfig { + return c.Logging +} + +func (c TestConfig) GetNetworkConfig() *ctf_config.NetworkConfig { + return c.Network +} + +func (c TestConfig) GetChainlinkImageConfig() *ctf_config.ChainlinkImageConfig { + return c.ChainlinkImage +} + +func (c TestConfig) GetPrivateEthereumNetworkConfig() *ctf_test_env.EthereumNetwork { + return c.PrivateEthereumNetwork +} + +func (c TestConfig) GetPyroscopeConfig() *ctf_config.PyroscopeConfig { + return c.Pyroscope +} + +func (c TestConfig) GetCommonConfig() *Common { + return c.Common +} + +func (c TestConfig) GetVRFv2Config() *vrfv2_config.Config { + return c.VRFv2 +} + +func (c TestConfig) GetFunctionsConfig() *f_config.Config { + return c.Functions +} + +func (c TestConfig) GetVRFv2PlusConfig() *vrfv2plus_config.Config { + return c.VRFv2Plus +} + +func (c TestConfig) GetChainlinkUpgradeImageConfig() *ctf_config.ChainlinkImageConfig { + return c.ChainlinkUpgradeImage +} + +func (c TestConfig) GetKeeperConfig() *keeper_config.Config { + return c.Keeper +} + +func (c TestConfig) GetOCRConfig() *ocr_config.Config { + return c.OCR +} + +func (c TestConfig) GetConfigurationName() string { + return c.ConfigurationName +} + +type Common struct { + ChainlinkNodeFunding *float64 `toml:"chainlink_node_funding"` +} + +func (c *Common) Validate() error { + if c.ChainlinkNodeFunding != nil && *c.ChainlinkNodeFunding < 0 { + return fmt.Errorf("chainlink node funding must be positive") + } + + return nil +} + +type Product string + +const ( + Automation Product = "automation" + Cron Product = "cron" + DirectRequest Product = "direct_request" + Flux Product = "flux" + ForwarderOcr Product = "forwarder_ocr" + ForwarderOcr2 Product = "forwarder_ocr2" + Functions Product = "functions" + Keeper Product = "keeper" + LogPoller Product = "log_poller" + Node Product = "node" + OCR Product = "ocr" + OCR2 Product = "ocr2" + OCR2VRF Product = "ocr2vrf" + RunLog Product = "runlog" + VRF Product = "vrf" + VRFv2 Product = "vrfv2" + VRFv2Plus Product = "vrfv2plus" +) + +var TestTypesWithLoki = []string{"Load", "Soak", "Stress", "Spike", "Volume"} + +const TestTypeEnvVarName = "TEST_TYPE" + +func GetConfigurationNameFromEnv() (string, error) { + testType := os.Getenv(TestTypeEnvVarName) + if testType == "" { + return "", fmt.Errorf("%s env var not set", TestTypeEnvVarName) + } + + return cases.Title(language.English, cases.NoLower).String(testType), nil +} + +const ( + Base64OverrideEnvVarName = k8s_config.EnvBase64ConfigOverride + NoKey = "NO_KEY" +) + +func GetConfig(configurationName string, product Product) (TestConfig, error) { + logger := logging.GetTestLogger(nil) + + configurationName = strings.ReplaceAll(configurationName, "/", "_") + configurationName = strings.ReplaceAll(configurationName, " ", "_") + configurationName = cases.Title(language.English, cases.NoLower).String(configurationName) + fileNames := []string{ + "default.toml", + fmt.Sprintf("%s.toml", product), + "overrides.toml", + } + + testConfig := TestConfig{} + testConfig.ConfigurationName = configurationName + logger.Debug().Msgf("Will apply configuration named '%s' if it is found in any of the configs", configurationName) + + var handleSpecialOverrides = func(logger zerolog.Logger, filename, configurationName string, target *TestConfig, content []byte, product Product) error { + switch product { + case Automation: + return handleAutomationConfigOverride(logger, filename, configurationName, target, content) + default: + err := ctf_config.BytesToAnyTomlStruct(logger, filename, configurationName, &testConfig, content) + if err != nil { + return errors.Wrapf(err, "error reading file %s", filename) + } + + return nil + } + } + + // read embedded configs is build tag "embed" is set + // this makes our life much easier when using a binary + if areConfigsEmbedded { + logger.Info().Msg("Reading embedded configs") + embeddedFiles := []string{"default.toml", fmt.Sprintf("%s/%s.toml", product, product)} + for _, fileName := range embeddedFiles { + file, err := embeddedConfigs.ReadFile(fileName) + if err != nil && errors.Is(err, os.ErrNotExist) { + logger.Debug().Msgf("Embedded config file %s not found. Continuing", fileName) + continue + } else if err != nil { + return TestConfig{}, errors.Wrapf(err, "error reading embedded config") + } + + err = handleSpecialOverrides(logger, fileName, configurationName, &testConfig, file, product) + if err != nil { + return TestConfig{}, errors.Wrapf(err, "error unmarshalling embedded config") + } + } + } + + logger.Info().Msg("Reading configs from file system") + for _, fileName := range fileNames { + logger.Debug().Msgf("Looking for config file %s", fileName) + filePath, err := osutil.FindFile(fileName, osutil.DEFAULT_STOP_FILE_NAME, 3) + + if err != nil && errors.Is(err, os.ErrNotExist) { + logger.Debug().Msgf("Config file %s not found", fileName) + continue + } else if err != nil { + return TestConfig{}, errors.Wrapf(err, "error looking for file %s", filePath) + } + logger.Debug().Str("location", filePath).Msgf("Found config file %s", fileName) + + content, err := readFile(filePath) + if err != nil { + return TestConfig{}, errors.Wrapf(err, "error reading file %s", filePath) + } + + err = handleSpecialOverrides(logger, fileName, configurationName, &testConfig, content, product) + if err != nil { + return TestConfig{}, errors.Wrapf(err, "error reading file %s", filePath) + } + } + + logger.Info().Msg("Reading configs from Base64 override env var") + configEncoded, isSet := os.LookupEnv(Base64OverrideEnvVarName) + if isSet && configEncoded != "" { + logger.Debug().Msgf("Found base64 config override environment variable '%s' found", Base64OverrideEnvVarName) + decoded, err := base64.StdEncoding.DecodeString(configEncoded) + if err != nil { + return TestConfig{}, err + } + + err = handleSpecialOverrides(logger, Base64OverrideEnvVarName, configurationName, &testConfig, decoded, product) + if err != nil { + return TestConfig{}, errors.Wrapf(err, "error unmarshaling base64 config") + } + } else { + logger.Debug().Msg("Base64 config override from environment variable not found") + } + + // it neede some custom logic, so we do it separately + err := testConfig.readNetworkConfiguration() + if err != nil { + return TestConfig{}, errors.Wrapf(err, "error reading network config") + } + + logger.Debug().Msg("Validating test config") + err = testConfig.Validate() + if err != nil { + return TestConfig{}, errors.Wrapf(err, "error validating test config") + } + + if testConfig.Common == nil { + testConfig.Common = &Common{} + } + + logger.Debug().Msg("Correct test config constructed successfully") + return testConfig, nil +} + +func (c *TestConfig) readNetworkConfiguration() error { + // currently we need to read that kind of secrets only for network configuration + if c == nil { + c.Network = &ctf_config.NetworkConfig{} + } + + c.Network.UpperCaseNetworkNames() + err := c.Network.Default() + if err != nil { + return errors.Wrapf(err, "error reading default network config") + } + + // this is the only value we need to generate dynamically before starting a new simulated chain + if c.PrivateEthereumNetwork != nil && c.PrivateEthereumNetwork.EthereumChainConfig != nil { + c.PrivateEthereumNetwork.EthereumChainConfig.GenerateGenesisTimestamp() + } + + return nil +} + +func (c *TestConfig) Validate() error { + defer func() { + if r := recover(); r != nil { + panic(fmt.Errorf("Panic during test config validation: '%v'. Most probably due to presence of partial product config", r)) + } + }() + if c.ChainlinkImage == nil { + return fmt.Errorf("chainlink image config must be set") + } + if err := c.ChainlinkImage.Validate(); err != nil { + return errors.Wrapf(err, "chainlink image config validation failed") + } + if c.ChainlinkUpgradeImage != nil { + if err := c.ChainlinkUpgradeImage.Validate(); err != nil { + return errors.Wrapf(err, "chainlink upgrade image config validation failed") + } + } + if err := c.Network.Validate(); err != nil { + return errors.Wrapf(err, "network config validation failed") + } + + if c.Logging == nil { + return fmt.Errorf("logging config must be set") + } + + if err := c.Logging.Validate(); err != nil { + return errors.Wrapf(err, "logging config validation failed") + } + + // require Loki config only if these tests run locally + _, willUseRemoteRunner := os.LookupEnv(k8s_config.EnvVarJobImage) + _, isInsideK8s := os.LookupEnv(k8s_config.EnvVarInsideK8s) + if (!willUseRemoteRunner && !isInsideK8s) && slices.Contains(TestTypesWithLoki, c.ConfigurationName) { + if c.Logging.Loki == nil { + return fmt.Errorf("for local execution you must set Loki config in logging config") + } + + if err := c.Logging.Loki.Validate(); err != nil { + return errors.Wrapf(err, "loki config validation failed") + } + } + + if c.Logging.LogStream != nil && slices.Contains(c.Logging.LogStream.LogTargets, "loki") { + if c.Logging.Loki == nil { + return fmt.Errorf("in order to use Loki as logging target you must set Loki config in logging config") + } + + if err := c.Logging.Loki.Validate(); err != nil { + return errors.Wrapf(err, "loki config validation failed") + } + } + + if c.Pyroscope != nil { + if err := c.Pyroscope.Validate(); err != nil { + return errors.Wrapf(err, "pyroscope config validation failed") + } + } + + if c.PrivateEthereumNetwork != nil { + if err := c.PrivateEthereumNetwork.Validate(); err != nil { + return errors.Wrapf(err, "private ethereum network config validation failed") + } + } + + if c.Common != nil { + if err := c.Common.Validate(); err != nil { + return errors.Wrapf(err, "Common config validation failed") + } + } + + if c.Automation != nil { + if err := c.Automation.Validate(); err != nil { + return errors.Wrapf(err, "Automation config validation failed") + } + } + + if c.Functions != nil { + if err := c.Functions.Validate(); err != nil { + return errors.Wrapf(err, "Functions config validation failed") + } + } + + if c.Keeper != nil { + if err := c.Keeper.Validate(); err != nil { + return errors.Wrapf(err, "Keeper config validation failed") + } + } + + if c.LogPoller != nil { + if err := c.LogPoller.Validate(); err != nil { + return errors.Wrapf(err, "LogPoller config validation failed") + } + } + + if c.OCR != nil { + if err := c.OCR.Validate(); err != nil { + return errors.Wrapf(err, "OCR config validation failed") + } + } + + if c.VRF != nil { + if err := c.VRF.Validate(); err != nil { + return errors.Wrapf(err, "VRF config validation failed") + } + } + + if c.VRFv2 != nil { + if err := c.VRFv2.Validate(); err != nil { + return errors.Wrapf(err, "VRFv2 config validation failed") + } + } + + if c.VRFv2Plus != nil { + if err := c.VRFv2Plus.Validate(); err != nil { + return errors.Wrapf(err, "VRFv2Plus config validation failed") + } + } + + return nil +} + +func readFile(filePath string) ([]byte, error) { + content, err := os.ReadFile(filePath) + if err != nil { + return nil, errors.Wrapf(err, "error reading file %s", filePath) + } + + return content, nil +} + +func handleAutomationConfigOverride(logger zerolog.Logger, filename, configurationName string, target *TestConfig, content []byte) error { + logger.Debug().Msgf("Handling automation config override for %s", filename) + oldConfig := MustCopy(target) + newConfig := TestConfig{} + + err := ctf_config.BytesToAnyTomlStruct(logger, filename, configurationName, &target, content) + if err != nil { + return errors.Wrapf(err, "error reading file %s", filename) + } + + err = ctf_config.BytesToAnyTomlStruct(logger, filename, configurationName, &newConfig, content) + if err != nil { + return errors.Wrapf(err, "error reading file %s", filename) + } + + // override instead of merging + if (newConfig.Automation != nil && len(newConfig.Automation.Load) > 0) && (oldConfig != nil && oldConfig.Automation != nil && len(oldConfig.Automation.Load) > 0) { + target.Automation.Load = newConfig.Automation.Load + } + + return nil +} diff --git a/integration-tests/testconfig/testconfig_test.go b/integration-tests/testconfig/testconfig_test.go new file mode 100644 index 0000000000..4a9dbdaade --- /dev/null +++ b/integration-tests/testconfig/testconfig_test.go @@ -0,0 +1,88 @@ +package testconfig + +import ( + "encoding/base64" + "math/big" + "os" + "testing" + + "github.com/pelletier/go-toml/v2" + "github.com/test-go/testify/require" + + ctf_config "github.com/smartcontractkit/chainlink-testing-framework/config" + "github.com/smartcontractkit/chainlink-testing-framework/utils/ptr" + a_config "github.com/smartcontractkit/chainlink/integration-tests/testconfig/automation" +) + +func TestBase64ConfigRead(t *testing.T) { + networkConfigTOML := ` + [RpcHttpUrls] + arbitrum_goerli = ["https://devnet-1.mt/ABC/rpc/"] + optimism_goerli = ["https://devnet-3.mt/ABC/rpc/"] + + [RpcWsUrls] + arbitrum_goerli = ["wss://devnet-1.mt/ABC/rpc/"] + optimism_goerli = ["wss://devnet-2.mt/ABC/rpc/"] + ` + networksEncoded := base64.StdEncoding.EncodeToString([]byte(networkConfigTOML)) + os.Setenv(ctf_config.Base64NetworkConfigEnvVarName, networksEncoded) + + testConfig := TestConfig{ + Automation: &a_config.Config{ + General: &a_config.General{ + NumberOfNodes: ptr.Ptr(7), + Duration: ptr.Ptr(9), + BlockTime: ptr.Ptr(10), + SpecType: ptr.Ptr("minimum"), + ChainlinkNodeLogLevel: ptr.Ptr("debug"), + }, + Load: []a_config.Load{ + { + NumberOfUpkeeps: ptr.Ptr(1), + NumberOfEvents: ptr.Ptr(2), + NumberOfSpamMatchingEvents: ptr.Ptr(3), + NumberOfSpamNonMatchingEvents: ptr.Ptr(4), + CheckBurnAmount: big.NewInt(5), + PerformBurnAmount: big.NewInt(6), + SharedTrigger: ptr.Ptr(true), + }, + { + NumberOfUpkeeps: ptr.Ptr(3), + NumberOfEvents: ptr.Ptr(2), + NumberOfSpamMatchingEvents: ptr.Ptr(3), + NumberOfSpamNonMatchingEvents: ptr.Ptr(7), + CheckBurnAmount: big.NewInt(5), + PerformBurnAmount: big.NewInt(6), + SharedTrigger: ptr.Ptr(false), + }, + }, + }, + Network: &ctf_config.NetworkConfig{ + SelectedNetworks: []string{"OPTIMISM_GOERLI"}, + RpcHttpUrls: map[string][]string{ + "OPTIMISM_GOERLI": {"http://localhost:8545"}, + }, + WalletKeys: map[string][]string{ + "OPTIMISM_GOERLI": {"0x3333333333333333333333333333333333333333"}, + }, + }, + } + + configMarshalled, err := toml.Marshal(testConfig) + require.NoError(t, err, "Error marshalling test config") + + testConfigEncoded := base64.StdEncoding.EncodeToString(configMarshalled) + os.Setenv(Base64OverrideEnvVarName, testConfigEncoded) + + readConfig, err := GetConfig("test", Automation) + require.NoError(t, err, "Error reading config") + + require.NotNil(t, readConfig.Automation, "Automation config read from base64 is nil") + require.Equal(t, testConfig.Automation.General, readConfig.Automation.General, "General automation config does not match expected") + require.EqualValues(t, testConfig.Automation.Load, readConfig.Automation.Load, "Load automation config does not match expected") + require.NotNil(t, readConfig.Network, "Network config read from base64 is nil") + require.Equal(t, testConfig.Network.SelectedNetworks, readConfig.Network.SelectedNetworks, "SelectedNetwork config entry read from base64 does not match expected") + require.Equal(t, []string{"http://localhost:8545"}, readConfig.Network.RpcHttpUrls["OPTIMISM_GOERLI"], "RpcHttpUrls config entry read from base64 does not match expected") + require.Equal(t, []string{"wss://devnet-2.mt/ABC/rpc/"}, readConfig.Network.RpcWsUrls["OPTIMISM_GOERLI"], "RpcWsUrls config entry read from base64 network defaults does not match expected") + require.Equal(t, testConfig.Network.WalletKeys, readConfig.Network.WalletKeys, "WalletKeys config entry read from base64 does not match expected") +} diff --git a/integration-tests/testconfig/vrf/config.go b/integration-tests/testconfig/vrf/config.go new file mode 100644 index 0000000000..d009f5bf66 --- /dev/null +++ b/integration-tests/testconfig/vrf/config.go @@ -0,0 +1,8 @@ +package vrf + +type Config struct { +} + +func (o *Config) Validate() error { + return nil +} diff --git a/integration-tests/testconfig/vrfv2/config.go b/integration-tests/testconfig/vrfv2/config.go new file mode 100644 index 0000000000..f539d91799 --- /dev/null +++ b/integration-tests/testconfig/vrfv2/config.go @@ -0,0 +1,330 @@ +package testconfig + +import ( + "errors" + + "github.com/ethereum/go-ethereum/common" + + "github.com/smartcontractkit/chainlink-testing-framework/blockchain" +) + +const ( + ErrDeviationShouldBeLessThanOriginal = "`RandomnessRequestCountPerRequestDeviation` should be less than `RandomnessRequestCountPerRequest`" +) + +type Config struct { + Common *Common `toml:"Common"` + General *General `toml:"General"` + ExistingEnvConfig *ExistingEnvConfig `toml:"ExistingEnv"` + NewEnvConfig *NewEnvConfig `toml:"NewEnv"` + Performance *PerformanceConfig `toml:"Performance"` +} + +func (c *Config) Validate() error { + if c.Common != nil { + if err := c.Common.Validate(); err != nil { + return err + } + } + if c.General != nil { + if err := c.General.Validate(); err != nil { + return err + } + } + if c.Performance != nil { + if err := c.Performance.Validate(); err != nil { + return err + } + if *c.Performance.UseExistingEnv { + if c.ExistingEnvConfig != nil { + if err := c.ExistingEnvConfig.Validate(); err != nil { + return err + } + } + } else { + if c.NewEnvConfig != nil { + if err := c.NewEnvConfig.Validate(); err != nil { + return err + } + } + } + } + + return nil +} + +type Common struct { + CancelSubsAfterTestRun *bool `toml:"cancel_subs_after_test_run"` +} + +func (c *Common) Validate() error { + return nil +} + +type PerformanceConfig struct { + TestDuration *blockchain.StrDuration `toml:"test_duration"` + RPS *int64 `toml:"rps"` + RateLimitUnitDuration *blockchain.StrDuration `toml:"rate_limit_unit_duration"` + + // Using existing environment and contracts + UseExistingEnv *bool `toml:"use_existing_env"` + CoordinatorAddress *string + ConsumerAddress *string + LinkAddress *string + SubID *uint64 + KeyHash *string +} + +func (c *PerformanceConfig) Validate() error { + if c.TestDuration == nil || c.TestDuration.Duration == 0 { + return errors.New("test_duration must be set to a positive value") + } + if c.RPS == nil || *c.RPS == 0 { + return errors.New("rps must be set to a positive value") + } + if c.RateLimitUnitDuration == nil { + return errors.New("rate_limit_unit_duration must be set ") + } + if c.UseExistingEnv == nil { + return errors.New("use_existing_env must be set ") + } + + return nil +} + +type ExistingEnvConfig struct { + CoordinatorAddress *string `toml:"coordinator_address"` + ConsumerAddress *string `toml:"consumer_address"` + LinkAddress *string `toml:"link_address"` + SubID *uint64 `toml:"sub_id"` + KeyHash *string `toml:"key_hash"` + CreateFundSubsAndAddConsumers *bool `toml:"create_fund_subs_and_add_consumers"` + NodeSendingKeys []string `toml:"node_sending_keys"` + Funding +} + +func (c *ExistingEnvConfig) Validate() error { + if c.CreateFundSubsAndAddConsumers == nil { + return errors.New("create_fund_subs_and_add_consumers must be set ") + } + if c.CoordinatorAddress == nil { + return errors.New("coordinator_address must be set when using existing environment") + } + if !common.IsHexAddress(*c.CoordinatorAddress) { + return errors.New("coordinator_address must be a valid hex address") + } + if c.KeyHash == nil { + return errors.New("key_hash must be set when using existing environment") + } + if *c.KeyHash == "" { + return errors.New("key_hash must be a non-empty string") + } + if c.LinkAddress != nil && !common.IsHexAddress(*c.LinkAddress) { + return errors.New("link_address must be a valid hex address") + } + + if *c.CreateFundSubsAndAddConsumers { + if err := c.Funding.Validate(); err != nil { + return err + } + if err := c.Funding.SubFunding.Validate(); err != nil { + return err + } + } else { + if c.ConsumerAddress == nil || *c.ConsumerAddress == "" { + return errors.New("consumer_address must be set when using existing environment") + } + if !common.IsHexAddress(*c.ConsumerAddress) { + return errors.New("consumer_address must be a valid hex address") + } + if c.SubID == nil { + return errors.New("sub_id must be set when using existing environment") + } + if *c.SubID == 0 { + return errors.New("sub_id must be a positive value") + } + } + + if c.NodeSendingKeys != nil { + for _, key := range c.NodeSendingKeys { + if !common.IsHexAddress(key) { + return errors.New("node_sending_keys must be a valid hex address") + } + } + } + + return nil +} + +type NewEnvConfig struct { + *Funding +} + +func (c *NewEnvConfig) Validate() error { + if c.Funding != nil { + return c.Funding.Validate() + } + + return nil +} + +type Funding struct { + SubFunding + NodeSendingKeyFunding *float64 `toml:"node_sending_key_funding"` + NodeSendingKeyFundingMin *float64 `toml:"node_sending_key_funding_min"` +} + +func (c *Funding) Validate() error { + if c.NodeSendingKeyFunding != nil && *c.NodeSendingKeyFunding <= 0 { + return errors.New("when set node_sending_key_funding must be a positive value") + } + if c.NodeSendingKeyFundingMin != nil && *c.NodeSendingKeyFundingMin <= 0 { + return errors.New("when set node_sending_key_funding_min must be a positive value") + } + + return nil +} + +type SubFunding struct { + SubFundsLink *float64 `toml:"sub_funds_link"` +} + +func (c *SubFunding) Validate() error { + if c.SubFundsLink != nil && *c.SubFundsLink < 0 { + return errors.New("when set sub_funds_link must be a non-negative value") + } + + return nil +} + +type General struct { + CLNodeMaxGasPriceGWei *int64 `toml:"max_gas_price_gwei"` // Max gas price in GWei for the chainlink node + LinkNativeFeedResponse *int64 `toml:"link_native_feed_response"` // Response of the LINK/ETH feed + MinimumConfirmations *uint16 `toml:"minimum_confirmations" ` // Minimum number of confirmations for the VRF Coordinator + SubscriptionFundingAmountLink *float64 `toml:"subscription_funding_amount_link"` // Amount of LINK to fund the subscription with + NumberOfWords *uint32 `toml:"number_of_words" ` // Number of words to request + CallbackGasLimit *uint32 `toml:"callback_gas_limit" ` // Gas limit for the callback + MaxGasLimitCoordinatorConfig *uint32 `toml:"max_gas_limit_coordinator_config"` // Max gas limit for the VRF Coordinator config + FallbackWeiPerUnitLink *int64 `toml:"fallback_wei_per_unit_link"` // Fallback wei per unit LINK for the VRF Coordinator config + StalenessSeconds *uint32 `toml:"staleness_seconds" ` // Staleness in seconds for the VRF Coordinator config + GasAfterPaymentCalculation *uint32 `toml:"gas_after_payment_calculation" ` // Gas after payment calculation for the VRF Coordinator + FulfillmentFlatFeeLinkPPMTier1 *uint32 `toml:"fulfilment_flat_fee_link_ppm_tier_1"` + FulfillmentFlatFeeLinkPPMTier2 *uint32 `toml:"fulfilment_flat_fee_link_ppm_tier_2"` + FulfillmentFlatFeeLinkPPMTier3 *uint32 `toml:"fulfilment_flat_fee_link_ppm_tier_3"` + FulfillmentFlatFeeLinkPPMTier4 *uint32 `toml:"fulfilment_flat_fee_link_ppm_tier_4"` + FulfillmentFlatFeeLinkPPMTier5 *uint32 `toml:"fulfilment_flat_fee_link_ppm_tier_5"` + ReqsForTier2 *int64 `toml:"reqs_for_tier_2"` + ReqsForTier3 *int64 `toml:"reqs_for_tier_3"` + ReqsForTier4 *int64 `toml:"reqs_for_tier_4"` + ReqsForTier5 *int64 `toml:"reqs_for_tier_5"` + + NumberOfSubToCreate *int `toml:"number_of_sub_to_create"` // Number of subscriptions to create + + RandomnessRequestCountPerRequest *uint16 `toml:"randomness_request_count_per_request"` // How many randomness requests to send per request + RandomnessRequestCountPerRequestDeviation *uint16 `toml:"randomness_request_count_per_request_deviation"` // How many randomness requests to send per request + + RandomWordsFulfilledEventTimeout *blockchain.StrDuration `toml:"random_words_fulfilled_event_timeout"` // How long to wait for the RandomWordsFulfilled event to be emitted + + // Wrapper Config + WrapperGasOverhead *uint32 `toml:"wrapped_gas_overhead"` + CoordinatorGasOverhead *uint32 `toml:"coordinator_gas_overhead"` + WrapperPremiumPercentage *uint8 `toml:"wrapper_premium_percentage"` + WrapperMaxNumberOfWords *uint8 `toml:"wrapper_max_number_of_words"` + WrapperConsumerFundingAmountNativeToken *float64 `toml:"wrapper_consumer_funding_amount_native_token"` + WrapperConsumerFundingAmountLink *int64 `toml:"wrapper_consumer_funding_amount_link"` +} + +func (c *General) Validate() error { + if c.CLNodeMaxGasPriceGWei == nil || *c.CLNodeMaxGasPriceGWei == 0 { + return errors.New("max_gas_price_gwei must be set to a positive value") + } + if c.LinkNativeFeedResponse == nil || *c.LinkNativeFeedResponse == 0 { + return errors.New("link_native_feed_response must be set to a positive value") + } + if c.MinimumConfirmations == nil { + return errors.New("minimum_confirmations must be set to a non-negative value") + } + if c.SubscriptionFundingAmountLink == nil || *c.SubscriptionFundingAmountLink == 0 { + return errors.New("subscription_funding_amount_link must be set to a positive value") + } + if c.NumberOfWords == nil || *c.NumberOfWords == 0 { + return errors.New("number_of_words must be set to a positive value") + } + if c.CallbackGasLimit == nil || *c.CallbackGasLimit == 0 { + return errors.New("callback_gas_limit must be set to a positive value") + } + if c.MaxGasLimitCoordinatorConfig == nil || *c.MaxGasLimitCoordinatorConfig == 0 { + return errors.New("max_gas_limit_coordinator_config must be set to a positive value") + } + if c.FallbackWeiPerUnitLink == nil || *c.FallbackWeiPerUnitLink == 0 { + return errors.New("fallback_wei_per_unit_link must be set to a positive value") + } + if c.StalenessSeconds == nil || *c.StalenessSeconds == 0 { + return errors.New("staleness_seconds must be set to a positive value") + } + if c.GasAfterPaymentCalculation == nil || *c.GasAfterPaymentCalculation == 0 { + return errors.New("gas_after_payment_calculation must be set to a positive value") + } + if c.FulfillmentFlatFeeLinkPPMTier1 == nil || *c.FulfillmentFlatFeeLinkPPMTier1 == 0 { + return errors.New("fulfilment_flat_fee_link_ppm_tier_1 must be set to a positive value") + } + if c.FulfillmentFlatFeeLinkPPMTier2 == nil || *c.FulfillmentFlatFeeLinkPPMTier2 == 0 { + return errors.New("fulfilment_flat_fee_link_ppm_tier_2 must be set to a positive value") + } + if c.FulfillmentFlatFeeLinkPPMTier3 == nil || *c.FulfillmentFlatFeeLinkPPMTier3 == 0 { + return errors.New("fulfilment_flat_fee_link_ppm_tier_3 must be set to a positive value") + } + if c.FulfillmentFlatFeeLinkPPMTier4 == nil || *c.FulfillmentFlatFeeLinkPPMTier4 == 0 { + return errors.New("fulfilment_flat_fee_link_ppm_tier_4 must be set to a positive value") + } + if c.FulfillmentFlatFeeLinkPPMTier5 == nil || *c.FulfillmentFlatFeeLinkPPMTier5 == 0 { + return errors.New("fulfilment_flat_fee_link_ppm_tier_5 must be set to a positive value") + } + if c.ReqsForTier2 == nil || *c.ReqsForTier2 < 0 { + return errors.New("reqs_for_tier_2 must be set to a non-negative value") + } + if c.ReqsForTier3 == nil || *c.ReqsForTier3 < 0 { + return errors.New("reqs_for_tier_3 must be set to a non-negative value") + } + if c.ReqsForTier4 == nil || *c.ReqsForTier4 < 0 { + return errors.New("reqs_for_tier_4 must be set to a non-negative value") + } + if c.ReqsForTier5 == nil || *c.ReqsForTier5 < 0 { + return errors.New("reqs_for_tier_5 must be set to a non-negative value") + } + if c.NumberOfSubToCreate == nil || *c.NumberOfSubToCreate == 0 { + return errors.New("number_of_sub_to_create must be set to a positive value") + } + if c.RandomnessRequestCountPerRequest == nil || *c.RandomnessRequestCountPerRequest == 0 { + return errors.New("randomness_request_count_per_request must be set to a positive value") + } + if c.RandomnessRequestCountPerRequestDeviation == nil { + return errors.New("randomness_request_count_per_request_deviation must be set to a non-negative value") + } + if c.RandomWordsFulfilledEventTimeout == nil || c.RandomWordsFulfilledEventTimeout.Duration == 0 { + return errors.New("random_words_fulfilled_event_timeout must be set to a positive value") + } + if c.WrapperGasOverhead == nil { + return errors.New("wrapped_gas_overhead must be set to a non-negative value") + } + if c.CoordinatorGasOverhead == nil || *c.CoordinatorGasOverhead == 0 { + return errors.New("coordinator_gas_overhead must be set to a non-negative value") + } + if c.WrapperPremiumPercentage == nil || *c.WrapperPremiumPercentage == 0 { + return errors.New("wrapper_premium_percentage must be set to a positive value") + } + if c.WrapperMaxNumberOfWords == nil || *c.WrapperMaxNumberOfWords == 0 { + return errors.New("wrapper_max_number_of_words must be set to a positive value") + } + if c.WrapperConsumerFundingAmountNativeToken == nil || *c.WrapperConsumerFundingAmountNativeToken < 0 { + return errors.New("wrapper_consumer_funding_amount_native_token must be set to a non-negative value") + } + if c.WrapperConsumerFundingAmountLink == nil || *c.WrapperConsumerFundingAmountLink < 0 { + return errors.New("wrapper_consumer_funding_amount_link must be set to a non-negative value") + } + if *c.RandomnessRequestCountPerRequest <= *c.RandomnessRequestCountPerRequestDeviation { + return errors.New(ErrDeviationShouldBeLessThanOriginal) + } + + return nil +} diff --git a/integration-tests/testconfig/vrfv2/example.toml b/integration-tests/testconfig/vrfv2/example.toml new file mode 100644 index 0000000000..bc826ebe05 --- /dev/null +++ b/integration-tests/testconfig/vrfv2/example.toml @@ -0,0 +1,136 @@ +# Example of full config with all fields +# General part +[ChainlinkImage] +image="public.ecr.aws/chainlink/chainlink" +version="2.7.0" + +[Logging] +# if set to true will save logs even if test did not fail +test_log_collect=false + +[Logging.LogStream] +# supported targets: file, loki, in-memory. if empty no logs will be persistet +log_targets=["file"] +# context timeout for starting log producer and also time-frame for requesting logs +log_producer_timeout="10s" +# number of retries before log producer gives up and stops listening to logs +log_producer_retry_limit=10 + +[Logging.Loki] +tenant_id="tenant_id" +# full URL of Loki ingest endpoint +endpoint="https://loki.url/api/v3/push" +# currently only needed when using public instance +basic_auth="loki-basic-auth" +# only needed for cloud grafana +bearer_token="bearer_token" + +# LogStream will try to shorten Grafana URLs by default (if all 3 variables are set) +[Logging.Grafana] +# grafana url (trailing "/" will be stripped) +base_url="http://grafana.url" +# url of your grafana dashboard (prefix and suffix "/" are stirpped), example: /d/ad61652-2712-1722/my-dashboard +dashboard_url="/d/your-dashboard" +bearer_token="my-awesome-token" + +# if you want to use polygon_mumbial +[Network] +selected_networks=["polygon_mumbai"] + +[Network.RpcHttpUrls] +polygon_mumbai = ["https://my-rpc-endpoint.io"] + +[Network.RpcWsUrls] +polygon_mumbai = ["https://my-rpc-endpoint.io"] + +[Network.WalletKeys] +polygon_mumbai = ["change-me-to-your-PK"] + +[PrivateEthereumNetwork] +# pos or pow +consensus_type="pos" +# only prysm supported currently +consensus_layer="prysm" +# geth, besu, nethermind or erigon +execution_layer="geth" +# if true after env started it will wait for at least 1 epoch to be finalised before continuing +wait_for_finalization=false + +[PrivateEthereumNetwork.EthereumChainConfig] +# duration of single slot, lower => faster block production, must be >= 4 +seconds_per_slot=12 +# numer of slots in epoch, lower => faster epoch finalisation, must be >= 4 +slots_per_epoch=6 +# extra genesis gelay, no need to modify, but it should be after all validators/beacon chain starts +genesis_delay=15 +# number of validators in the network +validator_count=8 +chain_id=1337 +# list of addresses to be prefunded in genesis +addresses_to_fund=["0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266"] + +# Common +[Common] +chainlink_node_funding = 0.5 + +# Product part +[VRFv2] +[VRFv2.Common] +cancel_subs_after_test_run = true + +[VRFv2.General] +max_gas_price_gwei = 1000 +link_native_feed_response = 1000000000000000000 +minimum_confirmations = 3 +subscription_funding_amount_link = 5.0 +number_of_words = 3 +callback_gas_limit = 1000000 +max_gas_limit_coordinator_config = 2500000 +fallback_wei_per_unit_link = 60000000000000000 +staleness_seconds = 86400 +gas_after_payment_calculation = 33825 +fulfilment_flat_fee_link_ppm_tier_1 = 500 +fulfilment_flat_fee_link_ppm_tier_2 = 500 +fulfilment_flat_fee_link_ppm_tier_3 = 500 +fulfilment_flat_fee_link_ppm_tier_4 = 500 +fulfilment_flat_fee_link_ppm_tier_5 = 500 +reqs_for_tier_2 = 0 +reqs_for_tier_3 = 0 +reqs_for_tier_4 = 0 +reqs_for_tier_5 = 0 +number_of_sub_to_create = 1 +randomness_request_count_per_request = 1 +randomness_request_count_per_request_deviation = 0 +random_words_fulfilled_event_timeout = "2m" +wrapped_gas_overhead = 50000 +coordinator_gas_overhead = 52000 +wrapper_premium_percentage = 25 +wrapper_max_number_of_words = 10 +wrapper_consumer_funding_amount_native_token = 1.0 +wrapper_consumer_funding_amount_link = 10 + +[VRFv2.Performance] +rate_limit_unit_duration = "3s" +rps = 1 + +[VRFv2.NewEnv] +sub_funds_link = 1000 +node_sending_key_funding = 1000 + +[VRFv2.ExistingEnv] +coordinator_address = "" +consumer_address = "" +sub_id = 1 +key_hash = "" +create_fund_subs_and_add_consumers = true +link_address = "" +sub_funds_link = 10 +node_sending_key_funding_min = 1 +node_sending_keys = [ + "", + "", + "", + "", + "", + "", +] \ No newline at end of file diff --git a/integration-tests/testconfig/vrfv2/vrfv2.toml b/integration-tests/testconfig/vrfv2/vrfv2.toml new file mode 100644 index 0000000000..64e628c4af --- /dev/null +++ b/integration-tests/testconfig/vrfv2/vrfv2.toml @@ -0,0 +1,143 @@ +# default config +[Common] +chainlink_node_funding = 0.1 + +[VRFv2] +[VRFv2.General] +max_gas_price_gwei = 10 +link_native_feed_response = 1000000000000000000 +minimum_confirmations = 3 +subscription_funding_amount_link = 5.0 +number_of_words = 3 +callback_gas_limit = 1000000 +max_gas_limit_coordinator_config = 2500000 +fallback_wei_per_unit_link = 60000000000000000 +staleness_seconds = 86400 +gas_after_payment_calculation = 33825 +fulfilment_flat_fee_link_ppm_tier_1 = 500 +fulfilment_flat_fee_link_ppm_tier_2 = 500 +fulfilment_flat_fee_link_ppm_tier_3 = 500 +fulfilment_flat_fee_link_ppm_tier_4 = 500 +fulfilment_flat_fee_link_ppm_tier_5 = 500 +reqs_for_tier_2 = 0 +reqs_for_tier_3 = 0 +reqs_for_tier_4 = 0 +reqs_for_tier_5 = 0 +number_of_sub_to_create = 1 +randomness_request_count_per_request = 1 +randomness_request_count_per_request_deviation = 0 +random_words_fulfilled_event_timeout = "2m" +wrapped_gas_overhead = 50000 +coordinator_gas_overhead = 52000 +wrapper_premium_percentage = 25 +wrapper_max_number_of_words = 10 +wrapper_consumer_funding_amount_native_token = 1.0 +wrapper_consumer_funding_amount_link = 10 + +# load test specific config +[Load.VRFv2] +[Load.VRFv2.Common] +cancel_subs_after_test_run = true + +[Load.VRFv2.General] +minimum_confirmations = 3 +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 +number_of_sub_to_create = 1 + +[Load.VRFv2.Performance] +# approx 60 RPM - 1 tx request with 3 rand requests in each tx every 3 seconds +rate_limit_unit_duration = "3s" +rps = 1 + +[Load.VRFv2.NewEnv] +sub_funds_link = 1000 +node_sending_key_funding = 1000 + +[Load.VRFv2.ExistingEnv] +sub_id = 1 +create_fund_subs_and_add_consumers = true +sub_funds_link = 10 +node_sending_key_funding_min = 1 +node_sending_keys = [] + +# soak test specific config +[Soak.VRFv2] +[VRFv2.Common] +cancel_subs_after_test_run = true + +[Soak.VRFv2.General] +minimum_confirmations = 3 +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 +number_of_sub_to_create = 1 + +[Soak.VRFv2.Performance] +# 10 RPM - 1 tx request with 1 rand request in each tx every 6 seconds +rate_limit_unit_duration = "6s" +rps = 1 + +[Soak.VRFv2.NewEnv] +sub_funds_link = 1000 +node_sending_key_funding = 1000 + +[Soak.VRFv2.ExistingEnv] +sub_id = 1 +create_fund_subs_and_add_consumers = true +sub_funds_link = 10 +node_sending_key_funding_min = 1 +node_sending_keys = [] + +# spike test specific config +[Spike.VRFv2] +[Spike.VRFv2.Common] +cancel_subs_after_test_run = true + +[Spike.VRFv2.General] +minimum_confirmations = 3 +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 +number_of_sub_to_create = 1 + +[Spike.VRFv2.Performance] +# approx 150 RPM - 1 tx request with 150 rand requests in each tx every 60 seconds +rate_limit_unit_duration = "1m" +rps = 1 + +[Spike.VRFv2.NewEnv] +sub_funds_link = 1000 +node_sending_key_funding = 1000 + +[Spike.VRFv2.ExistingEnv] +sub_id = 1 +create_fund_subs_and_add_consumers = true +sub_funds_link = 10 +node_sending_key_funding_min = 1 +node_sending_keys = [] + +# stress test specific config +[Stress.VRFv2] +[Stress.VRFv2.Common] +cancel_subs_after_test_run = true + +[Stress.VRFv2.General] +minimum_confirmations = 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 +number_of_sub_to_create = 1 + +[Stress.VRFv2.Performance] +# approx 540 RPM - 3 tx requests per second with 4 rand requests in each tx +rate_limit_unit_duration = "1s" +rps = 3 + +[Stress.VRFv2.NewEnv] +sub_funds_link = 1000 +node_sending_key_funding = 1000 + +[Stress.VRFv2.ExistingEnv] +sub_id = 1 +create_fund_subs_and_add_consumers = true +sub_funds_link = 10 +node_sending_key_funding_min = 1 +node_sending_keys = [] diff --git a/integration-tests/testconfig/vrfv2plus/config.go b/integration-tests/testconfig/vrfv2plus/config.go new file mode 100644 index 0000000000..667803e06b --- /dev/null +++ b/integration-tests/testconfig/vrfv2plus/config.go @@ -0,0 +1,158 @@ +package testconfig + +import ( + "errors" + + vrfv2 "github.com/smartcontractkit/chainlink/integration-tests/testconfig/vrfv2" +) + +type BillingType string + +const ( + BillingType_Link BillingType = "LINK" + BillingType_Native BillingType = "NATIVE" + BillingType_Link_and_Native BillingType = "LINK_AND_NATIVE" +) + +type Config struct { + Common *Common `toml:"Common"` + General *General `toml:"General"` + ExistingEnvConfig *ExistingEnvConfig `toml:"ExistingEnv"` + NewEnvConfig *NewEnvConfig `toml:"NewEnv"` + Performance *vrfv2.PerformanceConfig `toml:"Performance"` +} + +func (c *Config) Validate() error { + if c.Common != nil { + if err := c.Common.Validate(); err != nil { + return err + } + } + if c.General != nil { + if err := c.General.Validate(); err != nil { + return err + } + } + if c.Performance != nil { + if err := c.Performance.Validate(); err != nil { + return err + } + if *c.Performance.UseExistingEnv { + if c.ExistingEnvConfig != nil { + if err := c.ExistingEnvConfig.Validate(); err != nil { + return err + } + } + } else { + if c.NewEnvConfig != nil { + if err := c.NewEnvConfig.Validate(); err != nil { + return err + } + } + } + } + + return nil +} + +type Common struct { + *vrfv2.Common +} + +func (c *Common) Validate() error { + if c.Common == nil { + return nil + } + return c.Common.Validate() +} + +type General struct { + *vrfv2.General + SubscriptionBillingType *string `toml:"subscription_billing_type"` // Billing type for the subscription + SubscriptionFundingAmountNative *float64 `toml:"subscription_funding_amount_native"` // Amount of LINK to fund the subscription with + FulfillmentFlatFeeLinkPPM *uint32 `toml:"fulfillment_flat_fee_link_ppm"` // Flat fee in ppm for LINK for the VRF Coordinator config + FulfillmentFlatFeeNativePPM *uint32 `toml:"fulfillment_flat_fee_native_ppm"` // Flat fee in ppm for native currency for the VRF Coordinator config +} + +func (c *General) Validate() error { + if err := c.General.Validate(); err != nil { + return err + } + if c.SubscriptionBillingType == nil || *c.SubscriptionBillingType == "" { + return errors.New("subscription_billing_type must be set to either: LINK, NATIVE, LINK_AND_NATIVE") + } + if c.SubscriptionFundingAmountNative == nil || *c.SubscriptionFundingAmountNative <= 0 { + return errors.New("subscription_funding_amount_native must be greater than 0") + } + if c.FulfillmentFlatFeeLinkPPM == nil || *c.FulfillmentFlatFeeLinkPPM <= 0 { + return errors.New("fulfillment_flat_fee_link_ppm must be greater than 0") + } + if c.FulfillmentFlatFeeNativePPM == nil || *c.FulfillmentFlatFeeNativePPM <= 0 { + return errors.New("fulfillment_flat_fee_native_ppm must be greater than 0") + } + + return nil +} + +type NewEnvConfig struct { + *Funding +} + +func (c *NewEnvConfig) Validate() error { + if c.Funding == nil { + return nil + } + + return c.Funding.Validate() +} + +type ExistingEnvConfig struct { + *vrfv2.ExistingEnvConfig + Funding +} + +func (c *ExistingEnvConfig) Validate() error { + if c.ExistingEnvConfig != nil { + if err := c.ExistingEnvConfig.Validate(); err != nil { + return err + } + } + + return c.Funding.Validate() +} + +type Funding struct { + SubFunding + NodeSendingKeyFunding *float64 `toml:"node_sending_key_funding"` + NodeSendingKeyFundingMin *float64 `toml:"node_sending_key_funding_min"` +} + +func (c *Funding) Validate() error { + if c.NodeSendingKeyFunding != nil && *c.NodeSendingKeyFunding <= 0 { + return errors.New("when set node_sending_key_funding must be a positive value") + } + if c.NodeSendingKeyFundingMin != nil && *c.NodeSendingKeyFundingMin <= 0 { + return errors.New("when set node_sending_key_funding_min must be a positive value") + } + + return c.SubFunding.Validate() +} + +type SubFunding struct { + SubFundsLink *float64 `toml:"sub_funds_link"` + SubFundsNative *float64 `toml:"sub_funds_native"` +} + +func (c *SubFunding) Validate() error { + if c.SubFundsLink == nil || c.SubFundsNative == nil { + return errors.New("both sub_funds_link and sub_funds_native must be set") + } + if c.SubFundsLink != nil && *c.SubFundsLink < 0 { + return errors.New("sub_funds_link must be a non-negative number") + } + if c.SubFundsNative != nil && *c.SubFundsNative < 0 { + return errors.New("sub_funds_native must be a non-negative number") + } + + return nil +} diff --git a/integration-tests/testconfig/vrfv2plus/example.toml b/integration-tests/testconfig/vrfv2plus/example.toml new file mode 100644 index 0000000000..a9ce5b2dcf --- /dev/null +++ b/integration-tests/testconfig/vrfv2plus/example.toml @@ -0,0 +1,144 @@ +# Example of full config with all fields +# General part +[ChainlinkImage] +image="public.ecr.aws/chainlink/chainlink" +version="2.7.0" + +[Logging] +# if set to true will save logs even if test did not fail +test_log_collect=false + +[Logging.LogStream] +# supported targets: file, loki, in-memory. if empty no logs will be persistet +log_targets=["file"] +# context timeout for starting log producer and also time-frame for requesting logs +log_producer_timeout="10s" +# number of retries before log producer gives up and stops listening to logs +log_producer_retry_limit=10 + +[Logging.Loki] +tenant_id="tenant_id" +# full URL of Loki ingest endpoint +endpoint="https://loki.url/api/v3/push" +# currently only needed when using public instance +basic_auth="loki-basic-auth" +# only needed for cloud grafana +bearer_token="bearer_token" + +# LogStream will try to shorten Grafana URLs by default (if all 3 variables are set) +[Logging.Grafana] +# grafana url (trailing "/" will be stripped) +base_url="http://grafana.url" +# url of your grafana dashboard (prefix and suffix "/" are stirpped), example: /d/ad61652-2712-1722/my-dashboard +dashboard_url="/d/your-dashboard" +bearer_token="my-awesome-token" + +# if you want to use polygon_mumbial +[Network] +selected_networks=["polygon_mumbai"] + +[Network.RpcHttpUrls] +polygon_mumbai = ["https://my-rpc-endpoint.io"] + +[Network.RpcWsUrls] +polygon_mumbai = ["https://my-rpc-endpoint.io"] + +[Network.WalletKeys] +polygon_mumbai = ["change-me-to-your-PK"] + +[PrivateEthereumNetwork] +# pos or pow +consensus_type="pos" +# only prysm supported currently +consensus_layer="prysm" +# geth, besu, nethermind or erigon +execution_layer="geth" +# if true after env started it will wait for at least 1 epoch to be finalised before continuing +wait_for_finalization=false + +[PrivateEthereumNetwork.EthereumChainConfig] +# duration of single slot, lower => faster block production, must be >= 4 +seconds_per_slot=12 +# numer of slots in epoch, lower => faster epoch finalisation, must be >= 4 +slots_per_epoch=6 +# extra genesis gelay, no need to modify, but it should be after all validators/beacon chain starts +genesis_delay=15 +# number of validators in the network +validator_count=8 +chain_id=1337 +# list of addresses to be prefunded in genesis +addresses_to_fund=["0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266"] + +# Common +[Common] +chainlink_node_funding = 0.5 + +# Product part +[VRFv2Plus] +[VRFv2Plus.Common] +cancel_subs_after_test_run = true + +[VRFv2Plus.General] +max_gas_price_gwei = 1000 +link_native_feed_response = 1000000000000000000 +minimum_confirmations = 3 +subscription_billing_type = "LINK_AND_NATIVE" +subscription_funding_amount_link = 5.0 +number_of_words = 3 +callback_gas_limit = 1000000 +max_gas_limit_coordinator_config = 2500000 +fallback_wei_per_unit_link = 60000000000000000 +staleness_seconds = 86400 +gas_after_payment_calculation = 33825 +fulfilment_flat_fee_link_ppm_tier_1 = 500 +fulfilment_flat_fee_link_ppm_tier_2 = 500 +fulfilment_flat_fee_link_ppm_tier_3 = 500 +fulfilment_flat_fee_link_ppm_tier_4 = 500 +fulfilment_flat_fee_link_ppm_tier_5 = 500 +reqs_for_tier_2 = 0 +reqs_for_tier_3 = 0 +reqs_for_tier_4 = 0 +reqs_for_tier_5 = 0 +number_of_sub_to_create = 1 +randomness_request_count_per_request = 1 +randomness_request_count_per_request_deviation = 0 +random_words_fulfilled_event_timeout = "2m" +wrapped_gas_overhead = 50000 +coordinator_gas_overhead = 52000 +wrapper_premium_percentage = 25 +wrapper_max_number_of_words = 10 +wrapper_consumer_funding_amount_native_token = 1.0 +wrapper_consumer_funding_amount_link = 10 +subscription_funding_amount_native=1 +fulfillment_flat_fee_link_ppm=500 +fulfillment_flat_fee_native_ppm=500 + +[VRFv2Plus.Performance] +test_duration = "2m" +rate_limit_unit_duration = "3s" +rps = 1 +use_existing_env = false + +[VRFv2Plus.NewEnv] +sub_funds_link = 1 +sub_funds_native = 1 +node_funds = 10 +node_sending_key_funding = 1000 + +[VRFv2Plus.ExistingEnv] +coordinator_address = "" +consumer_address = "" +sub_id = 1 +key_hash = "" +create_fund_subs_and_add_consumers = true +link_address = "" +sub_funds_link = 10 +node_sending_key_funding_min = 1 +node_sending_keys = [ + "", + "", + "", + "", + "", + "", +] \ No newline at end of file diff --git a/integration-tests/testconfig/vrfv2plus/vrfv2plus.toml b/integration-tests/testconfig/vrfv2plus/vrfv2plus.toml new file mode 100644 index 0000000000..5e187d9de3 --- /dev/null +++ b/integration-tests/testconfig/vrfv2plus/vrfv2plus.toml @@ -0,0 +1,161 @@ +# default config +[Common] +chainlink_node_funding = 0.1 + +[VRFv2Plus] +[VRFv2Plus.General] +max_gas_price_gwei = 10 +link_native_feed_response = 1000000000000000000 +minimum_confirmations = 3 +subscription_billing_type = "LINK_AND_NATIVE" +subscription_funding_amount_link = 5.0 +number_of_words = 3 +callback_gas_limit = 1000000 +max_gas_limit_coordinator_config = 2500000 +fallback_wei_per_unit_link = 60000000000000000 +staleness_seconds = 86400 +gas_after_payment_calculation = 33825 +fulfilment_flat_fee_link_ppm_tier_1 = 500 +fulfilment_flat_fee_link_ppm_tier_2 = 500 +fulfilment_flat_fee_link_ppm_tier_3 = 500 +fulfilment_flat_fee_link_ppm_tier_4 = 500 +fulfilment_flat_fee_link_ppm_tier_5 = 500 +reqs_for_tier_2 = 0 +reqs_for_tier_3 = 0 +reqs_for_tier_4 = 0 +reqs_for_tier_5 = 0 +number_of_sub_to_create = 1 +randomness_request_count_per_request = 1 +randomness_request_count_per_request_deviation = 0 +random_words_fulfilled_event_timeout = "2m" +wrapped_gas_overhead = 50000 +coordinator_gas_overhead = 52000 +wrapper_premium_percentage = 25 +wrapper_max_number_of_words = 10 +wrapper_consumer_funding_amount_native_token = 1.0 +wrapper_consumer_funding_amount_link = 10 +subscription_funding_amount_native=1 +fulfillment_flat_fee_link_ppm=500 +fulfillment_flat_fee_native_ppm=500 + +# load test specific config +[Load.VRFv2Plus] +[Load.VRFv2Plus.Common] +cancel_subs_after_test_run = true + +[Load.VRFv2Plus.General] +minimum_confirmations = 3 +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 +number_of_sub_to_create = 1 + +[Load.VRFv2Plus.Performance] +test_duration = "2m" +# approx 60 RPM - 1 tx request with 3 rand requests in each tx every 3 seconds +rate_limit_unit_duration = "3s" +rps = 1 + +[Load.VRFv2Plus.NewEnv] +sub_funds_link = 1 +sub_funds_native = 1 +node_funds = 10 +node_sending_key_funding = 1000 + +[Load.VRFv2Plus.ExistingEnv] +sub_id = 1 +create_fund_subs_and_add_consumers = true +link_address = "" +sub_funds_link = 10 +node_sending_key_funding_min = 1 +node_sending_keys = [] + +# soak test specific config +[Soak.VRFv2Plus] +[Soak.VRFv2Plus.Common] +cancel_subs_after_test_run = true + +[Soak.VRFv2Plus.General] +minimum_confirmations = 3 +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 +number_of_sub_to_create = 1 + +[Soak.VRFv2Plus.Performance] +test_duration = "2m" +# 10 RPM - 1 tx request with 1 rand request in each tx every 6 seconds +rate_limit_unit_duration = "6s" +rps = 1 +use_existing_env = false + +[Soak.VRFv2Plus.NewEnv] +sub_funds_link = 1 +sub_funds_native = 1 +node_funds = 10 +node_sending_key_funding = 1000 + +[Soak.VRFv2Plus.ExistingEnv] +sub_id = 1 +create_fund_subs_and_add_consumers = true +sub_funds_link = 10 +node_sending_key_funding_min = 1 +node_sending_keys = [] + +# spike test specific config +[Spike.VRFv2Plus] +[Spike.VRFv2Plus.Common] +cancel_subs_after_test_run = true + +[Spike.VRFv2Plus.General] +minimum_confirmations = 3 +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 +number_of_sub_to_create = 1 + +[Spike.VRFv2Plus.Performance] +test_duration = "2m" +# approx 150 RPM - 1 tx request with 150 rand requests in each tx every 60 seconds +rate_limit_unit_duration = "1m" +rps = 1 + +[Spike.VRFv2Plus.NewEnv] +sub_funds_link = 1 +sub_funds_native = 1 +node_funds = 10 +node_sending_key_funding = 1000 + +[Spike.VRFv2Plus.ExistingEnv] +sub_id = 1 +create_fund_subs_and_add_consumers = true +sub_funds_link = 10 +node_sending_key_funding_min = 1 +node_sending_keys = [] + +# stress test specific config +[Stress.VRFv2Plus] +[Stress.VRFv2Plus.Common] +cancel_subs_after_test_run = true + +[Stress.VRFv2Plus.General] +minimum_confirmations = 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 +number_of_sub_to_create = 1 + +[Stress.VRFv2Plus.Performance] +test_duration = "2m" +# approx 540 RPM - 3 tx requests per second with 4 rand requests in each tx +rate_limit_unit_duration = "1s" +rps = 3 + +[Stress.VRFv2Plus.NewEnv] +sub_funds_link = 1 +sub_funds_native = 1 +node_funds = 10 +node_sending_key_funding = 1000 + +[Stress.VRFv2Plus.ExistingEnv] +sub_id = 1 +create_fund_subs_and_add_consumers = true +sub_funds_link = 10 +node_sending_key_funding_min = 1 +node_sending_keys = [] \ No newline at end of file diff --git a/integration-tests/testreporters/keeper_benchmark.go b/integration-tests/testreporters/keeper_benchmark.go index 5db6cca3ec..088ae929ab 100644 --- a/integration-tests/testreporters/keeper_benchmark.go +++ b/integration-tests/testreporters/keeper_benchmark.go @@ -15,11 +15,8 @@ import ( "github.com/slack-go/slack" "github.com/smartcontractkit/chainlink-testing-framework/testreporters" - "github.com/smartcontractkit/chainlink/integration-tests/client" -) -var ( - DashboardUrl = os.Getenv("GRAFANA_DASHBOARD_URL") + "github.com/smartcontractkit/chainlink/integration-tests/client" ) // KeeperBenchmarkTestReporter enables reporting on the keeper benchmark test @@ -249,7 +246,7 @@ func (k *KeeperBenchmarkTestReporter) WriteReport(folderLocation string) error { } // SendSlackNotification sends a slack notification on the results of the test -func (k *KeeperBenchmarkTestReporter) SendSlackNotification(t *testing.T, slackClient *slack.Client) error { +func (k *KeeperBenchmarkTestReporter) SendSlackNotification(t *testing.T, slackClient *slack.Client, grafanaUrlProvider testreporters.GrafanaURLProvider) error { if slackClient == nil { slackClient = slack.New(testreporters.SlackAPIKey) } @@ -267,7 +264,17 @@ func (k *KeeperBenchmarkTestReporter) SendSlackNotification(t *testing.T, slackC return err } - formattedDashboardUrl := fmt.Sprintf("%s&from=%d&to=%d&var-namespace=%s&var-cl_node=chainlink-0-0", DashboardUrl, k.Summary.StartTime, k.Summary.EndTime, k.namespace) + grafanaUrl, err := grafanaUrlProvider.GetGrafanaBaseURL() + if err != nil { + return err + } + + dashboardUrl, err := grafanaUrlProvider.GetGrafanaDashboardURL() + if err != nil { + return err + } + + formattedDashboardUrl := fmt.Sprintf("%s%s?from=%d&to=%d&var-namespace=%s&var-cl_node=chainlink-0-0", grafanaUrl, dashboardUrl, k.Summary.StartTime, k.Summary.EndTime, k.namespace) log.Info().Str("Dashboard", formattedDashboardUrl).Msg("Dashboard URL") if err := testreporters.UploadSlackFile(slackClient, slack.FileUploadParameters{ diff --git a/integration-tests/testreporters/ocr.go b/integration-tests/testreporters/ocr.go index 31f5eeab1b..9a9c4d0d4a 100644 --- a/integration-tests/testreporters/ocr.go +++ b/integration-tests/testreporters/ocr.go @@ -235,7 +235,7 @@ func (o *OCRSoakTestReporter) WriteReport(folderLocation string) error { } // SendNotification sends a slack message to a slack webhook and uploads test artifacts -func (o *OCRSoakTestReporter) SendSlackNotification(t *testing.T, slackClient *slack.Client) error { +func (o *OCRSoakTestReporter) SendSlackNotification(t *testing.T, slackClient *slack.Client, _ testreporters.GrafanaURLProvider) error { if slackClient == nil { slackClient = slack.New(testreporters.SlackAPIKey) } diff --git a/integration-tests/testreporters/profile.go b/integration-tests/testreporters/profile.go index ab9dec138e..464cfd685e 100644 --- a/integration-tests/testreporters/profile.go +++ b/integration-tests/testreporters/profile.go @@ -54,7 +54,7 @@ func (c *ChainlinkProfileTestReporter) WriteReport(folderLocation string) error } // SendNotification hasn't been implemented for this test -func (c *ChainlinkProfileTestReporter) SendSlackNotification(_ *testing.T, _ *slack.Client) error { +func (c *ChainlinkProfileTestReporter) SendSlackNotification(_ *testing.T, _ *slack.Client, _ testreporters.GrafanaURLProvider) error { log.Warn().Msg("No Slack notification integration for Chainlink profile tests") return nil } diff --git a/integration-tests/testreporters/vrfv2.go b/integration-tests/testreporters/vrfv2.go index 2a72e4d91d..4f4c7dc8fd 100644 --- a/integration-tests/testreporters/vrfv2.go +++ b/integration-tests/testreporters/vrfv2.go @@ -3,15 +3,14 @@ package testreporters import ( "fmt" "math/big" - "os" + "strings" "testing" "time" - "github.com/smartcontractkit/chainlink/integration-tests/actions/vrfv2_actions/vrfv2_config" - "github.com/slack-go/slack" "github.com/smartcontractkit/chainlink-testing-framework/testreporters" + "github.com/smartcontractkit/chainlink/integration-tests/types" ) type VRFV2TestReporter struct { @@ -21,7 +20,7 @@ type VRFV2TestReporter struct { AverageFulfillmentInMillions *big.Int SlowestFulfillment *big.Int FastestFulfillment *big.Int - Vrfv2Config *vrfv2_config.VRFV2Config + VRFv2TestConfig types.VRFv2TestConfig } func (o *VRFV2TestReporter) SetReportData( @@ -31,7 +30,7 @@ func (o *VRFV2TestReporter) SetReportData( AverageFulfillmentInMillions *big.Int, SlowestFulfillment *big.Int, FastestFulfillment *big.Int, - vrfv2Config vrfv2_config.VRFV2Config, + vrfv2TestConfig types.VRFv2TestConfig, ) { o.TestType = testType o.RequestCount = RequestCount @@ -39,7 +38,7 @@ func (o *VRFV2TestReporter) SetReportData( o.AverageFulfillmentInMillions = AverageFulfillmentInMillions o.SlowestFulfillment = SlowestFulfillment o.FastestFulfillment = FastestFulfillment - o.Vrfv2Config = &vrfv2Config + o.VRFv2TestConfig = vrfv2TestConfig } // SendSlackNotification sends a slack message to a slack webhook @@ -54,7 +53,14 @@ func (o *VRFV2TestReporter) SendSlackNotification(t *testing.T, slackClient *sla headerText = fmt.Sprintf(":x: VRF V2 %s Test FAILED :x:", o.TestType) } - messageBlocks := testreporters.SlackNotifyBlocks(headerText, os.Getenv("SELECTED_NETWORKS"), []string{ + perfCfg := o.VRFv2TestConfig.GetVRFv2Config().Performance + var sb strings.Builder + for _, n := range o.VRFv2TestConfig.GetNetworkConfig().SelectedNetworks { + sb.WriteString(n) + sb.WriteString(", ") + } + + messageBlocks := testreporters.SlackNotifyBlocks(headerText, sb.String(), []string{ fmt.Sprintf( "Summary\n"+ "Perf Test Type: %s\n"+ @@ -70,17 +76,17 @@ func (o *VRFV2TestReporter) SendSlackNotification(t *testing.T, slackClient *sla "RandomnessRequestCountPerRequest: %d\n"+ "RandomnessRequestCountPerRequestDeviation: %d\n", o.TestType, - o.Vrfv2Config.TestDuration.Truncate(time.Second).String(), - o.Vrfv2Config.UseExistingEnv, + perfCfg.TestDuration.Duration.Truncate(time.Second).String(), + *perfCfg.UseExistingEnv, o.RequestCount.String(), o.FulfilmentCount.String(), o.AverageFulfillmentInMillions.String(), o.SlowestFulfillment.String(), o.FastestFulfillment.String(), - o.Vrfv2Config.RPS, - o.Vrfv2Config.RateLimitUnitDuration.String(), - o.Vrfv2Config.RandomnessRequestCountPerRequest, - o.Vrfv2Config.RandomnessRequestCountPerRequestDeviation, + *perfCfg.RPS, + perfCfg.RateLimitUnitDuration.String(), + *o.VRFv2TestConfig.GetVRFv2Config().General.RandomnessRequestCountPerRequest, + *o.VRFv2TestConfig.GetVRFv2Config().General.RandomnessRequestCountPerRequestDeviation, ), }) diff --git a/integration-tests/testreporters/vrfv2plus.go b/integration-tests/testreporters/vrfv2plus.go index 21e4e52695..8d384b0786 100644 --- a/integration-tests/testreporters/vrfv2plus.go +++ b/integration-tests/testreporters/vrfv2plus.go @@ -3,11 +3,11 @@ package testreporters import ( "fmt" "math/big" - "os" + "strings" "testing" "time" - "github.com/smartcontractkit/chainlink/integration-tests/actions/vrfv2plus/vrfv2plus_config" + "github.com/smartcontractkit/chainlink/integration-tests/types" "github.com/slack-go/slack" @@ -21,7 +21,7 @@ type VRFV2PlusTestReporter struct { AverageFulfillmentInMillions *big.Int SlowestFulfillment *big.Int FastestFulfillment *big.Int - Vrfv2PlusConfig *vrfv2plus_config.VRFV2PlusConfig + VRFv2PlusTestConfig types.VRFv2PlusTestConfig } func (o *VRFV2PlusTestReporter) SetReportData( @@ -31,7 +31,7 @@ func (o *VRFV2PlusTestReporter) SetReportData( AverageFulfillmentInMillions *big.Int, SlowestFulfillment *big.Int, FastestFulfillment *big.Int, - vrfv2PlusConfig vrfv2plus_config.VRFV2PlusConfig, + vtfv2PlusTestConfig types.VRFv2PlusTestConfig, ) { o.TestType = testType o.RequestCount = RequestCount @@ -39,11 +39,11 @@ func (o *VRFV2PlusTestReporter) SetReportData( o.AverageFulfillmentInMillions = AverageFulfillmentInMillions o.SlowestFulfillment = SlowestFulfillment o.FastestFulfillment = FastestFulfillment - o.Vrfv2PlusConfig = &vrfv2PlusConfig + o.VRFv2PlusTestConfig = vtfv2PlusTestConfig } // SendSlackNotification sends a slack message to a slack webhook -func (o *VRFV2PlusTestReporter) SendSlackNotification(t *testing.T, slackClient *slack.Client) error { +func (o *VRFV2PlusTestReporter) SendSlackNotification(t *testing.T, slackClient *slack.Client, vtfv2PlusTestConfig types.VRFv2PlusTestConfig) error { if slackClient == nil { slackClient = slack.New(testreporters.SlackAPIKey) } @@ -54,7 +54,8 @@ func (o *VRFV2PlusTestReporter) SendSlackNotification(t *testing.T, slackClient headerText = fmt.Sprintf(":x: VRF V2 Plus %s Test FAILED :x:", o.TestType) } - messageBlocks := testreporters.SlackNotifyBlocks(headerText, os.Getenv("SELECTED_NETWORKS"), []string{ + vrfv2lusConfig := o.VRFv2PlusTestConfig.GetVRFv2PlusConfig().Performance + messageBlocks := testreporters.SlackNotifyBlocks(headerText, strings.Join(vtfv2PlusTestConfig.GetNetworkConfig().SelectedNetworks, ","), []string{ fmt.Sprintf( "Summary\n"+ "Perf Test Type: %s\n"+ @@ -70,17 +71,17 @@ func (o *VRFV2PlusTestReporter) SendSlackNotification(t *testing.T, slackClient "RandomnessRequestCountPerRequest: %d\n"+ "RandomnessRequestCountPerRequestDeviation: %d\n", o.TestType, - o.Vrfv2PlusConfig.TestDuration.Truncate(time.Second).String(), - o.Vrfv2PlusConfig.UseExistingEnv, + vrfv2lusConfig.TestDuration.Duration.Truncate(time.Second).String(), + *vrfv2lusConfig.UseExistingEnv, o.RequestCount.String(), o.FulfilmentCount.String(), o.AverageFulfillmentInMillions.String(), o.SlowestFulfillment.String(), o.FastestFulfillment.String(), - o.Vrfv2PlusConfig.RPS, - o.Vrfv2PlusConfig.RateLimitUnitDuration.String(), - o.Vrfv2PlusConfig.RandomnessRequestCountPerRequest, - o.Vrfv2PlusConfig.RandomnessRequestCountPerRequestDeviation, + *vrfv2lusConfig.RPS, + vrfv2lusConfig.RateLimitUnitDuration.String(), + *o.VRFv2PlusTestConfig.GetVRFv2PlusConfig().General.RandomnessRequestCountPerRequest, + *o.VRFv2PlusTestConfig.GetVRFv2PlusConfig().General.RandomnessRequestCountPerRequestDeviation, ), }) diff --git a/integration-tests/testsetups/keeper_benchmark.go b/integration-tests/testsetups/keeper_benchmark.go index 575ed3e7de..1330ea291b 100644 --- a/integration-tests/testsetups/keeper_benchmark.go +++ b/integration-tests/testsetups/keeper_benchmark.go @@ -38,6 +38,7 @@ import ( "github.com/smartcontractkit/chainlink/integration-tests/contracts" "github.com/smartcontractkit/chainlink/integration-tests/contracts/ethereum" "github.com/smartcontractkit/chainlink/integration-tests/testreporters" + tt "github.com/smartcontractkit/chainlink/integration-tests/types" ) // KeeperBenchmarkTest builds a test to check that chainlink nodes are able to upkeep a specified amount of Upkeep @@ -59,6 +60,7 @@ type KeeperBenchmarkTest struct { namespace string chainlinkNodes []*client.ChainlinkK8sClient chainClient blockchain.EVMClient + testConfig tt.KeeperBenchmarkTestConfig contractDeployer contracts.ContractDeployer linkToken contracts.LinkToken @@ -113,13 +115,14 @@ func NewKeeperBenchmarkTest(t *testing.T, inputs KeeperBenchmarkTestInputs) *Kee } // Setup prepares contracts for the test -func (k *KeeperBenchmarkTest) Setup(env *environment.Environment) { +func (k *KeeperBenchmarkTest) Setup(env *environment.Environment, config tt.KeeperBenchmarkTestConfig) { startTime := time.Now() k.TestReporter.Summary.StartTime = startTime.UnixMilli() k.ensureInputValues() k.env = env k.namespace = k.env.Cfg.Namespace inputs := k.Inputs + k.testConfig = config k.keeperRegistries = make([]contracts.KeeperRegistry, len(inputs.RegistryVersions)) k.keeperRegistrars = make([]contracts.KeeperRegistrar, len(inputs.RegistryVersions)) @@ -202,7 +205,7 @@ func (k *KeeperBenchmarkTest) Setup(env *environment.Environment) { } k.log.Info().Str("Setup Time", time.Since(startTime).String()).Msg("Finished Keeper Benchmark Test Setup") - err = k.SendSlackNotification(nil) + err = k.SendSlackNotification(nil, config) if err != nil { k.log.Warn().Msg("Sending test start slack notification failed") } @@ -405,9 +408,10 @@ func (k *KeeperBenchmarkTest) TearDownVals(t *testing.T) ( string, []*client.ChainlinkK8sClient, reportModel.TestReporter, + reportModel.GrafanaURLProvider, blockchain.EVMClient, ) { - return t, k.namespace, k.chainlinkNodes, &k.TestReporter, k.chainClient + return t, k.namespace, k.chainlinkNodes, &k.TestReporter, k.testConfig, k.chainClient } // ********************* @@ -571,13 +575,23 @@ func (k *KeeperBenchmarkTest) ensureInputValues() { } } -func (k *KeeperBenchmarkTest) SendSlackNotification(slackClient *slack.Client) error { +func (k *KeeperBenchmarkTest) SendSlackNotification(slackClient *slack.Client, config tt.KeeperBenchmarkTestConfig) error { if slackClient == nil { slackClient = slack.New(reportModel.SlackAPIKey) } + grafanaUrl, err := config.GetGrafanaBaseURL() + if err != nil { + return err + } + + dashboardUrl, err := config.GetGrafanaDashboardURL() + if err != nil { + return err + } + headerText := ":white_check_mark: Automation Benchmark Test STARTED :white_check_mark:" - formattedDashboardUrl := fmt.Sprintf("%s&from=%d&to=%s&var-namespace=%s&var-cl_node=chainlink-0-0", testreporters.DashboardUrl, k.TestReporter.Summary.StartTime, "now", k.env.Cfg.Namespace) + formattedDashboardUrl := fmt.Sprintf("%s%s?from=%d&to=%s&var-namespace=%s&var-cl_node=chainlink-0-0", grafanaUrl, dashboardUrl, k.TestReporter.Summary.StartTime, "now", k.env.Cfg.Namespace) log.Info().Str("Dashboard", formattedDashboardUrl).Msg("Dashboard URL") notificationBlocks := []slack.Block{} diff --git a/integration-tests/testsetups/ocr.go b/integration-tests/testsetups/ocr.go index f7e0e65d36..a2e2fe42ba 100644 --- a/integration-tests/testsetups/ocr.go +++ b/integration-tests/testsetups/ocr.go @@ -10,7 +10,6 @@ import ( "os" "os/signal" "sort" - "strconv" "strings" "syscall" "testing" @@ -19,7 +18,6 @@ import ( geth "github.com/ethereum/go-ethereum" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" - "github.com/kelseyhightower/envconfig" "github.com/pelletier/go-toml/v2" "github.com/rs/zerolog" "github.com/stretchr/testify/require" @@ -29,6 +27,7 @@ import ( "github.com/smartcontractkit/chainlink-testing-framework/blockchain" ctfClient "github.com/smartcontractkit/chainlink-testing-framework/client" + ctf_config "github.com/smartcontractkit/chainlink-testing-framework/config" "github.com/smartcontractkit/chainlink-testing-framework/k8s/environment" "github.com/smartcontractkit/chainlink-testing-framework/k8s/pkg/helm/chainlink" "github.com/smartcontractkit/chainlink-testing-framework/k8s/pkg/helm/ethereum" @@ -44,6 +43,9 @@ import ( "github.com/smartcontractkit/chainlink/integration-tests/config" "github.com/smartcontractkit/chainlink/integration-tests/contracts" "github.com/smartcontractkit/chainlink/integration-tests/testreporters" + tt "github.com/smartcontractkit/chainlink/integration-tests/types" + + tc "github.com/smartcontractkit/chainlink/integration-tests/testconfig" ) const ( @@ -53,7 +55,7 @@ const ( // OCRSoakTest defines a typical OCR soak test type OCRSoakTest struct { - Inputs *OCRSoakTestInputs + Config *tc.TestConfig TestReporter testreporters.OCRSoakTestReporter OperatorForwarderFlow bool @@ -80,51 +82,18 @@ type OCRSoakTest struct { ocrV2InstanceMap map[string]contracts.OffchainAggregatorV2 // address : instance } -// OCRSoakTestInputs define required inputs to run an OCR soak test -type OCRSoakTestInputs struct { - OCRVersion string `envconfig:"OCR_VERSION" default:"1"` // Version of OCR to use (1 or 2) - TestDuration time.Duration `envconfig:"TEST_DURATION" default:"15m"` // How long to run the test for - NumberOfContracts int `envconfig:"NUMBER_CONTRACTS" default:"2"` // Number of OCR contracts to launch - ChainlinkNodeFunding float64 `envconfig:"CHAINLINK_NODE_FUNDING" default:".1"` // Amount of native currency to fund each chainlink node with - bigChainlinkNodeFunding *big.Float // Convenience conversions for funding - TimeBetweenRounds time.Duration `envconfig:"TIME_BETWEEN_ROUNDS" default:"1m"` // How long to wait before starting a new round; controls frequency of rounds -} - -func (i OCRSoakTestInputs) setForRemoteRunner() { - os.Setenv("TEST_OCR_VERSION", i.OCRVersion) - os.Setenv("TEST_OCR_TEST_DURATION", i.TestDuration.String()) - os.Setenv("TEST_OCR_NUMBER_CONTRACTS", fmt.Sprint(i.NumberOfContracts)) - os.Setenv("TEST_OCR_CHAINLINK_NODE_FUNDING", strconv.FormatFloat(i.ChainlinkNodeFunding, 'f', -1, 64)) - os.Setenv("TEST_OCR_TIME_BETWEEN_ROUNDS", i.TimeBetweenRounds.String()) - - selectedNetworks := strings.Split(os.Getenv("SELECTED_NETWORKS"), ",") - for _, networkPrefix := range selectedNetworks { - urlEnv := fmt.Sprintf("%s_URLS", networkPrefix) - httpEnv := fmt.Sprintf("%s_HTTP_URLS", networkPrefix) - os.Setenv(fmt.Sprintf("TEST_%s", urlEnv), os.Getenv(urlEnv)) - os.Setenv(fmt.Sprintf("TEST_%s", httpEnv), os.Getenv(httpEnv)) - } -} - // NewOCRSoakTest creates a new OCR soak test to setup and run -func NewOCRSoakTest(t *testing.T, forwarderFlow bool) (*OCRSoakTest, error) { - var testInputs OCRSoakTestInputs - err := envconfig.Process("OCR", &testInputs) - if err != nil { - return nil, err - } - testInputs.setForRemoteRunner() - +func NewOCRSoakTest(t *testing.T, config *tc.TestConfig, forwarderFlow bool) (*OCRSoakTest, error) { test := &OCRSoakTest{ - Inputs: &testInputs, + Config: config, OperatorForwarderFlow: forwarderFlow, TestReporter: testreporters.OCRSoakTestReporter{ - OCRVersion: testInputs.OCRVersion, + OCRVersion: *config.OCR.Soak.OCRVersion, StartTime: time.Now(), }, t: t, startTime: time.Now(), - timeLeft: testInputs.TestDuration, + timeLeft: config.OCR.Common.TestDuration.Duration, log: logging.GetTestLogger(t), ocrRoundStates: make([]*testreporters.OCRRoundState, 0), ocrV1InstanceMap: make(map[string]contracts.OffchainAggregator), @@ -134,9 +103,9 @@ func NewOCRSoakTest(t *testing.T, forwarderFlow bool) (*OCRSoakTest, error) { } // DeployEnvironment deploys the test environment, starting all Chainlink nodes and other components for the test -func (o *OCRSoakTest) DeployEnvironment(customChainlinkNetworkTOML string) { - network := networks.MustGetSelectedNetworksFromEnv()[0] // Environment currently being used to soak test on - nsPre := fmt.Sprintf("soak-ocr-v%s-", o.Inputs.OCRVersion) +func (o *OCRSoakTest) DeployEnvironment(customChainlinkNetworkTOML string, ocrTestConfig tt.OcrTestConfig) { + network := networks.MustGetSelectedNetworkConfig(ocrTestConfig.GetNetworkConfig())[0] // Environment currently being used to soak test on + nsPre := fmt.Sprintf("soak-ocr-v%s-", *ocrTestConfig.GetOCRConfig().Soak.OCRVersion) if o.OperatorForwarderFlow { nsPre = fmt.Sprintf("%sforwarder-", nsPre) } @@ -149,18 +118,24 @@ func (o *OCRSoakTest) DeployEnvironment(customChainlinkNetworkTOML string) { } var conf string - if o.Inputs.OCRVersion == "1" { + if *ocrTestConfig.GetOCRConfig().Soak.OCRVersion == "1" { conf = config.BaseOCR1Config - } else if o.Inputs.OCRVersion == "2" { + } else if *ocrTestConfig.GetOCRConfig().Soak.OCRVersion == "2" { conf = config.BaseOCR2Config } - cd := chainlink.New(0, map[string]any{ + + var overrideFn = func(_ interface{}, target interface{}) { + ctf_config.MustConfigOverrideChainlinkVersion(ocrTestConfig.GetChainlinkImageConfig(), target) + ctf_config.MightConfigOverridePyroscopeKey(ocrTestConfig.GetPyroscopeConfig(), target) + } + + cd := chainlink.NewWithOverride(0, map[string]any{ "replicas": 6, - "toml": networks.AddNetworkDetailedConfig(conf, customChainlinkNetworkTOML, network), + "toml": networks.AddNetworkDetailedConfig(conf, ocrTestConfig.GetPyroscopeConfig(), customChainlinkNetworkTOML, network), "db": map[string]any{ "stateful": true, // stateful DB by default for soak tests }, - }) + }, ocrTestConfig.GetChainlinkImageConfig(), overrideFn) testEnvironment := environment.New(baseEnvironmentConfig). AddHelm(mockservercfg.New(nil)). @@ -178,9 +153,9 @@ func (o *OCRSoakTest) DeployEnvironment(customChainlinkNetworkTOML string) { } // LoadEnvironment loads an existing test environment using the provided URLs -func (o *OCRSoakTest) LoadEnvironment(chainlinkURLs []string, mockServerURL string) { +func (o *OCRSoakTest) LoadEnvironment(chainlinkURLs []string, mockServerURL string, ocrTestConfig tt.OcrTestConfig) { var ( - network = networks.MustGetSelectedNetworksFromEnv()[0] + network = networks.MustGetSelectedNetworkConfig(ocrTestConfig.GetNetworkConfig())[0] err error ) o.chainClient, err = blockchain.ConnectEVMClient(network, o.log) @@ -197,10 +172,10 @@ func (o *OCRSoakTest) Environment() *environment.Environment { return o.testEnvironment } -func (o *OCRSoakTest) Setup() { +func (o *OCRSoakTest) Setup(ocrTestConfig tt.OcrTestConfig) { var ( err error - network = networks.MustGetSelectedNetworksFromEnv()[0] + network = networks.MustGetSelectedNetworkConfig(ocrTestConfig.GetNetworkConfig())[0] ) // Environment currently being used to soak test on @@ -221,7 +196,8 @@ func (o *OCRSoakTest) Setup() { require.NoError(o.t, err, "Deploying Link Token Contract shouldn't fail") // Fund Chainlink nodes, excluding the bootstrap node - err = actions.FundChainlinkNodes(o.workerNodes, o.chainClient, o.Inputs.bigChainlinkNodeFunding) + o.log.Info().Float64("ETH amount per node", *o.Config.Common.ChainlinkNodeFunding).Msg("Funding Chainlink nodes") + err = actions.FundChainlinkNodes(o.workerNodes, o.chainClient, big.NewFloat(*o.Config.Common.ChainlinkNodeFunding)) require.NoError(o.t, err, "Error funding Chainlink nodes") if o.OperatorForwarderFlow { @@ -244,23 +220,23 @@ func (o *OCRSoakTest) Setup() { o.ocrV1Instances = actions.DeployOCRContractsForwarderFlow( o.t, - o.Inputs.NumberOfContracts, + *o.Config.OCR.Soak.NumberOfContracts, linkTokenContract, contractDeployer, o.workerNodes, authorizedForwarders, o.chainClient, ) - } else if o.Inputs.OCRVersion == "1" { + } else if *ocrTestConfig.GetOCRConfig().Soak.OCRVersion == "1" { o.ocrV1Instances, err = actions.DeployOCRContracts( - o.Inputs.NumberOfContracts, + *o.Config.OCR.Soak.NumberOfContracts, linkTokenContract, contractDeployer, o.workerNodes, o.chainClient, ) require.NoError(o.t, err) - } else if o.Inputs.OCRVersion == "2" { + } else if *ocrTestConfig.GetOCRConfig().Soak.OCRVersion == "2" { var transmitters []string for _, node := range o.workerNodes { nodeAddress, err := node.PrimaryEthAddress() @@ -269,7 +245,7 @@ func (o *OCRSoakTest) Setup() { } ocrOffchainOptions := contracts.DefaultOffChainAggregatorOptions() o.ocrV2Instances, err = actions.DeployOCRv2Contracts( - o.Inputs.NumberOfContracts, + *ocrTestConfig.GetOCRConfig().Soak.NumberOfContracts, linkTokenContract, contractDeployer, transmitters, @@ -285,11 +261,11 @@ func (o *OCRSoakTest) Setup() { err = o.chainClient.WaitForEvents() require.NoError(o.t, err, "Error waiting for OCR contracts to be deployed") - if o.Inputs.OCRVersion == "1" { + if *ocrTestConfig.GetOCRConfig().Soak.OCRVersion == "1" { for _, ocrInstance := range o.ocrV1Instances { o.ocrV1InstanceMap[ocrInstance.Address()] = ocrInstance } - } else if o.Inputs.OCRVersion == "2" { + } else if *ocrTestConfig.GetOCRConfig().Soak.OCRVersion == "2" { for _, ocrInstance := range o.ocrV2Instances { o.ocrV2InstanceMap[ocrInstance.Address()] = ocrInstance } @@ -300,6 +276,9 @@ func (o *OCRSoakTest) Setup() { // Run starts the OCR soak test func (o *OCRSoakTest) Run() { + config, err := tc.GetConfig("soak", tc.OCR) + require.NoError(o.t, err, "Error getting config") + ctx, cancel := context.WithTimeout(testcontext.Get(o.t), time.Second*5) latestBlockNum, err := o.chainClient.LatestBlockNumber(ctx) cancel() @@ -309,21 +288,21 @@ func (o *OCRSoakTest) Run() { startingValue := 5 if o.OperatorForwarderFlow { actions.CreateOCRJobsWithForwarder(o.t, o.ocrV1Instances, o.bootstrapNode, o.workerNodes, startingValue, o.mockServer, o.chainClient.GetChainID().String()) - } else if o.Inputs.OCRVersion == "1" { + } else if *config.OCR.Soak.OCRVersion == "1" { err := actions.CreateOCRJobs(o.ocrV1Instances, o.bootstrapNode, o.workerNodes, startingValue, o.mockServer, o.chainClient.GetChainID().String()) require.NoError(o.t, err, "Error creating OCR jobs") - } else if o.Inputs.OCRVersion == "2" { + } else if *config.OCR.Soak.OCRVersion == "2" { err := actions.CreateOCRv2Jobs(o.ocrV2Instances, o.bootstrapNode, o.workerNodes, o.mockServer, startingValue, o.chainClient.GetChainID().Uint64(), o.OperatorForwarderFlow) require.NoError(o.t, err, "Error creating OCR jobs") } o.log.Info(). - Str("Test Duration", o.Inputs.TestDuration.Truncate(time.Second).String()). - Int("Number of OCR Contracts", o.Inputs.NumberOfContracts). - Str("OCR Version", o.Inputs.OCRVersion). + Str("Test Duration", o.Config.OCR.Common.TestDuration.Duration.Truncate(time.Second).String()). + Int("Number of OCR Contracts", *config.OCR.Soak.NumberOfContracts). + Str("OCR Version", *config.OCR.Soak.OCRVersion). Msg("Starting OCR Soak Test") - o.testLoop(o.Inputs.TestDuration, startingValue) + o.testLoop(o.Config.OCR.Common.TestDuration.Duration, startingValue) o.complete() } @@ -333,9 +312,10 @@ func (o *OCRSoakTest) TearDownVals(t *testing.T) ( string, []*client.ChainlinkK8sClient, reportModel.TestReporter, + reportModel.GrafanaURLProvider, blockchain.EVMClient, ) { - return t, o.namespace, append(o.workerNodes, o.bootstrapNode), &o.TestReporter, o.chainClient + return t, o.namespace, append(o.workerNodes, o.bootstrapNode), &o.TestReporter, o.Config, o.chainClient } // ********************* @@ -375,9 +355,9 @@ func (o *OCRSoakTest) SaveState() error { StartingBlockNum: o.startingBlockNum, StartTime: o.startTime, TimeRunning: time.Since(o.startTime), - TestDuration: o.Inputs.TestDuration, + TestDuration: o.Config.OCR.Common.TestDuration.Duration, OCRContractAddresses: ocrAddresses, - OCRVersion: o.Inputs.OCRVersion, + OCRVersion: *o.Config.OCR.Soak.OCRVersion, ChainURL: o.chainClient.GetNetworkConfig().URL, MockServerURL: "http://mockserver:1080", // TODO: Make this dynamic @@ -426,15 +406,16 @@ func (o *OCRSoakTest) LoadState() error { OCRVersion: testState.OCRVersion, StartTime: testState.StartTime, } + duration := blockchain.StrDuration{Duration: testState.TestDuration} o.ocrRoundStates = testState.OCRRoundStates o.testIssues = testState.TestIssues - o.Inputs.TestDuration = testState.TestDuration + o.Config.OCR.Common.TestDuration = &duration o.timeLeft = testState.TestDuration - testState.TimeRunning o.startTime = testState.StartTime o.startingBlockNum = testState.StartingBlockNum - o.Inputs.OCRVersion = testState.OCRVersion + o.Config.OCR.Soak.OCRVersion = &testState.OCRVersion - network := networks.MustGetSelectedNetworksFromEnv()[0] + network := networks.MustGetSelectedNetworkConfig(o.Config.Network)[0] o.chainClient, err = blockchain.ConnectEVMClient(network, o.log) if err != nil { return err @@ -488,13 +469,13 @@ func (o *OCRSoakTest) Resume() { Message: "Test Resumed", }) o.log.Info(). - Str("Total Duration", o.Inputs.TestDuration.String()). + Str("Total Duration", o.Config.OCR.Common.TestDuration.String()). Str("Time Left", o.timeLeft.String()). Msg("Resuming OCR Soak Test") - ocrAddresses := make([]common.Address, o.Inputs.NumberOfContracts) + ocrAddresses := make([]common.Address, *o.Config.OCR.Soak.NumberOfContracts) - if o.Inputs.OCRVersion == "1" { + if *o.Config.OCR.Soak.OCRVersion == "1" { for i, ocrInstance := range o.ocrV1Instances { ocrAddresses[i] = common.HexToAddress(ocrInstance.Address()) } @@ -505,7 +486,7 @@ func (o *OCRSoakTest) Resume() { Topics: [][]common.Hash{{contractABI.Events["AnswerUpdated"].ID}}, FromBlock: big.NewInt(0).SetUint64(o.startingBlockNum), } - } else if o.Inputs.OCRVersion == "2" { + } else if *o.Config.OCR.Soak.OCRVersion == "2" { for i, ocrInstance := range o.ocrV2Instances { ocrAddresses[i] = common.HexToAddress(ocrInstance.Address()) } @@ -569,7 +550,7 @@ func (o *OCRSoakTest) testLoop(testDuration time.Duration, newValue int) { return case <-newRoundTrigger.C: err := o.triggerNewRound(newValue) - timerReset := o.Inputs.TimeBetweenRounds + timerReset := o.Config.OCR.Soak.TimeBetweenRounds.Duration if err != nil { timerReset = time.Second * 5 o.log.Error().Err(err). @@ -641,7 +622,7 @@ func (o *OCRSoakTest) observeOCREvents() error { for { select { case event := <-eventLogs: - if o.Inputs.OCRVersion == "1" { + if *o.Config.OCR.Soak.OCRVersion == "1" { answerUpdated, err := o.ocrV1Instances[0].ParseEventAnswerUpdated(event) if err != nil { o.log.Warn(). @@ -657,7 +638,7 @@ func (o *OCRSoakTest) observeOCREvents() error { Uint64("Round ID", answerUpdated.RoundId.Uint64()). Int64("Answer", answerUpdated.Current.Int64()). Msg("Answer Updated Event") - } else if o.Inputs.OCRVersion == "2" { + } else if *o.Config.OCR.Soak.OCRVersion == "2" { answerUpdated, err := o.ocrV2Instances[0].ParseEventAnswerUpdated(event) if err != nil { o.log.Warn(). @@ -704,9 +685,9 @@ func (o *OCRSoakTest) triggerNewRound(newValue int) error { } var err error - if o.Inputs.OCRVersion == "1" { + if *o.Config.OCR.Soak.OCRVersion == "1" { err = actions.SetAllAdapterResponsesToTheSameValue(newValue, o.ocrV1Instances, o.workerNodes, o.mockServer) - } else if o.Inputs.OCRVersion == "2" { + } else if *o.Config.OCR.Soak.OCRVersion == "2" { err = actions.SetOCR2AllAdapterResponsesToTheSameValue(newValue, o.ocrV2Instances, o.workerNodes, o.mockServer) } if err != nil { @@ -718,11 +699,11 @@ func (o *OCRSoakTest) triggerNewRound(newValue int) error { Answer: int64(newValue), FoundEvents: make(map[string][]*testreporters.FoundEvent), } - if o.Inputs.OCRVersion == "1" { + if *o.Config.OCR.Soak.OCRVersion == "1" { for _, ocrInstance := range o.ocrV1Instances { expectedState.FoundEvents[ocrInstance.Address()] = make([]*testreporters.FoundEvent, 0) } - } else if o.Inputs.OCRVersion == "2" { + } else if *o.Config.OCR.Soak.OCRVersion == "2" { for _, ocrInstance := range o.ocrV2Instances { expectedState.FoundEvents[ocrInstance.Address()] = make([]*testreporters.FoundEvent, 0) } @@ -763,7 +744,7 @@ func (o *OCRSoakTest) collectEvents() error { sortedFoundEvents := make([]*testreporters.FoundEvent, 0) for _, event := range contractEvents { - if o.Inputs.OCRVersion == "1" { + if *o.Config.OCR.Soak.OCRVersion == "1" { answerUpdated, err := o.ocrV1Instances[0].ParseEventAnswerUpdated(event) if err != nil { return fmt.Errorf("error parsing EventAnswerUpdated for event: %v, %w", event, err) @@ -775,7 +756,7 @@ func (o *OCRSoakTest) collectEvents() error { RoundID: answerUpdated.RoundId.Uint64(), BlockNumber: event.BlockNumber, }) - } else if o.Inputs.OCRVersion == "2" { + } else if *o.Config.OCR.Soak.OCRVersion == "2" { answerUpdated, err := o.ocrV2Instances[0].ParseEventAnswerUpdated(event) if err != nil { return fmt.Errorf("error parsing EventAnswerUpdated for event: %v, %w", event, err) @@ -819,26 +800,26 @@ func (o *OCRSoakTest) collectEvents() error { // ensureValues ensures that all values needed to run the test are present func (o *OCRSoakTest) ensureInputValues() error { - inputs := o.Inputs - if inputs.OCRVersion != "1" && inputs.OCRVersion != "2" { - return fmt.Errorf("OCR version must be 1 or 2, found %s", inputs.OCRVersion) + ocrConfig := o.Config.OCR.Soak + if *ocrConfig.OCRVersion != "1" && *ocrConfig.OCRVersion != "2" { + return fmt.Errorf("OCR version must be 1 or 2, found %s", *ocrConfig.OCRVersion) } - if inputs.NumberOfContracts <= 0 { - return fmt.Errorf("Number of OCR contracts must be greater than 0, found %d", inputs.NumberOfContracts) + if ocrConfig.NumberOfContracts != nil && *ocrConfig.NumberOfContracts <= 0 { + return fmt.Errorf("Number of OCR contracts must be set and greater than 0, found %d", ocrConfig.NumberOfContracts) } - if inputs.ChainlinkNodeFunding <= 0 { - return fmt.Errorf("Chainlink node funding must be greater than 0, found %f", inputs.ChainlinkNodeFunding) + if o.Config.Common.ChainlinkNodeFunding != nil && *o.Config.Common.ChainlinkNodeFunding <= 0 { + return fmt.Errorf("Chainlink node funding must be greater than 0, found %f", *o.Config.Common.ChainlinkNodeFunding) } - if inputs.TestDuration <= time.Minute { - return fmt.Errorf("Test duration must be greater than 1 minute, found %s", inputs.TestDuration.String()) + if o.Config.OCR.Common.TestDuration != nil && o.Config.OCR.Common.TestDuration.Duration <= time.Minute { + return fmt.Errorf("Test duration must be greater than 1 minute, found %s", o.Config.OCR.Common.TestDuration) } - if inputs.TimeBetweenRounds >= time.Hour { - return fmt.Errorf("Time between rounds must be less than 1 hour, found %s", inputs.TimeBetweenRounds.String()) + if ocrConfig.TimeBetweenRounds != nil && ocrConfig.TimeBetweenRounds.Duration >= time.Hour { + return fmt.Errorf("Time between rounds must be less than 1 hour, found %s", ocrConfig.TimeBetweenRounds) } - if inputs.TimeBetweenRounds < time.Second*30 { - return fmt.Errorf("Time between rounds must be greater or equal to 30 seconds, found %s", inputs.TimeBetweenRounds.String()) + if ocrConfig.TimeBetweenRounds != nil && ocrConfig.TimeBetweenRounds.Duration < time.Second*30 { + return fmt.Errorf("Time between rounds must be greater or equal to 30 seconds, found %s", ocrConfig.TimeBetweenRounds) } - o.Inputs.bigChainlinkNodeFunding = big.NewFloat(inputs.ChainlinkNodeFunding) + return nil } diff --git a/integration-tests/types/testconfigs.go b/integration-tests/types/testconfigs.go new file mode 100644 index 0000000000..0c704f0cd7 --- /dev/null +++ b/integration-tests/types/testconfigs.go @@ -0,0 +1,44 @@ +package types + +import ( + "github.com/smartcontractkit/chainlink-testing-framework/testreporters" + tc "github.com/smartcontractkit/chainlink/integration-tests/testconfig" +) + +type VRFv2TestConfig interface { + tc.CommonTestConfig + tc.GlobalTestConfig + tc.VRFv2TestConfig +} + +type VRFv2PlusTestConfig interface { + tc.CommonTestConfig + tc.GlobalTestConfig + tc.VRFv2PlusTestConfig +} + +type FunctionsTestConfig interface { + tc.CommonTestConfig + tc.GlobalTestConfig + tc.FunctionsTestConfig +} + +type AutomationTestConfig interface { + tc.GlobalTestConfig + tc.CommonTestConfig + tc.UpgradeableChainlinkTestConfig +} + +type KeeperBenchmarkTestConfig interface { + tc.GlobalTestConfig + tc.CommonTestConfig + tc.KeeperTestConfig + tc.NamedConfiguration + testreporters.GrafanaURLProvider +} + +type OcrTestConfig interface { + tc.GlobalTestConfig + tc.CommonTestConfig + tc.OcrTestConfig +} diff --git a/integration-tests/universal/log_poller/config.go b/integration-tests/universal/log_poller/config.go deleted file mode 100644 index d42520397e..0000000000 --- a/integration-tests/universal/log_poller/config.go +++ /dev/null @@ -1,249 +0,0 @@ -package logpoller - -import ( - "fmt" - "os" - "strconv" - - "cosmossdk.io/errors" - "github.com/ethereum/go-ethereum/accounts/abi" - "github.com/pelletier/go-toml/v2" - "github.com/rs/zerolog/log" - - commonconfig "github.com/smartcontractkit/chainlink-common/pkg/config" -) - -const ( - DefaultConfigFilename = "config.toml" - - ErrReadPerfConfig = "failed to read TOML config for performance tests" - ErrUnmarshalPerfConfig = "failed to unmarshal TOML config for performance tests" -) - -type GeneratorType = string - -const ( - GeneratorType_WASP = "wasp" - GeneratorType_Looped = "looped" -) - -type Config struct { - General *General `toml:"general"` - ChaosConfig *ChaosConfig `toml:"chaos"` - Wasp *WaspConfig `toml:"wasp"` - LoopedConfig *LoopedConfig `toml:"looped"` -} - -type LoopedConfig struct { - ContractConfig `toml:"contract"` - FuzzConfig `toml:"fuzz"` -} - -type ContractConfig struct { - ExecutionCount int `toml:"execution_count"` -} - -type FuzzConfig struct { - MinEmitWaitTimeMs int `toml:"min_emit_wait_time_ms"` - MaxEmitWaitTimeMs int `toml:"max_emit_wait_time_ms"` -} - -type General struct { - Generator string `toml:"generator"` - EventsToEmit []abi.Event `toml:"-"` - Contracts int `toml:"contracts"` - EventsPerTx int `toml:"events_per_tx"` - UseFinalityTag bool `toml:"use_finality_tag"` -} - -type ChaosConfig struct { - ExperimentCount int `toml:"experiment_count"` -} - -type WaspConfig struct { - Load *Load `toml:"load"` -} - -type Load struct { - RPS int64 `toml:"rps"` - LPS int64 `toml:"lps"` - RateLimitUnitDuration *commonconfig.Duration `toml:"rate_limit_unit_duration"` - Duration *commonconfig.Duration `toml:"duration"` - CallTimeout *commonconfig.Duration `toml:"call_timeout"` -} - -func ReadConfig(configName string) (*Config, error) { - var cfg *Config - d, err := os.ReadFile(configName) - if err != nil { - return nil, errors.Wrap(err, ErrReadPerfConfig) - } - err = toml.Unmarshal(d, &cfg) - if err != nil { - return nil, errors.Wrap(err, ErrUnmarshalPerfConfig) - } - - if err := cfg.validate(); err != nil { - return nil, err - } - - log.Debug().Interface("Config", cfg).Msg("Parsed config") - return cfg, nil -} - -func (c *Config) OverrideFromEnv() error { - if contr := os.Getenv("CONTRACTS"); contr != "" { - c.General.Contracts = mustParseInt(contr) - } - - if eventsPerTx := os.Getenv("EVENTS_PER_TX"); eventsPerTx != "" { - c.General.EventsPerTx = mustParseInt(eventsPerTx) - } - - if useFinalityTag := os.Getenv("USE_FINALITY_TAG"); useFinalityTag != "" { - c.General.UseFinalityTag = mustParseBool(useFinalityTag) - } - - if duration := os.Getenv("LOAD_DURATION"); duration != "" { - d, err := commonconfig.ParseDuration(duration) - if err != nil { - return err - } - - if c.General.Generator == GeneratorType_WASP { - c.Wasp.Load.Duration = &d - } else { - // this is completely arbitrary and practice shows that even with this values - // test executes much longer than specified, probably due to network latency - c.LoopedConfig.FuzzConfig.MinEmitWaitTimeMs = 400 - c.LoopedConfig.FuzzConfig.MaxEmitWaitTimeMs = 600 - // divide by 4 based on past runs, but we should do it in a better way - c.LoopedConfig.ContractConfig.ExecutionCount = int(d.Duration().Seconds() / 4) - } - } - - return nil -} - -func (c *Config) validate() error { - if c.General == nil { - return fmt.Errorf("General config is nil") - } - - err := c.General.validate() - if err != nil { - return fmt.Errorf("General config validation failed: %w", err) - } - - switch c.General.Generator { - case GeneratorType_WASP: - if c.Wasp == nil { - return fmt.Errorf("wasp config is nil") - } - if c.Wasp.Load == nil { - return fmt.Errorf("wasp load config is nil") - } - - err = c.Wasp.validate() - if err != nil { - return fmt.Errorf("wasp config validation failed: %w", err) - } - case GeneratorType_Looped: - if c.LoopedConfig == nil { - return fmt.Errorf("looped config is nil") - } - - err = c.LoopedConfig.validate() - if err != nil { - return fmt.Errorf("looped config validation failed: %w", err) - } - default: - return fmt.Errorf("unknown generator type: %s", c.General.Generator) - } - - return nil -} - -func (g *General) validate() error { - if g.Generator == "" { - return fmt.Errorf("generator is empty") - } - - if g.Contracts == 0 { - return fmt.Errorf("contracts is 0, but must be > 0") - } - - if g.EventsPerTx == 0 { - return fmt.Errorf("events_per_tx is 0, but must be > 0") - } - - return nil -} - -func (w *WaspConfig) validate() error { - if w.Load == nil { - return fmt.Errorf("Load config is nil") - } - - err := w.Load.validate() - if err != nil { - return fmt.Errorf("Load config validation failed: %w", err) - } - - return nil -} - -func (l *Load) validate() error { - if l.RPS == 0 && l.LPS == 0 { - return fmt.Errorf("either RPS or LPS needs to be set") - } - - if l.RPS != 0 && l.LPS != 0 { - return fmt.Errorf("only one of RPS or LPS can be set") - } - - if l.Duration == nil { - return fmt.Errorf("duration is nil") - } - - if l.CallTimeout == nil { - return fmt.Errorf("call_timeout is nil") - } - if l.RateLimitUnitDuration == nil { - return fmt.Errorf("rate_limit_unit_duration is nil") - } - - return nil -} - -func (l *LoopedConfig) validate() error { - if l.ExecutionCount == 0 { - return fmt.Errorf("execution_count is 0, but must be > 0") - } - - if l.MinEmitWaitTimeMs == 0 { - return fmt.Errorf("min_emit_wait_time_ms is 0, but must be > 0") - } - - if l.MaxEmitWaitTimeMs == 0 { - return fmt.Errorf("max_emit_wait_time_ms is 0, but must be > 0") - } - - return nil -} - -func mustParseInt(s string) int { - i, err := strconv.Atoi(s) - if err != nil { - panic(err) - } - return i -} - -func mustParseBool(s string) bool { - b, err := strconv.ParseBool(s) - if err != nil { - panic(err) - } - return b -} diff --git a/integration-tests/universal/log_poller/helpers.go b/integration-tests/universal/log_poller/helpers.go index 8ad115ecec..db7eaee625 100644 --- a/integration-tests/universal/log_poller/helpers.go +++ b/integration-tests/universal/log_poller/helpers.go @@ -17,6 +17,7 @@ import ( "github.com/ethereum/go-ethereum/common" geth_types "github.com/ethereum/go-ethereum/core/types" "github.com/jmoiron/sqlx" + "github.com/onsi/gomega" "github.com/rs/zerolog" "github.com/scylladb/go-reflectx" "github.com/stretchr/testify/require" @@ -29,6 +30,7 @@ import ( "github.com/smartcontractkit/chainlink-testing-framework/logging" "github.com/smartcontractkit/chainlink-testing-framework/networks" "github.com/smartcontractkit/chainlink-testing-framework/utils/ptr" + "github.com/smartcontractkit/chainlink-testing-framework/utils/testcontext" "github.com/smartcontractkit/chainlink/integration-tests/actions" "github.com/smartcontractkit/chainlink/integration-tests/client" "github.com/smartcontractkit/chainlink/integration-tests/contracts" @@ -42,6 +44,9 @@ import ( le "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/log_emitter" core_logger "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/pg" + + tc "github.com/smartcontractkit/chainlink/integration-tests/testconfig" + lp_config "github.com/smartcontractkit/chainlink/integration-tests/testconfig/log_poller" ) var ( @@ -133,6 +138,7 @@ var registerSingleTopicFilter = func(registry contracts.KeeperRegistry, upkeepID // return nil // } +// NewOrm returns a new logpoller.DbORM instance func NewOrm(logger core_logger.SugaredLogger, chainID *big.Int, postgresDb *ctf_test_env.PostgresDb) (*logpoller.DbORM, *sqlx.DB, error) { dsn := fmt.Sprintf("host=%s port=%s user=%s password=%s dbname=%s sslmode=disable", "127.0.0.1", postgresDb.ExternalPort, postgresDb.User, postgresDb.Password, postgresDb.DbName) db, err := sqlx.Open("postgres", dsn) @@ -149,7 +155,8 @@ type ExpectedFilter struct { topic common.Hash } -func getExpectedFilters(logEmitters []*contracts.LogEmitter, cfg *Config) []ExpectedFilter { +// GetExpectedFilters returns a slice of ExpectedFilter structs based on the provided log emitters and config +func GetExpectedFilters(logEmitters []*contracts.LogEmitter, cfg *lp_config.Config) []ExpectedFilter { expectedFilters := make([]ExpectedFilter, 0) for _, emitter := range logEmitters { for _, event := range cfg.General.EventsToEmit { @@ -163,16 +170,17 @@ func getExpectedFilters(logEmitters []*contracts.LogEmitter, cfg *Config) []Expe return expectedFilters } -var nodeHasExpectedFilters = func(expectedFilters []ExpectedFilter, logger core_logger.SugaredLogger, chainID *big.Int, postgresDb *ctf_test_env.PostgresDb) (bool, error) { +// NodeHasExpectedFilters returns true if the provided node has all the expected filters registered +func NodeHasExpectedFilters(expectedFilters []ExpectedFilter, logger core_logger.SugaredLogger, chainID *big.Int, postgresDb *ctf_test_env.PostgresDb) (bool, string, error) { orm, db, err := NewOrm(logger, chainID, postgresDb) if err != nil { - return false, err + return false, "", err } defer db.Close() knownFilters, err := orm.LoadFilters() if err != nil { - return false, err + return false, "", err } for _, expectedFilter := range expectedFilters { @@ -185,14 +193,15 @@ var nodeHasExpectedFilters = func(expectedFilters []ExpectedFilter, logger core_ } if !filterFound { - return false, fmt.Errorf("no filter found for emitter %s and topic %s", expectedFilter.emitterAddress.String(), expectedFilter.topic.Hex()) + return false, fmt.Sprintf("no filter found for emitter %s and topic %s", expectedFilter.emitterAddress.String(), expectedFilter.topic.Hex()), nil } } - return true, nil + return true, "", nil } -var randomWait = func(minMilliseconds, maxMilliseconds int) { +// randomWait waits for a random amount of time between minMilliseconds and maxMilliseconds +func randomWait(minMilliseconds, maxMilliseconds int) { rand.New(rand.NewSource(time.Now().UnixNano())) randomMilliseconds := rand.Intn(maxMilliseconds-minMilliseconds+1) + minMilliseconds time.Sleep(time.Duration(randomMilliseconds) * time.Millisecond) @@ -201,10 +210,9 @@ var randomWait = func(minMilliseconds, maxMilliseconds int) { type LogEmitterChannel struct { logsEmitted int err error - // unused - // currentIndex int } +// getIntSlice returns a slice of ints of the provided length func getIntSlice(length int) []int { result := make([]int, length) for i := 0; i < length; i++ { @@ -214,6 +222,7 @@ func getIntSlice(length int) []int { return result } +// getStringSlice returns a slice of strings of the provided length func getStringSlice(length int) []string { result := make([]string, length) for i := 0; i < length; i++ { @@ -223,75 +232,67 @@ func getStringSlice(length int) []string { return result } -var emitEvents = func(ctx context.Context, l zerolog.Logger, logEmitter *contracts.LogEmitter, cfg *Config, wg *sync.WaitGroup, results chan LogEmitterChannel) { +// emitEvents emits events from the provided log emitter concurrently according to the provided config +func emitEvents(ctx context.Context, l zerolog.Logger, logEmitter *contracts.LogEmitter, cfg *lp_config.Config, wg *sync.WaitGroup, results chan LogEmitterChannel) { address := (*logEmitter).Address().String() localCounter := 0 - select { - case <-ctx.Done(): - l.Warn().Str("Emitter address", address).Msg("Context cancelled, not emitting events") - return - default: - defer wg.Done() - for i := 0; i < cfg.LoopedConfig.ExecutionCount; i++ { - for _, event := range cfg.General.EventsToEmit { + defer wg.Done() + for i := 0; i < *cfg.LoopedConfig.ExecutionCount; i++ { + for _, event := range cfg.General.EventsToEmit { + select { + case <-ctx.Done(): + l.Warn().Str("Emitter address", address).Msg("Context cancelled, not emitting events") + return + default: l.Debug().Str("Emitter address", address).Str("Event type", event.Name).Str("index", fmt.Sprintf("%d/%d", (i+1), cfg.LoopedConfig.ExecutionCount)).Msg("Emitting log from emitter") var err error switch event.Name { case "Log1": - _, err = (*logEmitter).EmitLogInts(getIntSlice(cfg.General.EventsPerTx)) + _, err = (*logEmitter).EmitLogInts(getIntSlice(*cfg.General.EventsPerTx)) case "Log2": - _, err = (*logEmitter).EmitLogIntsIndexed(getIntSlice(cfg.General.EventsPerTx)) + _, err = (*logEmitter).EmitLogIntsIndexed(getIntSlice(*cfg.General.EventsPerTx)) case "Log3": - _, err = (*logEmitter).EmitLogStrings(getStringSlice(cfg.General.EventsPerTx)) + _, err = (*logEmitter).EmitLogStrings(getStringSlice(*cfg.General.EventsPerTx)) + case "Log4": + _, err = (*logEmitter).EmitLogIntMultiIndexed(1, 1, *cfg.General.EventsPerTx) default: err = fmt.Errorf("unknown event name: %s", event.Name) } if err != nil { results <- LogEmitterChannel{ - logsEmitted: 0, - err: err, + err: err, } return } - localCounter += cfg.General.EventsPerTx + localCounter += *cfg.General.EventsPerTx - randomWait(cfg.LoopedConfig.FuzzConfig.MinEmitWaitTimeMs, cfg.LoopedConfig.FuzzConfig.MaxEmitWaitTimeMs) + randomWait(*cfg.LoopedConfig.MinEmitWaitTimeMs, *cfg.LoopedConfig.MaxEmitWaitTimeMs) } if (i+1)%10 == 0 { - l.Info().Str("Emitter address", address).Str("Index", fmt.Sprintf("%d/%d", i+1, cfg.LoopedConfig.ExecutionCount)).Msg("Emitted all three events") + l.Info().Str("Emitter address", address).Str("Index", fmt.Sprintf("%d/%d", i+1, *cfg.LoopedConfig.ExecutionCount)).Msg("Emitted all three events") } } - - l.Info().Str("Emitter address", address).Int("Total logs emitted", localCounter).Msg("Finished emitting events") - - results <- LogEmitterChannel{ - logsEmitted: localCounter, - err: nil, - } } -} -var chainHasFinalisedEndBlock = func(l zerolog.Logger, evmClient blockchain.EVMClient, endBlock int64) (bool, error) { - effectiveEndBlock := endBlock + 1 - lastFinalisedBlockHeader, err := evmClient.GetLatestFinalizedBlockHeader(context.Background()) - if err != nil { - return false, err - } + l.Info().Str("Emitter address", address).Int("Total logs emitted", localCounter).Msg("Finished emitting events") - l.Info().Int64("Last finalised block header", lastFinalisedBlockHeader.Number.Int64()).Int64("End block", effectiveEndBlock).Int64("Blocks left till end block", effectiveEndBlock-lastFinalisedBlockHeader.Number.Int64()).Msg("Waiting for the finalized block to move beyond end block") - - return lastFinalisedBlockHeader.Number.Int64() > effectiveEndBlock, nil + results <- LogEmitterChannel{ + logsEmitted: localCounter, + err: nil, + } } -var logPollerHasFinalisedEndBlock = func(endBlock int64, chainID *big.Int, l zerolog.Logger, coreLogger core_logger.SugaredLogger, nodes *test_env.ClCluster) (bool, error) { +// LogPollerHasFinalisedEndBlock returns true if all CL nodes have finalised processing the provided end block +func LogPollerHasFinalisedEndBlock(endBlock int64, chainID *big.Int, l zerolog.Logger, coreLogger core_logger.SugaredLogger, nodes *test_env.ClCluster) (bool, error) { wg := &sync.WaitGroup{} type boolQueryResult struct { - nodeName string - hasFinalised bool - err error + nodeName string + hasFinalised bool + finalizedBlock int64 + err error } endBlockCh := make(chan boolQueryResult, len(nodes.Nodes)-1) @@ -327,9 +328,10 @@ var logPollerHasFinalisedEndBlock = func(endBlock int64, chainID *big.Int, l zer } r <- boolQueryResult{ - nodeName: clNode.ContainerName, - hasFinalised: latestBlock.FinalizedBlockNumber > endBlock, - err: nil, + nodeName: clNode.ContainerName, + finalizedBlock: latestBlock.FinalizedBlockNumber, + hasFinalised: latestBlock.FinalizedBlockNumber > endBlock, + err: nil, } } @@ -352,7 +354,7 @@ var logPollerHasFinalisedEndBlock = func(endBlock int64, chainID *big.Int, l zer if r.hasFinalised { l.Info().Str("Node name", r.nodeName).Msg("CL node has finalised end block") } else { - l.Warn().Str("Node name", r.nodeName).Msg("CL node has not finalised end block yet") + l.Warn().Int64("Has", r.finalizedBlock).Int64("Want", endBlock).Str("Node name", r.nodeName).Msg("CL node has not finalised end block yet") } if len(foundMap) == len(nodes.Nodes)-1 { @@ -376,7 +378,8 @@ var logPollerHasFinalisedEndBlock = func(endBlock int64, chainID *big.Int, l zer return <-allFinalisedCh, err } -var clNodesHaveExpectedLogCount = func(startBlock, endBlock int64, chainID *big.Int, expectedLogCount int, expectedFilters []ExpectedFilter, l zerolog.Logger, coreLogger core_logger.SugaredLogger, nodes *test_env.ClCluster) (bool, error) { +// ClNodesHaveExpectedLogCount returns true if all CL nodes have the expected log count in the provided block range and matching the provided filters +func ClNodesHaveExpectedLogCount(startBlock, endBlock int64, chainID *big.Int, expectedLogCount int, expectedFilters []ExpectedFilter, l zerolog.Logger, coreLogger core_logger.SugaredLogger, nodes *test_env.ClCluster) (bool, error) { wg := &sync.WaitGroup{} type logQueryResult struct { @@ -386,13 +389,13 @@ var clNodesHaveExpectedLogCount = func(startBlock, endBlock int64, chainID *big. err error } - queryCh := make(chan logQueryResult, len(nodes.Nodes)-1) + resultChan := make(chan logQueryResult, len(nodes.Nodes)-1) ctx, cancelFn := context.WithCancel(context.Background()) for i := 1; i < len(nodes.Nodes); i++ { wg.Add(1) - go func(clNode *test_env.ClNode, r chan logQueryResult) { + go func(clNode *test_env.ClNode, resultChan chan logQueryResult) { defer wg.Done() select { case <-ctx.Done(): @@ -400,7 +403,7 @@ var clNodesHaveExpectedLogCount = func(startBlock, endBlock int64, chainID *big. default: orm, db, err := NewOrm(coreLogger, chainID, clNode.PostgresDb) if err != nil { - r <- logQueryResult{ + resultChan <- logQueryResult{ nodeName: clNode.ContainerName, logCount: 0, hasExpectedCount: false, @@ -414,7 +417,7 @@ var clNodesHaveExpectedLogCount = func(startBlock, endBlock int64, chainID *big. for _, filter := range expectedFilters { logs, err := orm.SelectLogs(startBlock, endBlock, filter.emitterAddress, filter.topic) if err != nil { - r <- logQueryResult{ + resultChan <- logQueryResult{ nodeName: clNode.ContainerName, logCount: 0, hasExpectedCount: false, @@ -425,14 +428,14 @@ var clNodesHaveExpectedLogCount = func(startBlock, endBlock int64, chainID *big. foundLogsCount += len(logs) } - r <- logQueryResult{ + resultChan <- logQueryResult{ nodeName: clNode.ContainerName, logCount: foundLogsCount, hasExpectedCount: foundLogsCount >= expectedLogCount, - err: err, + err: nil, } } - }(nodes.Nodes[i], queryCh) + }(nodes.Nodes[i], resultChan) } var err error @@ -440,7 +443,7 @@ var clNodesHaveExpectedLogCount = func(startBlock, endBlock int64, chainID *big. go func() { foundMap := make(map[string]bool, 0) - for r := range queryCh { + for r := range resultChan { if r.err != nil { err = r.err cancelFn() @@ -449,15 +452,22 @@ var clNodesHaveExpectedLogCount = func(startBlock, endBlock int64, chainID *big. foundMap[r.nodeName] = r.hasExpectedCount if r.hasExpectedCount { - l.Info().Str("Node name", r.nodeName).Int("Logs count", r.logCount).Msg("Expected log count found in CL node") + l.Debug(). + Str("Node name", r.nodeName). + Int("Logs count", r.logCount). + Msg("Expected log count found in CL node") } else { - l.Warn().Str("Node name", r.nodeName).Str("Found/Expected logs", fmt.Sprintf("%d/%d", r.logCount, expectedLogCount)).Int("Missing logs", expectedLogCount-r.logCount).Msg("Too low log count found in CL node") + l.Debug(). + Str("Node name", r.nodeName). + Str("Found/Expected logs", fmt.Sprintf("%d/%d", r.logCount, expectedLogCount)). + Int("Missing logs", expectedLogCount-r.logCount). + Msg("Too low log count found in CL node") } if len(foundMap) == len(nodes.Nodes)-1 { allFound := true - for _, v := range foundMap { - if !v { + for _, hadAllLogs := range foundMap { + if !hadAllLogs { allFound = false break } @@ -470,13 +480,14 @@ var clNodesHaveExpectedLogCount = func(startBlock, endBlock int64, chainID *big. }() wg.Wait() - close(queryCh) + close(resultChan) return <-allFoundCh, err } type MissingLogs map[string][]geth_types.Log +// IsEmpty returns true if there are no missing logs func (m *MissingLogs) IsEmpty() bool { for _, v := range *m { if len(v) > 0 { @@ -487,7 +498,8 @@ func (m *MissingLogs) IsEmpty() bool { return true } -var getMissingLogs = func(startBlock, endBlock int64, logEmitters []*contracts.LogEmitter, evmClient blockchain.EVMClient, clnodeCluster *test_env.ClCluster, l zerolog.Logger, coreLogger core_logger.SugaredLogger, cfg *Config) (MissingLogs, error) { +// GetMissingLogs returns a map of CL node name to missing logs in that node compared to EVM node to which the provided evm client is connected +func GetMissingLogs(startBlock, endBlock int64, logEmitters []*contracts.LogEmitter, evmClient blockchain.EVMClient, clnodeCluster *test_env.ClCluster, l zerolog.Logger, coreLogger core_logger.SugaredLogger, cfg *lp_config.Config) (MissingLogs, error) { wg := &sync.WaitGroup{} type dbQueryResult struct { @@ -511,7 +523,7 @@ var getMissingLogs = func(startBlock, endBlock int64, logEmitters []*contracts.L default: nodeName := clnodeCluster.Nodes[i].ContainerName - l.Info().Str("Node name", nodeName).Msg("Fetching log poller logs") + l.Debug().Str("Node name", nodeName).Msg("Fetching log poller logs") orm, db, err := NewOrm(coreLogger, evmClient.GetChainID(), clnodeCluster.Nodes[i].PostgresDb) if err != nil { r <- dbQueryResult{ @@ -528,7 +540,7 @@ var getMissingLogs = func(startBlock, endBlock int64, logEmitters []*contracts.L address := (*logEmitters[j]).Address() for _, event := range cfg.General.EventsToEmit { - l.Debug().Str("Event name", event.Name).Str("Emitter address", address.String()).Msg("Fetching single emitter's logs") + l.Trace().Str("Event name", event.Name).Str("Emitter address", address.String()).Msg("Fetching single emitter's logs") result, err := orm.SelectLogs(startBlock, endBlock, address, event.ID) if err != nil { r <- dbQueryResult{ @@ -544,11 +556,11 @@ var getMissingLogs = func(startBlock, endBlock int64, logEmitters []*contracts.L logs = append(logs, result...) - l.Debug().Str("Event name", event.Name).Str("Emitter address", address.String()).Int("Log count", len(result)).Msg("Logs found per node") + l.Trace().Str("Event name", event.Name).Str("Emitter address", address.String()).Int("Log count", len(result)).Msg("Logs found per node") } } - l.Warn().Int("Count", len(logs)).Str("Node name", nodeName).Msg("Fetched log poller logs") + l.Info().Int("Count", len(logs)).Str("Node name", nodeName).Msg("Fetched log poller logs") r <- dbQueryResult{ err: nil, @@ -595,16 +607,17 @@ var getMissingLogs = func(startBlock, endBlock int64, logEmitters []*contracts.L logs []geth_types.Log } - l.Info().Msg("Started comparison of logs from EVM node and CL nodes. This may take a while if there's a lot of logs") - missingCh := make(chan missingLogResult, len(clnodeCluster.Nodes)-1) evmLogCount := len(allLogsInEVMNode) + l.Info().Int("Log count", evmLogCount).Msg("Started comparison of logs from EVM node and CL nodes. This may take a while if there's a lot of logs") + + missingCh := make(chan missingLogResult, len(clnodeCluster.Nodes)-1) for i := 1; i < len(clnodeCluster.Nodes); i++ { wg.Add(1) go func(i int, result chan missingLogResult) { defer wg.Done() nodeName := clnodeCluster.Nodes[i].ContainerName - l.Info().Str("Node name", nodeName).Str("Progress", fmt.Sprintf("0/%d", evmLogCount)).Msg("Comparing single CL node's logs with EVM logs") + l.Debug().Str("Node name", nodeName).Str("Progress", fmt.Sprintf("0/%d", evmLogCount)).Msg("Comparing single CL node's logs with EVM logs") missingLogs := make([]geth_types.Log, 0) for i, evmLog := range allLogsInEVMNode { @@ -618,7 +631,7 @@ var getMissingLogs = func(startBlock, endBlock int64, logEmitters []*contracts.L } if i%10000 == 0 && i != 0 { - l.Info().Str("Node name", nodeName).Str("Progress", fmt.Sprintf("%d/%d", i, evmLogCount)).Msg("Comparing single CL node's logs with EVM logs") + l.Debug().Str("Node name", nodeName).Str("Progress", fmt.Sprintf("%d/%d", i, evmLogCount)).Msg("Comparing single CL node's logs with EVM logs") } if !logFound { @@ -648,15 +661,18 @@ var getMissingLogs = func(startBlock, endBlock int64, logEmitters []*contracts.L } } - expectedTotalLogsEmitted := getExpectedLogCount(cfg) + expectedTotalLogsEmitted := GetExpectedLogCount(cfg) if int64(len(allLogsInEVMNode)) != expectedTotalLogsEmitted { - l.Warn().Str("Actual/Expected", fmt.Sprintf("%d/%d", expectedTotalLogsEmitted, len(allLogsInEVMNode))).Msg("Some of the test logs were not found in EVM node. This is a bug in the test") + l.Warn(). + Str("Actual/Expected", fmt.Sprintf("%d/%d", expectedTotalLogsEmitted, len(allLogsInEVMNode))). + Msg("Some of the test logs were not found in EVM node. This is a bug in the test") } return missingLogs, nil } -var printMissingLogsByType = func(missingLogs map[string][]geth_types.Log, l zerolog.Logger, cfg *Config) { +// PrintMissingLogsInfo prints various useful information about the missing logs +func PrintMissingLogsInfo(missingLogs map[string][]geth_types.Log, l zerolog.Logger, cfg *lp_config.Config) { var findHumanName = func(topic common.Hash) string { for _, event := range cfg.General.EventsToEmit { if event.ID == topic { @@ -675,12 +691,39 @@ var printMissingLogsByType = func(missingLogs map[string][]geth_types.Log, l zer } } + l.Debug().Msg("Missing log by event name") for k, v := range missingByType { - l.Warn().Str("Event name", k).Int("Missing count", v).Msg("Missing logs by type") + l.Debug().Str("Event name", k).Int("Missing count", v).Msg("Missing logs by type") + } + + missingByBlock := make(map[uint64]int) + for _, logs := range missingLogs { + for _, l := range logs { + missingByBlock[l.BlockNumber]++ + } + } + + l.Debug().Msg("Missing logs by block") + for k, v := range missingByBlock { + l.Debug().Uint64("Block number", k).Int("Missing count", v).Msg("Missing logs by block") + } + + missingByEmitter := make(map[string]int) + for _, logs := range missingLogs { + for _, l := range logs { + missingByEmitter[l.Address.String()]++ + } + } + + l.Debug().Msg("Missing logs by emitter") + for k, v := range missingByEmitter { + l.Debug().Str("Emitter address", k).Int("Missing count", v).Msg("Missing logs by emitter") } } -var getEVMLogs = func(startBlock, endBlock int64, logEmitters []*contracts.LogEmitter, evmClient blockchain.EVMClient, l zerolog.Logger, cfg *Config) ([]geth_types.Log, error) { +// getEVMLogs returns a slice of all logs emitted by the provided log emitters in the provided block range, +// which are present in the EVM node to which the provided evm client is connected +func getEVMLogs(startBlock, endBlock int64, logEmitters []*contracts.LogEmitter, evmClient blockchain.EVMClient, l zerolog.Logger, cfg *lp_config.Config) ([]geth_types.Log, error) { allLogsInEVMNode := make([]geth_types.Log, 0) for j := 0; j < len(logEmitters); j++ { address := (*logEmitters[j]).Address() @@ -705,27 +748,29 @@ var getEVMLogs = func(startBlock, endBlock int64, logEmitters []*contracts.LogEm } } - l.Warn().Int("Count", len(allLogsInEVMNode)).Msg("Logs in EVM node") + l.Info().Int("Count", len(allLogsInEVMNode)).Msg("Logs in EVM node") return allLogsInEVMNode, nil } -func executeGenerator(t *testing.T, cfg *Config, logEmitters []*contracts.LogEmitter) (int, error) { - if cfg.General.Generator == GeneratorType_WASP { +// ExecuteGenerator executes the configured generator and returns the total number of logs emitted +func ExecuteGenerator(t *testing.T, cfg *lp_config.Config, logEmitters []*contracts.LogEmitter) (int, error) { + if *cfg.General.Generator == lp_config.GeneratorType_WASP { return runWaspGenerator(t, cfg, logEmitters) } return runLoopedGenerator(t, cfg, logEmitters) } -func runWaspGenerator(t *testing.T, cfg *Config, logEmitters []*contracts.LogEmitter) (int, error) { +// runWaspGenerator runs the wasp generator and returns the total number of logs emitted +func runWaspGenerator(t *testing.T, cfg *lp_config.Config, logEmitters []*contracts.LogEmitter) (int, error) { l := logging.GetTestLogger(t) var RPSprime int64 // if LPS is set, we need to calculate based on countract count and events per transaction - if cfg.Wasp.Load.LPS > 0 { - RPSprime = cfg.Wasp.Load.LPS / int64(cfg.General.Contracts) / int64(cfg.General.EventsPerTx) / int64(len(cfg.General.EventsToEmit)) + if *cfg.Wasp.LPS > 0 { + RPSprime = *cfg.Wasp.LPS / int64(*cfg.General.Contracts) / int64(*cfg.General.EventsPerTx) / int64(len(cfg.General.EventsToEmit)) if RPSprime < 1 { return 0, fmt.Errorf("invalid load configuration, effective RPS would have been zero. Adjust LPS, contracts count, events per tx or events to emit") @@ -733,8 +778,8 @@ func runWaspGenerator(t *testing.T, cfg *Config, logEmitters []*contracts.LogEmi } // if RPS is set simply split it between contracts - if cfg.Wasp.Load.RPS > 0 { - RPSprime = cfg.Wasp.Load.RPS / int64(cfg.General.Contracts) + if *cfg.Wasp.RPS > 0 { + RPSprime = *cfg.Wasp.RPS / int64(*cfg.General.Contracts) } counter := &Counter{ @@ -749,16 +794,16 @@ func runWaspGenerator(t *testing.T, cfg *Config, logEmitters []*contracts.LogEmi T: t, LoadType: wasp.RPS, GenName: fmt.Sprintf("log_poller_gen_%s", (*logEmitter).Address().String()), - RateLimitUnitDuration: cfg.Wasp.Load.RateLimitUnitDuration.Duration(), - CallTimeout: cfg.Wasp.Load.CallTimeout.Duration(), + RateLimitUnitDuration: cfg.Wasp.RateLimitUnitDuration.Duration, + CallTimeout: cfg.Wasp.CallTimeout.Duration, Schedule: wasp.Plain( RPSprime, - cfg.Wasp.Load.Duration.Duration(), + cfg.Wasp.Duration.Duration, ), Gun: NewLogEmitterGun( logEmitter, cfg.General.EventsToEmit, - cfg.General.EventsPerTx, + *cfg.General.EventsPerTx, l, ), SharedData: counter, @@ -775,7 +820,8 @@ func runWaspGenerator(t *testing.T, cfg *Config, logEmitters []*contracts.LogEmi return counter.value, nil } -func runLoopedGenerator(t *testing.T, cfg *Config, logEmitters []*contracts.LogEmitter) (int, error) { +// runLoopedGenerator runs the looped generator and returns the total number of logs emitted +func runLoopedGenerator(t *testing.T, cfg *lp_config.Config, logEmitters []*contracts.LogEmitter) (int, error) { l := logging.GetTestLogger(t) // Start emitting events in parallel, each contract is emitting events in a separate goroutine @@ -797,82 +843,119 @@ func runLoopedGenerator(t *testing.T, cfg *Config, logEmitters []*contracts.LogE aggrChan := make(chan int, len(logEmitters)) go func() { - for emitter := range emitterCh { - if emitter.err != nil { - emitErr = emitter.err - cancelFn() + for { + select { + case <-ctx.Done(): return + case emitter := <-emitterCh: + if emitter.err != nil { + emitErr = emitter.err + cancelFn() + return + } + aggrChan <- emitter.logsEmitted } - aggrChan <- emitter.logsEmitted } }() wg.Wait() close(emitterCh) - for i := 0; i < len(logEmitters); i++ { - total += <-aggrChan - } - if emitErr != nil { return 0, emitErr } + for i := 0; i < len(logEmitters); i++ { + total += <-aggrChan + } + return int(total), nil } -func getExpectedLogCount(cfg *Config) int64 { - if cfg.General.Generator == GeneratorType_WASP { - if cfg.Wasp.Load.RPS != 0 { - return cfg.Wasp.Load.RPS * int64(cfg.Wasp.Load.Duration.Duration().Seconds()) * int64(cfg.General.EventsPerTx) +// GetExpectedLogCount returns the expected number of logs to be emitted based on the provided config +func GetExpectedLogCount(cfg *lp_config.Config) int64 { + if *cfg.General.Generator == lp_config.GeneratorType_WASP { + if *cfg.Wasp.RPS != 0 { + return *cfg.Wasp.RPS * int64(cfg.Wasp.Duration.Seconds()) * int64(*cfg.General.EventsPerTx) } - return cfg.Wasp.Load.LPS * int64(cfg.Wasp.Load.Duration.Duration().Seconds()) + return *cfg.Wasp.LPS * int64(cfg.Wasp.Duration.Duration.Seconds()) } - return int64(len(cfg.General.EventsToEmit) * cfg.LoopedConfig.ExecutionCount * cfg.General.Contracts * cfg.General.EventsPerTx) + return int64(len(cfg.General.EventsToEmit) * *cfg.LoopedConfig.ExecutionCount * *cfg.General.Contracts * *cfg.General.EventsPerTx) +} + +type PauseData struct { + StartBlock uint64 + EndBlock uint64 + TargetComponent string + ContaineName string } -var chaosPauseSyncFn = func(l zerolog.Logger, testEnv *test_env.CLClusterTestEnv) error { +var ChaosPauses = []PauseData{} + +// chaosPauseSyncFn pauses ranom container of the provided type for a random amount of time between 5 and 20 seconds +func chaosPauseSyncFn(l zerolog.Logger, testEnv *test_env.CLClusterTestEnv, targetComponent string) ChaosPauseData { rand.New(rand.NewSource(time.Now().UnixNano())) - randomBool := rand.Intn(2) == 0 randomNode := testEnv.ClCluster.Nodes[rand.Intn(len(testEnv.ClCluster.Nodes)-1)+1] var component ctf_test_env.EnvComponent - if randomBool { + switch strings.ToLower(targetComponent) { + case "chainlink": component = randomNode.EnvComponent - } else { + case "postgres": component = randomNode.PostgresDb.EnvComponent + default: + return ChaosPauseData{Err: fmt.Errorf("unknown component %s", targetComponent)} } + ctx := context.Background() + pauseStartBlock, err := testEnv.EVMClient.LatestBlockNumber(ctx) + if err != nil { + return ChaosPauseData{Err: err} + } pauseTimeSec := rand.Intn(20-5) + 5 l.Info().Str("Container", component.ContainerName).Int("Pause time", pauseTimeSec).Msg("Pausing component") pauseTimeDur := time.Duration(pauseTimeSec) * time.Second - err := component.ChaosPause(l, pauseTimeDur) + err = component.ChaosPause(l, pauseTimeDur) + if err != nil { + return ChaosPauseData{Err: err} + } l.Info().Str("Container", component.ContainerName).Msg("Component unpaused") + pauseEndBlock, err := testEnv.EVMClient.LatestBlockNumber(ctx) if err != nil { - return err + return ChaosPauseData{Err: err} } - return nil + return ChaosPauseData{PauseData: PauseData{ + StartBlock: pauseStartBlock, + EndBlock: pauseEndBlock, + TargetComponent: targetComponent, + ContaineName: component.ContainerName, + }} +} + +type ChaosPauseData struct { + Err error + PauseData PauseData } -var executeChaosExperiment = func(l zerolog.Logger, testEnv *test_env.CLClusterTestEnv, cfg *Config, errorCh chan error) { - if cfg.ChaosConfig == nil || cfg.ChaosConfig.ExperimentCount == 0 { +// ExecuteChaosExperiment executes the configured chaos experiment, which consist of pausing CL node or Postgres containers +func ExecuteChaosExperiment(l zerolog.Logger, testEnv *test_env.CLClusterTestEnv, cfg *lp_config.Config, errorCh chan error) { + if cfg.ChaosConfig == nil || *cfg.ChaosConfig.ExperimentCount == 0 { errorCh <- nil return } - chaosChan := make(chan error, cfg.ChaosConfig.ExperimentCount) - + chaosChan := make(chan ChaosPauseData, *cfg.ChaosConfig.ExperimentCount) wg := &sync.WaitGroup{} go func() { // if we wanted to have more than 1 container paused, we'd need to make sure we aren't trying to pause an already paused one guardChan := make(chan struct{}, 1) - for i := 0; i < cfg.ChaosConfig.ExperimentCount; i++ { + for i := 0; i < *cfg.ChaosConfig.ExperimentCount; i++ { i := i wg.Add(1) guardChan <- struct{}{} @@ -880,9 +963,11 @@ var executeChaosExperiment = func(l zerolog.Logger, testEnv *test_env.CLClusterT defer func() { <-guardChan wg.Done() - l.Info().Str("Current/Total", fmt.Sprintf("%d/%d", i, cfg.ChaosConfig.ExperimentCount)).Msg("Done with experiment") + current := i + 1 + l.Info().Str("Current/Total", fmt.Sprintf("%d/%d", current, cfg.ChaosConfig.ExperimentCount)).Msg("Done with experiment") }() - chaosChan <- chaosPauseSyncFn(l, testEnv) + chaosChan <- chaosPauseSyncFn(l, testEnv, *cfg.ChaosConfig.TargetComponent) + time.Sleep(10 * time.Second) }() } @@ -892,25 +977,28 @@ var executeChaosExperiment = func(l zerolog.Logger, testEnv *test_env.CLClusterT }() go func() { - for err := range chaosChan { - // This will receive errors until chaosChan is closed - if err != nil { - // If an error is encountered, log it, send it to the error channel, and return from the function - l.Err(err).Msg("Error encountered during chaos experiment") - errorCh <- err + var pauseData []PauseData + for result := range chaosChan { + if result.Err != nil { + l.Err(result.Err).Msg("Error encountered during chaos experiment") + errorCh <- result.Err return // Return on actual error } - // No need for an else block here, because if err is nil (which happens when the channel is closed), - // the loop will exit and the following log and nil send will execute. + + pauseData = append(pauseData, result.PauseData) } - // After the loop exits, which it will do when chaosChan is closed, log that all experiments are finished. l.Info().Msg("All chaos experiments finished") errorCh <- nil // Only send nil once, after all errors have been handled and the channel is closed + + for _, p := range pauseData { + l.Debug().Str("Target component", p.TargetComponent).Str("Container", p.ContaineName).Str("Block range", fmt.Sprintf("%d - %d", p.StartBlock, p.EndBlock)).Msgf("Details of executed chaos pause") + } }() } -var GetFinalityDepth = func(chainId int64) (int64, error) { +// GetFinalityDepth returns the finality depth for the provided chain ID +func GetFinalityDepth(chainId int64) (int64, error) { var finalityDepth int64 switch chainId { // Ethereum Sepolia @@ -929,8 +1017,9 @@ var GetFinalityDepth = func(chainId int64) (int64, error) { return finalityDepth, nil } -var GetEndBlockToWaitFor = func(endBlock, chainId int64, cfg *Config) (int64, error) { - if cfg.General.UseFinalityTag { +// GetEndBlockToWaitFor returns the end block to wait for based on chain id and finality tag provided in config +func GetEndBlockToWaitFor(endBlock, chainId int64, cfg *lp_config.Config) (int64, error) { + if *cfg.General.UseFinalityTag { return endBlock + 1, nil } @@ -951,7 +1040,7 @@ const ( ) var ( - defaultOCRRegistryConfig = contracts.KeeperRegistrySettings{ + DefaultOCRRegistryConfig = contracts.KeeperRegistrySettings{ PaymentPremiumPPB: uint32(200000000), FlatFeeMicroLINK: uint32(0), BlockCountPerTurn: big.NewInt(10), @@ -982,13 +1071,15 @@ var ( } ) -func setupLogPollerTestDocker( +// SetupLogPollerTestDocker starts the DON and private Ethereum network +func SetupLogPollerTestDocker( t *testing.T, registryVersion ethereum.KeeperRegistryVersion, registryConfig contracts.KeeperRegistrySettings, upkeepsNeeded int, lpPollingInterval time.Duration, finalityTagEnabled bool, + testConfig *tc.TestConfig, ) ( blockchain.EVMClient, []*client.ChainlinkClient, @@ -999,9 +1090,10 @@ func setupLogPollerTestDocker( *test_env.CLClusterTestEnv, ) { l := logging.GetTestLogger(t) + // Add registry version to config registryConfig.RegistryVersion = registryVersion - network := networks.MustGetSelectedNetworksFromEnv()[0] + network := networks.MustGetSelectedNetworkConfig(testConfig.Network)[0] finalityDepth, err := GetFinalityDepth(network.ChainID) require.NoError(t, err, "Error getting finality depth") @@ -1042,15 +1134,15 @@ func setupLogPollerTestDocker( WithConsensusType(ctf_test_env.ConsensusType_PoS). WithConsensusLayer(ctf_test_env.ConsensusLayer_Prysm). WithExecutionLayer(ctf_test_env.ExecutionLayer_Geth). - WithWaitingForFinalization(). WithEthereumChainConfig(ctf_test_env.EthereumChainConfig{ - SecondsPerSlot: 8, + SecondsPerSlot: 4, SlotsPerEpoch: 2, }). Build() require.NoError(t, err, "Error building ethereum network config") env, err = test_env.NewCLTestEnvBuilder(). + WithTestConfig(testConfig). WithTestInstance(t). WithPrivateEthereumNetwork(cfg). WithCLNodes(clNodesCount). @@ -1116,3 +1208,131 @@ func setupLogPollerTestDocker( return env.EVMClient, nodeClients, env.ContractDeployer, linkToken, registry, registrar, env } + +// UploadLogEmitterContractsAndWaitForFinalisation uploads the configured number of log emitter contracts and waits for the upload blocks to be finalised +func UploadLogEmitterContractsAndWaitForFinalisation(l zerolog.Logger, t *testing.T, testEnv *test_env.CLClusterTestEnv, cfg *lp_config.Config) []*contracts.LogEmitter { + logEmitters := make([]*contracts.LogEmitter, 0) + for i := 0; i < *cfg.General.Contracts; i++ { + logEmitter, err := testEnv.ContractDeployer.DeployLogEmitterContract() + logEmitters = append(logEmitters, &logEmitter) + require.NoError(t, err, "Error deploying log emitter contract") + l.Info().Str("Contract address", logEmitter.Address().Hex()).Msg("Log emitter contract deployed") + time.Sleep(200 * time.Millisecond) + } + afterUploadBlock, err := testEnv.EVMClient.LatestBlockNumber(testcontext.Get(t)) + require.NoError(t, err, "Error getting latest block number") + + gom := gomega.NewGomegaWithT(t) + gom.Eventually(func(g gomega.Gomega) { + targetBlockNumber := int64(afterUploadBlock + 1) + finalized, err := testEnv.EVMClient.GetLatestFinalizedBlockHeader(testcontext.Get(t)) + if err != nil { + l.Warn().Err(err).Msg("Error checking if contract were uploaded. Retrying...") + return + } + finalizedBlockNumber := finalized.Number.Int64() + + if finalizedBlockNumber < targetBlockNumber { + l.Debug().Int64("Finalized block", finalized.Number.Int64()).Int64("After upload block", int64(afterUploadBlock+1)).Msg("Waiting for contract upload to finalise") + } + + g.Expect(finalizedBlockNumber >= targetBlockNumber).To(gomega.BeTrue(), "Contract upload did not finalize in time") + }, "2m", "10s").Should(gomega.Succeed()) + + return logEmitters +} + +// AssertUpkeepIdsUniqueness asserts that the provided upkeep IDs are unique +func AssertUpkeepIdsUniqueness(upkeepIDs []*big.Int) error { + upKeepIdSeen := make(map[int64]bool) + for _, upkeepID := range upkeepIDs { + if _, ok := upKeepIdSeen[upkeepID.Int64()]; ok { + return fmt.Errorf("Duplicate upkeep ID %d", upkeepID.Int64()) + } + upKeepIdSeen[upkeepID.Int64()] = true + } + + return nil +} + +// AssertContractAddressUniquneness asserts that the provided contract addresses are unique +func AssertContractAddressUniquneness(logEmitters []*contracts.LogEmitter) error { + contractAddressSeen := make(map[string]bool) + for _, logEmitter := range logEmitters { + address := (*logEmitter).Address().String() + if _, ok := contractAddressSeen[address]; ok { + return fmt.Errorf("Duplicate contract address %s", address) + } + contractAddressSeen[address] = true + } + + return nil +} + +// RegisterFiltersAndAssertUniquness registers the configured log filters and asserts that the filters are unique +// meaning that for each log emitter address and topic there is only one filter +func RegisterFiltersAndAssertUniquness(l zerolog.Logger, registry contracts.KeeperRegistry, upkeepIDs []*big.Int, logEmitters []*contracts.LogEmitter, cfg *lp_config.Config, upKeepsNeeded int) error { + uniqueFilters := make(map[string]bool) + + upkeepIdIndex := 0 + for i := 0; i < len(logEmitters); i++ { + for j := 0; j < len(cfg.General.EventsToEmit); j++ { + emitterAddress := (*logEmitters[i]).Address() + topicId := cfg.General.EventsToEmit[j].ID + + upkeepID := upkeepIDs[upkeepIdIndex] + l.Debug().Int("Upkeep id", int(upkeepID.Int64())).Str("Emitter address", emitterAddress.String()).Str("Topic", topicId.Hex()).Msg("Registering log trigger for log emitter") + err := registerSingleTopicFilter(registry, upkeepID, emitterAddress, topicId) + randomWait(150, 300) + if err != nil { + return fmt.Errorf("%w: Error registering log trigger for log emitter %s", err, emitterAddress.String()) + } + + if i%10 == 0 { + l.Info().Msgf("Registered log trigger for topic %d for log emitter %d/%d", j, i, len(logEmitters)) + } + + key := fmt.Sprintf("%s-%s", emitterAddress.String(), topicId.Hex()) + if _, ok := uniqueFilters[key]; ok { + return fmt.Errorf("Duplicate filter %s", key) + } + uniqueFilters[key] = true + upkeepIdIndex++ + } + } + + if upKeepsNeeded != len(uniqueFilters) { + return fmt.Errorf("Number of unique filters should be equal to number of upkeeps. Expected %d. Got %d", upKeepsNeeded, len(uniqueFilters)) + } + + return nil +} + +// FluentlyCheckIfAllNodesHaveLogCount checks if all CL nodes have the expected log count for the provided block range and expected filters +// It will retry until the provided duration is reached or until all nodes have the expected log count +func FluentlyCheckIfAllNodesHaveLogCount(duration string, startBlock, endBlock int64, expectedLogCount int, expectedFilters []ExpectedFilter, l zerolog.Logger, coreLogger core_logger.SugaredLogger, testEnv *test_env.CLClusterTestEnv) (bool, error) { + logCountWaitDuration, err := time.ParseDuration(duration) + if err != nil { + return false, err + } + endTime := time.Now().Add(logCountWaitDuration) + + // not using gomega here, because I want to see which logs were missing + allNodesLogCountMatches := false + for time.Now().Before(endTime) { + logCountMatches, clErr := ClNodesHaveExpectedLogCount(startBlock, endBlock, testEnv.EVMClient.GetChainID(), expectedLogCount, expectedFilters, l, coreLogger, testEnv.ClCluster) + if clErr != nil { + l.Warn(). + Err(clErr). + Msg("Error checking if CL nodes have expected log count. Retrying...") + } + if logCountMatches { + allNodesLogCountMatches = true + break + } + l.Warn(). + Msg("At least one CL node did not have expected log count. Retrying...") + } + + return allNodesLogCountMatches, nil +} diff --git a/integration-tests/universal/log_poller/scenarios.go b/integration-tests/universal/log_poller/scenarios.go deleted file mode 100644 index 5331c63f75..0000000000 --- a/integration-tests/universal/log_poller/scenarios.go +++ /dev/null @@ -1,496 +0,0 @@ -package logpoller - -import ( - "fmt" - "math/big" - "testing" - "time" - - "github.com/onsi/gomega" - "github.com/stretchr/testify/require" - - "github.com/smartcontractkit/chainlink-testing-framework/logging" - "github.com/smartcontractkit/chainlink-testing-framework/utils/testcontext" - "github.com/smartcontractkit/chainlink/integration-tests/actions" - "github.com/smartcontractkit/chainlink/integration-tests/contracts" - "github.com/smartcontractkit/chainlink/integration-tests/contracts/ethereum" - core_logger "github.com/smartcontractkit/chainlink/v2/core/logger" -) - -func ExecuteBasicLogPollerTest(t *testing.T, cfg *Config) { - l := logging.GetTestLogger(t) - coreLogger := core_logger.TestLogger(t) //needed by ORM ¯\_(ツ)_/¯ - - if cfg.General.EventsToEmit == nil || len(cfg.General.EventsToEmit) == 0 { - l.Warn().Msg("No events to emit specified, using all events from log emitter contract") - for _, event := range EmitterABI.Events { - cfg.General.EventsToEmit = append(cfg.General.EventsToEmit, event) - } - } - - l.Info().Msg("Starting basic log poller test") - - var ( - err error - upKeepsNeeded = cfg.General.Contracts * len(cfg.General.EventsToEmit) - ) - - chainClient, _, contractDeployer, linkToken, registry, registrar, testEnv := setupLogPollerTestDocker( - t, ethereum.RegistryVersion_2_1, defaultOCRRegistryConfig, upKeepsNeeded, time.Duration(500*time.Millisecond), cfg.General.UseFinalityTag, - ) - - _, upkeepIDs := actions.DeployConsumers( - t, - registry, - registrar, - linkToken, - contractDeployer, - chainClient, - upKeepsNeeded, - big.NewInt(automationDefaultLinkFunds), - automationDefaultUpkeepGasLimit, - true, - false, - ) - - // Deploy Log Emitter contracts - logEmitters := make([]*contracts.LogEmitter, 0) - for i := 0; i < cfg.General.Contracts; i++ { - logEmitter, err := testEnv.ContractDeployer.DeployLogEmitterContract() - logEmitters = append(logEmitters, &logEmitter) - require.NoError(t, err, "Error deploying log emitter contract") - l.Info().Str("Contract address", logEmitter.Address().Hex()).Msg("Log emitter contract deployed") - time.Sleep(200 * time.Millisecond) - } - - // Register log triggered upkeep for each combination of log emitter contract and event signature (topic) - // We need to register a separate upkeep for each event signature, because log trigger doesn't support multiple topics (even if log poller does) - for i := 0; i < len(upkeepIDs); i++ { - emitterAddress := (*logEmitters[i%cfg.General.Contracts]).Address() - upkeepID := upkeepIDs[i] - topicId := cfg.General.EventsToEmit[i%len(cfg.General.EventsToEmit)].ID - - l.Info().Int("Upkeep id", int(upkeepID.Int64())).Str("Emitter address", emitterAddress.String()).Str("Topic", topicId.Hex()).Msg("Registering log trigger for log emitter") - err = registerSingleTopicFilter(registry, upkeepID, emitterAddress, topicId) - randomWait(50, 200) - require.NoError(t, err, "Error registering log trigger for log emitter") - } - - err = chainClient.WaitForEvents() - require.NoError(t, err, "Error encountered when waiting for setting trigger config for upkeeps") - - // Make sure that all nodes have expected filters registered before starting to emit events - expectedFilters := getExpectedFilters(logEmitters, cfg) - gom := gomega.NewGomegaWithT(t) - gom.Eventually(func(g gomega.Gomega) { - for i := 1; i < len(testEnv.ClCluster.Nodes); i++ { - nodeName := testEnv.ClCluster.Nodes[i].ContainerName - l.Info().Str("Node name", nodeName).Msg("Fetching filters from log poller's DB") - - hasFilters, err := nodeHasExpectedFilters(expectedFilters, coreLogger, testEnv.EVMClient.GetChainID(), testEnv.ClCluster.Nodes[i].PostgresDb) - if err != nil { - l.Warn().Err(err).Msg("Error checking if node has expected filters. Retrying...") - return - } - - g.Expect(hasFilters).To(gomega.BeTrue(), "Not all expected filters were found in the DB") - } - }, "30s", "1s").Should(gomega.Succeed()) - l.Info().Msg("All nodes have expected filters registered") - l.Info().Int("Count", len(expectedFilters)).Msg("Expected filters count") - - // Save block number before starting to emit events, so that we can later use it when querying logs - sb, err := testEnv.EVMClient.LatestBlockNumber(testcontext.Get(t)) - require.NoError(t, err, "Error getting latest block number") - startBlock := int64(sb) - - l.Info().Msg("STARTING EVENT EMISSION") - startTime := time.Now() - - // Start chaos experimnents by randomly pausing random containers (Chainlink nodes or their DBs) - chaosDoneCh := make(chan error, 1) - go func() { - executeChaosExperiment(l, testEnv, cfg, chaosDoneCh) - }() - - totalLogsEmitted, err := executeGenerator(t, cfg, logEmitters) - endTime := time.Now() - require.NoError(t, err, "Error executing event generator") - - expectedLogsEmitted := getExpectedLogCount(cfg) - duration := int(endTime.Sub(startTime).Seconds()) - l.Info().Int("Total logs emitted", totalLogsEmitted).Int64("Expected total logs emitted", expectedLogsEmitted).Str("Duration", fmt.Sprintf("%d sec", duration)).Str("LPS", fmt.Sprintf("%d/sec", totalLogsEmitted/duration)).Msg("FINISHED EVENT EMISSION") - - // Save block number after finishing to emit events, so that we can later use it when querying logs - eb, err := testEnv.EVMClient.LatestBlockNumber(testcontext.Get(t)) - require.NoError(t, err, "Error getting latest block number") - - endBlock, err := GetEndBlockToWaitFor(int64(eb), testEnv.EVMClient.GetChainID().Int64(), cfg) - require.NoError(t, err, "Error getting end block to wait for") - - l.Info().Msg("Waiting before proceeding with test until all chaos experiments finish") - chaosError := <-chaosDoneCh - require.NoError(t, chaosError, "Error encountered during chaos experiment") - - // Wait until last block in which events were emitted has been finalised - // how long should we wait here until all logs are processed? wait for block X to be processed by all nodes? - waitDuration := "15m" - l.Warn().Str("Duration", waitDuration).Msg("Waiting for logs to be processed by all nodes and for chain to advance beyond finality") - - gom.Eventually(func(g gomega.Gomega) { - hasAdvanced, err := chainHasFinalisedEndBlock(l, testEnv.EVMClient, endBlock) - if err != nil { - l.Warn().Err(err).Msg("Error checking if chain has advanced beyond finality. Retrying...") - } - g.Expect(hasAdvanced).To(gomega.BeTrue(), "Chain has not advanced beyond finality") - }, waitDuration, "30s").Should(gomega.Succeed()) - - l.Warn().Str("Duration", "1m").Msg("Waiting for all CL nodes to have end block finalised") - gom.Eventually(func(g gomega.Gomega) { - hasFinalised, err := logPollerHasFinalisedEndBlock(endBlock, testEnv.EVMClient.GetChainID(), l, coreLogger, testEnv.ClCluster) - if err != nil { - l.Warn().Err(err).Msg("Error checking if nodes have finalised end block. Retrying...") - } - g.Expect(hasFinalised).To(gomega.BeTrue(), "Some nodes have not finalised end block") - }, "1m", "30s").Should(gomega.Succeed()) - - gom.Eventually(func(g gomega.Gomega) { - logCountMatches, err := clNodesHaveExpectedLogCount(startBlock, endBlock, testEnv.EVMClient.GetChainID(), totalLogsEmitted, expectedFilters, l, coreLogger, testEnv.ClCluster) - if err != nil { - l.Warn().Err(err).Msg("Error checking if CL nodes have expected log count. Retrying...") - } - g.Expect(logCountMatches).To(gomega.BeTrue(), "Not all CL nodes have expected log count") - }, waitDuration, "5s").Should(gomega.Succeed()) - - // Wait until all CL nodes have exactly the same logs emitted by test contracts as the EVM node has - logConsistencyWaitDuration := "1m" - l.Warn().Str("Duration", logConsistencyWaitDuration).Msg("Waiting for CL nodes to have all the logs that EVM node has") - - gom.Eventually(func(g gomega.Gomega) { - missingLogs, err := getMissingLogs(startBlock, endBlock, logEmitters, testEnv.EVMClient, testEnv.ClCluster, l, coreLogger, cfg) - if err != nil { - l.Warn().Err(err).Msg("Error getting missing logs. Retrying...") - } - - if !missingLogs.IsEmpty() { - printMissingLogsByType(missingLogs, l, cfg) - } - g.Expect(missingLogs.IsEmpty()).To(gomega.BeTrue(), "Some CL nodes were missing logs") - }, logConsistencyWaitDuration, "5s").Should(gomega.Succeed()) -} - -func ExecuteLogPollerReplay(t *testing.T, cfg *Config, consistencyTimeout string) { - l := logging.GetTestLogger(t) - coreLogger := core_logger.TestLogger(t) //needed by ORM ¯\_(ツ)_/¯ - - if cfg.General.EventsToEmit == nil || len(cfg.General.EventsToEmit) == 0 { - l.Warn().Msg("No events to emit specified, using all events from log emitter contract") - for _, event := range EmitterABI.Events { - cfg.General.EventsToEmit = append(cfg.General.EventsToEmit, event) - } - } - - l.Info().Msg("Starting replay log poller test") - - var ( - err error - upKeepsNeeded = cfg.General.Contracts * len(cfg.General.EventsToEmit) - ) - - // we set blockBackfillDepth to 0, to make sure nothing will be backfilled and won't interfere with our test - chainClient, _, contractDeployer, linkToken, registry, registrar, testEnv := setupLogPollerTestDocker( - t, ethereum.RegistryVersion_2_1, defaultOCRRegistryConfig, upKeepsNeeded, time.Duration(1000*time.Millisecond), cfg.General.UseFinalityTag) - - _, upkeepIDs := actions.DeployConsumers( - t, - registry, - registrar, - linkToken, - contractDeployer, - chainClient, - upKeepsNeeded, - big.NewInt(automationDefaultLinkFunds), - automationDefaultUpkeepGasLimit, - true, - false, - ) - - // Deploy Log Emitter contracts - logEmitters := make([]*contracts.LogEmitter, 0) - for i := 0; i < cfg.General.Contracts; i++ { - logEmitter, err := testEnv.ContractDeployer.DeployLogEmitterContract() - logEmitters = append(logEmitters, &logEmitter) - require.NoError(t, err, "Error deploying log emitter contract") - l.Info().Str("Contract address", logEmitter.Address().Hex()).Msg("Log emitter contract deployed") - time.Sleep(200 * time.Millisecond) - } - - //wait for contracts to be uploaded to chain, TODO: could make this wait fluent - time.Sleep(5 * time.Second) - - // Save block number before starting to emit events, so that we can later use it when querying logs - sb, err := testEnv.EVMClient.LatestBlockNumber(testcontext.Get(t)) - require.NoError(t, err, "Error getting latest block number") - startBlock := int64(sb) - - l.Info().Msg("STARTING EVENT EMISSION") - startTime := time.Now() - totalLogsEmitted, err := executeGenerator(t, cfg, logEmitters) - endTime := time.Now() - require.NoError(t, err, "Error executing event generator") - expectedLogsEmitted := getExpectedLogCount(cfg) - duration := int(endTime.Sub(startTime).Seconds()) - l.Info().Int("Total logs emitted", totalLogsEmitted).Int64("Expected total logs emitted", expectedLogsEmitted).Str("Duration", fmt.Sprintf("%d sec", duration)).Str("LPS", fmt.Sprintf("%d/sec", totalLogsEmitted/duration)).Msg("FINISHED EVENT EMISSION") - - // Save block number after finishing to emit events, so that we can later use it when querying logs - eb, err := testEnv.EVMClient.LatestBlockNumber(testcontext.Get(t)) - require.NoError(t, err, "Error getting latest block number") - - endBlock, err := GetEndBlockToWaitFor(int64(eb), testEnv.EVMClient.GetChainID().Int64(), cfg) - require.NoError(t, err, "Error getting end block to wait for") - - // Lets make sure no logs are in DB yet - expectedFilters := getExpectedFilters(logEmitters, cfg) - logCountMatches, err := clNodesHaveExpectedLogCount(startBlock, endBlock, testEnv.EVMClient.GetChainID(), 0, expectedFilters, l, coreLogger, testEnv.ClCluster) - require.NoError(t, err, "Error checking if CL nodes have expected log count") - require.True(t, logCountMatches, "Some CL nodes already had logs in DB") - l.Info().Msg("No logs were saved by CL nodes yet, as expected. Proceeding.") - - // Register log triggered upkeep for each combination of log emitter contract and event signature (topic) - // We need to register a separate upkeep for each event signature, because log trigger doesn't support multiple topics (even if log poller does) - for i := 0; i < len(upkeepIDs); i++ { - emitterAddress := (*logEmitters[i%cfg.General.Contracts]).Address() - upkeepID := upkeepIDs[i] - topicId := cfg.General.EventsToEmit[i%len(cfg.General.EventsToEmit)].ID - - l.Info().Int("Upkeep id", int(upkeepID.Int64())).Str("Emitter address", emitterAddress.String()).Str("Topic", topicId.Hex()).Msg("Registering log trigger for log emitter") - err = registerSingleTopicFilter(registry, upkeepID, emitterAddress, topicId) - require.NoError(t, err, "Error registering log trigger for log emitter") - } - - err = chainClient.WaitForEvents() - require.NoError(t, err, "Error encountered when waiting for setting trigger config for upkeeps") - - // Make sure that all nodes have expected filters registered before starting to emit events - gom := gomega.NewGomegaWithT(t) - gom.Eventually(func(g gomega.Gomega) { - for i := 1; i < len(testEnv.ClCluster.Nodes); i++ { - nodeName := testEnv.ClCluster.Nodes[i].ContainerName - l.Info().Str("Node name", nodeName).Msg("Fetching filters from log poller's DB") - - hasFilters, err := nodeHasExpectedFilters(expectedFilters, coreLogger, testEnv.EVMClient.GetChainID(), testEnv.ClCluster.Nodes[i].PostgresDb) - if err != nil { - l.Warn().Err(err).Msg("Error checking if node has expected filters. Retrying...") - return - } - - g.Expect(hasFilters).To(gomega.BeTrue(), "Not all expected filters were found in the DB") - } - }, "30s", "1s").Should(gomega.Succeed()) - l.Info().Msg("All nodes have expected filters registered") - l.Info().Int("Count", len(expectedFilters)).Msg("Expected filters count") - - l.Warn().Str("Duration", "1m").Msg("Waiting for all CL nodes to have end block finalised") - gom.Eventually(func(g gomega.Gomega) { - hasFinalised, err := logPollerHasFinalisedEndBlock(endBlock, testEnv.EVMClient.GetChainID(), l, coreLogger, testEnv.ClCluster) - if err != nil { - l.Warn().Err(err).Msg("Error checking if nodes have finalised end block. Retrying...") - } - g.Expect(hasFinalised).To(gomega.BeTrue(), "Some nodes have not finalised end block") - }, "1m", "30s").Should(gomega.Succeed()) - - // Trigger replay - l.Info().Msg("Triggering log poller's replay") - for i := 1; i < len(testEnv.ClCluster.Nodes); i++ { - nodeName := testEnv.ClCluster.Nodes[i].ContainerName - response, _, err := testEnv.ClCluster.Nodes[i].API.ReplayLogPollerFromBlock(startBlock, testEnv.EVMClient.GetChainID().Int64()) - require.NoError(t, err, "Error triggering log poller's replay on node %s", nodeName) - require.Equal(t, "Replay started", response.Data.Attributes.Message, "Unexpected response message from log poller's replay") - } - - l.Warn().Str("Duration", consistencyTimeout).Msg("Waiting for replay logs to be processed by all nodes") - - gom.Eventually(func(g gomega.Gomega) { - logCountMatches, err := clNodesHaveExpectedLogCount(startBlock, endBlock, testEnv.EVMClient.GetChainID(), totalLogsEmitted, expectedFilters, l, coreLogger, testEnv.ClCluster) - if err != nil { - l.Warn().Err(err).Msg("Error checking if CL nodes have expected log count. Retrying...") - } - g.Expect(logCountMatches).To(gomega.BeTrue(), "Not all CL nodes have expected log count") - }, consistencyTimeout, "30s").Should(gomega.Succeed()) - - // Wait until all CL nodes have exactly the same logs emitted by test contracts as the EVM node has - l.Warn().Str("Duration", consistencyTimeout).Msg("Waiting for CL nodes to have all the logs that EVM node has") - - gom.Eventually(func(g gomega.Gomega) { - missingLogs, err := getMissingLogs(startBlock, endBlock, logEmitters, testEnv.EVMClient, testEnv.ClCluster, l, coreLogger, cfg) - if err != nil { - l.Warn().Err(err).Msg("Error getting missing logs. Retrying...") - } - - if !missingLogs.IsEmpty() { - printMissingLogsByType(missingLogs, l, cfg) - } - g.Expect(missingLogs.IsEmpty()).To(gomega.BeTrue(), "Some CL nodes were missing logs") - }, consistencyTimeout, "10s").Should(gomega.Succeed()) -} - -type FinalityBlockFn = func(chainId int64, endBlock int64) (int64, error) - -func ExecuteCILogPollerTest(t *testing.T, cfg *Config) { - l := logging.GetTestLogger(t) - coreLogger := core_logger.TestLogger(t) //needed by ORM ¯\_(ツ)_/¯ - - if cfg.General.EventsToEmit == nil || len(cfg.General.EventsToEmit) == 0 { - l.Warn().Msg("No events to emit specified, using all events from log emitter contract") - for _, event := range EmitterABI.Events { - cfg.General.EventsToEmit = append(cfg.General.EventsToEmit, event) - } - } - - l.Info().Msg("Starting CI log poller test") - - var ( - err error - upKeepsNeeded = cfg.General.Contracts * len(cfg.General.EventsToEmit) - ) - - chainClient, _, contractDeployer, linkToken, registry, registrar, testEnv := setupLogPollerTestDocker( - t, ethereum.RegistryVersion_2_1, defaultOCRRegistryConfig, upKeepsNeeded, time.Duration(1000*time.Millisecond), cfg.General.UseFinalityTag, - ) - - _, upkeepIDs := actions.DeployConsumers( - t, - registry, - registrar, - linkToken, - contractDeployer, - chainClient, - upKeepsNeeded, - big.NewInt(automationDefaultLinkFunds), - automationDefaultUpkeepGasLimit, - true, - false, - ) - - // Deploy Log Emitter contracts - logEmitters := make([]*contracts.LogEmitter, 0) - for i := 0; i < cfg.General.Contracts; i++ { - logEmitter, err := testEnv.ContractDeployer.DeployLogEmitterContract() - logEmitters = append(logEmitters, &logEmitter) - require.NoError(t, err, "Error deploying log emitter contract") - l.Info().Str("Contract address", logEmitter.Address().Hex()).Msg("Log emitter contract deployed") - time.Sleep(200 * time.Millisecond) - } - - // Register log triggered upkeep for each combination of log emitter contract and event signature (topic) - // We need to register a separate upkeep for each event signature, because log trigger doesn't support multiple topics (even if log poller does) - for i := 0; i < len(upkeepIDs); i++ { - emitterAddress := (*logEmitters[i%cfg.General.Contracts]).Address() - upkeepID := upkeepIDs[i] - topicId := cfg.General.EventsToEmit[i%len(cfg.General.EventsToEmit)].ID - - l.Info().Int("Upkeep id", int(upkeepID.Int64())).Str("Emitter address", emitterAddress.String()).Str("Topic", topicId.Hex()).Msg("Registering log trigger for log emitter") - err = registerSingleTopicFilter(registry, upkeepID, emitterAddress, topicId) - randomWait(50, 200) - require.NoError(t, err, "Error registering log trigger for log emitter") - } - - err = chainClient.WaitForEvents() - require.NoError(t, err, "Error encountered when waiting for setting trigger config for upkeeps") - - // Make sure that all nodes have expected filters registered before starting to emit events - expectedFilters := getExpectedFilters(logEmitters, cfg) - gom := gomega.NewGomegaWithT(t) - gom.Eventually(func(g gomega.Gomega) { - for i := 1; i < len(testEnv.ClCluster.Nodes); i++ { - nodeName := testEnv.ClCluster.Nodes[i].ContainerName - l.Info().Str("Node name", nodeName).Msg("Fetching filters from log poller's DB") - - hasFilters, err := nodeHasExpectedFilters(expectedFilters, coreLogger, testEnv.EVMClient.GetChainID(), testEnv.ClCluster.Nodes[i].PostgresDb) - if err != nil { - l.Warn().Err(err).Msg("Error checking if node has expected filters. Retrying...") - return - } - - g.Expect(hasFilters).To(gomega.BeTrue(), "Not all expected filters were found in the DB") - } - }, "1m", "1s").Should(gomega.Succeed()) - l.Info().Msg("All nodes have expected filters registered") - l.Info().Int("Count", len(expectedFilters)).Msg("Expected filters count") - - // Save block number before starting to emit events, so that we can later use it when querying logs - sb, err := testEnv.EVMClient.LatestBlockNumber(testcontext.Get(t)) - require.NoError(t, err, "Error getting latest block number") - startBlock := int64(sb) - - l.Info().Msg("STARTING EVENT EMISSION") - startTime := time.Now() - - // Start chaos experimnents by randomly pausing random containers (Chainlink nodes or their DBs) - chaosDoneCh := make(chan error, 1) - go func() { - executeChaosExperiment(l, testEnv, cfg, chaosDoneCh) - }() - - totalLogsEmitted, err := executeGenerator(t, cfg, logEmitters) - endTime := time.Now() - require.NoError(t, err, "Error executing event generator") - - expectedLogsEmitted := getExpectedLogCount(cfg) - duration := int(endTime.Sub(startTime).Seconds()) - l.Info().Int("Total logs emitted", totalLogsEmitted).Int64("Expected total logs emitted", expectedLogsEmitted).Str("Duration", fmt.Sprintf("%d sec", duration)).Str("LPS", fmt.Sprintf("%d/sec", totalLogsEmitted/duration)).Msg("FINISHED EVENT EMISSION") - - // Save block number after finishing to emit events, so that we can later use it when querying logs - eb, err := testEnv.EVMClient.LatestBlockNumber(testcontext.Get(t)) - require.NoError(t, err, "Error getting latest block number") - - endBlock, err := GetEndBlockToWaitFor(int64(eb), testEnv.EVMClient.GetChainID().Int64(), cfg) - require.NoError(t, err, "Error getting end block to wait for") - - l.Info().Msg("Waiting before proceeding with test until all chaos experiments finish") - chaosError := <-chaosDoneCh - require.NoError(t, chaosError, "Error encountered during chaos experiment") - - // Wait until last block in which events were emitted has been finalised (with buffer) - waitDuration := "45m" - l.Warn().Str("Duration", waitDuration).Msg("Waiting for chain to advance beyond finality") - - gom.Eventually(func(g gomega.Gomega) { - hasAdvanced, err := chainHasFinalisedEndBlock(l, testEnv.EVMClient, endBlock) - if err != nil { - l.Warn().Err(err).Msg("Error checking if chain has advanced beyond finality. Retrying...") - } - g.Expect(hasAdvanced).To(gomega.BeTrue(), "Chain has not advanced beyond finality") - }, waitDuration, "30s").Should(gomega.Succeed()) - - l.Warn().Str("Duration", waitDuration).Msg("Waiting for all CL nodes to have end block finalised") - gom.Eventually(func(g gomega.Gomega) { - hasFinalised, err := logPollerHasFinalisedEndBlock(endBlock, testEnv.EVMClient.GetChainID(), l, coreLogger, testEnv.ClCluster) - if err != nil { - l.Warn().Err(err).Msg("Error checking if nodes have finalised end block. Retrying...") - } - g.Expect(hasFinalised).To(gomega.BeTrue(), "Some nodes have not finalised end block") - }, waitDuration, "30s").Should(gomega.Succeed()) - - // Wait until all CL nodes have exactly the same logs emitted by test contracts as the EVM node has - logConsistencyWaitDuration := "10m" - l.Warn().Str("Duration", logConsistencyWaitDuration).Msg("Waiting for CL nodes to have all the logs that EVM node has") - - gom.Eventually(func(g gomega.Gomega) { - missingLogs, err := getMissingLogs(startBlock, endBlock, logEmitters, testEnv.EVMClient, testEnv.ClCluster, l, coreLogger, cfg) - if err != nil { - l.Warn().Err(err).Msg("Error getting missing logs. Retrying...") - } - - if !missingLogs.IsEmpty() { - printMissingLogsByType(missingLogs, l, cfg) - } - g.Expect(missingLogs.IsEmpty()).To(gomega.BeTrue(), "Some CL nodes were missing logs") - }, logConsistencyWaitDuration, "20s").Should(gomega.Succeed()) - - evmLogs, _ := getEVMLogs(startBlock, endBlock, logEmitters, testEnv.EVMClient, l, cfg) - - if totalLogsEmitted != len(evmLogs) { - l.Warn().Int("Total logs emitted", totalLogsEmitted).Int("Total logs in EVM", len(evmLogs)).Msg("Test passed, but total logs emitted does not match total logs in EVM") - } -} diff --git a/operator_ui/TAG b/operator_ui/TAG index 584c67d8d2..f5e57863f9 100644 --- a/operator_ui/TAG +++ b/operator_ui/TAG @@ -1 +1 @@ -v0.8.0-0953c48 +v0.8.0-8da47c3 diff --git a/plugins/utils.go b/plugins/cmd.go similarity index 73% rename from plugins/utils.go rename to plugins/cmd.go index 5e5e4142e8..9a312c5388 100644 --- a/plugins/utils.go +++ b/plugins/cmd.go @@ -7,8 +7,9 @@ import ( // CmdConfig is configuration used to register the LOOP and generate an exec type CmdConfig struct { - ID string // unique string used by the node to track the LOOP. typically supplied by the loop logger name - Cmd string // string value of executable to exec + ID string // unique string used by the node to track the LOOP. typically supplied by the loop logger name + Cmd string // string value of executable to exec + Env []string // environment variables as described in [exec.Cmd.Env] } // NewCmdFactory is helper to ensure synchronization between the loop registry and os cmd to exec the LOOP @@ -19,6 +20,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 + cmd.Env = append(cmd.Env, lcfg.Env...) cmd.Env = append(cmd.Env, registeredLoop.EnvCfg.AsCmdEnv()...) return cmd }, nil diff --git a/plugins/cmd_test.go b/plugins/cmd_test.go new file mode 100644 index 0000000000..8068977314 --- /dev/null +++ b/plugins/cmd_test.go @@ -0,0 +1,51 @@ +package plugins + +import ( + "fmt" + "strings" + "testing" + + "github.com/smartcontractkit/chainlink-common/pkg/loop" +) + +func TestNewCmdFactory_RegisterSuccess(t *testing.T) { + mockRegister := func(id string) (*RegisteredLoop, error) { + return &RegisteredLoop{EnvCfg: loop.EnvConfig{}}, nil + } + + cmdConfig := CmdConfig{ + ID: "test-loop", + Cmd: "echo", + Env: []string{"TEST_ENV=1"}, + } + + cmdFactory, err := NewCmdFactory(mockRegister, cmdConfig) + if err != nil { + t.Fatalf("Expected no error, got %v", err) + } + + cmd := cmdFactory() + if cmd.Args[0] != "echo" { + t.Errorf("Expected command 'echo', got %s", cmd.Args[0]) + } +} + +func TestNewCmdFactory_RegisterFail(t *testing.T) { + mockRegister := func(id string) (*RegisteredLoop, error) { + return nil, fmt.Errorf("registration failed") + } + + cmdConfig := CmdConfig{ + ID: "test-loop", + Cmd: "echo", + Env: []string{"TEST_ENV=1"}, + } + + _, err := NewCmdFactory(mockRegister, cmdConfig) + if err == nil { + t.Fatal("Expected error, got nil") + } + if !strings.Contains(err.Error(), "failed to register") { + t.Errorf("Unexpected error message: %v", err) + } +} diff --git a/plugins/env.go b/plugins/env.go new file mode 100644 index 0000000000..016a4e862d --- /dev/null +++ b/plugins/env.go @@ -0,0 +1,31 @@ +package plugins + +import ( + "os" + + "github.com/hashicorp/go-envparse" +) + +// ParseEnvFile returns a slice of key/value pairs parsed from the file at filepath. +// As a special case, empty filepath returns nil without error. +func ParseEnvFile(filepath string) ([]string, error) { + if filepath == "" { + return nil, nil + } + f, err := os.Open(filepath) + if err != nil { + return nil, err + } + defer func() { + _ = f.Close() + }() + m, err := envparse.Parse(f) + if err != nil { + return nil, err + } + r := make([]string, 0, len(m)) + for k, v := range m { + r = append(r, k+"="+v) + } + return r, nil +} diff --git a/plugins/env_test.go b/plugins/env_test.go new file mode 100644 index 0000000000..6dd171b6cc --- /dev/null +++ b/plugins/env_test.go @@ -0,0 +1,25 @@ +package plugins + +import ( + _ "embed" + "os" + "testing" + + "github.com/stretchr/testify/require" +) + +func TestParseEnvFile(t *testing.T) { + t.Run("valid", func(t *testing.T) { + got, err := ParseEnvFile("testdata/valid.env") + require.NoError(t, err) + require.Equal(t, []string{"GOMEMLIMIT=1MiB"}, got) + }) + t.Run("invalid", func(t *testing.T) { + _, err := ParseEnvFile("testdata/invalid.env") + require.Error(t, err) + }) + t.Run("missing", func(t *testing.T) { + _, err := ParseEnvFile("testdata/missing.env") + require.ErrorIs(t, err, os.ErrNotExist) + }) +} diff --git a/plugins/loop_registry.go b/plugins/loop_registry.go index 7a5274803d..a2fcd8ef37 100644 --- a/plugins/loop_registry.go +++ b/plugins/loop_registry.go @@ -2,19 +2,18 @@ package plugins import ( "errors" + "fmt" "sort" "sync" + "github.com/hashicorp/consul/sdk/freeport" + "github.com/smartcontractkit/chainlink-common/pkg/logger" "github.com/smartcontractkit/chainlink-common/pkg/loop" "github.com/smartcontractkit/chainlink/v2/core/config" ) -const ( - pluginDefaultPort = 2112 -) - var ErrExists = errors.New("plugin already registered") type RegisteredLoop struct { @@ -49,8 +48,14 @@ func (m *LoopRegistry) Register(id string) (*RegisteredLoop, error) { if _, exists := m.registry[id]; exists { return nil, ErrExists } - nextPort := pluginDefaultPort + len(m.registry) - envCfg := loop.EnvConfig{PrometheusPort: nextPort} + ports, err := freeport.Take(1) + if err != nil { + return nil, fmt.Errorf("failed to get free port: %v", err) + } + if len(ports) != 1 { + return nil, fmt.Errorf("failed to get free port: no ports returned") + } + envCfg := loop.EnvConfig{PrometheusPort: ports[0]} if m.cfgTracing != nil { envCfg.TracingEnabled = m.cfgTracing.Enabled() diff --git a/plugins/medianpoc/plugin_test.go b/plugins/medianpoc/plugin_test.go index ba06d5ea46..d4470eef70 100644 --- a/plugins/medianpoc/plugin_test.go +++ b/plugins/medianpoc/plugin_test.go @@ -12,6 +12,7 @@ import ( "github.com/smartcontractkit/chainlink-common/pkg/types" "github.com/smartcontractkit/chainlink-common/pkg/utils/tests" + "github.com/smartcontractkit/chainlink/v2/core/logger" ) @@ -75,6 +76,10 @@ func (p provider) ChainReader() types.ChainReader { return nil } +func (p provider) Codec() types.Codec { + return nil +} + func TestNewPlugin(t *testing.T) { lggr := logger.TestLogger(t) p := NewPlugin(lggr) diff --git a/plugins/config.go b/plugins/registrar.go similarity index 77% rename from plugins/config.go rename to plugins/registrar.go index 01574d8209..90300b738b 100644 --- a/plugins/config.go +++ b/plugins/registrar.go @@ -8,7 +8,7 @@ import ( // RegistrarConfig generates contains static configuration inher type RegistrarConfig interface { - RegisterLOOP(loopId string, cmdName string) (func() *exec.Cmd, loop.GRPCOpts, error) + RegisterLOOP(config CmdConfig) (func() *exec.Cmd, loop.GRPCOpts, error) } type registarConfig struct { @@ -27,11 +27,8 @@ func NewRegistrarConfig(grpcOpts loop.GRPCOpts, loopRegistrationFn func(loopId s } // RegisterLOOP calls the configured loopRegistrationFn. The loopRegistrationFn must act as a global registry for LOOPs and must be idempotent. -func (pc *registarConfig) RegisterLOOP(loopID string, cmdName string) (func() *exec.Cmd, loop.GRPCOpts, error) { - cmdFn, err := NewCmdFactory(pc.loopRegistrationFn, CmdConfig{ - ID: loopID, - Cmd: cmdName, - }) +func (pc *registarConfig) RegisterLOOP(cfg CmdConfig) (func() *exec.Cmd, loop.GRPCOpts, error) { + cmdFn, err := NewCmdFactory(pc.loopRegistrationFn, cfg) if err != nil { return nil, loop.GRPCOpts{}, err } diff --git a/plugins/testdata/invalid.env b/plugins/testdata/invalid.env new file mode 100644 index 0000000000..b2f2407bcc --- /dev/null +++ b/plugins/testdata/invalid.env @@ -0,0 +1,2 @@ +FOO BAR +Baz: "Value" diff --git a/plugins/testdata/valid.env b/plugins/testdata/valid.env new file mode 100644 index 0000000000..5a73d037c6 --- /dev/null +++ b/plugins/testdata/valid.env @@ -0,0 +1 @@ +GOMEMLIMIT=1MiB diff --git a/sonar-project.properties b/sonar-project.properties index 9d6296cc55..560d396332 100644 --- a/sonar-project.properties +++ b/sonar-project.properties @@ -3,7 +3,7 @@ sonar.sources=. sonar.python.version=3.8 # Full exclusions from the static analysis -sonar.exclusions=**/node_modules/**/*,**/mocks/**/*, **/testdata/**/*, **/contracts/typechain/**/*, **/contracts/artifacts/**/*, **/contracts/cache/**/*, **/contracts/scripts/**/*, **/generated/**/*, **/fixtures/**/*, **/docs/**/*, **/tools/**/*, **/*.pb.go, **/*report.xml, **/*.config.ts, **/*.txt, **/*.abi, **/*.bin, **/*_codecgen.go +sonar.exclusions=**/node_modules/**/*,**/mocks/**/*, **/testdata/**/*, **/contracts/typechain/**/*, **/contracts/artifacts/**/*, **/contracts/cache/**/*, **/contracts/scripts/**/*, **/generated/**/*, **/fixtures/**/*, **/docs/**/*, **/tools/**/*, **/*.pb.go, **/*report.xml, **/*.config.ts, **/*.txt, **/*.abi, **/*.bin, **/*_codecgen.go, core/services/relay/evm/types/*_gen.go, core/services/relay/evm/types/gen/main.go, core/services/relay/evm/testfiles/*, **/core/web/assets**, core/scripts/chaincli/handler/debug.go # Coverage exclusions sonar.coverage.exclusions=**/*.test.ts, **/*_test.go, **/contracts/test/**/*, **/contracts/**/tests/**/*, **/core/**/testutils/**/*, **/core/**/mocks/**/*, **/core/**/cltest/**/*, **/integration-tests/**/*, **/generated/**/*, **/core/scripts**/* , **/*.pb.go, ./plugins/**/*, **/main.go, **/0195_add_not_null_to_evm_chain_id_in_job_specs.go # Duplication exclusions diff --git a/testdata/scripts/metrics/multi-node.txtar b/testdata/scripts/metrics/multi-node.txtar new file mode 100644 index 0000000000..c392816044 --- /dev/null +++ b/testdata/scripts/metrics/multi-node.txtar @@ -0,0 +1,78 @@ +# Check that metrics specified in the expected_metrics are present in /metrics response +# start node +exec sh -c 'eval "echo \"$(cat config.toml.tmpl)\" > config.toml"' +exec chainlink node -c config.toml start -p password -a creds & + +# ensure node is up and running +env NODEURL=http://localhost:$PORT +exec curl --retry 10 --retry-max-time 60 --retry-connrefused $NODEURL + + +# Check +chmod 700 ./script.sh +exec sh -c './script.sh' + +-- script.sh -- + +maxRetries=5 +for retriesNum in $(seq 1 $maxRetries); do + passedAllChecks=true + curl $NODEURL/metrics > metrics.txt + while IFS= read -r expectedMetric; do + grep -q $expectedMetric metrics.txt && continue + + if [[ $retriesNum -ge $maxRetries ]]; then + cat metrics.txt + echo "FAIL Expected metric $expectedMetric to be present in GET /metrics response" + exit 1 + fi + + echo "Metric $expectedMetric is not present in GET /metrics response - retrying after 5s" + passedAllChecks=false + sleep 5 + break + done < expected_metrics.txt + + $passedAllChecks && break +done + +-- testdb.txt -- +CL_DATABASE_URL +-- testport.txt -- +PORT + +-- password -- +T.tLHkcmwePT/p,]sYuntjwHKAsrhm#4eRs4LuKHwvHejWYAC2JP4M8HimwgmbaZ +-- creds -- +notreal@fakeemail.ch +fj293fbBnlQ!f9vNs + +-- config.toml.tmpl -- +[Webserver] +HTTPPort = $PORT + +[[EVM]] +ChainID = '68472' + +[[EVM.Nodes]] +Name = 'BlueEVMPrimaryNode' +WSURL = 'wss://primaryfoo.bar/ws' +HTTPURL = 'https://primaryfoo.bar' + +[[EVM.Nodes]] +Name = 'YellowEVMPrimaryNode' +WSURL = 'wss://sendonlyfoo.bar/ws' +HTTPURL = 'https://sendonlyfoo.bar' +SendOnly = true + +-- expected_metrics.txt -- +evm_pool_rpc_node_dials_total{evmChainID="68472",nodeName="BlueEVMPrimaryNode"} +evm_pool_rpc_node_dials_total{evmChainID="68472",nodeName="YellowEVMPrimaryNode"} +multi_node_states{chainId="68472",network="EVM",state="Alive"} +multi_node_states{chainId="68472",network="EVM",state="Closed"} +multi_node_states{chainId="68472",network="EVM",state="Dialed"} +multi_node_states{chainId="68472",network="EVM",state="InvalidChainID"} +multi_node_states{chainId="68472",network="EVM",state="OutOfSync"} +multi_node_states{chainId="68472",network="EVM",state="Undialed"} +multi_node_states{chainId="68472",network="EVM",state="Unreachable"} +multi_node_states{chainId="68472",network="EVM",state="Unusable"} \ No newline at end of file diff --git a/testdata/scripts/node/validate/default.txtar b/testdata/scripts/node/validate/default.txtar index f3ee21246b..da0ca1a93d 100644 --- a/testdata/scripts/node/validate/default.txtar +++ b/testdata/scripts/node/validate/default.txtar @@ -53,8 +53,6 @@ MaxBatchSize = 50 SendInterval = '500ms' SendTimeout = '10s' UseBatchSend = true -URL = '' -ServerPubKey = '' [AuditLogger] Enabled = false diff --git a/testdata/scripts/node/validate/disk-based-logging-disabled.txtar b/testdata/scripts/node/validate/disk-based-logging-disabled.txtar index 9e43c9595e..793ca98aee 100644 --- a/testdata/scripts/node/validate/disk-based-logging-disabled.txtar +++ b/testdata/scripts/node/validate/disk-based-logging-disabled.txtar @@ -97,8 +97,6 @@ MaxBatchSize = 50 SendInterval = '500ms' SendTimeout = '10s' UseBatchSend = true -URL = '' -ServerPubKey = '' [AuditLogger] Enabled = false 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 0753a51f2d..32e1dee9ab 100644 --- a/testdata/scripts/node/validate/disk-based-logging-no-dir.txtar +++ b/testdata/scripts/node/validate/disk-based-logging-no-dir.txtar @@ -97,8 +97,6 @@ MaxBatchSize = 50 SendInterval = '500ms' SendTimeout = '10s' UseBatchSend = true -URL = '' -ServerPubKey = '' [AuditLogger] Enabled = false diff --git a/testdata/scripts/node/validate/disk-based-logging.txtar b/testdata/scripts/node/validate/disk-based-logging.txtar index 33e664fb6e..b736e3b486 100644 --- a/testdata/scripts/node/validate/disk-based-logging.txtar +++ b/testdata/scripts/node/validate/disk-based-logging.txtar @@ -97,8 +97,6 @@ MaxBatchSize = 50 SendInterval = '500ms' SendTimeout = '10s' UseBatchSend = true -URL = '' -ServerPubKey = '' [AuditLogger] Enabled = false diff --git a/testdata/scripts/node/validate/invalid.txtar b/testdata/scripts/node/validate/invalid.txtar index 991d48b428..f656a89fc5 100644 --- a/testdata/scripts/node/validate/invalid.txtar +++ b/testdata/scripts/node/validate/invalid.txtar @@ -87,8 +87,6 @@ MaxBatchSize = 50 SendInterval = '500ms' SendTimeout = '10s' UseBatchSend = true -URL = '' -ServerPubKey = '' [AuditLogger] Enabled = false diff --git a/testdata/scripts/node/validate/valid.txtar b/testdata/scripts/node/validate/valid.txtar index 71380db934..0fda8f8204 100644 --- a/testdata/scripts/node/validate/valid.txtar +++ b/testdata/scripts/node/validate/valid.txtar @@ -94,8 +94,6 @@ MaxBatchSize = 50 SendInterval = '500ms' SendTimeout = '10s' UseBatchSend = true -URL = '' -ServerPubKey = '' [AuditLogger] Enabled = false diff --git a/testdata/scripts/node/validate/warnings.txtar b/testdata/scripts/node/validate/warnings.txtar index fed8f06efb..b875dae7b1 100644 --- a/testdata/scripts/node/validate/warnings.txtar +++ b/testdata/scripts/node/validate/warnings.txtar @@ -76,8 +76,6 @@ MaxBatchSize = 50 SendInterval = '500ms' SendTimeout = '10s' UseBatchSend = true -URL = '' -ServerPubKey = '' [AuditLogger] Enabled = false diff --git a/tools/bin/go_core_fuzz b/tools/bin/go_core_fuzz new file mode 100755 index 0000000000..3ea7d9bb0c --- /dev/null +++ b/tools/bin/go_core_fuzz @@ -0,0 +1,36 @@ +#!/usr/bin/env bash +set -o pipefail +set +e + +SCRIPT_PATH=`dirname "$0"`; SCRIPT_PATH=`eval "cd \"$SCRIPT_PATH\" && pwd"` +OUTPUT_FILE=${OUTPUT_FILE:-"./output.txt"} +USE_TEE="${USE_TEE:-true}" + +echo "Failed tests and panics: ---------------------" +echo "" +GO_LDFLAGS=$(bash tools/bin/ldflags) +use_tee() { + if [ "$USE_TEE" = "true" ]; then + tee "$@" + else + cat > "$@" + fi +} +go test -json -ldflags "$GO_LDFLAGS" github.com/smartcontractkit/chainlink/v2/core/services/relay/evm -fuzz . -fuzztime 12s | use_tee $OUTPUT_FILE +EXITCODE=${PIPESTATUS[0]} + +# Assert no known sensitive strings present in test logger output +printf "\n----------------------------------------------\n\n" +echo "Beginning check of output logs for sensitive strings" +$SCRIPT_PATH/scrub_logs $OUTPUT_FILE +if [[ $? != 0 ]]; then + exit 1 +fi + +echo "Exit code: $EXITCODE" +if [[ $EXITCODE != 0 ]]; then + echo "Encountered test failures." +else + echo "All tests passed!" +fi +exit $EXITCODE