diff --git a/.github/workflows/ci-core.yml b/.github/workflows/ci-core.yml index 7b0b5e36ad7..db867f70c4d 100644 --- a/.github/workflows/ci-core.yml +++ b/.github/workflows/ci-core.yml @@ -80,7 +80,7 @@ jobs: if: needs.init.outputs.on_trigger_lint == 'true' uses: golangci/golangci-lint-action@3a919529898de77ec3da873e3063ca4b10e7f5cc # v3.7.0 with: - version: v1.53.3 + version: v1.54.2 only-new-issues: ${{ github.event.schedule == '' }} # show only new issues, unless it's a scheduled run args: --out-format checkstyle:golangci-lint-report.xml - name: Print lint report artifact @@ -289,7 +289,7 @@ jobs: -gh_sha=$GITHUB_SHA \ -gh_event_path=$GITHUB_EVENT_PATH \ -command=./tools/bin/go_core_tests \ - `ls -R ./artifacts/go_core_tests*/output-short.txt` + `ls -R ./artifacts/go_core_tests*/output.txt` - name: Store logs artifacts if: always() uses: actions/upload-artifact@3cea5372237819ed00197afe530f5a7ea3e805c8 # v3.1.0 diff --git a/.github/workflows/integration-staging-tests.yml b/.github/workflows/integration-staging-tests.yml new file mode 100644 index 00000000000..a6fda178d50 --- /dev/null +++ b/.github/workflows/integration-staging-tests.yml @@ -0,0 +1,63 @@ +name: E2E Functions staging tests + +on: +# TODO: enable when env will be stable +# schedule: +# - cron: "0 0 * * *" + workflow_dispatch: + inputs: + network: + description: Blockchain network (testnet) + type: choice + default: "MUMBAI" + options: + - "MUMBAI" + test_type: + description: Test type + type: choice + default: "mumbai_functions_soak_test_real" + options: + - "mumbai_functions_soak_test_http" + - "mumbai_functions_stress_test_http" + - "mumbai_functions_soak_test_only_secrets" + - "mumbai_functions_stress_test_only_secrets" + - "mumbai_functions_soak_test_real" + - "mumbai_functions_stress_test_real" +# TODO: disabled, need GATI access +# - "gateway_secrets_set_soak_test" +# - "gateway_secrets_list_soak_test" + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + e2e-soak-test: + environment: sdlc + runs-on: ubuntu20.04-8cores-32GB + permissions: + contents: read + id-token: write + 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@v3 + with: + fetch-depth: 0 + - name: Run E2E soak tests + run: | + cd integration-tests/load/functions + if [[ $SELECTED_TEST == mumbai_functions* ]]; then + go test -v -timeout 6h -run TestFunctionsLoad/$SELECTED_TEST + elif [[ $SELECTED_TEST == gateway* ]]; then + go test -v -timeout 6h -run TestGatewayLoad/$SELECTED_TEST + fi \ No newline at end of file diff --git a/.github/workflows/integration-tests.yml b/.github/workflows/integration-tests.yml index 8c1d5be828c..1b0d0d091ed 100644 --- a/.github/workflows/integration-tests.yml +++ b/.github/workflows/integration-tests.yml @@ -3,8 +3,7 @@ on: merge_group: pull_request: schedule: - # - cron: "0 0 * * *" - - cron: "0 * * * *" # every hour while we debug for flakes + - cron: "0 0 * * *" push: tags: - "*" @@ -111,6 +110,7 @@ jobs: echo "\`${GITHUB_SHA}\`" >>$GITHUB_STEP_SUMMARY build-test-image: + if: startsWith(github.ref, 'refs/tags/') || github.event_name == 'schedule' || (github.event_name == 'push' && startsWith(github.ref, 'refs/tags/')) || contains(join(github.event.pull_request.labels.*.name, ' '), 'build-test-image') environment: integration permissions: id-token: write @@ -140,14 +140,36 @@ jobs: QA_AWS_REGION: ${{ secrets.QA_AWS_REGION }} QA_AWS_ACCOUNT_NUMBER: ${{ secrets.QA_AWS_ACCOUNT_NUMBER }} - eth-smoke-tests-matrix: + compare-tests: + needs: [changes] + runs-on: ubuntu-latest + name: Compare/Build Automation Test List + outputs: + matrix: ${{ env.MATRIX_JSON }} + steps: + - name: Checkout the repo + uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0 + - name: Compare Test Lists + run: | + cd ./integration-tests + ./scripts/compareTestList.sh ./smoke/automation_test.go + ./scripts/compareTestList.sh ./smoke/keeper_test.go + - name: Build Test Matrix Lists + id: build-test-matrix-list + run: | + cd ./integration-tests + MATRIX_JSON_AUTOMATION=$(./scripts/buildTestMatrixList.sh ./smoke/automation_test.go automation ubuntu20.04-8cores-32GB) + MATRIX_JSON_KEEPER=$(./scripts/buildTestMatrixList.sh ./smoke/keeper_test.go keeper ubuntu20.04-8cores-32GB) + COMBINED_ARRAY=$(jq -c -n "$MATRIX_JSON_AUTOMATION + $MATRIX_JSON_KEEPER") + echo "MATRIX_JSON=${COMBINED_ARRAY}" >> $GITHUB_ENV + eth-smoke-tests-matrix-automation: environment: integration permissions: checks: write pull-requests: write id-token: write contents: read - needs: [build-chainlink, changes, build-test-image] + needs: [build-chainlink, changes, compare-tests] env: SELECTED_NETWORKS: SIMULATED,SIMULATED_1,SIMULATED_2 CHAINLINK_COMMIT_SHA: ${{ github.sha }} @@ -156,16 +178,7 @@ jobs: strategy: fail-fast: false matrix: - product: - - name: automation - nodes: 19 - os: ubuntu-latest - pyroscope_env: ci-smoke-automation-evm-simulated - # temporarily disabled - # - name: ocr2vrf - # nodes: 2 - # os: ubuntu-latest - # pyroscope_env: ci-smoke-ocr2vrf-evm-simulated + product: ${{fromJson(needs.compare-tests.outputs.matrix)}} runs-on: ${{ matrix.product.os }} name: ETH Smoke Tests ${{ matrix.product.name }} steps: @@ -173,23 +186,31 @@ jobs: uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0 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 ## 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@00c6214deb10a3f374c6d3430c32c5202015d463 # v2.2.12 env: - TESTCONTAINERS_RYUK_DISABLED: true 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: make test_need_operator_assets && cd ./integration-tests && go test -timeout 30m -count=1 -json -test.parallel=${{ matrix.product.nodes }} ./smoke/${{ matrix.product.name }}_test.go 2>&1 | tee /tmp/gotest.log | gotestfmt + test_command_to_run: make test_need_operator_assets && cd ./integration-tests && go test -timeout 30m -count=1 -json -test.parallel=${{ matrix.product.nodes }} ${{ steps.build-go-test-command.outputs.run_command }} 2>&1 | tee /tmp/gotest.log | gotestfmt test_download_vendor_packages_command: cd ./integration-tests && go mod download cl_repo: ${{ env.CHAINLINK_IMAGE }} cl_image_tag: ${{ github.sha }} aws_registries: ${{ secrets.QA_AWS_ACCOUNT_NUMBER }} artifacts_location: ./integration-tests/smoke/logs - publish_check_name: EVM Smoke Test Results ${{ matrix.product.name }} + 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 }} @@ -197,28 +218,6 @@ jobs: QA_AWS_REGION: ${{ secrets.QA_AWS_REGION }} QA_AWS_ROLE_TO_ASSUME: ${{ secrets.QA_AWS_ROLE_TO_ASSUME }} QA_KUBECONFIG: ${{ secrets.QA_KUBECONFIG }} - - ## 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@00c6214deb10a3f374c6d3430c32c5202015d463 # v2.2.12 - with: - test_download_vendor_packages_command: cd ./integration-tests && go mod download - 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: ${{ secrets.QA_KUBECONFIG }} - - - name: Upload test log - uses: actions/upload-artifact@0b7f8abb1508181956e8e162db84b466c27e18ce # v3.1.2 - if: failure() - with: - name: test-log-${{ matrix.product.name }} - path: /tmp/gotest.log - retention-days: 7 - continue-on-error: true - name: Collect Metrics if: always() id: collect-gha-metrics @@ -229,8 +228,7 @@ jobs: this-job-name: ETH Smoke Tests ${{ matrix.product.name }} test-results-file: '{"testType":"go","filePath":"/tmp/gotest.log"}' continue-on-error: true - - eth-smoke-tests-matrix-docker: + eth-smoke-tests-matrix: environment: integration permissions: checks: write @@ -287,98 +285,6 @@ jobs: nodes: 1 os: ubuntu20.04-8cores-32GB pyroscope_env: ci-smoke-forwarder-ocr-evm-simulated - - # Keeper tests split out to use minimal environments - - name: keeper-1 - nodes: 1 - os: ubuntu20.04-8cores-32GB - pyroscope_env: ci-smoke-keeper-evm-simulated - file: keeper - run: -run ^TestKeeperBasicSmoke$ - - name: keeper-2 - nodes: 1 - os: ubuntu20.04-8cores-32GB - pyroscope_env: ci-smoke-keeper-evm-simulated - file: keeper - run: -run ^TestKeeperBlockCountPerTurn/registry_1_1$ - - name: keeper-3 - nodes: 1 - os: ubuntu20.04-8cores-32GB - pyroscope_env: ci-smoke-keeper-evm-simulated - file: keeper - run: -run ^TestKeeperBlockCountPerTurn/registry_1_2$ - - name: keeper-4 - nodes: 1 - os: ubuntu20.04-8cores-32GB - pyroscope_env: ci-smoke-keeper-evm-simulated - file: keeper - run: -run ^TestKeeperBlockCountPerTurn/registry_1_3$ - - name: keeper-5 - nodes: 1 - os: ubuntu20.04-8cores-32GB - pyroscope_env: ci-smoke-keeper-evm-simulated - file: keeper - run: -run ^TestKeeperSimulation$ - - name: keeper-6 - nodes: 1 - os: ubuntu20.04-8cores-32GB - pyroscope_env: ci-smoke-keeper-evm-simulated - file: keeper - run: -run ^TestKeeperCheckPerformGasLimit/registry_1_2$ - - name: keeper-7 - nodes: 1 - os: ubuntu20.04-8cores-32GB - pyroscope_env: ci-smoke-keeper-evm-simulated - file: keeper - run: -run ^TestKeeperCheckPerformGasLimit/registry_1_3$ - - name: keeper-8 - nodes: 1 - os: ubuntu20.04-8cores-32GB - pyroscope_env: ci-smoke-keeper-evm-simulated - file: keeper - run: -run ^TestKeeperRegisterUpkeep$ - - name: keeper-9 - nodes: 1 - os: ubuntu20.04-8cores-32GB - pyroscope_env: ci-smoke-keeper-evm-simulated - file: keeper - run: -run ^TestKeeperAddFunds$ - - name: keeper-10 - nodes: 1 - os: ubuntu20.04-8cores-32GB - pyroscope_env: ci-smoke-keeper-evm-simulated - file: keeper - run: -run ^TestKeeperRemove$ - - name: keeper-11 - nodes: 1 - os: ubuntu20.04-8cores-32GB - pyroscope_env: ci-smoke-keeper-evm-simulated - file: keeper - run: -run ^TestKeeperPauseRegistry$ - - name: keeper-12 - nodes: 1 - os: ubuntu20.04-8cores-32GB - pyroscope_env: ci-smoke-keeper-evm-simulated - file: keeper - run: -run ^TestKeeperMigrateRegistry$ - - name: keeper-13 - nodes: 1 - os: ubuntu20.04-8cores-32GB - pyroscope_env: ci-smoke-keeper-evm-simulated - file: keeper - run: -run ^TestKeeperNodeDown/registry_1_1$ - - name: keeper-14 - nodes: 1 - os: ubuntu20.04-8cores-32GB - pyroscope_env: ci-smoke-keeper-evm-simulated - file: keeper - run: -run ^TestKeeperNodeDown/registry_1_2$ - - name: keeper-15 - nodes: 1 - os: ubuntu20.04-8cores-32GB - pyroscope_env: ci-smoke-keeper-evm-simulated - file: keeper - run: -run ^TestKeeperNodeDown/registry_1_3$ runs-on: ${{ matrix.product.os }} name: ETH Smoke Tests ${{ matrix.product.name }} steps: @@ -410,7 +316,7 @@ jobs: cl_image_tag: ${{ github.sha }} aws_registries: ${{ secrets.QA_AWS_ACCOUNT_NUMBER }} artifacts_location: ./integration-tests/smoke/logs - publish_check_name: EVM Smoke Test Results ${{ matrix.product.name }} + 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 }} @@ -455,10 +361,10 @@ jobs: if: always() runs-on: ubuntu-latest name: ETH Smoke Tests - needs: [eth-smoke-tests-matrix,eth-smoke-tests-matrix-docker] + needs: [eth-smoke-tests-matrix, eth-smoke-tests-matrix-automation] steps: - name: Check smoke test matrix status - if: needs.eth-smoke-tests-matrix.result != 'success' || needs.eth-smoke-tests-matrix-docker.result != 'success' + if: needs.eth-smoke-tests-matrix.result != 'success' || needs.eth-smoke-tests-matrix-automation.result != 'success' run: exit 1 - name: Collect Metrics if: always() @@ -700,7 +606,7 @@ jobs: CONTRACT_ARTIFACTS_PATH: contracts/target/deploy steps: - name: Collect Metrics - if: needs.changes.outputs.src == 'true' + if: needs.changes.outputs.src == 'true' && needs.solana-test-image-exists.outputs.exists == 'false' id: collect-gha-metrics uses: smartcontractkit/push-gha-metrics-action@d2c2b7bdc9012651230b2608a1bcb0c48538b6ec with: @@ -709,6 +615,7 @@ 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' uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0 with: repository: smartcontractkit/chainlink-solana @@ -722,6 +629,8 @@ jobs: QA_AWS_ROLE_TO_ASSUME: ${{ secrets.QA_AWS_ROLE_TO_ASSUME }} QA_AWS_REGION: ${{ secrets.QA_AWS_REGION }} QA_AWS_ACCOUNT_NUMBER: ${{ secrets.QA_AWS_ACCOUNT_NUMBER }} + - run: echo "this exists so we don't have to run anything else if the build is skipped" + if: needs.changes.outputs.src == 'false' || needs.solana-test-image-exists.outputs.exists == 'true' solana-smoke-tests: environment: integration diff --git a/.github/workflows/operator-ui.yml b/.github/workflows/operator-ui-cd.yml similarity index 59% rename from .github/workflows/operator-ui.yml rename to .github/workflows/operator-ui-cd.yml index bd3655436c3..488e93778e6 100644 --- a/.github/workflows/operator-ui.yml +++ b/.github/workflows/operator-ui-cd.yml @@ -1,4 +1,4 @@ -name: Operator UI +name: Operator UI CD on: push: @@ -6,10 +6,12 @@ on: - develop workflow_dispatch: schedule: - - cron: '0 */1 * * *' # Run every hour + - cron: "0 */1 * * *" # Run every hour jobs: update-version: + permissions: + id-token: write name: Update Version runs-on: ubuntu-latest steps: @@ -22,10 +24,25 @@ jobs: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: ./operator_ui/check.sh + - name: Assume role capable of dispatching action + uses: aws-actions/configure-aws-credentials@5fd3084fc36e372ff1fff382a39b10d03659f355 # v2.2.0 + with: + role-to-assume: ${{ secrets.AWS_OIDC_CHAINLINK_CI_AUTO_PR_TOKEN_ISSUER_ROLE_ARN }} + role-duration-seconds: ${{ secrets.aws-role-duration-seconds }} + role-session-name: operator-ui-cd.update-version + aws-region: ${{ secrets.AWS_REGION }} + + - name: Get Github Token + id: get-gh-token + uses: smartcontractkit/chainlink-github-actions/github-app-token-issuer@chore/update-github-app-token-issuer + with: + url: ${{ secrets.AWS_INFRA_RELENG_TOKEN_ISSUER_LAMBDA_URL }} + - name: Open PR uses: peter-evans/create-pull-request@38e0b6e68b4c852a5500a94740f0e535e0d7ba54 # v4.2.4 with: title: Update Operator UI from ${{ steps.update.outputs.current_tag }} to ${{ steps.update.outputs.latest_tag }} + token: ${{ steps.get-gh-token.outputs.access-token }} branch: chore/update-operator-ui commit-message: Update Operator UI from ${{ steps.update.outputs.current_tag }} to ${{ steps.update.outputs.latest_tag }} body: ${{ steps.update.outputs.body }} diff --git a/.github/workflows/operator-ui-ci.yml b/.github/workflows/operator-ui-ci.yml new file mode 100644 index 00000000000..b73106177c5 --- /dev/null +++ b/.github/workflows/operator-ui-ci.yml @@ -0,0 +1,46 @@ +name: Operator UI CI +on: + pull_request: + +jobs: + check-gql: + permissions: + id-token: write + contents: read + # To allow writing comments to the current PR + pull-requests: write + + name: Breaking Changes GQL Check + runs-on: ubuntu-latest + steps: + - name: Collect Metrics + id: collect-gha-metrics + uses: smartcontractkit/push-gha-metrics-action@v1 + with: + basic-auth: ${{ secrets.GRAFANA_CLOUD_BASIC_AUTH }} + hostname: ${{ secrets.GRAFANA_CLOUD_HOST }} + this-job-name: Breaking Changes GQL Check + continue-on-error: true + + - name: Assume role capable of dispatching action + uses: aws-actions/configure-aws-credentials@5fd3084fc36e372ff1fff382a39b10d03659f355 # v2.2.0 + with: + role-to-assume: ${{ secrets.AWS_OIDC_CHAINLINK_CI_OPERATOR_UI_ACCESS_TOKEN_ISSUER_ROLE_ARN }} + role-duration-seconds: 3600 + role-session-name: operator-ui-ci.check-gql + aws-region: ${{ secrets.AWS_REGION }} + + - name: Get Github Token + id: get-gh-token + uses: smartcontractkit/chainlink-github-actions/github-app-token-issuer@main + with: + url: ${{ secrets.AWS_INFRA_RELENG_TOKEN_ISSUER_LAMBDA_URL }} + + - uses: convictional/trigger-workflow-and-wait@f69fa9eedd3c62a599220f4d5745230e237904be #v1.6.5 + with: + owner: smartcontractkit + repo: operator-ui + comment_downstream_url: ${{ github.event.pull_request.comments_url }} + github_token: ${{ steps.get-gh-token.outputs.access-token }} + workflow_file_name: chainlink-ci.yml + client_payload: '{"ref": "${{ github.event.pull_request.head.sha }}"}' diff --git a/.github/workflows/solidity-foundry.yml b/.github/workflows/solidity-foundry.yml index abdb64d1763..9af9b1dd566 100644 --- a/.github/workflows/solidity-foundry.yml +++ b/.github/workflows/solidity-foundry.yml @@ -72,8 +72,9 @@ jobs: FOUNDRY_PROFILE: ${{ matrix.product }} - name: Run Forge snapshot + if: ${{ !contains(fromJson('["vrf"]'), matrix.product) }} run: | - forge snapshot --check gas-snapshots/${{ matrix.product }}.gas-snapshot + forge snapshot --nmt "testFuzz_\w{1,}?" --check gas-snapshots/${{ matrix.product }}.gas-snapshot id: snapshot working-directory: contracts env: diff --git a/.tool-versions b/.tool-versions index c7deac35bf5..f7934265340 100644 --- a/.tool-versions +++ b/.tool-versions @@ -4,5 +4,5 @@ nodejs 16.16.0 postgres 13.3 helm 3.10.3 zig 0.10.1 -golangci-lint 1.53.3 +golangci-lint 1.54.2 shellspec 0.28.1 diff --git a/GNUmakefile b/GNUmakefile index 8b6fd2d2ac4..71279f43651 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -146,7 +146,7 @@ config-docs: ## Generate core node configuration documentation .PHONY: golangci-lint golangci-lint: ## Run golangci-lint for all issues. [ -d "./golangci-lint" ] || mkdir ./golangci-lint && \ - docker run --rm -v $(shell pwd):/app -w /app golangci/golangci-lint:v1.53.2 golangci-lint run --max-issues-per-linter 0 --max-same-issues 0 > ./golangci-lint/$(shell date +%Y-%m-%d_%s).txt + docker run --rm -v $(shell pwd):/app -w /app golangci/golangci-lint:v1.54.2 golangci-lint run --max-issues-per-linter 0 --max-same-issues 0 > ./golangci-lint/$(shell date +%Y-%m-%d_%H:%M:%S).txt GORELEASER_CONFIG ?= .goreleaser.yaml diff --git a/contracts/GNUmakefile b/contracts/GNUmakefile index 501ef968482..5a5376bb1eb 100644 --- a/contracts/GNUmakefile +++ b/contracts/GNUmakefile @@ -13,9 +13,11 @@ ALL_FOUNDRY_PRODUCTS = vrf automation llo-feeds functions automation-dev shared # make snapshot # make call example # make FOUNDRY_PROFILE=llo-feeds snapshot +# note make snapshot skips fuzz tests named according to best practices, although forge uses +# a static fuzz seed by default, flaky gas results per platform are still observed. .PHONY: snapshot snapshot: ## Make a snapshot for a specific product. - export FOUNDRY_PROFILE=$(FOUNDRY_PROFILE) && forge snapshot --snap gas-snapshots/$(FOUNDRY_PROFILE).gas-snapshot + export FOUNDRY_PROFILE=$(FOUNDRY_PROFILE) && forge snapshot --nmt "testFuzz_\w{1,}?" --snap gas-snapshots/$(FOUNDRY_PROFILE).gas-snapshot .PHONY: snapshot-all snapshot-all: ## Make a snapshot for all products. diff --git a/contracts/gas-snapshots/functions.gas-snapshot b/contracts/gas-snapshots/functions.gas-snapshot index 7ee4f779d6a..da2a8f49583 100644 --- a/contracts/gas-snapshots/functions.gas-snapshot +++ b/contracts/gas-snapshots/functions.gas-snapshot @@ -1,3 +1,7 @@ +FunctionsBilling_EstimateCost:test_EstimateCost_RevertsIfGasPriceAboveCeiling() (gas: 32391) +FunctionsBilling_EstimateCost:test_EstimateCost_Success() (gas: 53002) +FunctionsBilling_OracleWithdrawAll:test_OracleWithdrawAll_RevertIfNotOwner() (gas: 13274) +FunctionsBilling_OracleWithdrawAll:test_OracleWithdrawAll_SuccessPaysTransmittersWithBalance() (gas: 146635) FunctionsOracle_sendRequest:testEmptyRequestDataReverts() (gas: 13452) FunctionsOracle_setDONPublicKey:testEmptyPublicKeyReverts() (gas: 10974) FunctionsOracle_setDONPublicKey:testOnlyOwnerReverts() (gas: 11255) @@ -8,10 +12,165 @@ FunctionsOracle_setRegistry:testOnlyOwnerReverts() (gas: 10927) FunctionsOracle_setRegistry:testSetRegistrySuccess() (gas: 35791) FunctionsOracle_setRegistry:testSetRegistry_gas() (gas: 31987) FunctionsOracle_typeAndVersion:testTypeAndVersionSuccess() (gas: 6905) +FunctionsRouter_Constructor:test_Constructor_Success() (gas: 12073) +FunctionsRouter_Fulfill:test_Fulfill_RequestNotProcessedCostExceedsCommitment() (gas: 48079) +FunctionsRouter_Fulfill:test_Fulfill_RequestNotProcessedInsufficientGas() (gas: 38613) +FunctionsRouter_Fulfill:test_Fulfill_RequestNotProcessedInvalidCommitment() (gas: 36022) +FunctionsRouter_Fulfill:test_Fulfill_RequestNotProcessedInvalidRequestId() (gas: 35147) +FunctionsRouter_Fulfill:test_Fulfill_RequestNotProcessedSubscriptionBalanceInvariant() (gas: 210) +FunctionsRouter_Fulfill:test_Fulfill_RevertIfNotCommittedCoordinator() (gas: 27993) +FunctionsRouter_Fulfill:test_Fulfill_RevertIfPaused() (gas: 33184) +FunctionsRouter_Fulfill:test_Fulfill_SuccessClientNoLongerExists() (gas: 93416) +FunctionsRouter_Fulfill:test_Fulfill_SuccessFulfilled() (gas: 103212) +FunctionsRouter_Fulfill:test_Fulfill_SuccessUserCallbackReverts() (gas: 1762498) +FunctionsRouter_Fulfill:test_Fulfill_SuccessUserCallbackRunsOutOfGas() (gas: 205574) +FunctionsRouter_GetAdminFee:test_GetAdminFee_Success() (gas: 18005) +FunctionsRouter_GetAllowListId:test_GetAllowListId_Success() (gas: 12926) +FunctionsRouter_GetConfig:test_GetConfig_Success() (gas: 37136) +FunctionsRouter_GetContractById:test_GetContractById_RevertIfRouteDoesNotExist() (gas: 13871) +FunctionsRouter_GetContractById:test_GetContractById_SuccessIfRouteExists() (gas: 17395) +FunctionsRouter_GetProposedContractById:test_GetProposedContractById_RevertIfRouteDoesNotExist() (gas: 16382) +FunctionsRouter_GetProposedContractById:test_GetProposedContractById_SuccessIfRouteExists() (gas: 23934) +FunctionsRouter_GetProposedContractSet:test_GetProposedContractSet_Success() (gas: 25958) +FunctionsRouter_IsValidCallbackGasLimit:test_IsValidCallbackGasLimit_RevertGasLimitTooBig() (gas: 28034) +FunctionsRouter_IsValidCallbackGasLimit:test_IsValidCallbackGasLimit_RevertInvalidConfig() (gas: 41004) +FunctionsRouter_IsValidCallbackGasLimit:test_IsValidCallbackGasLimit_Success() (gas: 24551) FunctionsRouter_Pause:test_Pause_RevertIfNotOwner() (gas: 13315) -FunctionsRouter_Pause:test_Pause_Success() (gas: 20254) -FunctionsRouter_Unpause:test_Unpause_RevertIfNotOwner() (gas: 13294) -FunctionsRouter_Unpause:test_Unpause_Success() (gas: 77334) +FunctionsRouter_Pause:test_Pause_Success() (gas: 20298) +FunctionsRouter_ProposeContractsUpdate:test_ProposeContractsUpdate_RevertIfEmptyAddress() (gas: 14768) +FunctionsRouter_ProposeContractsUpdate:test_ProposeContractsUpdate_RevertIfExceedsMaxProposal() (gas: 22661) +FunctionsRouter_ProposeContractsUpdate:test_ProposeContractsUpdate_RevertIfLengthMismatch() (gas: 14647) +FunctionsRouter_ProposeContractsUpdate:test_ProposeContractsUpdate_RevertIfNotNewContract() (gas: 19025) +FunctionsRouter_ProposeContractsUpdate:test_ProposeContractsUpdate_RevertIfNotOwner() (gas: 23326) +FunctionsRouter_ProposeContractsUpdate:test_ProposeContractsUpdate_Success() (gas: 118413) +FunctionsRouter_SendRequest:test_SendRequest_RevertIfConsumerNotAllowed() (gas: 59304) +FunctionsRouter_SendRequest:test_SendRequest_RevertIfDuplicateRequestId() (gas: 192143) +FunctionsRouter_SendRequest:test_SendRequest_RevertIfEmptyData() (gas: 29405) +FunctionsRouter_SendRequest:test_SendRequest_RevertIfIncorrectDonId() (gas: 57926) +FunctionsRouter_SendRequest:test_SendRequest_RevertIfInsufficientSubscriptionBalance() (gas: 185987) +FunctionsRouter_SendRequest:test_SendRequest_RevertIfInvalidCallbackGasLimit() (gas: 50902) +FunctionsRouter_SendRequest:test_SendRequest_RevertIfInvalidDonId() (gas: 25061) +FunctionsRouter_SendRequest:test_SendRequest_RevertIfNoSubscription() (gas: 29111) +FunctionsRouter_SendRequest:test_SendRequest_RevertIfPaused() (gas: 34247) +FunctionsRouter_SendRequest:test_SendRequest_Success() (gas: 197669) +FunctionsRouter_SendRequestToProposed:test_SendRequestToProposed_RevertIfConsumerNotAllowed() (gas: 65800) +FunctionsRouter_SendRequestToProposed:test_SendRequestToProposed_RevertIfEmptyData() (gas: 35991) +FunctionsRouter_SendRequestToProposed:test_SendRequestToProposed_RevertIfIncorrectDonId() (gas: 29897) +FunctionsRouter_SendRequestToProposed:test_SendRequestToProposed_RevertIfInvalidCallbackGasLimit() (gas: 57488) +FunctionsRouter_SendRequestToProposed:test_SendRequestToProposed_RevertIfInvalidDonId() (gas: 27482) +FunctionsRouter_SendRequestToProposed:test_SendRequestToProposed_RevertIfNoSubscription() (gas: 35696) +FunctionsRouter_SendRequestToProposed:test_SendRequestToProposed_RevertIfPaused() (gas: 40766) +FunctionsRouter_SendRequestToProposed:test_SendRequestToProposed_Success() (gas: 204227) +FunctionsRouter_SendRequestToProposed:test_SendRequest_RevertIfInsufficientSubscriptionBalance() (gas: 192506) +FunctionsRouter_SetAllowListId:test_SetAllowListId_Success() (gas: 30687) +FunctionsRouter_SetAllowListId:test_UpdateConfig_RevertIfNotOwner() (gas: 13380) +FunctionsRouter_Unpause:test_Unpause_RevertIfNotOwner() (gas: 13337) +FunctionsRouter_Unpause:test_Unpause_Success() (gas: 77421) +FunctionsRouter_UpdateConfig:test_UpdateConfig_RevertIfNotOwner() (gas: 24437) +FunctionsRouter_UpdateConfig:test_UpdateConfig_Success() (gas: 60653) +FunctionsRouter_UpdateContracts:test_UpdateContracts_RevertIfNotOwner() (gas: 13293) +FunctionsRouter_UpdateContracts:test_UpdateContracts_Success() (gas: 38716) +FunctionsSubscriptions_AcceptSubscriptionOwnerTransfer:test_AcceptSubscriptionOwnerTransfer_RevertIfNotAllowedSender() (gas: 60333) +FunctionsSubscriptions_AcceptSubscriptionOwnerTransfer:test_AcceptSubscriptionOwnerTransfer_RevertIfPaused() (gas: 60962) +FunctionsSubscriptions_AcceptSubscriptionOwnerTransfer:test_AcceptSubscriptionOwnerTransfer_RevertIfSenderBecomesBlocked() (gas: 94681) +FunctionsSubscriptions_AcceptSubscriptionOwnerTransfer:test_AcceptSubscriptionOwnerTransfer_RevertIfSenderIsNotNewOwner() (gas: 62691) +FunctionsSubscriptions_AcceptSubscriptionOwnerTransfer:test_AcceptSubscriptionOwnerTransfer_Success() (gas: 59679) +FunctionsSubscriptions_AddConsumer:test_AddConsumer_RevertIfMaximumConsumers() (gas: 137833) +FunctionsSubscriptions_AddConsumer:test_AddConsumer_RevertIfMaximumConsumersAfterConfigUpdate() (gas: 164777) +FunctionsSubscriptions_AddConsumer:test_AddConsumer_RevertIfNoSubscription() (gas: 12926) +FunctionsSubscriptions_AddConsumer:test_AddConsumer_RevertIfNotAllowedSender() (gas: 57789) +FunctionsSubscriptions_AddConsumer:test_AddConsumer_RevertIfNotSubscriptionOwner() (gas: 87166) +FunctionsSubscriptions_AddConsumer:test_AddConsumer_RevertIfPaused() (gas: 18051) +FunctionsSubscriptions_AddConsumer:test_AddConsumer_Success() (gas: 95481) +FunctionsSubscriptions_CancelSubscription:test_CancelSubscription_RevertIfNoSubscription() (gas: 15085) +FunctionsSubscriptions_CancelSubscription:test_CancelSubscription_RevertIfNotAllowedSender() (gas: 57929) +FunctionsSubscriptions_CancelSubscription:test_CancelSubscription_RevertIfNotSubscriptionOwner() (gas: 89340) +FunctionsSubscriptions_CancelSubscription:test_CancelSubscription_RevertIfPaused() (gas: 20191) +FunctionsSubscriptions_CancelSubscription:test_CancelSubscription_RevertIfPendingRequests() (gas: 193277) +FunctionsSubscriptions_CancelSubscription:test_CancelSubscription_SuccessForfeitAllBalanceAsDeposit() (gas: 114636) +FunctionsSubscriptions_CancelSubscription:test_CancelSubscription_SuccessForfeitSomeBalanceAsDeposit() (gas: 125891) +FunctionsSubscriptions_CancelSubscription:test_CancelSubscription_SuccessRecieveDeposit() (gas: 312021) +FunctionsSubscriptions_Constructor:test_Constructor_Success() (gas: 7654) +FunctionsSubscriptions_CreateSubscriptionWithConsumer:test_CreateSubscriptionWithConsumer_RevertIfNotAllowedSender() (gas: 28637) +FunctionsSubscriptions_CreateSubscriptionWithConsumer:test_CreateSubscriptionWithConsumer_RevertIfPaused() (gas: 17948) +FunctionsSubscriptions_CreateSubscriptionWithConsumer:test_CreateSubscriptionWithConsumer_Success() (gas: 371980) +FunctionsSubscriptions_GetConsumer:test_GetConsumer_Success() (gas: 16225) +FunctionsSubscriptions_GetFlags:test_GetFlags_Success() (gas: 40858) +FunctionsSubscriptions_GetSubscription:test_GetSubscription_Success() (gas: 30959) +FunctionsSubscriptions_GetSubscriptionCount:test_GetSubscriptionCount_Success() (gas: 12967) +FunctionsSubscriptions_GetSubscriptionsInRange:test_GetSubscriptionsInRange_RevertIfEndIsAfterLastSubscription() (gas: 16523) +FunctionsSubscriptions_GetSubscriptionsInRange:test_GetSubscriptionsInRange_RevertIfStartIsAfterEnd() (gas: 13436) +FunctionsSubscriptions_GetSubscriptionsInRange:test_GetSubscriptionsInRange_Success() (gas: 59568) +FunctionsSubscriptions_GetTotalBalance:test_GetTotalBalance_Success() (gas: 15032) +FunctionsSubscriptions_OnTokenTransfer:test_OnTokenTransfer_RevertIfCallerIsNoCalldata() (gas: 27594) +FunctionsSubscriptions_OnTokenTransfer:test_OnTokenTransfer_RevertIfCallerIsNoSubscription() (gas: 30071) +FunctionsSubscriptions_OnTokenTransfer:test_OnTokenTransfer_RevertIfCallerIsNotLink() (gas: 13402) +FunctionsSubscriptions_OnTokenTransfer:test_OnTokenTransfer_RevertIfPaused() (gas: 35000) +FunctionsSubscriptions_OnTokenTransfer:test_OnTokenTransfer_Success() (gas: 56279) +FunctionsSubscriptions_OracleWithdraw:test_OracleWithdraw_RevertIfAmountMoreThanBalance() (gas: 20745) +FunctionsSubscriptions_OracleWithdraw:test_OracleWithdraw_RevertIfBalanceInvariant() (gas: 189) +FunctionsSubscriptions_OracleWithdraw:test_OracleWithdraw_RevertIfNoAmount() (gas: 15638) +FunctionsSubscriptions_OracleWithdraw:test_OracleWithdraw_RevertIfPaused() (gas: 20833) +FunctionsSubscriptions_OracleWithdraw:test_OracleWithdraw_SuccessPaysRecipient() (gas: 59732) +FunctionsSubscriptions_OracleWithdraw:test_OracleWithdraw_SuccessSetsBalanceToZero() (gas: 57701) +FunctionsSubscriptions_OwnerCancelSubscription:test_OwnerCancelSubscription_RevertIfNoSubscription() (gas: 12818) +FunctionsSubscriptions_OwnerCancelSubscription:test_OwnerCancelSubscription_RevertIfNotOwner() (gas: 15549) +FunctionsSubscriptions_OwnerCancelSubscription:test_OwnerCancelSubscription_Success() (gas: 54867) +FunctionsSubscriptions_OwnerCancelSubscription:test_OwnerCancelSubscription_SuccessDeletesSubscription() (gas: 49624) +FunctionsSubscriptions_OwnerCancelSubscription:test_OwnerCancelSubscription_SuccessSubOwnerRefunded() (gas: 50896) +FunctionsSubscriptions_OwnerCancelSubscription:test_OwnerCancelSubscription_SuccessWhenRequestInFlight() (gas: 163911) +FunctionsSubscriptions_OwnerWithdraw:test_OwnerWithdraw_RevertIfAmountMoreThanBalance() (gas: 17924) +FunctionsSubscriptions_OwnerWithdraw:test_OwnerWithdraw_RevertIfBalanceInvariant() (gas: 165) +FunctionsSubscriptions_OwnerWithdraw:test_OwnerWithdraw_RevertIfNotOwner() (gas: 15555) +FunctionsSubscriptions_OwnerWithdraw:test_OwnerWithdraw_SuccessIfNoAmount() (gas: 37396) +FunctionsSubscriptions_OwnerWithdraw:test_OwnerWithdraw_SuccessPaysRecipient() (gas: 54435) +FunctionsSubscriptions_OwnerWithdraw:test_OwnerWithdraw_SuccessSetsBalanceToZero() (gas: 37790) +FunctionsSubscriptions_PendingRequestExists:test_PendingRequestExists_SuccessFalseIfNoPendingRequests() (gas: 15025) +FunctionsSubscriptions_PendingRequestExists:test_PendingRequestExists_SuccessTrueIfPendingRequests() (gas: 175411) +FunctionsSubscriptions_ProposeSubscriptionOwnerTransfer:test_ProposeSubscriptionOwnerTransfer_RevertIfEmptyNewOwner() (gas: 27610) +FunctionsSubscriptions_ProposeSubscriptionOwnerTransfer:test_ProposeSubscriptionOwnerTransfer_RevertIfInvalidNewOwner() (gas: 57707) +FunctionsSubscriptions_ProposeSubscriptionOwnerTransfer:test_ProposeSubscriptionOwnerTransfer_RevertIfNoSubscription() (gas: 15000) +FunctionsSubscriptions_ProposeSubscriptionOwnerTransfer:test_ProposeSubscriptionOwnerTransfer_RevertIfNotAllowedSender() (gas: 75130) +FunctionsSubscriptions_ProposeSubscriptionOwnerTransfer:test_ProposeSubscriptionOwnerTransfer_RevertIfNotSubscriptionOwner() (gas: 17959) +FunctionsSubscriptions_ProposeSubscriptionOwnerTransfer:test_ProposeSubscriptionOwnerTransfer_RevertIfPaused() (gas: 20104) +FunctionsSubscriptions_ProposeSubscriptionOwnerTransfer:test_ProposeSubscriptionOwnerTransfer_Success() (gas: 68216) +FunctionsSubscriptions_RecoverFunds:test_OwnerCancelSubscription_RevertIfNotOwner() (gas: 15532) +FunctionsSubscriptions_RecoverFunds:test_RecoverFunds_Success() (gas: 41093) +FunctionsSubscriptions_RemoveConsumer:test_RemoveConsumer_RevertIfInvalidConsumer() (gas: 30238) +FunctionsSubscriptions_RemoveConsumer:test_RemoveConsumer_RevertIfNoSubscription() (gas: 14997) +FunctionsSubscriptions_RemoveConsumer:test_RemoveConsumer_RevertIfNotAllowedSender() (gas: 57778) +FunctionsSubscriptions_RemoveConsumer:test_RemoveConsumer_RevertIfNotSubscriptionOwner() (gas: 87210) +FunctionsSubscriptions_RemoveConsumer:test_RemoveConsumer_RevertIfPaused() (gas: 18004) +FunctionsSubscriptions_RemoveConsumer:test_RemoveConsumer_RevertIfPendingRequests() (gas: 190701) +FunctionsSubscriptions_RemoveConsumer:test_RemoveConsumer_Success() (gas: 41979) +FunctionsSubscriptions_SetFlags:test_SetFlags_RevertIfNoSubscription() (gas: 12847) +FunctionsSubscriptions_SetFlags:test_SetFlags_RevertIfNotOwner() (gas: 15640) +FunctionsSubscriptions_SetFlags:test_SetFlags_Success() (gas: 35549) +FunctionsSubscriptions_TimeoutRequests:test_TimeoutRequests_RevertIfPaused() (gas: 25859) +FunctionsSubscriptions_TimeoutRequests:test_TimeoutRequests_RevertIfTimeoutNotExceeded() (gas: 25188) +FunctionsSubscriptions_TimeoutRequests:test_TimeoutRequests_RevertInvalidRequest() (gas: 28142) +FunctionsSubscriptions_TimeoutRequests:test_TimeoutRequests_Success() (gas: 57634) FunctionsSubscriptions_createSubscription:test_CreateSubscription_RevertIfNotAllowedSender() (gas: 26368) FunctionsSubscriptions_createSubscription:test_CreateSubscription_RevertIfPaused() (gas: 15714) -FunctionsSubscriptions_createSubscription:test_CreateSubscription_Success() (gas: 152436) \ No newline at end of file +FunctionsSubscriptions_createSubscription:test_CreateSubscription_Success() (gas: 152510) +FunctionsTermsOfServiceAllowList_AcceptTermsOfService:test_AcceptTermsOfService_RevertIfAcceptorIsNotSender() (gas: 25855) +FunctionsTermsOfServiceAllowList_AcceptTermsOfService:test_AcceptTermsOfService_RevertIfBlockedSender() (gas: 44366) +FunctionsTermsOfServiceAllowList_AcceptTermsOfService:test_AcceptTermsOfService_RevertIfInvalidSigner() (gas: 23615) +FunctionsTermsOfServiceAllowList_AcceptTermsOfService:test_AcceptTermsOfService_RevertIfRecipientContractIsNotSender() (gas: 1458273) +FunctionsTermsOfServiceAllowList_AcceptTermsOfService:test_AcceptTermsOfService_RevertIfRecipientIsNotSender() (gas: 26021) +FunctionsTermsOfServiceAllowList_AcceptTermsOfService:test_AcceptTermsOfService_SuccessIfAcceptingForContract() (gas: 1538382) +FunctionsTermsOfServiceAllowList_AcceptTermsOfService:test_AcceptTermsOfService_SuccessIfAcceptingForSelf() (gas: 94702) +FunctionsTermsOfServiceAllowList_BlockSender:test_BlockSender_RevertIfNotOwner() (gas: 15469) +FunctionsTermsOfServiceAllowList_BlockSender:test_BlockSender_Success() (gas: 50442) +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: 11592) +FunctionsTermsOfServiceAllowList_HasAccess:test_HasAccess_FalseWhenEnabled() (gas: 15931) +FunctionsTermsOfServiceAllowList_HasAccess:test_HasAccess_TrueWhenDisabled() (gas: 23445) +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: 95208) +FunctionsTermsOfServiceAllowList_UpdateConfig:test_UpdateConfig_RevertIfNotOwner() (gas: 13736) +FunctionsTermsOfServiceAllowList_UpdateConfig:test_UpdateConfig_Success() (gas: 22082) \ No newline at end of file diff --git a/contracts/gas-snapshots/llo-feeds.gas-snapshot b/contracts/gas-snapshots/llo-feeds.gas-snapshot index 1d28475c217..6dd9eff24c2 100644 --- a/contracts/gas-snapshots/llo-feeds.gas-snapshot +++ b/contracts/gas-snapshots/llo-feeds.gas-snapshot @@ -1,255 +1,265 @@ -FeeManagerProcessFeeTest:test_DiscountIsAppliedForNative() (gas: 47621) -FeeManagerProcessFeeTest:test_V1PayloadVerifies() (gas: 21051) -FeeManagerProcessFeeTest:test_V1PayloadVerifiesAndReturnsChange() (gas: 52298) -FeeManagerProcessFeeTest:test_V2PayloadVerifies() (gas: 112748) -FeeManagerProcessFeeTest:test_V2PayloadWithoutQuoteFails() (gas: 23646) -FeeManagerProcessFeeTest:test_V2PayloadWithoutZeroFee() (gas: 69576) -FeeManagerProcessFeeTest:test_WithdrawERC20() (gas: 63969) -FeeManagerProcessFeeTest:test_WithdrawNonAdminAddr() (gas: 48730) -FeeManagerProcessFeeTest:test_WithdrawUnwrappedNative() (gas: 20326) -FeeManagerProcessFeeTest:test_baseFeeIsAppliedForLink() (gas: 14621) -FeeManagerProcessFeeTest:test_baseFeeIsAppliedForNative() (gas: 17579) -FeeManagerProcessFeeTest:test_correctDiscountIsAppliedWhenBothTokensAreDiscounted() (gas: 83432) -FeeManagerProcessFeeTest:test_discountAIsNotAppliedWhenSetForOtherUsers() (gas: 51511) -FeeManagerProcessFeeTest:test_discountFeeRoundsDownWhenUneven() (gas: 47789) -FeeManagerProcessFeeTest:test_discountIsAppliedForLink() (gas: 44614) -FeeManagerProcessFeeTest:test_discountIsAppliedWith100PercentSurcharge() (gas: 71358) -FeeManagerProcessFeeTest:test_discountIsNoLongerAppliedAfterRemoving() (gas: 40470) -FeeManagerProcessFeeTest:test_discountIsNotAppliedForInvalidTokenAddress() (gas: 12600) -FeeManagerProcessFeeTest:test_discountIsNotAppliedToOtherFeeds() (gas: 49535) -FeeManagerProcessFeeTest:test_emptyQuoteRevertsWithError() (gas: 12339) -FeeManagerProcessFeeTest:test_eventIsEmittedAfterSurchargeIsSet() (gas: 36370) -FeeManagerProcessFeeTest:test_eventIsEmittedIfNotEnoughLink() (gas: 251051) -FeeManagerProcessFeeTest:test_eventIsEmittedUponWithdraw() (gas: 61024) -FeeManagerProcessFeeTest:test_feeIsUpdatedAfterDiscountIsRemoved() (gas: 43696) -FeeManagerProcessFeeTest:test_feeIsUpdatedAfterNewDiscountIsApplied() (gas: 60080) -FeeManagerProcessFeeTest:test_feeIsUpdatedAfterNewSurchargeIsApplied() (gas: 56719) -FeeManagerProcessFeeTest:test_feeIsZeroWith100PercentDiscount() (gas: 47021) -FeeManagerProcessFeeTest:test_getBaseRewardWithLinkQuote() (gas: 14641) -FeeManagerProcessFeeTest:test_getLinkFeeIsRoundedUp() (gas: 44805) -FeeManagerProcessFeeTest:test_getLinkRewardIsSameAsFee() (gas: 50542) -FeeManagerProcessFeeTest:test_getLinkRewardWithNativeQuoteAndSurchargeWithLinkDiscount() (gas: 75290) -FeeManagerProcessFeeTest:test_getRewardWithLinkDiscount() (gas: 44657) -FeeManagerProcessFeeTest:test_getRewardWithLinkQuoteAndLinkDiscount() (gas: 44615) -FeeManagerProcessFeeTest:test_getRewardWithNativeQuote() (gas: 17579) -FeeManagerProcessFeeTest:test_getRewardWithNativeQuoteAndSurcharge() (gas: 45838) -FeeManagerProcessFeeTest:test_linkAvailableForPaymentReturnsLinkBalance() (gas: 47404) -FeeManagerProcessFeeTest:test_nativeSurcharge0Percent() (gas: 25823) -FeeManagerProcessFeeTest:test_nativeSurcharge100Percent() (gas: 45814) -FeeManagerProcessFeeTest:test_nativeSurchargeCannotExceed100Percent() (gas: 12211) -FeeManagerProcessFeeTest:test_nativeSurchargeEventIsEmittedOnUpdate() (gas: 36393) -FeeManagerProcessFeeTest:test_noFeeIsAppliedWhenReportHasZeroFee() (gas: 46866) -FeeManagerProcessFeeTest:test_noFeeIsAppliedWhenReportHasZeroFeeAndDiscountAndSurchargeIsSet() (gas: 70581) -FeeManagerProcessFeeTest:test_nonAdminProxyUserCannotProcessFee() (gas: 19160) -FeeManagerProcessFeeTest:test_nonAdminUserCanNotSetDiscount() (gas: 14846) -FeeManagerProcessFeeTest:test_payLinkDeficit() (gas: 187316) -FeeManagerProcessFeeTest:test_payLinkDeficitOnlyCallableByAdmin() (gas: 12367) -FeeManagerProcessFeeTest:test_payLinkDeficitPaysAllFeesProcessed() (gas: 206512) -FeeManagerProcessFeeTest:test_payLinkDeficitTwice() (gas: 189668) -FeeManagerProcessFeeTest:test_processFeeAsProxy() (gas: 113142) -FeeManagerProcessFeeTest:test_processFeeDefaultReportsStillVerifiesWithEmptyQuote() (gas: 21857) -FeeManagerProcessFeeTest:test_processFeeEmitsEventIfNotEnoughLink() (gas: 153995) -FeeManagerProcessFeeTest:test_processFeeIfSubscriberIsSelf() (gas: 22485) -FeeManagerProcessFeeTest:test_processFeeNative() (gas: 166691) -FeeManagerProcessFeeTest:test_processFeeUsesCorrectDigest() (gas: 114102) -FeeManagerProcessFeeTest:test_processFeeWithDefaultReportPayloadAndQuoteStillVerifies() (gas: 24176) -FeeManagerProcessFeeTest:test_processFeeWithInvalidReportVersionFailsToDecode() (gas: 25660) -FeeManagerProcessFeeTest:test_processFeeWithUnwrappedNative() (gas: 176693) -FeeManagerProcessFeeTest:test_processFeeWithUnwrappedNativeLinkAddress() (gas: 128211) -FeeManagerProcessFeeTest:test_processFeeWithUnwrappedNativeLinkAddressExcessiveFee() (gas: 152075) -FeeManagerProcessFeeTest:test_processFeeWithUnwrappedNativeShortFunds() (gas: 87203) -FeeManagerProcessFeeTest:test_processFeeWithUnwrappedNativeWithExcessiveFee() (gas: 183653) -FeeManagerProcessFeeTest:test_processFeeWithWithCorruptQuotePayload() (gas: 23529) -FeeManagerProcessFeeTest:test_processFeeWithWithEmptyQuotePayload() (gas: 23997) -FeeManagerProcessFeeTest:test_processFeeWithWithZeroQuotePayload() (gas: 24986) -FeeManagerProcessFeeTest:test_processFeeWithZeroLinkNonZeroNativeWithLinkQuote() (gas: 30202) -FeeManagerProcessFeeTest:test_processFeeWithZeroLinkNonZeroNativeWithNativeQuote() (gas: 146602) -FeeManagerProcessFeeTest:test_processFeeWithZeroNativeNonZeroLinkReturnsChange() (gas: 50621) -FeeManagerProcessFeeTest:test_processFeeWithZeroNativeNonZeroLinkWithLinkQuote() (gas: 113108) -FeeManagerProcessFeeTest:test_processFeeWithZeroNativeNonZeroLinkWithNativeQuote() (gas: 32904) -FeeManagerProcessFeeTest:test_processMultipleLinkAndNativeUnwrappedReports() (gas: 286610) -FeeManagerProcessFeeTest:test_processMultipleLinkAndNativeWrappedReports() (gas: 267369) -FeeManagerProcessFeeTest:test_processMultipleLinkReports() (gas: 229026) -FeeManagerProcessFeeTest:test_processMultipleUnwrappedNativeReports() (gas: 262798) -FeeManagerProcessFeeTest:test_processMultipleV1Reports() (gas: 66250) -FeeManagerProcessFeeTest:test_processMultipleWrappedNativeReports() (gas: 243449) -FeeManagerProcessFeeTest:test_processV1V2V3Reports() (gas: 271565) -FeeManagerProcessFeeTest:test_processV1V2V3ReportsWithUnwrapped() (gas: 290783) -FeeManagerProcessFeeTest:test_reportWithNoExpiryOrFeeReturnsZero() (gas: 11011) -FeeManagerProcessFeeTest:test_setDiscountOver100Percent() (gas: 14580) -FeeManagerProcessFeeTest:test_subscriberDiscountEventIsEmittedOnUpdate() (gas: 41313) -FeeManagerProcessFeeTest:test_surchargeFeeRoundsUpWhenUneven() (gas: 46123) -FeeManagerProcessFeeTest:test_surchargeIsApplied() (gas: 46091) -FeeManagerProcessFeeTest:test_surchargeIsAppliedForNativeFeeWithDiscount() (gas: 71754) -FeeManagerProcessFeeTest:test_surchargeIsNoLongerAppliedAfterRemoving() (gas: 41011) -FeeManagerProcessFeeTest:test_surchargeIsNotAppliedForLinkFee() (gas: 44871) -FeeManagerProcessFeeTest:test_surchargeIsNotAppliedWith100PercentDiscount() (gas: 70774) -FeeManagerProcessFeeTest:test_testRevertIfReportHasExpired() (gas: 15198) -RewardManagerClaimTest:test_claimAllRecipients() (gas: 263344) -RewardManagerClaimTest:test_claimMultipleRecipients() (gas: 145864) -RewardManagerClaimTest:test_claimRewardsWithDuplicatePoolIdsDoesNotPayoutTwice() (gas: 315564) -RewardManagerClaimTest:test_claimSingleRecipient() (gas: 83367) -RewardManagerClaimTest:test_claimUnevenAmountRoundsDown() (gas: 300721) -RewardManagerClaimTest:test_claimUnregisteredPoolId() (gas: 29488) -RewardManagerClaimTest:test_claimUnregisteredRecipient() (gas: 35524) -RewardManagerClaimTest:test_eventIsEmittedUponClaim() (gas: 81096) -RewardManagerClaimTest:test_eventIsNotEmittedUponUnsuccessfulClaim() (gas: 19727) -RewardManagerClaimTest:test_recipientsClaimMultipleDeposits() (gas: 360373) -RewardManagerClaimTest:test_singleRecipientClaimMultipleDeposits() (gas: 128499) -RewardManagerNoRecipientSet:test_claimAllRecipientsAfterRecipientsSet() (gas: 464475) -RewardManagerPayRecipientsTest:test_addFundsToPoolAsNonOwnerOrFeeManager() (gas: 13550) -RewardManagerPayRecipientsTest:test_addFundsToPoolAsOwner() (gas: 51601) -RewardManagerPayRecipientsTest:test_payAllRecipients() (gas: 244544) -RewardManagerPayRecipientsTest:test_payAllRecipientsFromNonAdminUser() (gas: 15559) -RewardManagerPayRecipientsTest:test_payAllRecipientsFromRecipientInPool() (gas: 244790) -RewardManagerPayRecipientsTest:test_payAllRecipientsWithAdditionalInvalidRecipient() (gas: 255968) -RewardManagerPayRecipientsTest:test_payAllRecipientsWithAdditionalUnregisteredRecipient() (gas: 259108) -RewardManagerPayRecipientsTest:test_payRecipientWithInvalidPool() (gas: 23623) -RewardManagerPayRecipientsTest:test_payRecipientsEmptyRecipientList() (gas: 20065) -RewardManagerPayRecipientsTest:test_payRecipientsWithInvalidPoolId() (gas: 26139) -RewardManagerPayRecipientsTest:test_paySingleRecipient() (gas: 79428) -RewardManagerPayRecipientsTest:test_paySubsetOfRecipientsInPool() (gas: 192529) -RewardManagerRecipientClaimDifferentWeightsTest:test_allRecipientsClaimingReceiveExpectedAmount() (gas: 267295) -RewardManagerRecipientClaimMultiplePoolsTest:test_claimAllRecipientsMultiplePools() (gas: 487453) -RewardManagerRecipientClaimMultiplePoolsTest:test_claimAllRecipientsSinglePool() (gas: 269391) -RewardManagerRecipientClaimMultiplePoolsTest:test_claimEmptyPoolWhenSecondPoolContainsFunds() (gas: 276703) -RewardManagerRecipientClaimMultiplePoolsTest:test_claimMultipleRecipientsMultiplePools() (gas: 249180) -RewardManagerRecipientClaimMultiplePoolsTest:test_claimMultipleRecipientsSinglePool() (gas: 145948) -RewardManagerRecipientClaimMultiplePoolsTest:test_claimSingleRecipientMultiplePools() (gas: 124471) -RewardManagerRecipientClaimMultiplePoolsTest:test_claimSingleUniqueRecipient() (gas: 97872) -RewardManagerRecipientClaimMultiplePoolsTest:test_claimUnevenAmountRoundsDown() (gas: 551064) -RewardManagerRecipientClaimMultiplePoolsTest:test_claimUnregisteredRecipient() (gas: 56091) -RewardManagerRecipientClaimMultiplePoolsTest:test_getRewardsAvailableToRecipientInBothPools() (gas: 28864) -RewardManagerRecipientClaimMultiplePoolsTest:test_getRewardsAvailableToRecipientInBothPoolsWhereAlreadyClaimed() (gas: 139395) -RewardManagerRecipientClaimMultiplePoolsTest:test_getRewardsAvailableToRecipientInNoPools() (gas: 18363) -RewardManagerRecipientClaimMultiplePoolsTest:test_getRewardsAvailableToRecipientInSinglePool() (gas: 24381) -RewardManagerRecipientClaimMultiplePoolsTest:test_recipientsClaimMultipleDeposits() (gas: 364823) -RewardManagerRecipientClaimMultiplePoolsTest:test_singleRecipientClaimMultipleDeposits() (gas: 128515) -RewardManagerRecipientClaimUnevenWeightTest:test_allRecipientsClaimingReceiveExpectedAmount() (gas: 190638) -RewardManagerRecipientClaimUnevenWeightTest:test_allRecipientsClaimingReceiveExpectedAmountWithSmallDeposit() (gas: 210530) -RewardManagerSetRecipientsTest:test_eventIsEmittedUponSetRecipients() (gas: 186872) -RewardManagerSetRecipientsTest:test_setRecipientContainsDuplicateRecipients() (gas: 121134) -RewardManagerSetRecipientsTest:test_setRewardRecipientFromManagerAddress() (gas: 186535) -RewardManagerSetRecipientsTest:test_setRewardRecipientFromNonOwnerOrFeeManagerAddress() (gas: 16504) -RewardManagerSetRecipientsTest:test_setRewardRecipientTwice() (gas: 185999) -RewardManagerSetRecipientsTest:test_setRewardRecipientWeights() (gas: 175763) -RewardManagerSetRecipientsTest:test_setRewardRecipientWithZeroAddress() (gas: 85276) -RewardManagerSetRecipientsTest:test_setRewardRecipientWithZeroWeight() (gas: 178782) -RewardManagerSetRecipientsTest:test_setRewardRecipients() (gas: 180711) -RewardManagerSetRecipientsTest:test_setRewardRecipientsIsEmpty() (gas: 82166) -RewardManagerSetRecipientsTest:test_setSingleRewardRecipient() (gas: 105471) -RewardManagerSetupTest:test_eventEmittedUponFeeManagerUpdate() (gas: 16367) -RewardManagerSetupTest:test_eventEmittedUponFeePaid() (gas: 255602) -RewardManagerSetupTest:test_rejectsZeroLinkAddressOnConstruction() (gas: 59390) -RewardManagerSetupTest:test_setFeeManagerZeroAddress() (gas: 12039) -RewardManagerUpdateRewardRecipientsMultiplePoolsTest:test_updatePrimaryRecipientWeights() (gas: 356489) -RewardManagerUpdateRewardRecipientsTest:test_eventIsEmittedUponUpdateRecipients() (gas: 274297) -RewardManagerUpdateRewardRecipientsTest:test_onlyAdminCanUpdateRecipients() (gas: 14757) -RewardManagerUpdateRewardRecipientsTest:test_partialUpdateRecipientWeights() (gas: 206711) -RewardManagerUpdateRewardRecipientsTest:test_updateAllRecipientsWithSameAddressAndWeight() (gas: 268121) -RewardManagerUpdateRewardRecipientsTest:test_updatePartialRecipientsToSubset() (gas: 240361) -RewardManagerUpdateRewardRecipientsTest:test_updatePartialRecipientsWithExcessiveWeight() (gas: 254433) -RewardManagerUpdateRewardRecipientsTest:test_updatePartialRecipientsWithSameAddressAndWeight() (gas: 144023) -RewardManagerUpdateRewardRecipientsTest:test_updatePartialRecipientsWithUnderWeightSet() (gas: 254507) -RewardManagerUpdateRewardRecipientsTest:test_updateRecipientWeights() (gas: 351970) -RewardManagerUpdateRewardRecipientsTest:test_updateRecipientWithNewZeroAddress() (gas: 253649) -RewardManagerUpdateRewardRecipientsTest:test_updateRecipientsContainsDuplicateRecipients() (gas: 283778) -RewardManagerUpdateRewardRecipientsTest:test_updateRecipientsToDifferentLargerSet() (gas: 256457) -RewardManagerUpdateRewardRecipientsTest:test_updateRecipientsToDifferentPartialSet() (gas: 254436) -RewardManagerUpdateRewardRecipientsTest:test_updateRecipientsToDifferentSet() (gas: 255845) -RewardManagerUpdateRewardRecipientsTest:test_updateRecipientsToDifferentSetWithInvalidWeights() (gas: 254576) -RewardManagerUpdateRewardRecipientsTest:test_updateRecipientsUpdateAndRemoveExistingForLargerSet() (gas: 246971) -RewardManagerUpdateRewardRecipientsTest:test_updateRecipientsUpdateAndRemoveExistingForSmallerSet() (gas: 245257) +FeeManagerProcessFeeTest:test_DiscountIsAppliedForNative() (gas: 52634) +FeeManagerProcessFeeTest:test_DiscountIsReturnedForNative() (gas: 52566) +FeeManagerProcessFeeTest:test_DiscountIsReturnedForNativeWithSurcharge() (gas: 78769) +FeeManagerProcessFeeTest:test_V1PayloadVerifies() (gas: 25961) +FeeManagerProcessFeeTest:test_V1PayloadVerifiesAndReturnsChange() (gas: 57252) +FeeManagerProcessFeeTest:test_V2PayloadVerifies() (gas: 118189) +FeeManagerProcessFeeTest:test_V2PayloadWithoutQuoteFails() (gas: 28568) +FeeManagerProcessFeeTest:test_V2PayloadWithoutZeroFee() (gas: 72501) +FeeManagerProcessFeeTest:test_WithdrawERC20() (gas: 71670) +FeeManagerProcessFeeTest:test_WithdrawNonAdminAddr() (gas: 56292) +FeeManagerProcessFeeTest:test_WithdrawUnwrappedNative() (gas: 25344) +FeeManagerProcessFeeTest:test_baseFeeIsAppliedForLink() (gas: 14623) +FeeManagerProcessFeeTest:test_baseFeeIsAppliedForNative() (gas: 17581) +FeeManagerProcessFeeTest:test_correctDiscountIsAppliedWhenBothTokensAreDiscounted() (gas: 90945) +FeeManagerProcessFeeTest:test_discountAIsNotAppliedWhenSetForOtherUsers() (gas: 56524) +FeeManagerProcessFeeTest:test_discountFeeRoundsDownWhenUneven() (gas: 52803) +FeeManagerProcessFeeTest:test_discountIsAppliedForLink() (gas: 49627) +FeeManagerProcessFeeTest:test_discountIsAppliedWith100PercentSurcharge() (gas: 78817) +FeeManagerProcessFeeTest:test_discountIsNoLongerAppliedAfterRemoving() (gas: 46428) +FeeManagerProcessFeeTest:test_discountIsNotAppliedForInvalidTokenAddress() (gas: 17568) +FeeManagerProcessFeeTest:test_discountIsNotAppliedToOtherFeeds() (gas: 54571) +FeeManagerProcessFeeTest:test_discountIsReturnedForLink() (gas: 49581) +FeeManagerProcessFeeTest:test_emptyQuoteRevertsWithError() (gas: 12392) +FeeManagerProcessFeeTest:test_eventIsEmittedAfterSurchargeIsSet() (gas: 41412) +FeeManagerProcessFeeTest:test_eventIsEmittedIfNotEnoughLink() (gas: 259447) +FeeManagerProcessFeeTest:test_eventIsEmittedUponWithdraw() (gas: 69018) +FeeManagerProcessFeeTest:test_feeIsUpdatedAfterDiscountIsRemoved() (gas: 49706) +FeeManagerProcessFeeTest:test_feeIsUpdatedAfterNewDiscountIsApplied() (gas: 67635) +FeeManagerProcessFeeTest:test_feeIsUpdatedAfterNewSurchargeIsApplied() (gas: 64232) +FeeManagerProcessFeeTest:test_feeIsZeroWith100PercentDiscount() (gas: 52012) +FeeManagerProcessFeeTest:test_getBaseRewardWithLinkQuote() (gas: 14621) +FeeManagerProcessFeeTest:test_getLinkFeeIsRoundedUp() (gas: 49774) +FeeManagerProcessFeeTest:test_getLinkRewardIsSameAsFee() (gas: 55561) +FeeManagerProcessFeeTest:test_getLinkRewardWithNativeQuoteAndSurchargeWithLinkDiscount() (gas: 82702) +FeeManagerProcessFeeTest:test_getRewardWithLinkDiscount() (gas: 49602) +FeeManagerProcessFeeTest:test_getRewardWithLinkQuoteAndLinkDiscount() (gas: 49604) +FeeManagerProcessFeeTest:test_getRewardWithNativeQuote() (gas: 17601) +FeeManagerProcessFeeTest:test_getRewardWithNativeQuoteAndSurcharge() (gas: 50826) +FeeManagerProcessFeeTest:test_linkAvailableForPaymentReturnsLinkBalance() (gas: 52375) +FeeManagerProcessFeeTest:test_nativeSurcharge0Percent() (gas: 30814) +FeeManagerProcessFeeTest:test_nativeSurcharge100Percent() (gas: 50827) +FeeManagerProcessFeeTest:test_nativeSurchargeCannotExceed100Percent() (gas: 17166) +FeeManagerProcessFeeTest:test_nativeSurchargeEventIsEmittedOnUpdate() (gas: 41370) +FeeManagerProcessFeeTest:test_noFeeIsAppliedWhenReportHasZeroFee() (gas: 51879) +FeeManagerProcessFeeTest:test_noFeeIsAppliedWhenReportHasZeroFeeAndDiscountAndSurchargeIsSet() (gas: 78062) +FeeManagerProcessFeeTest:test_nonAdminProxyUserCannotProcessFee() (gas: 21892) +FeeManagerProcessFeeTest:test_nonAdminUserCanNotSetDiscount() (gas: 19836) +FeeManagerProcessFeeTest:test_payLinkDeficit() (gas: 195521) +FeeManagerProcessFeeTest:test_payLinkDeficitOnlyCallableByAdmin() (gas: 17360) +FeeManagerProcessFeeTest:test_payLinkDeficitPaysAllFeesProcessed() (gas: 216708) +FeeManagerProcessFeeTest:test_payLinkDeficitTwice() (gas: 199820) +FeeManagerProcessFeeTest:test_processFeeAsProxy() (gas: 118561) +FeeManagerProcessFeeTest:test_processFeeDefaultReportsStillVerifiesWithEmptyQuote() (gas: 26811) +FeeManagerProcessFeeTest:test_processFeeEmitsEventIfNotEnoughLink() (gas: 163961) +FeeManagerProcessFeeTest:test_processFeeIfSubscriberIsSelf() (gas: 27362) +FeeManagerProcessFeeTest:test_processFeeNative() (gas: 174559) +FeeManagerProcessFeeTest:test_processFeeUsesCorrectDigest() (gas: 119521) +FeeManagerProcessFeeTest:test_processFeeWithDefaultReportPayloadAndQuoteStillVerifies() (gas: 29175) +FeeManagerProcessFeeTest:test_processFeeWithDiscountEmitsEvent() (gas: 244302) +FeeManagerProcessFeeTest:test_processFeeWithInvalidReportVersionFailsToDecode() (gas: 30610) +FeeManagerProcessFeeTest:test_processFeeWithNoDiscountDoesNotEmitEvent() (gas: 168476) +FeeManagerProcessFeeTest:test_processFeeWithUnwrappedNative() (gas: 182111) +FeeManagerProcessFeeTest:test_processFeeWithUnwrappedNativeLinkAddress() (gas: 133607) +FeeManagerProcessFeeTest:test_processFeeWithUnwrappedNativeLinkAddressExcessiveFee() (gas: 157494) +FeeManagerProcessFeeTest:test_processFeeWithUnwrappedNativeShortFunds() (gas: 94743) +FeeManagerProcessFeeTest:test_processFeeWithUnwrappedNativeWithExcessiveFee() (gas: 189049) +FeeManagerProcessFeeTest:test_processFeeWithWithCorruptQuotePayload() (gas: 28473) +FeeManagerProcessFeeTest:test_processFeeWithWithEmptyQuotePayload() (gas: 28919) +FeeManagerProcessFeeTest:test_processFeeWithWithZeroQuotePayload() (gas: 29914) +FeeManagerProcessFeeTest:test_processFeeWithZeroLinkNonZeroNativeWithLinkQuote() (gas: 35154) +FeeManagerProcessFeeTest:test_processFeeWithZeroLinkNonZeroNativeWithNativeQuote() (gas: 154448) +FeeManagerProcessFeeTest:test_processFeeWithZeroNativeNonZeroLinkReturnsChange() (gas: 55617) +FeeManagerProcessFeeTest:test_processFeeWithZeroNativeNonZeroLinkWithLinkQuote() (gas: 118462) +FeeManagerProcessFeeTest:test_processFeeWithZeroNativeNonZeroLinkWithNativeQuote() (gas: 37856) +FeeManagerProcessFeeTest:test_processMultipleLinkAndNativeUnwrappedReports() (gas: 295021) +FeeManagerProcessFeeTest:test_processMultipleLinkAndNativeWrappedReports() (gas: 278263) +FeeManagerProcessFeeTest:test_processMultipleLinkReports() (gas: 235077) +FeeManagerProcessFeeTest:test_processMultipleUnwrappedNativeReports() (gas: 268847) +FeeManagerProcessFeeTest:test_processMultipleV1Reports() (gas: 71419) +FeeManagerProcessFeeTest:test_processMultipleWrappedNativeReports() (gas: 251978) +FeeManagerProcessFeeTest:test_processV1V2V3Reports() (gas: 282317) +FeeManagerProcessFeeTest:test_processV1V2V3ReportsWithUnwrapped() (gas: 299043) +FeeManagerProcessFeeTest:test_reportWithNoExpiryOrFeeReturnsZero() (gas: 11038) +FeeManagerProcessFeeTest:test_setDiscountOver100Percent() (gas: 19548) +FeeManagerProcessFeeTest:test_subscriberDiscountEventIsEmittedOnUpdate() (gas: 46281) +FeeManagerProcessFeeTest:test_surchargeFeeRoundsUpWhenUneven() (gas: 51157) +FeeManagerProcessFeeTest:test_surchargeIsApplied() (gas: 51082) +FeeManagerProcessFeeTest:test_surchargeIsAppliedForNativeFeeWithDiscount() (gas: 79236) +FeeManagerProcessFeeTest:test_surchargeIsNoLongerAppliedAfterRemoving() (gas: 47004) +FeeManagerProcessFeeTest:test_surchargeIsNotAppliedForLinkFee() (gas: 49862) +FeeManagerProcessFeeTest:test_surchargeIsNotAppliedWith100PercentDiscount() (gas: 78233) +FeeManagerProcessFeeTest:test_testRevertIfReportHasExpired() (gas: 15251) +RewardManagerClaimTest:test_claimAllRecipients() (gas: 275763) +RewardManagerClaimTest:test_claimMultipleRecipients() (gas: 153306) +RewardManagerClaimTest:test_claimRewardsWithDuplicatePoolIdsDoesNotPayoutTwice() (gas: 328322) +RewardManagerClaimTest:test_claimSingleRecipient() (gas: 88340) +RewardManagerClaimTest:test_claimUnevenAmountRoundsDown() (gas: 313526) +RewardManagerClaimTest:test_claimUnregisteredPoolId() (gas: 34461) +RewardManagerClaimTest:test_claimUnregisteredRecipient() (gas: 40491) +RewardManagerClaimTest:test_eventIsEmittedUponClaim() (gas: 86069) +RewardManagerClaimTest:test_eventIsNotEmittedUponUnsuccessfulClaim() (gas: 24700) +RewardManagerClaimTest:test_recipientsClaimMultipleDeposits() (gas: 383191) +RewardManagerClaimTest:test_singleRecipientClaimMultipleDeposits() (gas: 136266) +RewardManagerNoRecipientSet:test_claimAllRecipientsAfterRecipientsSet() (gas: 489469) +RewardManagerPayRecipientsTest:test_addFundsToPoolAsNonOwnerOrFeeManager() (gas: 11405) +RewardManagerPayRecipientsTest:test_addFundsToPoolAsOwner() (gas: 53858) +RewardManagerPayRecipientsTest:test_payAllRecipients() (gas: 249449) +RewardManagerPayRecipientsTest:test_payAllRecipientsFromNonAdminUser() (gas: 20452) +RewardManagerPayRecipientsTest:test_payAllRecipientsFromRecipientInPool() (gas: 249695) +RewardManagerPayRecipientsTest:test_payAllRecipientsWithAdditionalInvalidRecipient() (gas: 260899) +RewardManagerPayRecipientsTest:test_payAllRecipientsWithAdditionalUnregisteredRecipient() (gas: 264035) +RewardManagerPayRecipientsTest:test_payRecipientWithInvalidPool() (gas: 28526) +RewardManagerPayRecipientsTest:test_payRecipientsEmptyRecipientList() (gas: 24947) +RewardManagerPayRecipientsTest:test_payRecipientsWithInvalidPoolId() (gas: 31032) +RewardManagerPayRecipientsTest:test_paySingleRecipient() (gas: 84331) +RewardManagerPayRecipientsTest:test_paySubsetOfRecipientsInPool() (gas: 197426) +RewardManagerRecipientClaimDifferentWeightsTest:test_allRecipientsClaimingReceiveExpectedAmount() (gas: 279714) +RewardManagerRecipientClaimMultiplePoolsTest:test_claimAllRecipientsMultiplePools() (gas: 509889) +RewardManagerRecipientClaimMultiplePoolsTest:test_claimAllRecipientsSinglePool() (gas: 281811) +RewardManagerRecipientClaimMultiplePoolsTest:test_claimEmptyPoolWhenSecondPoolContainsFunds() (gas: 291640) +RewardManagerRecipientClaimMultiplePoolsTest:test_claimMultipleRecipientsMultiplePools() (gas: 261589) +RewardManagerRecipientClaimMultiplePoolsTest:test_claimMultipleRecipientsSinglePool() (gas: 153434) +RewardManagerRecipientClaimMultiplePoolsTest:test_claimSingleRecipientMultiplePools() (gas: 131911) +RewardManagerRecipientClaimMultiplePoolsTest:test_claimSingleUniqueRecipient() (gas: 105312) +RewardManagerRecipientClaimMultiplePoolsTest:test_claimUnevenAmountRoundsDown() (gas: 576243) +RewardManagerRecipientClaimMultiplePoolsTest:test_claimUnregisteredRecipient() (gas: 63555) +RewardManagerRecipientClaimMultiplePoolsTest:test_getAvailableRewardsCursorAndTotalPoolsEqual() (gas: 10202) +RewardManagerRecipientClaimMultiplePoolsTest:test_getAvailableRewardsCursorCannotBeGreaterThanTotalPools() (gas: 12680) +RewardManagerRecipientClaimMultiplePoolsTest:test_getAvailableRewardsCursorSingleResult() (gas: 19606) +RewardManagerRecipientClaimMultiplePoolsTest:test_getRewardsAvailableToRecipientInBothPools() (gas: 29052) +RewardManagerRecipientClaimMultiplePoolsTest:test_getRewardsAvailableToRecipientInBothPoolsWhereAlreadyClaimed() (gas: 147218) +RewardManagerRecipientClaimMultiplePoolsTest:test_getRewardsAvailableToRecipientInNoPools() (gas: 18532) +RewardManagerRecipientClaimMultiplePoolsTest:test_getRewardsAvailableToRecipientInSinglePool() (gas: 24569) +RewardManagerRecipientClaimMultiplePoolsTest:test_recipientsClaimMultipleDeposits() (gas: 387641) +RewardManagerRecipientClaimMultiplePoolsTest:test_singleRecipientClaimMultipleDeposits() (gas: 136305) +RewardManagerRecipientClaimUnevenWeightTest:test_allRecipientsClaimingReceiveExpectedAmount() (gas: 198427) +RewardManagerRecipientClaimUnevenWeightTest:test_allRecipientsClaimingReceiveExpectedAmountWithSmallDeposit() (gas: 218297) +RewardManagerSetRecipientsTest:test_eventIsEmittedUponSetRecipients() (gas: 191821) +RewardManagerSetRecipientsTest:test_setRecipientContainsDuplicateRecipients() (gas: 126091) +RewardManagerSetRecipientsTest:test_setRewardRecipientFromManagerAddress() (gas: 193972) +RewardManagerSetRecipientsTest:test_setRewardRecipientFromNonOwnerOrFeeManagerAddress() (gas: 21452) +RewardManagerSetRecipientsTest:test_setRewardRecipientTwice() (gas: 193416) +RewardManagerSetRecipientsTest:test_setRewardRecipientWeights() (gas: 180711) +RewardManagerSetRecipientsTest:test_setRewardRecipientWithZeroAddress() (gas: 90224) +RewardManagerSetRecipientsTest:test_setRewardRecipientWithZeroWeight() (gas: 183724) +RewardManagerSetRecipientsTest:test_setRewardRecipients() (gas: 185681) +RewardManagerSetRecipientsTest:test_setRewardRecipientsIsEmpty() (gas: 87113) +RewardManagerSetRecipientsTest:test_setSingleRewardRecipient() (gas: 110394) +RewardManagerSetupTest:test_eventEmittedUponFeeManagerUpdate() (gas: 21388) +RewardManagerSetupTest:test_eventEmittedUponFeePaid() (gas: 259190) +RewardManagerSetupTest:test_rejectsZeroLinkAddressOnConstruction() (gas: 59418) +RewardManagerSetupTest:test_setFeeManagerZeroAddress() (gas: 17038) +RewardManagerUpdateRewardRecipientsMultiplePoolsTest:test_updatePrimaryRecipientWeights() (gas: 373696) +RewardManagerUpdateRewardRecipientsTest:test_eventIsEmittedUponUpdateRecipients() (gas: 279303) +RewardManagerUpdateRewardRecipientsTest:test_onlyAdminCanUpdateRecipients() (gas: 19749) +RewardManagerUpdateRewardRecipientsTest:test_partialUpdateRecipientWeights() (gas: 218972) +RewardManagerUpdateRewardRecipientsTest:test_updateAllRecipientsWithSameAddressAndWeight() (gas: 273125) +RewardManagerUpdateRewardRecipientsTest:test_updatePartialRecipientsToSubset() (gas: 245331) +RewardManagerUpdateRewardRecipientsTest:test_updatePartialRecipientsWithExcessiveWeight() (gas: 259403) +RewardManagerUpdateRewardRecipientsTest:test_updatePartialRecipientsWithSameAddressAndWeight() (gas: 149004) +RewardManagerUpdateRewardRecipientsTest:test_updatePartialRecipientsWithUnderWeightSet() (gas: 259477) +RewardManagerUpdateRewardRecipientsTest:test_updateRecipientWeights() (gas: 369177) +RewardManagerUpdateRewardRecipientsTest:test_updateRecipientWithNewZeroAddress() (gas: 258619) +RewardManagerUpdateRewardRecipientsTest:test_updateRecipientsContainsDuplicateRecipients() (gas: 288757) +RewardManagerUpdateRewardRecipientsTest:test_updateRecipientsToDifferentLargerSet() (gas: 261428) +RewardManagerUpdateRewardRecipientsTest:test_updateRecipientsToDifferentPartialSet() (gas: 259406) +RewardManagerUpdateRewardRecipientsTest:test_updateRecipientsToDifferentSet() (gas: 260816) +RewardManagerUpdateRewardRecipientsTest:test_updateRecipientsToDifferentSetWithInvalidWeights() (gas: 259546) +RewardManagerUpdateRewardRecipientsTest:test_updateRecipientsUpdateAndRemoveExistingForLargerSet() (gas: 251938) +RewardManagerUpdateRewardRecipientsTest:test_updateRecipientsUpdateAndRemoveExistingForSmallerSet() (gas: 250223) VerificationdeactivateConfigWhenThereAreMultipleDigestsTest:test_correctlyRemovesAMiddleDigest() (gas: 24177) VerificationdeactivateConfigWhenThereAreMultipleDigestsTest:test_correctlyRemovesTheFirstDigest() (gas: 24144) VerificationdeactivateConfigWhenThereAreMultipleDigestsTest:test_correctlyUnsetsDigestsInSequence() (gas: 44109) -VerificationdeactivateConfigWhenThereAreMultipleDigestsTest:test_revertsIfCalledByNonOwner() (gas: 11278) +VerificationdeactivateConfigWhenThereAreMultipleDigestsTest:test_revertsIfCalledByNonOwner() (gas: 15016) VerificationdeactivateConfigWhenThereAreMultipleDigestsTest:test_revertsIfRemovingAnEmptyDigest() (gas: 10907) VerificationdeactivateConfigWhenThereAreMultipleDigestsTest:test_revertsIfRemovingAnNonExistentDigest() (gas: 13381) -VerifierActivateConfigTest:test_revertsIfDigestIsEmpty() (gas: 10962) +VerifierActivateConfigTest:test_revertsIfDigestIsEmpty() (gas: 10984) VerifierActivateConfigTest:test_revertsIfDigestNotSet() (gas: 13394) -VerifierActivateConfigTest:test_revertsIfNotOwner() (gas: 13433) -VerifierActivateConfigWithDeactivatedConfigTest:test_allowsVerification() (gas: 93473) +VerifierActivateConfigTest:test_revertsIfNotOwner() (gas: 17171) +VerifierActivateConfigWithDeactivatedConfigTest:test_allowsVerification() (gas: 97164) VerifierActivateFeedTest:test_revertsIfNoFeedExistsActivate() (gas: 13179) VerifierActivateFeedTest:test_revertsIfNoFeedExistsDeactivate() (gas: 13157) -VerifierActivateFeedTest:test_revertsIfNotOwnerActivateFeed() (gas: 13360) -VerifierActivateFeedTest:test_revertsIfNotOwnerDeactivateFeed() (gas: 13415) -VerifierBulkVerifyBillingReport:test_verifyBulkReportWithUnwrappedAndWrappedNativeDefaultsToUnwrapped() (gas: 386271) -VerifierBulkVerifyBillingReport:test_verifyBulkWithLinkAndUnwrappedNative() (gas: 694977) -VerifierBulkVerifyBillingReport:test_verifyBulkWithLinkAndWrappedNative() (gas: 677095) -VerifierBulkVerifyBillingReport:test_verifyMultiVersions() (gas: 560297) -VerifierBulkVerifyBillingReport:test_verifyMultiVersionsReturnsVerifiedReports() (gas: 773047) -VerifierBulkVerifyBillingReport:test_verifyWithBulkLink() (gas: 572112) -VerifierBulkVerifyBillingReport:test_verifyWithBulkNative() (gas: 573880) -VerifierBulkVerifyBillingReport:test_verifyWithBulkNativeUnwrapped() (gas: 583847) -VerifierBulkVerifyBillingReport:test_verifyWithBulkNativeUnwrappedReturnsChange() (gas: 590874) +VerifierActivateFeedTest:test_revertsIfNotOwnerActivateFeed() (gas: 17098) +VerifierActivateFeedTest:test_revertsIfNotOwnerDeactivateFeed() (gas: 17153) +VerifierBulkVerifyBillingReport:test_verifyBulkReportWithUnwrappedAndWrappedNativeDefaultsToUnwrapped() (gas: 391378) +VerifierBulkVerifyBillingReport:test_verifyBulkWithLinkAndUnwrappedNative() (gas: 700956) +VerifierBulkVerifyBillingReport:test_verifyBulkWithLinkAndWrappedNative() (gas: 685536) +VerifierBulkVerifyBillingReport:test_verifyMultiVersions() (gas: 568369) +VerifierBulkVerifyBillingReport:test_verifyMultiVersionsReturnsVerifiedReports() (gas: 781180) +VerifierBulkVerifyBillingReport:test_verifyWithBulkLink() (gas: 578147) +VerifierBulkVerifyBillingReport:test_verifyWithBulkNative() (gas: 581753) +VerifierBulkVerifyBillingReport:test_verifyWithBulkNativeUnwrapped() (gas: 589227) +VerifierBulkVerifyBillingReport:test_verifyWithBulkNativeUnwrappedReturnsChange() (gas: 596254) VerifierConstructorTest:test_revertsIfInitializedWithEmptyVerifierProxy() (gas: 59967) VerifierConstructorTest:test_setsTheCorrectProperties() (gas: 1815769) -VerifierDeactivateFeedWithVerifyTest:test_currentReportAllowsVerification() (gas: 188300) -VerifierDeactivateFeedWithVerifyTest:test_currentReportFailsVerification() (gas: 109631) -VerifierDeactivateFeedWithVerifyTest:test_previousReportAllowsVerification() (gas: 95877) -VerifierDeactivateFeedWithVerifyTest:test_previousReportFailsVerification() (gas: 66189) -VerifierProxyAccessControlledVerificationTest:test_proxiesToTheVerifierIfHasAccess() (gas: 201062) -VerifierProxyAccessControlledVerificationTest:test_revertsIfNoAccess() (gas: 105778) -VerifierProxyConstructorTest:test_correctlySetsTheCorrectAccessControllerInterface() (gas: 1357277) -VerifierProxyConstructorTest:test_correctlySetsTheOwner() (gas: 1337313) -VerifierProxyConstructorTest:test_correctlySetsVersion() (gas: 6939) -VerifierProxyInitializeVerifierTest:test_revertsIfDigestAlreadySet() (gas: 50355) +VerifierDeactivateFeedWithVerifyTest:test_currentReportAllowsVerification() (gas: 192062) +VerifierDeactivateFeedWithVerifyTest:test_currentReportFailsVerification() (gas: 113377) +VerifierDeactivateFeedWithVerifyTest:test_previousReportAllowsVerification() (gas: 99613) +VerifierDeactivateFeedWithVerifyTest:test_previousReportFailsVerification() (gas: 69932) +VerifierProxyAccessControlledVerificationTest:test_proxiesToTheVerifierIfHasAccess() (gas: 204836) +VerifierProxyAccessControlledVerificationTest:test_revertsIfNoAccess() (gas: 109546) +VerifierProxyConstructorTest:test_correctlySetsTheCorrectAccessControllerInterface() (gas: 1439877) +VerifierProxyConstructorTest:test_correctlySetsTheOwner() (gas: 1419891) +VerifierProxyConstructorTest:test_correctlySetsVersion() (gas: 6873) +VerifierProxyInitializeVerifierTest:test_revertsIfDigestAlreadySet() (gas: 54107) VerifierProxyInitializeVerifierTest:test_revertsIfNotCorrectVerifier() (gas: 13572) -VerifierProxyInitializeVerifierTest:test_revertsIfNotOwner() (gas: 13441) -VerifierProxyInitializeVerifierTest:test_revertsIfVerifierAlreadyInitialized() (gas: 42047) +VerifierProxyInitializeVerifierTest:test_revertsIfNotOwner() (gas: 17179) +VerifierProxyInitializeVerifierTest:test_revertsIfVerifierAlreadyInitialized() (gas: 42069) VerifierProxyInitializeVerifierTest:test_revertsIfZeroAddress() (gas: 10970) -VerifierProxyInitializeVerifierTest:test_setFeeManagerZeroAddress() (gas: 10913) -VerifierProxyInitializeVerifierTest:test_updatesVerifierIfVerifier() (gas: 49605) +VerifierProxyInitializeVerifierTest:test_setFeeManagerWhichDoesntHonourIERC165Interface() (gas: 13815) +VerifierProxyInitializeVerifierTest:test_setFeeManagerWhichDoesntHonourInterface() (gas: 16301) +VerifierProxyInitializeVerifierTest:test_setFeeManagerZeroAddress() (gas: 10947) +VerifierProxyInitializeVerifierTest:test_updatesVerifierIfVerifier() (gas: 53337) VerifierProxySetAccessControllerTest:test_emitsTheCorrectEvent() (gas: 35384) -VerifierProxySetAccessControllerTest:test_revertsIfCalledByNonOwner() (gas: 11367) +VerifierProxySetAccessControllerTest:test_revertsIfCalledByNonOwner() (gas: 15105) VerifierProxySetAccessControllerTest:test_successfullySetsNewAccessController() (gas: 32120) VerifierProxySetAccessControllerTest:test_successfullySetsNewAccessControllerIsEmpty() (gas: 12219) VerifierProxyUnsetVerifierTest:test_revertsIfDigestDoesNotExist() (gas: 13141) -VerifierProxyUnsetVerifierTest:test_revertsIfNotAdmin() (gas: 11227) +VerifierProxyUnsetVerifierTest:test_revertsIfNotAdmin() (gas: 14965) VerifierProxyUnsetVerifierWithPreviouslySetVerifierTest:test_correctlyUnsetsVerifier() (gas: 12697) -VerifierProxyUnsetVerifierWithPreviouslySetVerifierTest:test_emitsAnEventAfterUnsettingVerifier() (gas: 17943) -VerifierProxyVerifyTest:test_proxiesToTheCorrectVerifier() (gas: 198408) -VerifierProxyVerifyTest:test_revertsIfNoVerifierConfigured() (gas: 116352) -VerifierSetConfigFromSourceMultipleDigestsTest:test_correctlySetsConfigWhenDigestsAreRemoved() (gas: 538851) -VerifierSetConfigFromSourceMultipleDigestsTest:test_correctlyUpdatesDigestsOnMultipleVerifiersInTheProxy() (gas: 964679) -VerifierSetConfigFromSourceMultipleDigestsTest:test_correctlyUpdatesTheDigestInTheProxy() (gas: 520412) -VerifierSetConfigFromSourceTest:test_revertsIfCalledByNonOwner() (gas: 179453) +VerifierProxyUnsetVerifierWithPreviouslySetVerifierTest:test_emitsAnEventAfterUnsettingVerifier() (gas: 17965) +VerifierProxyVerifyTest:test_proxiesToTheCorrectVerifier() (gas: 198420) +VerifierProxyVerifyTest:test_revertsIfNoVerifierConfigured() (gas: 116319) +VerifierSetConfigFromSourceMultipleDigestsTest:test_correctlySetsConfigWhenDigestsAreRemoved() (gas: 538873) +VerifierSetConfigFromSourceMultipleDigestsTest:test_correctlyUpdatesDigestsOnMultipleVerifiersInTheProxy() (gas: 964634) +VerifierSetConfigFromSourceMultipleDigestsTest:test_correctlyUpdatesTheDigestInTheProxy() (gas: 520434) +VerifierSetConfigFromSourceTest:test_revertsIfCalledByNonOwner() (gas: 183215) VerifierSetConfigTest:test_correctlyUpdatesTheConfig() (gas: 1057922) -VerifierSetConfigTest:test_revertsIfCalledByNonOwner() (gas: 179244) -VerifierSetConfigTest:test_revertsIfDuplicateSigners() (gas: 251602) +VerifierSetConfigTest:test_revertsIfCalledByNonOwner() (gas: 182984) +VerifierSetConfigTest:test_revertsIfDuplicateSigners() (gas: 251559) VerifierSetConfigTest:test_revertsIfFaultToleranceIsZero() (gas: 176543) VerifierSetConfigTest:test_revertsIfNotEnoughSigners() (gas: 15835) -VerifierSetConfigTest:test_revertsIfSetWithTooManySigners() (gas: 22191) +VerifierSetConfigTest:test_revertsIfSetWithTooManySigners() (gas: 22213) VerifierSetConfigTest:test_revertsIfSignerContainsZeroAddress() (gas: 228032) -VerifierSetConfigWhenThereAreMultipleDigestsTest:test_correctlySetsConfigWhenDigestsAreRemoved() (gas: 538600) -VerifierSetConfigWhenThereAreMultipleDigestsTest:test_correctlyUpdatesDigestsOnMultipleVerifiersInTheProxy() (gas: 964168) -VerifierSetConfigWhenThereAreMultipleDigestsTest:test_correctlyUpdatesTheDigestInTheProxy() (gas: 520152) +VerifierSetConfigWhenThereAreMultipleDigestsTest:test_correctlySetsConfigWhenDigestsAreRemoved() (gas: 538622) +VerifierSetConfigWhenThereAreMultipleDigestsTest:test_correctlyUpdatesDigestsOnMultipleVerifiersInTheProxy() (gas: 964123) +VerifierSetConfigWhenThereAreMultipleDigestsTest:test_correctlyUpdatesTheDigestInTheProxy() (gas: 520174) VerifierSupportsInterfaceTest:test_falseIfIsNotCorrectInterface() (gas: 5590) -VerifierSupportsInterfaceTest:test_trueIfIsCorrectInterface() (gas: 5611) -VerifierTestBillingReport:test_verifyWithLink() (gas: 273128) -VerifierTestBillingReport:test_verifyWithNative() (gas: 313819) -VerifierTestBillingReport:test_verifyWithNativeUnwrapped() (gas: 318543) -VerifierTestBillingReport:test_verifyWithNativeUnwrappedReturnsChange() (gas: 325609) -VerifierVerifyMultipleConfigDigestTest:test_canVerifyNewerReportsWithNewerConfigs() (gas: 127491) -VerifierVerifyMultipleConfigDigestTest:test_canVerifyOlderReportsWithOlderConfigs() (gas: 183370) -VerifierVerifyMultipleConfigDigestTest:test_revertsIfAReportIsVerifiedWithAnExistingButIncorrectDigest() (gas: 84461) -VerifierVerifyMultipleConfigDigestTest:test_revertsIfVerifyingWithAnUnsetDigest() (gas: 124325) -VerifierVerifySingleConfigDigestTest:test_emitsAnEventIfReportVerified() (gas: 183205) -VerifierVerifySingleConfigDigestTest:test_returnsThePriceAndBlockNumIfReportVerified() (gas: 183374) -VerifierVerifySingleConfigDigestTest:test_revertsIfConfigDigestNotSet() (gas: 112427) -VerifierVerifySingleConfigDigestTest:test_revertsIfDuplicateSignersHaveSigned() (gas: 178569) -VerifierVerifySingleConfigDigestTest:test_revertsIfMismatchedSignatureLength() (gas: 49272) -VerifierVerifySingleConfigDigestTest:test_revertsIfReportHasUnconfiguredFeedID() (gas: 100230) +VerifierSupportsInterfaceTest:test_trueIfIsCorrectInterface() (gas: 5633) +VerifierTestBillingReport:test_verifyWithLink() (gas: 278542) +VerifierTestBillingReport:test_verifyWithNative() (gas: 319232) +VerifierTestBillingReport:test_verifyWithNativeUnwrapped() (gas: 321475) +VerifierTestBillingReport:test_verifyWithNativeUnwrappedReturnsChange() (gas: 328541) +VerifierVerifyMultipleConfigDigestTest:test_canVerifyNewerReportsWithNewerConfigs() (gas: 131228) +VerifierVerifyMultipleConfigDigestTest:test_canVerifyOlderReportsWithOlderConfigs() (gas: 187132) +VerifierVerifyMultipleConfigDigestTest:test_revertsIfAReportIsVerifiedWithAnExistingButIncorrectDigest() (gas: 88205) +VerifierVerifyMultipleConfigDigestTest:test_revertsIfVerifyingWithAnUnsetDigest() (gas: 128062) +VerifierVerifySingleConfigDigestTest:test_emitsAnEventIfReportVerified() (gas: 186945) +VerifierVerifySingleConfigDigestTest:test_returnsThePriceAndBlockNumIfReportVerified() (gas: 187114) +VerifierVerifySingleConfigDigestTest:test_revertsIfConfigDigestNotSet() (gas: 116130) +VerifierVerifySingleConfigDigestTest:test_revertsIfDuplicateSignersHaveSigned() (gas: 182315) +VerifierVerifySingleConfigDigestTest:test_revertsIfMismatchedSignatureLength() (gas: 53037) +VerifierVerifySingleConfigDigestTest:test_revertsIfReportHasUnconfiguredFeedID() (gas: 103976) VerifierVerifySingleConfigDigestTest:test_revertsIfVerifiedByNonProxy() (gas: 100992) -VerifierVerifySingleConfigDigestTest:test_revertsIfVerifiedWithIncorrectAddresses() (gas: 180320) -VerifierVerifySingleConfigDigestTest:test_revertsIfWrongNumberOfSigners() (gas: 106285) -VerifierVerifySingleConfigDigestTest:test_setsTheCorrectEpoch() (gas: 190530) -Verifier_accessControlledVerify:testVerifyWithAccessControl_gas() (gas: 205085) -Verifier_bulkVerifyWithFee:testBulkVerifyProxyWithLinkFeeSuccess_gas() (gas: 542038) -Verifier_bulkVerifyWithFee:testBulkVerifyProxyWithNativeFeeSuccess_gas() (gas: 565410) -Verifier_setConfig:testSetConfigSuccess_gas() (gas: 922637) -Verifier_verify:testVerifyProxySuccess_gas() (gas: 195530) -Verifier_verify:testVerifySuccess_gas() (gas: 182991) -Verifier_verifyWithFee:testVerifyProxyWithLinkFeeSuccess_gas() (gas: 244551) -Verifier_verifyWithFee:testVerifyProxyWithNativeFeeSuccess_gas() (gas: 262962) \ No newline at end of file +VerifierVerifySingleConfigDigestTest:test_revertsIfVerifiedWithIncorrectAddresses() (gas: 184066) +VerifierVerifySingleConfigDigestTest:test_revertsIfWrongNumberOfSigners() (gas: 110031) +VerifierVerifySingleConfigDigestTest:test_setsTheCorrectEpoch() (gas: 194270) +Verifier_accessControlledVerify:testVerifyWithAccessControl_gas() (gas: 208853) +Verifier_bulkVerifyWithFee:testBulkVerifyProxyWithLinkFeeSuccess_gas() (gas: 540669) +Verifier_bulkVerifyWithFee:testBulkVerifyProxyWithNativeFeeSuccess_gas() (gas: 564041) +Verifier_setConfig:testSetConfigSuccess_gas() (gas: 922659) +Verifier_verify:testVerifyProxySuccess_gas() (gas: 195542) +Verifier_verify:testVerifySuccess_gas() (gas: 186725) +Verifier_verifyWithFee:testVerifyProxyWithLinkFeeSuccess_gas() (gas: 242491) +Verifier_verifyWithFee:testVerifyProxyWithNativeFeeSuccess_gas() (gas: 260968) \ No newline at end of file diff --git a/contracts/gas-snapshots/vrf.gas-snapshot b/contracts/gas-snapshots/vrf.gas-snapshot deleted file mode 100644 index 44145caadaa..00000000000 --- a/contracts/gas-snapshots/vrf.gas-snapshot +++ /dev/null @@ -1,18 +0,0 @@ -TrustedBlockhashStoreTest:testGenericBHSFunctions() (gas: 53507) -TrustedBlockhashStoreTest:testTrustedBHSFunctions() (gas: 54617) -VRFCoordinatorV2Plus_Migration:testDeregister() (gas: 101083) -VRFCoordinatorV2Plus_Migration:testMigrateRevertsWhenInvalidCaller() (gas: 33190) -VRFCoordinatorV2Plus_Migration:testMigrateRevertsWhenInvalidCoordinator() (gas: 19877) -VRFCoordinatorV2Plus_Migration:testMigrateRevertsWhenPendingFulfillment() (gas: 237679) -VRFCoordinatorV2Plus_Migration:testMigrateRevertsWhenReentrant() (gas: 357765) -VRFCoordinatorV2Plus_Migration:testMigration() (gas: 471605) -VRFCoordinatorV2Plus_Migration:testMigrationNoLink() (gas: 431075) -VRFV2Plus:testCancelSubWithNoLink() (gas: 160279) -VRFV2Plus:testCreateSubscription() (gas: 181127) -VRFV2Plus:testGetActiveSubscriptionIds() (gas: 3453681) -VRFV2Plus:testRegisterProvingKey() (gas: 101085) -VRFV2Plus:testRequestAndFulfillRandomWordsLINK() (gas: 755144) -VRFV2Plus:testRequestAndFulfillRandomWordsNative() (gas: 705591) -VRFV2Plus:testSetConfig() (gas: 73032) -VRFV2PlusWrapperTest:testRequestAndFulfillRandomWordsLINKWrapper() (gas: 393885) -VRFV2PlusWrapperTest:testRequestAndFulfillRandomWordsNativeWrapper() (gas: 294434) \ No newline at end of file diff --git a/contracts/package.json b/contracts/package.json index 5f7a8c3d325..2683b49cc02 100644 --- a/contracts/package.json +++ b/contracts/package.json @@ -51,15 +51,15 @@ "@types/deep-equal-in-any-order": "^1.0.1", "@types/mocha": "^8.2.2", "@types/node": "^15.12.2", - "@typescript-eslint/eslint-plugin": "^5.59.5", - "@typescript-eslint/parser": "^5.59.5", + "@typescript-eslint/eslint-plugin": "^6.6.0", + "@typescript-eslint/parser": "^6.6.0", "abi-to-sol": "^0.6.6", "chai": "^4.3.4", "debug": "^4.3.2", - "eslint": "^8.40.0", - "eslint-config-prettier": "^8.8.0", + "eslint": "^8.48.0", + "eslint-config-prettier": "^9.0.0", "deep-equal-in-any-order": "^2.0.6", - "eslint-plugin-prettier": "^4.2.1", + "eslint-plugin-prettier": "^5.0.0", "ethereum-waffle": "^3.3.0", "ethers": "~5.6.0", "hardhat": "~2.12.7", @@ -69,10 +69,10 @@ "hardhat-ignore-warnings": "^0.2.6", "istanbul": "^0.4.5", "moment": "^2.29.4", - "prettier": "^2.8.8", + "prettier": "^3.0.3", "prettier-plugin-solidity": "1.1.3", "rlp": "^2.0.0", - "solhint": "^3.4.1", + "solhint": "^3.6.2", "solhint-plugin-prettier": "^0.0.5", "solidity-coverage": "^0.8.4", "ts-node": "^10.0.0", diff --git a/contracts/pnpm-lock.yaml b/contracts/pnpm-lock.yaml index da673532152..fde49eb9fdc 100644 --- a/contracts/pnpm-lock.yaml +++ b/contracts/pnpm-lock.yaml @@ -83,11 +83,11 @@ devDependencies: specifier: ^15.12.2 version: 15.14.9 '@typescript-eslint/eslint-plugin': - specifier: ^5.59.5 - version: 5.59.8(@typescript-eslint/parser@5.59.8)(eslint@8.42.0)(typescript@4.9.5) + specifier: ^6.6.0 + version: 6.6.0(@typescript-eslint/parser@6.6.0)(eslint@8.48.0)(typescript@4.9.5) '@typescript-eslint/parser': - specifier: ^5.59.5 - version: 5.59.8(eslint@8.42.0)(typescript@4.9.5) + specifier: ^6.6.0 + version: 6.6.0(eslint@8.48.0)(typescript@4.9.5) abi-to-sol: specifier: ^0.6.6 version: 0.6.6 @@ -101,14 +101,14 @@ devDependencies: specifier: ^2.0.6 version: 2.0.6 eslint: - specifier: ^8.40.0 - version: 8.42.0 + specifier: ^8.48.0 + version: 8.48.0 eslint-config-prettier: - specifier: ^8.8.0 - version: 8.8.0(eslint@8.42.0) + specifier: ^9.0.0 + version: 9.0.0(eslint@8.48.0) eslint-plugin-prettier: - specifier: ^4.2.1 - version: 4.2.1(eslint-config-prettier@8.8.0)(eslint@8.42.0)(prettier@2.8.8) + specifier: ^5.0.0 + version: 5.0.0(eslint-config-prettier@9.0.0)(eslint@8.48.0)(prettier@3.0.3) ethereum-waffle: specifier: ^3.3.0 version: 3.3.0(typescript@4.9.5) @@ -137,20 +137,20 @@ devDependencies: specifier: ^2.29.4 version: 2.29.4 prettier: - specifier: ^2.8.8 - version: 2.8.8 + specifier: ^3.0.3 + version: 3.0.3 prettier-plugin-solidity: specifier: 1.1.3 - version: 1.1.3(prettier@2.8.8) + version: 1.1.3(prettier@3.0.3) rlp: specifier: ^2.0.0 version: 2.2.7 solhint: - specifier: ^3.4.1 - version: 3.4.1 + specifier: ^3.6.2 + version: 3.6.2 solhint-plugin-prettier: specifier: ^0.0.5 - version: 0.0.5(prettier-plugin-solidity@1.1.3)(prettier@2.8.8) + version: 0.0.5(prettier-plugin-solidity@1.1.3)(prettier@3.0.3) solidity-coverage: specifier: ^0.8.4 version: 0.8.4(hardhat@2.12.7) @@ -169,6 +169,11 @@ devDependencies: packages: + /@aashutoshrathi/word-wrap@1.2.6: + resolution: {integrity: sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==} + engines: {node: '>=0.10.0'} + dev: true + /@babel/code-frame@7.18.6: resolution: {integrity: sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==} engines: {node: '>=6.9.0'} @@ -248,14 +253,14 @@ packages: deprecated: Please use @ensdomains/ens-contracts dev: true - /@eslint-community/eslint-utils@4.4.0(eslint@8.42.0): + /@eslint-community/eslint-utils@4.4.0(eslint@8.48.0): resolution: {integrity: sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 dependencies: - eslint: 8.42.0 - eslint-visitor-keys: 3.4.1 + eslint: 8.48.0 + eslint-visitor-keys: 3.4.3 dev: true /@eslint-community/regexpp@4.5.1: @@ -263,13 +268,18 @@ packages: engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} dev: true - /@eslint/eslintrc@2.0.3: - resolution: {integrity: sha512-+5gy6OQfk+xx3q0d6jGZZC3f3KzAkXc/IanVxd1is/VIIziRqqt3ongQz0FiTUXqTk0c7aDB3OaFuKnuSoJicQ==} + /@eslint-community/regexpp@4.8.0: + resolution: {integrity: sha512-JylOEEzDiOryeUnFbQz+oViCXS0KsvR1mvHkoMiu5+UiBvy+RYX7tzlIIIEstF/gVa2tj9AQXk3dgnxv6KxhFg==} + engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} + dev: true + + /@eslint/eslintrc@2.1.2: + resolution: {integrity: sha512-+wvgpDsrB1YqAMdEUCcnTlpfVBH7Vqn6A/NT3D8WVXFIaKMlErPIZT3oCIAVCOtarRpMtelZLqJeU3t7WY6X6g==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} dependencies: ajv: 6.12.6 debug: 4.3.4(supports-color@8.1.1) - espree: 9.5.2 + espree: 9.6.1 globals: 13.20.0 ignore: 5.2.4 import-fresh: 3.3.0 @@ -280,8 +290,8 @@ packages: - supports-color dev: true - /@eslint/js@8.42.0: - resolution: {integrity: sha512-6SWlXpWU5AvId8Ac7zjzmIOqMOba/JWY8XZ4A7q7Gn1Vlfg/SFFIlrtHXt9nPn4op9ZPAkl91Jao+QQv3r/ukw==} + /@eslint/js@8.48.0: + resolution: {integrity: sha512-ZSjtmelB7IJfWD2Fvb7+Z+ChTIKWq6kjda95fLcQKNS5aheVHn4IkfgRQE3sIIzTcSLwLcLZUD9UBt+V7+h+Pw==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} dev: true @@ -1440,6 +1450,18 @@ packages: - supports-color dev: true + /@pkgr/utils@2.4.2: + resolution: {integrity: sha512-POgTXhjrTfbTV63DiFXav4lBHiICLKKwDeaKn9Nphwj7WH6m0hMMCaJkMyRWjgtPFyRKRVoMXXjczsTQRDEhYw==} + engines: {node: ^12.20.0 || ^14.18.0 || >=16.0.0} + dependencies: + cross-spawn: 7.0.3 + fast-glob: 3.3.1 + is-glob: 4.0.3 + open: 9.1.0 + picocolors: 1.0.0 + tslib: 2.6.2 + dev: true + /@resolver-engine/core@0.3.3: resolution: {integrity: sha512-eB8nEbKDJJBi5p5SrvrvILn4a0h42bKtbCTri3ZxCGt6UvoQyp7HnGOfki944bUjBSHKK3RvgfViHn+kqdXtnQ==} dependencies: @@ -1850,8 +1872,8 @@ packages: resolution: {integrity: sha512-SZs7ekbP8CN0txVG2xVRH6EgKmEm31BOxA07vkFaETzZz1xh+cbt8BcI0slpymvwhx5dlFnQG2rTlPVQn+iRPQ==} dev: true - /@types/json-schema@7.0.11: - resolution: {integrity: sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==} + /@types/json-schema@7.0.12: + resolution: {integrity: sha512-Hr5Jfhc9eYOQNPYO5WLDq/n4jqijdHNlDXjuAQkkt+mWdQR+XJToOHrsD4cPaMXpn6KO7y2+wM8AZEs8VpBLVA==} dev: true /@types/keyv@3.1.4: @@ -1969,133 +1991,134 @@ packages: '@types/underscore': 1.11.4 dev: true - /@typescript-eslint/eslint-plugin@5.59.8(@typescript-eslint/parser@5.59.8)(eslint@8.42.0)(typescript@4.9.5): - resolution: {integrity: sha512-JDMOmhXteJ4WVKOiHXGCoB96ADWg9q7efPWHRViT/f09bA8XOMLAVHHju3l0MkZnG1izaWXYmgvQcUjTRcpShQ==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + /@typescript-eslint/eslint-plugin@6.6.0(@typescript-eslint/parser@6.6.0)(eslint@8.48.0)(typescript@4.9.5): + resolution: {integrity: sha512-CW9YDGTQnNYMIo5lMeuiIG08p4E0cXrXTbcZ2saT/ETE7dWUrNxlijsQeU04qAAKkILiLzdQz+cGFxCJjaZUmA==} + engines: {node: ^16.0.0 || >=18.0.0} peerDependencies: - '@typescript-eslint/parser': ^5.0.0 - eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 + '@typescript-eslint/parser': ^6.0.0 || ^6.0.0-alpha + eslint: ^7.0.0 || ^8.0.0 typescript: '*' peerDependenciesMeta: typescript: optional: true dependencies: '@eslint-community/regexpp': 4.5.1 - '@typescript-eslint/parser': 5.59.8(eslint@8.42.0)(typescript@4.9.5) - '@typescript-eslint/scope-manager': 5.59.8 - '@typescript-eslint/type-utils': 5.59.8(eslint@8.42.0)(typescript@4.9.5) - '@typescript-eslint/utils': 5.59.8(eslint@8.42.0)(typescript@4.9.5) + '@typescript-eslint/parser': 6.6.0(eslint@8.48.0)(typescript@4.9.5) + '@typescript-eslint/scope-manager': 6.6.0 + '@typescript-eslint/type-utils': 6.6.0(eslint@8.48.0)(typescript@4.9.5) + '@typescript-eslint/utils': 6.6.0(eslint@8.48.0)(typescript@4.9.5) + '@typescript-eslint/visitor-keys': 6.6.0 debug: 4.3.4(supports-color@8.1.1) - eslint: 8.42.0 - grapheme-splitter: 1.0.4 + eslint: 8.48.0 + graphemer: 1.4.0 ignore: 5.2.4 - natural-compare-lite: 1.4.0 - semver: 7.5.0 - tsutils: 3.21.0(typescript@4.9.5) + natural-compare: 1.4.0 + semver: 7.5.4 + ts-api-utils: 1.0.3(typescript@4.9.5) typescript: 4.9.5 transitivePeerDependencies: - supports-color dev: true - /@typescript-eslint/parser@5.59.8(eslint@8.42.0)(typescript@4.9.5): - resolution: {integrity: sha512-AnR19RjJcpjoeGojmwZtCwBX/RidqDZtzcbG3xHrmz0aHHoOcbWnpDllenRDmDvsV0RQ6+tbb09/kyc+UT9Orw==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + /@typescript-eslint/parser@6.6.0(eslint@8.48.0)(typescript@4.9.5): + resolution: {integrity: sha512-setq5aJgUwtzGrhW177/i+DMLqBaJbdwGj2CPIVFFLE0NCliy5ujIdLHd2D1ysmlmsjdL2GWW+hR85neEfc12w==} + engines: {node: ^16.0.0 || >=18.0.0} peerDependencies: - eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 + eslint: ^7.0.0 || ^8.0.0 typescript: '*' peerDependenciesMeta: typescript: optional: true dependencies: - '@typescript-eslint/scope-manager': 5.59.8 - '@typescript-eslint/types': 5.59.8 - '@typescript-eslint/typescript-estree': 5.59.8(typescript@4.9.5) + '@typescript-eslint/scope-manager': 6.6.0 + '@typescript-eslint/types': 6.6.0 + '@typescript-eslint/typescript-estree': 6.6.0(typescript@4.9.5) + '@typescript-eslint/visitor-keys': 6.6.0 debug: 4.3.4(supports-color@8.1.1) - eslint: 8.42.0 + eslint: 8.48.0 typescript: 4.9.5 transitivePeerDependencies: - supports-color dev: true - /@typescript-eslint/scope-manager@5.59.8: - resolution: {integrity: sha512-/w08ndCYI8gxGf+9zKf1vtx/16y8MHrZs5/tnjHhMLNSixuNcJavSX4wAiPf4aS5x41Es9YPCn44MIe4cxIlig==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + /@typescript-eslint/scope-manager@6.6.0: + resolution: {integrity: sha512-pT08u5W/GT4KjPUmEtc2kSYvrH8x89cVzkA0Sy2aaOUIw6YxOIjA8ilwLr/1fLjOedX1QAuBpG9XggWqIIfERw==} + engines: {node: ^16.0.0 || >=18.0.0} dependencies: - '@typescript-eslint/types': 5.59.8 - '@typescript-eslint/visitor-keys': 5.59.8 + '@typescript-eslint/types': 6.6.0 + '@typescript-eslint/visitor-keys': 6.6.0 dev: true - /@typescript-eslint/type-utils@5.59.8(eslint@8.42.0)(typescript@4.9.5): - resolution: {integrity: sha512-+5M518uEIHFBy3FnyqZUF3BMP+AXnYn4oyH8RF012+e7/msMY98FhGL5SrN29NQ9xDgvqCgYnsOiKp1VjZ/fpA==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + /@typescript-eslint/type-utils@6.6.0(eslint@8.48.0)(typescript@4.9.5): + resolution: {integrity: sha512-8m16fwAcEnQc69IpeDyokNO+D5spo0w1jepWWY2Q6y5ZKNuj5EhVQXjtVAeDDqvW6Yg7dhclbsz6rTtOvcwpHg==} + engines: {node: ^16.0.0 || >=18.0.0} peerDependencies: - eslint: '*' + eslint: ^7.0.0 || ^8.0.0 typescript: '*' peerDependenciesMeta: typescript: optional: true dependencies: - '@typescript-eslint/typescript-estree': 5.59.8(typescript@4.9.5) - '@typescript-eslint/utils': 5.59.8(eslint@8.42.0)(typescript@4.9.5) + '@typescript-eslint/typescript-estree': 6.6.0(typescript@4.9.5) + '@typescript-eslint/utils': 6.6.0(eslint@8.48.0)(typescript@4.9.5) debug: 4.3.4(supports-color@8.1.1) - eslint: 8.42.0 - tsutils: 3.21.0(typescript@4.9.5) + eslint: 8.48.0 + ts-api-utils: 1.0.3(typescript@4.9.5) typescript: 4.9.5 transitivePeerDependencies: - supports-color dev: true - /@typescript-eslint/types@5.59.8: - resolution: {integrity: sha512-+uWuOhBTj/L6awoWIg0BlWy0u9TyFpCHrAuQ5bNfxDaZ1Ppb3mx6tUigc74LHcbHpOHuOTOJrBoAnhdHdaea1w==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + /@typescript-eslint/types@6.6.0: + resolution: {integrity: sha512-CB6QpJQ6BAHlJXdwUmiaXDBmTqIE2bzGTDLADgvqtHWuhfNP3rAOK7kAgRMAET5rDRr9Utt+qAzRBdu3AhR3sg==} + engines: {node: ^16.0.0 || >=18.0.0} dev: true - /@typescript-eslint/typescript-estree@5.59.8(typescript@4.9.5): - resolution: {integrity: sha512-Jy/lPSDJGNow14vYu6IrW790p7HIf/SOV1Bb6lZ7NUkLc2iB2Z9elESmsaUtLw8kVqogSbtLH9tut5GCX1RLDg==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + /@typescript-eslint/typescript-estree@6.6.0(typescript@4.9.5): + resolution: {integrity: sha512-hMcTQ6Al8MP2E6JKBAaSxSVw5bDhdmbCEhGW/V8QXkb9oNsFkA4SBuOMYVPxD3jbtQ4R/vSODBsr76R6fP3tbA==} + engines: {node: ^16.0.0 || >=18.0.0} peerDependencies: typescript: '*' peerDependenciesMeta: typescript: optional: true dependencies: - '@typescript-eslint/types': 5.59.8 - '@typescript-eslint/visitor-keys': 5.59.8 + '@typescript-eslint/types': 6.6.0 + '@typescript-eslint/visitor-keys': 6.6.0 debug: 4.3.4(supports-color@8.1.1) globby: 11.1.0 is-glob: 4.0.3 - semver: 7.5.0 - tsutils: 3.21.0(typescript@4.9.5) + semver: 7.5.4 + ts-api-utils: 1.0.3(typescript@4.9.5) typescript: 4.9.5 transitivePeerDependencies: - supports-color dev: true - /@typescript-eslint/utils@5.59.8(eslint@8.42.0)(typescript@4.9.5): - resolution: {integrity: sha512-Tr65630KysnNn9f9G7ROF3w1b5/7f6QVCJ+WK9nhIocWmx9F+TmCAcglF26Vm7z8KCTwoKcNEBZrhlklla3CKg==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + /@typescript-eslint/utils@6.6.0(eslint@8.48.0)(typescript@4.9.5): + resolution: {integrity: sha512-mPHFoNa2bPIWWglWYdR0QfY9GN0CfvvXX1Sv6DlSTive3jlMTUy+an67//Gysc+0Me9pjitrq0LJp0nGtLgftw==} + engines: {node: ^16.0.0 || >=18.0.0} peerDependencies: - eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 + eslint: ^7.0.0 || ^8.0.0 dependencies: - '@eslint-community/eslint-utils': 4.4.0(eslint@8.42.0) - '@types/json-schema': 7.0.11 + '@eslint-community/eslint-utils': 4.4.0(eslint@8.48.0) + '@types/json-schema': 7.0.12 '@types/semver': 7.5.0 - '@typescript-eslint/scope-manager': 5.59.8 - '@typescript-eslint/types': 5.59.8 - '@typescript-eslint/typescript-estree': 5.59.8(typescript@4.9.5) - eslint: 8.42.0 - eslint-scope: 5.1.1 - semver: 7.5.0 + '@typescript-eslint/scope-manager': 6.6.0 + '@typescript-eslint/types': 6.6.0 + '@typescript-eslint/typescript-estree': 6.6.0(typescript@4.9.5) + eslint: 8.48.0 + semver: 7.5.4 transitivePeerDependencies: - supports-color - typescript dev: true - /@typescript-eslint/visitor-keys@5.59.8: - resolution: {integrity: sha512-pJhi2ms0x0xgloT7xYabil3SGGlojNNKjK/q6dB3Ey0uJLMjK2UDGJvHieiyJVW/7C3KI+Z4Q3pEHkm4ejA+xQ==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + /@typescript-eslint/visitor-keys@6.6.0: + resolution: {integrity: sha512-L61uJT26cMOfFQ+lMZKoJNbAEckLe539VhTxiGHrWl5XSKQgA0RTBZJW2HFPy5T0ZvPVSD93QsrTKDkfNwJGyQ==} + engines: {node: ^16.0.0 || >=18.0.0} dependencies: - '@typescript-eslint/types': 5.59.8 + '@typescript-eslint/types': 6.6.0 eslint-visitor-keys: 3.4.1 dev: true @@ -2187,16 +2210,16 @@ packages: negotiator: 0.6.2 dev: true - /acorn-jsx@5.3.2(acorn@8.8.0): + /acorn-jsx@5.3.2(acorn@8.10.0): resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} peerDependencies: acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 dependencies: - acorn: 8.8.0 + acorn: 8.10.0 dev: true - /acorn@8.8.0: - resolution: {integrity: sha512-QOxyigPVrpZ2GXT+PFyZTl6TtOFc5egxHIP9IlQ+RbupQuX4RkT/Bee4/kQuC02Xkzg84JcT7oLYtDIQxp+v7w==} + /acorn@8.10.0: + resolution: {integrity: sha512-F0SAmZ8iUtS//m8DmCTA0jlh6TDKkHQyK6xc6V4KDTyZKA9dnvX9/3sRTVQrWm79glUAZbnmmNcdYwUIHWVybw==} engines: {node: '>=0.4.0'} hasBin: true dev: true @@ -3109,6 +3132,11 @@ packages: engines: {node: '>=0.6'} dev: true + /big-integer@1.6.51: + resolution: {integrity: sha512-GPEid2Y9QU1Exl1rpO9B2IPJGHPSupF5GnVIP0blYvNOMer2bTvSWs1jGOUg04hTmu67nmLsQ9TBo1puaotBHg==} + engines: {node: '>=0.6'} + dev: true + /big.js@6.2.1: resolution: {integrity: sha512-bCtHMwL9LeDIozFn+oNhhFoq+yQ3BNdnsLSASUxLciOb1vgvpHsIO1dsENiGMgbb4SkP5TrzWzRiLddn8ahVOQ==} dev: true @@ -3200,6 +3228,13 @@ packages: resolution: {integrity: sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==} dev: true + /bplist-parser@0.2.0: + resolution: {integrity: sha512-z0M+byMThzQmD9NILRniCUXYsYpjwnlO8N5uCFaCqIOpqRsJCrQL9NK3JsD67CN5a08nF5oIL2bD6loTdHOuKw==} + engines: {node: '>= 5.10.0'} + dependencies: + big-integer: 1.6.51 + dev: true + /brace-expansion@1.1.11: resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==} dependencies: @@ -3375,6 +3410,13 @@ packages: engines: {node: '>=8.0.0'} dev: false + /bundle-name@3.0.0: + resolution: {integrity: sha512-PKA4BeSvBpQKQ8iPOGCSiell+N8P+Tf1DlwqmYhpe2gAhKPHn8EYOxVT+ShuGmhg8lN8XiSlS80yiExKXrURlw==} + engines: {node: '>=12'} + dependencies: + run-applescript: 5.0.0 + dev: true + /busboy@1.6.0: resolution: {integrity: sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==} engines: {node: '>=10.16.0'} @@ -3880,7 +3922,7 @@ packages: dev: true /concat-map@0.0.1: - resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} + resolution: {integrity: sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=} dev: true /concat-stream@1.6.2: @@ -4242,6 +4284,24 @@ packages: resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} dev: true + /default-browser-id@3.0.0: + resolution: {integrity: sha512-OZ1y3y0SqSICtE8DE4S8YOE9UZOJ8wO16fKWVP5J1Qz42kV9jcnMVFrEE/noXb/ss3Q4pZIH79kxofzyNNtUNA==} + engines: {node: '>=12'} + dependencies: + bplist-parser: 0.2.0 + untildify: 4.0.0 + dev: true + + /default-browser@4.0.0: + resolution: {integrity: sha512-wX5pXO1+BrhMkSbROFsyxUm0i/cJEScyNhA4PPxc41ICuv05ZZB/MX28s8aZx6xjmatvebIapF6hLEKEcpneUA==} + engines: {node: '>=14.16'} + dependencies: + bundle-name: 3.0.0 + default-browser-id: 3.0.0 + execa: 7.2.0 + titleize: 3.0.0 + dev: true + /defer-to-connect@1.1.1: resolution: {integrity: sha512-J7thop4u3mRTkYRQ+Vpfwy2G5Ehoy82I14+14W4YMDLKdWloI9gSzRbV30s/NckQGVJtPkWNcW4oMAUigTdqiQ==} requiresBuild: true @@ -4266,6 +4326,11 @@ packages: inherits: 2.0.4 dev: true + /define-lazy-prop@3.0.0: + resolution: {integrity: sha512-N+MeXYoqr3pOgn8xfyRPREN7gHakLYjhsHhWGT3fWAiL4IkAt0iDw14QiiEm2bE30c5XX5q0FtAA3CK5f9/BUg==} + engines: {node: '>=12'} + dev: true + /define-properties@1.1.4: resolution: {integrity: sha512-uckOqKcfaVvtBdsVkdPv3XjveQJsNQqmhXgRi8uhvWWuPYZCNlzT8qAyblUgNoXdHdjMTzAqeGjAoli8f+bzPA==} engines: {node: '>= 0.4'} @@ -4645,42 +4710,38 @@ packages: source-map: 0.2.0 dev: true - /eslint-config-prettier@8.8.0(eslint@8.42.0): - resolution: {integrity: sha512-wLbQiFre3tdGgpDv67NQKnJuTlcUVYHas3k+DZCc2U2BadthoEY4B7hLPvAxaqdyOGCzuLfii2fqGph10va7oA==} + /eslint-config-prettier@9.0.0(eslint@8.48.0): + resolution: {integrity: sha512-IcJsTkJae2S35pRsRAwoCE+925rJJStOdkKnLVgtE+tEpqU0EVVM7OqrwxqgptKdX29NUwC82I5pXsGFIgSevw==} hasBin: true peerDependencies: eslint: '>=7.0.0' dependencies: - eslint: 8.42.0 + eslint: 8.48.0 dev: true - /eslint-plugin-prettier@4.2.1(eslint-config-prettier@8.8.0)(eslint@8.42.0)(prettier@2.8.8): - resolution: {integrity: sha512-f/0rXLXUt0oFYs8ra4w49wYZBG5GKZpAYsJSm6rnYL5uVDjd+zowwMwVZHnAjf4edNrKpCDYfXDgmRE/Ak7QyQ==} - engines: {node: '>=12.0.0'} + /eslint-plugin-prettier@5.0.0(eslint-config-prettier@9.0.0)(eslint@8.48.0)(prettier@3.0.3): + resolution: {integrity: sha512-AgaZCVuYDXHUGxj/ZGu1u8H8CYgDY3iG6w5kUFw4AzMVXzB7VvbKgYR4nATIN+OvUrghMbiDLeimVjVY5ilq3w==} + engines: {node: ^14.18.0 || >=16.0.0} peerDependencies: - eslint: '>=7.28.0' + '@types/eslint': '>=8.0.0' + eslint: '>=8.0.0' eslint-config-prettier: '*' - prettier: '>=2.0.0' + prettier: '>=3.0.0' peerDependenciesMeta: + '@types/eslint': + optional: true eslint-config-prettier: optional: true dependencies: - eslint: 8.42.0 - eslint-config-prettier: 8.8.0(eslint@8.42.0) - prettier: 2.8.8 + eslint: 8.48.0 + eslint-config-prettier: 9.0.0(eslint@8.48.0) + prettier: 3.0.3 prettier-linter-helpers: 1.0.0 + synckit: 0.8.5 dev: true - /eslint-scope@5.1.1: - resolution: {integrity: sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==} - engines: {node: '>=8.0.0'} - dependencies: - esrecurse: 4.3.0 - estraverse: 4.3.0 - dev: true - - /eslint-scope@7.2.0: - resolution: {integrity: sha512-DYj5deGlHBfMt15J7rdtyKNq/Nqlv5KfU4iodrQ019XESsRnwXH9KAE0y3cwtUHDo2ob7CypAnCqefh6vioWRw==} + /eslint-scope@7.2.2: + resolution: {integrity: sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} dependencies: esrecurse: 4.3.0 @@ -4692,15 +4753,20 @@ packages: engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} dev: true - /eslint@8.42.0: - resolution: {integrity: sha512-ulg9Ms6E1WPf67PHaEY4/6E2tEn5/f7FXGzr3t9cBMugOmf1INYvuUwwh1aXQN4MfJ6a5K2iNwP3w4AColvI9A==} + /eslint-visitor-keys@3.4.3: + resolution: {integrity: sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + dev: true + + /eslint@8.48.0: + resolution: {integrity: sha512-sb6DLeIuRXxeM1YljSe1KEx9/YYeZFQWcV8Rq9HfigmdDEugjLEVEa1ozDjL6YDjBpQHPJxJzze+alxi4T3OLg==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} hasBin: true dependencies: - '@eslint-community/eslint-utils': 4.4.0(eslint@8.42.0) - '@eslint-community/regexpp': 4.5.1 - '@eslint/eslintrc': 2.0.3 - '@eslint/js': 8.42.0 + '@eslint-community/eslint-utils': 4.4.0(eslint@8.48.0) + '@eslint-community/regexpp': 4.8.0 + '@eslint/eslintrc': 2.1.2 + '@eslint/js': 8.48.0 '@humanwhocodes/config-array': 0.11.10 '@humanwhocodes/module-importer': 1.0.1 '@nodelib/fs.walk': 1.2.8 @@ -4710,9 +4776,9 @@ packages: debug: 4.3.4(supports-color@8.1.1) doctrine: 3.0.0 escape-string-regexp: 4.0.0 - eslint-scope: 7.2.0 - eslint-visitor-keys: 3.4.1 - espree: 9.5.2 + eslint-scope: 7.2.2 + eslint-visitor-keys: 3.4.3 + espree: 9.6.1 esquery: 1.5.0 esutils: 2.0.3 fast-deep-equal: 3.1.3 @@ -4721,8 +4787,7 @@ packages: glob-parent: 6.0.2 globals: 13.20.0 graphemer: 1.4.0 - ignore: 5.2.0 - import-fresh: 3.3.0 + ignore: 5.2.4 imurmurhash: 0.1.4 is-glob: 4.0.3 is-path-inside: 3.0.3 @@ -4732,21 +4797,20 @@ packages: lodash.merge: 4.6.2 minimatch: 3.1.2 natural-compare: 1.4.0 - optionator: 0.9.1 + optionator: 0.9.3 strip-ansi: 6.0.1 - strip-json-comments: 3.1.1 text-table: 0.2.0 transitivePeerDependencies: - supports-color dev: true - /espree@9.5.2: - resolution: {integrity: sha512-7OASN1Wma5fum5SrNhFMAMJxOUAbhyfQ8dQ//PJaJbNw0URTPWqIghHWt1MmAANKhHZIYOHruW4Kw4ruUWOdGw==} + /espree@9.6.1: + resolution: {integrity: sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} dependencies: - acorn: 8.8.0 - acorn-jsx: 5.3.2(acorn@8.8.0) - eslint-visitor-keys: 3.4.1 + acorn: 8.10.0 + acorn-jsx: 5.3.2(acorn@8.10.0) + eslint-visitor-keys: 3.4.3 dev: true /esprima@2.7.3: @@ -4780,11 +4844,6 @@ packages: engines: {node: '>=0.10.0'} dev: true - /estraverse@4.3.0: - resolution: {integrity: sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==} - engines: {node: '>=4.0'} - dev: true - /estraverse@5.3.0: resolution: {integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==} engines: {node: '>=4.0'} @@ -5300,6 +5359,36 @@ packages: safe-buffer: 5.2.1 dev: true + /execa@5.1.1: + resolution: {integrity: sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==} + engines: {node: '>=10'} + dependencies: + cross-spawn: 7.0.3 + get-stream: 6.0.1 + human-signals: 2.1.0 + is-stream: 2.0.1 + merge-stream: 2.0.0 + npm-run-path: 4.0.1 + onetime: 5.1.2 + signal-exit: 3.0.7 + strip-final-newline: 2.0.0 + dev: true + + /execa@7.2.0: + resolution: {integrity: sha512-UduyVP7TLB5IcAQl+OzLyLcS/l32W/GLg+AhHJ+ow40FOk2U3SAllPwR44v4vmdFwIWqpdwxxpQbF1n5ta9seA==} + engines: {node: ^14.18.0 || ^16.14.0 || >=18.0.0} + dependencies: + cross-spawn: 7.0.3 + get-stream: 6.0.1 + human-signals: 4.3.1 + is-stream: 3.0.0 + merge-stream: 2.0.0 + npm-run-path: 5.1.0 + onetime: 6.0.0 + signal-exit: 3.0.7 + strip-final-newline: 3.0.0 + dev: true + /expand-brackets@2.1.4: resolution: {integrity: sha512-w/ozOKR9Obk3qoWeY/WDi6MFta9AoMR+zud60mdnbniMcBxRuFJyDt2LdX/14A1UABeqk+Uk+LDfUpvoGKppZA==} engines: {node: '>=0.10.0'} @@ -5436,6 +5525,17 @@ packages: micromatch: 4.0.5 dev: true + /fast-glob@3.3.1: + resolution: {integrity: sha512-kNFPyjhh5cKjrUltxs+wFx+ZkbRaxxmZ+X0ZU31SOsxCEtP9VPgtq2teZw1DebupL5GmDaNQ6yKMMVcM41iqDg==} + engines: {node: '>=8.6.0'} + dependencies: + '@nodelib/fs.stat': 2.0.5 + '@nodelib/fs.walk': 1.2.8 + glob-parent: 5.1.2 + merge2: 1.4.1 + micromatch: 4.0.5 + dev: true + /fast-json-stable-stringify@2.1.0: resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==} dev: true @@ -6494,6 +6594,16 @@ packages: - supports-color dev: true + /human-signals@2.1.0: + resolution: {integrity: sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==} + engines: {node: '>=10.17.0'} + dev: true + + /human-signals@4.3.1: + resolution: {integrity: sha512-nZXjEF2nbo7lIw3mgYjItAfgQXog3OjJogSbKa2CQIIvSGWcKgeJnQlNXip6NglNzYH45nSRiEVimMvYL8DDqQ==} + engines: {node: '>=14.18.0'} + dev: true + /iconv-lite@0.4.24: resolution: {integrity: sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==} engines: {node: '>=0.10.0'} @@ -6519,11 +6629,6 @@ packages: resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==} dev: true - /ignore@5.2.0: - resolution: {integrity: sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==} - engines: {node: '>= 4'} - dev: true - /ignore@5.2.4: resolution: {integrity: sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==} engines: {node: '>= 4'} @@ -6727,6 +6832,12 @@ packages: hasBin: true dev: true + /is-docker@3.0.0: + resolution: {integrity: sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + hasBin: true + dev: true + /is-extendable@0.1.1: resolution: {integrity: sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==} engines: {node: '>=0.10.0'} @@ -6792,6 +6903,14 @@ packages: engines: {node: '>=6.5.0', npm: '>=3'} dev: true + /is-inside-container@1.0.0: + resolution: {integrity: sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA==} + engines: {node: '>=14.16'} + hasBin: true + dependencies: + is-docker: 3.0.0 + dev: true + /is-lower-case@1.1.3: resolution: {integrity: sha512-+5A1e/WJpLLXZEDlgz4G//WYSHyQBD32qa4Jd3Lw06qQlv3fJHnp3YIHjTQSGzHMgzmVKz2ZP3rBxTHkPw/lxA==} dependencies: @@ -6872,6 +6991,16 @@ packages: engines: {node: '>=0.10.0'} dev: true + /is-stream@2.0.1: + resolution: {integrity: sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==} + engines: {node: '>=8'} + dev: true + + /is-stream@3.0.0: + resolution: {integrity: sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + dev: true + /is-string@1.0.7: resolution: {integrity: sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==} engines: {node: '>= 0.4'} @@ -7664,6 +7793,10 @@ packages: resolution: {integrity: sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==} dev: true + /merge-stream@2.0.0: + resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==} + dev: true + /merge2@1.4.1: resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} engines: {node: '>= 8'} @@ -7754,6 +7887,16 @@ packages: hasBin: true dev: true + /mimic-fn@2.1.0: + resolution: {integrity: sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==} + engines: {node: '>=6'} + dev: true + + /mimic-fn@4.0.0: + resolution: {integrity: sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==} + engines: {node: '>=12'} + dev: true + /mimic-response@1.0.1: resolution: {integrity: sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==} engines: {node: '>=4'} @@ -8064,10 +8207,6 @@ packages: resolution: {integrity: sha512-A0xLykHtARfueITVDernsAWdtIMbOJgKgcluwENp3AlsKN/PloyO10HtmoqnFAQAcxPkgZN7wdfPfEd0zNGxbg==} dev: true - /natural-compare-lite@1.4.0: - resolution: {integrity: sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g==} - dev: true - /natural-compare@1.4.0: resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} dev: true @@ -8191,6 +8330,20 @@ packages: engines: {node: '>=10'} dev: true + /npm-run-path@4.0.1: + resolution: {integrity: sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==} + engines: {node: '>=8'} + dependencies: + path-key: 3.1.1 + dev: true + + /npm-run-path@5.1.0: + resolution: {integrity: sha512-sJOdmRGrY2sjNTRMbSvluQqg+8X7ZK61yvzBEIDhz4f8z1TZFYABsqjjCBd/0PUNE9M6QDgHJXQkGUEm7Q+l9Q==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + dependencies: + path-key: 4.0.0 + dev: true + /nth-check@2.1.1: resolution: {integrity: sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==} dependencies: @@ -8324,6 +8477,20 @@ packages: wrappy: 1.0.2 dev: true + /onetime@5.1.2: + resolution: {integrity: sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==} + engines: {node: '>=6'} + dependencies: + mimic-fn: 2.1.0 + dev: true + + /onetime@6.0.0: + resolution: {integrity: sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==} + engines: {node: '>=12'} + dependencies: + mimic-fn: 4.0.0 + dev: true + /open@7.4.2: resolution: {integrity: sha512-MVHddDVweXZF3awtlAS+6pgKLlm/JgxZ90+/NBurBoQctVOOB/zDdVjcyPzQ+0laDGbsWgrRkflI65sQeOgT9Q==} engines: {node: '>=8'} @@ -8332,6 +8499,16 @@ packages: is-wsl: 2.2.0 dev: true + /open@9.1.0: + resolution: {integrity: sha512-OS+QTnw1/4vrf+9hh1jc1jnYjzSG4ttTBB8UxOwAnInG3Uo4ssetzC1ihqaIHjLJnA5GGlRl6QlZXOTQhRBUvg==} + engines: {node: '>=14.16'} + dependencies: + default-browser: 4.0.0 + define-lazy-prop: 3.0.0 + is-inside-container: 1.0.0 + is-wsl: 2.2.0 + dev: true + /optionator@0.8.3: resolution: {integrity: sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==} engines: {node: '>= 0.8.0'} @@ -8344,16 +8521,16 @@ packages: word-wrap: 1.2.3 dev: true - /optionator@0.9.1: - resolution: {integrity: sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==} + /optionator@0.9.3: + resolution: {integrity: sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==} engines: {node: '>= 0.8.0'} dependencies: + '@aashutoshrathi/word-wrap': 1.2.6 deep-is: 0.1.4 fast-levenshtein: 2.0.6 levn: 0.4.1 prelude-ls: 1.2.1 type-check: 0.4.0 - word-wrap: 1.2.3 dev: true /os-homedir@1.0.2: @@ -8629,6 +8806,11 @@ packages: engines: {node: '>=8'} dev: true + /path-key@4.0.0: + resolution: {integrity: sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==} + engines: {node: '>=12'} + dev: true + /path-parse@1.0.7: resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} dev: true @@ -8669,6 +8851,10 @@ packages: resolution: {integrity: sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==} dev: true + /picocolors@1.0.0: + resolution: {integrity: sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==} + dev: true + /picomatch@2.3.1: resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} engines: {node: '>=8.6'} @@ -8755,6 +8941,19 @@ packages: semver: 7.5.0 solidity-comments-extractor: 0.0.7 dev: true + optional: true + + /prettier-plugin-solidity@1.1.3(prettier@3.0.3): + resolution: {integrity: sha512-fQ9yucPi2sBbA2U2Xjh6m4isUTJ7S7QLc/XDDsktqqxYfTwdYKJ0EnnywXHwCGAaYbQNK+HIYPL1OemxuMsgeg==} + engines: {node: '>=12'} + peerDependencies: + prettier: '>=2.3.0 || >=3.0.0-alpha.0' + dependencies: + '@solidity-parser/parser': 0.16.0 + prettier: 3.0.3 + semver: 7.5.0 + solidity-comments-extractor: 0.0.7 + dev: true /prettier@2.8.8: resolution: {integrity: sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==} @@ -8762,6 +8961,12 @@ packages: hasBin: true dev: true + /prettier@3.0.3: + resolution: {integrity: sha512-L/4pUDMxcNa8R/EthV08Zt42WBO4h1rarVtK0K+QJG0X187OLo7l699jWw0GKuwzkPQ//jMFA/8Xm6Fh3J/DAg==} + engines: {node: '>=14'} + hasBin: true + dev: true + /private@0.1.8: resolution: {integrity: sha512-VvivMrbvd2nKkiG38qjULzlc+4Vx4wm/whI9pQD35YrARNnhxeiRktSOhSukRLFNlzg6Br/cJPet5J/u19r/mg==} engines: {node: '>= 0.6'} @@ -9319,6 +9524,13 @@ packages: bn.js: 5.2.1 dev: true + /run-applescript@5.0.0: + resolution: {integrity: sha512-XcT5rBksx1QdIhlFOCtgZkB99ZEouFZ1E2Kc2LHqNW13U3/74YGdkQRmThTwxy4QIyookibDKYZOPqX//6BlAg==} + engines: {node: '>=12'} + dependencies: + execa: 5.1.1 + dev: true + /run-parallel-limit@1.1.0: resolution: {integrity: sha512-jJA7irRNM91jaKc3Hcl1npHsFLOXOoTkPCUL1JEa1R82O2miplXXRaGdjW/KM/98YQWDhJLiSs793CnXfblJUw==} dependencies: @@ -9466,6 +9678,14 @@ packages: lru-cache: 6.0.0 dev: true + /semver@7.5.4: + resolution: {integrity: sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==} + engines: {node: '>=10'} + hasBin: true + dependencies: + lru-cache: 6.0.0 + dev: true + /send@0.17.1: resolution: {integrity: sha512-BsVKsiGcQMFwT8UxypobUKyv7irCNRHk1T0G680vk88yf6LBByGcZJOTJCrTP2xVN6yI+XjPJcNuE3V4fT9sAg==} engines: {node: '>= 0.8.0'} @@ -9756,19 +9976,19 @@ packages: - debug dev: true - /solhint-plugin-prettier@0.0.5(prettier-plugin-solidity@1.1.3)(prettier@2.8.8): + /solhint-plugin-prettier@0.0.5(prettier-plugin-solidity@1.1.3)(prettier@3.0.3): resolution: {integrity: sha512-7jmWcnVshIrO2FFinIvDQmhQpfpS2rRRn3RejiYgnjIE68xO2bvrYvjqVNfrio4xH9ghOqn83tKuTzLjEbmGIA==} peerDependencies: prettier: ^1.15.0 || ^2.0.0 prettier-plugin-solidity: ^1.0.0-alpha.14 dependencies: - prettier: 2.8.8 + prettier: 3.0.3 prettier-linter-helpers: 1.0.0 - prettier-plugin-solidity: 1.1.3(prettier@2.8.8) + prettier-plugin-solidity: 1.1.3(prettier@3.0.3) dev: true - /solhint@3.4.1: - resolution: {integrity: sha512-pzZn2RlZhws1XwvLPVSsxfHrwsteFf5eySOhpAytzXwKQYbTCJV6z8EevYDiSVKMpWrvbKpEtJ055CuEmzp4Xg==} + /solhint@3.6.2: + resolution: {integrity: sha512-85EeLbmkcPwD+3JR7aEMKsVC9YrRSxd4qkXuMzrlf7+z2Eqdfm1wHWq1ffTuo5aDhoZxp2I9yF3QkxZOxOL7aQ==} hasBin: true dependencies: '@solidity-parser/parser': 0.16.0 @@ -9784,7 +10004,7 @@ packages: js-yaml: 4.1.0 lodash: 4.17.21 pluralize: 8.0.0 - semver: 6.3.0 + semver: 7.5.4 strip-ansi: 6.0.1 table: 6.8.1 text-table: 0.2.0 @@ -10209,6 +10429,16 @@ packages: is-utf8: 0.2.1 dev: true + /strip-final-newline@2.0.0: + resolution: {integrity: sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==} + engines: {node: '>=6'} + dev: true + + /strip-final-newline@3.0.0: + resolution: {integrity: sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==} + engines: {node: '>=12'} + dev: true + /strip-hex-prefix@1.0.0: resolution: {integrity: sha512-q8d4ue7JGEiVcypji1bALTos+0pWtyGlivAWyPuTkHzuTCJqrK9sWxYQZUq6Nq3cuyv3bm734IhHvHtGGURU6A==} engines: {node: '>=6.5.0', npm: '>=3'} @@ -10318,6 +10548,14 @@ packages: get-port: 3.2.0 dev: true + /synckit@0.8.5: + resolution: {integrity: sha512-L1dapNV6vu2s/4Sputv8xGsCdAVlb5nRDMFU/E27D44l5U6cw1g0dGd45uLc+OXjNMmF4ntiMdCimzcjFKQI8Q==} + engines: {node: ^14.18.0 || >=16.0.0} + dependencies: + '@pkgr/utils': 2.4.2 + tslib: 2.6.2 + dev: true + /table-layout@1.0.2: resolution: {integrity: sha512-qd/R7n5rQTRFi+Zf2sk5XVVd9UQl6ZkduPFC3S7WEGJAmetDTjY3qPN50eSKzwuzEyQKy5TN2TiZdkIjos2L6A==} engines: {node: '>=8.0.0'} @@ -10441,6 +10679,11 @@ packages: upper-case: 1.1.3 dev: true + /titleize@3.0.0: + resolution: {integrity: sha512-KxVu8EYHDPBdUYdKZdKtU2aj2XfEx9AfjXxE/Aj0vT06w2icA09Vus1rh6eSu1y01akYg6BjIK/hxyLJINoMLQ==} + engines: {node: '>=12'} + dev: true + /tmp@0.0.33: resolution: {integrity: sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==} engines: {node: '>=0.6.0'} @@ -10525,6 +10768,15 @@ packages: engines: {node: '>=0.10.0'} dev: true + /ts-api-utils@1.0.3(typescript@4.9.5): + resolution: {integrity: sha512-wNMeqtMz5NtwpT/UZGY5alT+VoKdSsOOP/kqHFcUW1P/VRhH2wJ48+DN2WwUliNbQ976ETwDL0Ifd2VVvgonvg==} + engines: {node: '>=16.13.0'} + peerDependencies: + typescript: '>=4.2.0' + dependencies: + typescript: 4.9.5 + dev: true + /ts-command-line-args@2.5.1: resolution: {integrity: sha512-H69ZwTw3rFHb5WYpQya40YAX2/w7Ut75uUECbgBIsLmM+BNuYnxsltfyyLMxy6sEeKxgijLTnQtLd0nKd6+IYw==} hasBin: true @@ -10607,18 +10859,12 @@ packages: resolution: {integrity: sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==} dev: true - /tsort@0.0.1: - resolution: {integrity: sha512-Tyrf5mxF8Ofs1tNoxA13lFeZ2Zrbd6cKbuH3V+MQ5sb6DtBj5FjrXVsRWT8YvNAQTqNoz66dz1WsbigI22aEnw==} + /tslib@2.6.2: + resolution: {integrity: sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==} dev: true - /tsutils@3.21.0(typescript@4.9.5): - resolution: {integrity: sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==} - engines: {node: '>= 6'} - peerDependencies: - typescript: '>=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta' - dependencies: - tslib: 1.14.1 - typescript: 4.9.5 + /tsort@0.0.1: + resolution: {integrity: sha512-Tyrf5mxF8Ofs1tNoxA13lFeZ2Zrbd6cKbuH3V+MQ5sb6DtBj5FjrXVsRWT8YvNAQTqNoz66dz1WsbigI22aEnw==} dev: true /tunnel-agent@0.6.0: @@ -10846,6 +11092,11 @@ packages: isobject: 3.0.1 dev: true + /untildify@4.0.0: + resolution: {integrity: sha512-KK8xQ1mkzZeg9inewmFVDNkg3l5LUhoq9kN6iWYB/CC9YMG8HA+c1Q8HwDe6dEX7kErrEVNVBO3fWsVq5iDgtw==} + engines: {node: '>=8'} + dev: true + /upper-case-first@1.1.2: resolution: {integrity: sha512-wINKYvI3Db8dtjikdAqoBbZoP6Q+PZUyfMR7pmwHzjC2quzSkUq5DmPrTtPEqHaz8AGtmsB4TqwapMTM1QAQOQ==} dependencies: diff --git a/contracts/scripts/native_solc_compile_all_vrf b/contracts/scripts/native_solc_compile_all_vrf index 72be6eebf8d..feebbdcf145 100755 --- a/contracts/scripts/native_solc_compile_all_vrf +++ b/contracts/scripts/native_solc_compile_all_vrf @@ -51,6 +51,7 @@ compileContract vrf/BatchBlockhashStore.sol compileContract vrf/BatchVRFCoordinatorV2.sol compileContract vrf/testhelpers/VRFCoordinatorV2TestHelper.sol compileContractAltOpts vrf/VRFCoordinatorV2.sol 10000 +compileContract mocks/VRFCoordinatorV2Mock.sol compileContract vrf/VRFOwner.sol # VRF V2Plus diff --git a/contracts/src/v0.8/dev/automation/2_1/KeeperRegistryBase2_1.sol b/contracts/src/v0.8/dev/automation/2_1/KeeperRegistryBase2_1.sol index e58dbf05f87..ccd286fda2f 100644 --- a/contracts/src/v0.8/dev/automation/2_1/KeeperRegistryBase2_1.sol +++ b/contracts/src/v0.8/dev/automation/2_1/KeeperRegistryBase2_1.sol @@ -398,6 +398,7 @@ abstract contract KeeperRegistryBase2_1 is ConfirmedOwner, ExecutionPrevention { * not necessarily the block number that the log was emitted in!!!! */ struct LogTrigger { + bytes32 logBlockHash; bytes32 txHash; uint32 logIndex; uint32 blockNum; @@ -794,7 +795,7 @@ abstract contract KeeperRegistryBase2_1 is ConfirmedOwner, ExecutionPrevention { UpkeepTransmitInfo memory transmitInfo ) internal returns (bool, bytes32) { LogTrigger memory trigger = abi.decode(rawTrigger, (LogTrigger)); - bytes32 dedupID = keccak256(abi.encodePacked(upkeepId, trigger.txHash, trigger.logIndex)); + bytes32 dedupID = keccak256(abi.encodePacked(upkeepId, trigger.logBlockHash, trigger.txHash, trigger.logIndex)); if ( (trigger.blockHash != bytes32("") && _blockHash(trigger.blockNum) != trigger.blockHash) || trigger.blockNum >= _blockNum() diff --git a/contracts/src/v0.8/dev/vrf/SubscriptionAPI.sol b/contracts/src/v0.8/dev/vrf/SubscriptionAPI.sol index e9652d0bf6b..9e3181978f5 100644 --- a/contracts/src/v0.8/dev/vrf/SubscriptionAPI.sol +++ b/contracts/src/v0.8/dev/vrf/SubscriptionAPI.sol @@ -36,6 +36,7 @@ abstract contract SubscriptionAPI is ConfirmedOwner, IERC677Receiver, IVRFSubscr error FailedToSendEther(); error FailedToTransferLink(); error IndexOutOfRange(); + error LinkNotSet(); // We use the subscription struct (1 word) // at fulfillment time. @@ -158,6 +159,14 @@ abstract contract SubscriptionAPI is ConfirmedOwner, IERC677Receiver, IVRFSubscr * @param to address to send link to */ function recoverFunds(address to) external onlyOwner { + // If LINK is not set, we cannot recover funds. + // It is possible that this coordinator address was funded with LINK + // by accident by a user but the LINK token needs to be set first + // before we can recover it. + if (address(LINK) == address(0)) { + revert LinkNotSet(); + } + uint256 externalBalance = LINK.balanceOf(address(this)); uint256 internalBalance = uint256(s_totalBalance); if (internalBalance > externalBalance) { @@ -200,6 +209,9 @@ abstract contract SubscriptionAPI is ConfirmedOwner, IERC677Receiver, IVRFSubscr * @param amount amount to withdraw */ function oracleWithdraw(address recipient, uint96 amount) external nonReentrant { + if (address(LINK) == address(0)) { + revert LinkNotSet(); + } if (s_withdrawableTokens[msg.sender] < amount) { revert InsufficientBalance(); } @@ -239,7 +251,7 @@ abstract contract SubscriptionAPI is ConfirmedOwner, IERC677Receiver, IVRFSubscr if (s_subscriptionConfigs[subId].owner == address(0)) { revert InvalidSubscription(); } - // We do not check that the msg.sender is the subscription owner, + // We do not check that the sender is the subscription owner, // anyone can fund a subscription. uint256 oldBalance = s_subscriptions[subId].balance; s_subscriptions[subId].balance += uint96(amount); @@ -426,8 +438,4 @@ abstract contract SubscriptionAPI is ConfirmedOwner, IERC677Receiver, IVRFSubscr } _; } - - function getConsumerKey(address consumer, uint256 subId) internal pure returns (bytes32) { - return keccak256(abi.encodePacked(subId, consumer)); - } } diff --git a/contracts/src/v0.8/dev/vrf/testhelpers/ExposedVRFCoordinatorV2Plus.sol b/contracts/src/v0.8/dev/vrf/testhelpers/ExposedVRFCoordinatorV2Plus.sol index 82f4068112d..0d493867370 100644 --- a/contracts/src/v0.8/dev/vrf/testhelpers/ExposedVRFCoordinatorV2Plus.sol +++ b/contracts/src/v0.8/dev/vrf/testhelpers/ExposedVRFCoordinatorV2Plus.sol @@ -33,4 +33,36 @@ contract ExposedVRFCoordinatorV2Plus is VRFCoordinatorV2Plus { function getActiveSubscriptionIdsLength() external view returns (uint256) { return s_subIds.length(); } + + function getSubscriptionConfig(uint256 subId) external view returns (SubscriptionConfig memory) { + return s_subscriptionConfigs[subId]; + } + + function getSubscriptionStruct(uint256 subId) external view returns (Subscription memory) { + return s_subscriptions[subId]; + } + + function setTotalBalanceTestingOnlyXXX(uint96 newBalance) external { + s_totalBalance = newBalance; + } + + function setTotalEthBalanceTestingOnlyXXX(uint96 newBalance) external { + s_totalEthBalance = newBalance; + } + + function setWithdrawableTokensTestingOnlyXXX(address oracle, uint96 newBalance) external { + s_withdrawableTokens[oracle] = newBalance; + } + + function getWithdrawableTokensTestingOnlyXXX(address oracle) external view returns (uint96) { + return s_withdrawableTokens[oracle]; + } + + function setWithdrawableEthTestingOnlyXXX(address oracle, uint96 newBalance) external { + s_withdrawableEth[oracle] = newBalance; + } + + function getWithdrawableEthTestingOnlyXXX(address oracle) external view returns (uint96) { + return s_withdrawableEth[oracle]; + } } diff --git a/contracts/src/v0.8/functions/dev/1_0_0/FunctionsBilling.sol b/contracts/src/v0.8/functions/dev/1_0_0/FunctionsBilling.sol index 8e8607078e5..c616f7355d2 100644 --- a/contracts/src/v0.8/functions/dev/1_0_0/FunctionsBilling.sol +++ b/contracts/src/v0.8/functions/dev/1_0_0/FunctionsBilling.sol @@ -10,17 +10,15 @@ import {FunctionsResponse} from "./libraries/FunctionsResponse.sol"; import {SafeCast} from "../../../vendor/openzeppelin-solidity/v4.8.0/contracts/utils/math/SafeCast.sol"; -/** - * @title Functions Billing contract - * @notice Contract that calculates payment from users to the nodes of the Decentralized Oracle Network (DON). - * @dev THIS CONTRACT HAS NOT GONE THROUGH ANY SECURITY REVIEW. DO NOT USE IN PROD. - */ +/// @title Functions Billing contract +/// @notice Contract that calculates payment from users to the nodes of the Decentralized Oracle Network (DON). +/// @dev THIS CONTRACT HAS NOT GONE THROUGH ANY SECURITY REVIEW. DO NOT USE IN PROD. abstract contract FunctionsBilling is Routable, IFunctionsBilling { using FunctionsResponse for FunctionsResponse.RequestMeta; using FunctionsResponse for FunctionsResponse.Commitment; using FunctionsResponse for FunctionsResponse.FulfillResult; - uint32 private constant REASONABLE_GAS_PRICE_CEILING = 1_000_000; + uint256 private constant REASONABLE_GAS_PRICE_CEILING = 1_000_000_000_000_000; // 1 million gwei // ================================================================ // | Request Commitment state | // ================================================================ @@ -34,15 +32,14 @@ abstract contract FunctionsBilling is Routable, IFunctionsBilling { // ================================================================ struct Config { - uint32 maxCallbackGasLimit; // ══════════════════╗ Maximum amount of gas that can be given to a request's client callback + uint32 fulfillmentGasPriceOverEstimationBP; // ══╗ Percentage of gas price overestimation to account for changes in gas price between request and response. Held as basis points (one hundredth of 1 percentage point) uint32 feedStalenessSeconds; // ║ How long before we consider the feed price to be stale and fallback to fallbackNativePerUnitLink. uint32 gasOverheadBeforeCallback; // ║ Represents the average gas execution cost before the fulfillment callback. This amount is always billed for every request. uint32 gasOverheadAfterCallback; // ║ Represents the average gas execution cost after the fulfillment callback. This amount is always billed for every request. uint32 requestTimeoutSeconds; // ║ How many seconds it takes before we consider a request to be timed out uint72 donFee; // ║ Additional flat fee (in Juels of LINK) that will be split between Node Operators. Max value is 2^80 - 1 == 1.2m LINK. uint16 maxSupportedRequestDataVersion; // ═══════╝ The highest support request data version supported by the node. All lower versions should also be supported. - uint32 fulfillmentGasPriceOverEstimationBP; // ══╗ Percentage of gas price overestimation to account for changes in gas price between request and response. Held as basis points (one hundredth of 1 percentage point) - uint224 fallbackNativePerUnitLink; // ═══════════╝ fallback NATIVE CURRENCY / LINK conversion rate if the data feed is stale + uint224 fallbackNativePerUnitLink; // ═══════════╸ fallback NATIVE CURRENCY / LINK conversion rate if the data feed is stale } Config private s_config; @@ -83,14 +80,14 @@ abstract contract FunctionsBilling is Routable, IFunctionsBilling { // | Configuration | // ================================================================ - // @notice Gets the Chainlink Coordinator's billing configuration - // @return config + /// @notice Gets the Chainlink Coordinator's billing configuration + /// @return config function getConfig() external view returns (Config memory) { return s_config; } - // @notice Sets the Chainlink Coordinator's billing configuration - // @param config - See the contents of the Config struct in IFunctionsBilling.Config for more information + /// @notice Sets the Chainlink Coordinator's billing configuration + /// @param config - See the contents of the Config struct in IFunctionsBilling.Config for more information function updateConfig(Config memory config) public { _onlyOwner(); @@ -102,17 +99,17 @@ abstract contract FunctionsBilling is Routable, IFunctionsBilling { // | Fee Calculation | // ================================================================ - // @inheritdoc IFunctionsBilling + /// @inheritdoc IFunctionsBilling function getDONFee(bytes memory /* requestData */) public view override returns (uint72) { return s_config.donFee; } - // @inheritdoc IFunctionsBilling + /// @inheritdoc IFunctionsBilling function getAdminFee() public view override returns (uint72) { return _getRouter().getAdminFee(); } - // @inheritdoc IFunctionsBilling + /// @inheritdoc IFunctionsBilling function getWeiPerUnitLink() public view returns (uint256) { Config memory config = s_config; (, int256 weiPerUnitLink, , uint256 timestamp, ) = s_linkToNativeFeed.latestRoundData(); @@ -126,47 +123,47 @@ abstract contract FunctionsBilling is Routable, IFunctionsBilling { return uint256(weiPerUnitLink); } - function _getJuelsPerGas(uint256 gasPriceGwei) private view returns (uint96) { + function _getJuelsPerGas(uint256 gasPriceWei) private view returns (uint96) { // (1e18 juels/link) * (wei/gas) / (wei/link) = juels per gas // There are only 1e9*1e18 = 1e27 juels in existence, should not exceed uint96 (2^96 ~ 7e28) - return SafeCast.toUint96((1e18 * gasPriceGwei) / getWeiPerUnitLink()); + return SafeCast.toUint96((1e18 * gasPriceWei) / getWeiPerUnitLink()); } // ================================================================ // | Cost Estimation | // ================================================================ - // @inheritdoc IFunctionsBilling + /// @inheritdoc IFunctionsBilling function estimateCost( uint64 subscriptionId, bytes calldata data, uint32 callbackGasLimit, - uint256 gasPriceGwei + uint256 gasPriceWei ) external view override returns (uint96) { _getRouter().isValidCallbackGasLimit(subscriptionId, callbackGasLimit); // Reasonable ceilings to prevent integer overflows - if (gasPriceGwei > REASONABLE_GAS_PRICE_CEILING) { + if (gasPriceWei > REASONABLE_GAS_PRICE_CEILING) { revert InvalidCalldata(); } uint72 adminFee = getAdminFee(); uint72 donFee = getDONFee(data); - return _calculateCostEstimate(callbackGasLimit, gasPriceGwei, donFee, adminFee); + return _calculateCostEstimate(callbackGasLimit, gasPriceWei, donFee, adminFee); } - // @notice Estimate the cost in Juels of LINK + /// @notice Estimate the cost in Juels of LINK // that will be charged to a subscription to fulfill a Functions request // Gas Price can be overestimated to account for flucuations between request and response time function _calculateCostEstimate( uint32 callbackGasLimit, - uint256 gasPriceGwei, + uint256 gasPriceWei, uint72 donFee, uint72 adminFee ) internal view returns (uint96) { uint256 executionGas = s_config.gasOverheadBeforeCallback + s_config.gasOverheadAfterCallback + callbackGasLimit; - uint256 gasPriceWithOverestimation = gasPriceGwei + - ((gasPriceGwei * s_config.fulfillmentGasPriceOverEstimationBP) / 10_000); - // @NOTE: Basis Points are 1/100th of 1%, divide by 10_000 to bring back to original units + uint256 gasPriceWithOverestimation = gasPriceWei + + ((gasPriceWei * s_config.fulfillmentGasPriceOverEstimationBP) / 10_000); + /// @NOTE: Basis Points are 1/100th of 1%, divide by 10_000 to bring back to original units uint96 juelsPerGas = _getJuelsPerGas(gasPriceWithOverestimation); uint256 estimatedGasReimbursement = juelsPerGas * executionGas; @@ -179,12 +176,10 @@ abstract contract FunctionsBilling is Routable, IFunctionsBilling { // | Billing | // ================================================================ - // @notice Initiate the billing process for an Functions request - // @dev Only callable by the Functions Router - // @param data - Encoded Chainlink Functions request data, use FunctionsClient API to encode a request - // @param requestDataVersion - Version number of the structure of the request data - // @param billing - Billing configuration for the request - // @return commitment - The parameters of the request that must be held consistent at response time + /// @notice Initiate the billing process for an Functions request + /// @dev Only callable by the Functions Router + /// @param request - Chainlink Functions request data, see FunctionsResponse.RequestMeta for the structure + /// @return commitment - The parameters of the request that must be held consistent at response time function _startBilling( FunctionsResponse.RequestMeta memory request ) internal returns (FunctionsResponse.Commitment memory commitment) { @@ -234,8 +229,8 @@ abstract contract FunctionsBilling is Routable, IFunctionsBilling { return commitment; } - // @notice Generate a keccak hash request ID - // @dev uses the number of requests that the consumer of a subscription has sent as a nonce + /// @notice Generate a keccak hash request ID + /// @dev uses the number of requests that the consumer of a subscription has sent as a nonce function _computeRequestId( address don, address client, @@ -245,13 +240,13 @@ abstract contract FunctionsBilling is Routable, IFunctionsBilling { return keccak256(abi.encode(don, client, subscriptionId, nonce)); } - // @notice Finalize billing process for an Functions request by sending a callback to the Client contract and then charging the subscription - // @param requestId identifier for the request that was generated by the Registry in the beginBilling commitment - // @param response response data from DON consensus - // @param err error from DON consensus - // @return result fulfillment result - // @dev Only callable by a node that has been approved on the Coordinator - // @dev simulated offchain to determine if sufficient balance is present to fulfill the request + /// @notice Finalize billing process for an Functions request by sending a callback to the Client contract and then charging the subscription + /// @param requestId identifier for the request that was generated by the Registry in the beginBilling commitment + /// @param response response data from DON consensus + /// @param err error from DON consensus + /// @return result fulfillment result + /// @dev Only callable by a node that has been approved on the Coordinator + /// @dev simulated offchain to determine if sufficient balance is present to fulfill the request function _fulfillAndBill( bytes32 requestId, bytes memory response, @@ -261,14 +256,14 @@ abstract contract FunctionsBilling is Routable, IFunctionsBilling { ) internal returns (FunctionsResponse.FulfillResult) { FunctionsResponse.Commitment memory commitment = abi.decode(onchainMetadata, (FunctionsResponse.Commitment)); - if (s_requestCommitments[requestId] != keccak256(abi.encode(commitment))) { - return FunctionsResponse.FulfillResult.INVALID_COMMITMENT; - } - if (s_requestCommitments[requestId] == bytes32(0)) { return FunctionsResponse.FulfillResult.INVALID_REQUEST_ID; } + if (s_requestCommitments[requestId] != keccak256(abi.encode(commitment))) { + return FunctionsResponse.FulfillResult.INVALID_COMMITMENT; + } + uint96 juelsPerGas = _getJuelsPerGas(tx.gasprice); // Gas overhead without callback uint96 gasOverheadJuels = juelsPerGas * @@ -306,25 +301,20 @@ abstract contract FunctionsBilling is Routable, IFunctionsBilling { // | Request Timeout | // ================================================================ - // @inheritdoc IFunctionsBilling - // @dev Only callable by the Router - // @dev Used by FunctionsRouter.sol during timeout of a request - function deleteCommitment(bytes32 requestId) external override onlyRouter returns (bool) { - // Ensure that commitment exists - if (s_requestCommitments[requestId] == bytes32(0)) { - return false; - } + /// @inheritdoc IFunctionsBilling + /// @dev Only callable by the Router + /// @dev Used by FunctionsRouter.sol during timeout of a request + function deleteCommitment(bytes32 requestId) external override onlyRouter { // Delete commitment delete s_requestCommitments[requestId]; emit CommitmentDeleted(requestId); - return true; } // ================================================================ // | Fund withdrawal | // ================================================================ - // @inheritdoc IFunctionsBilling + /// @inheritdoc IFunctionsBilling function oracleWithdraw(address recipient, uint96 amount) external { _disperseFeePool(); @@ -337,8 +327,8 @@ abstract contract FunctionsBilling is Routable, IFunctionsBilling { IFunctionsSubscriptions(address(_getRouter())).oracleWithdraw(recipient, amount); } - // @inheritdoc IFunctionsBilling - // @dev Only callable by the Coordinator owner + /// @inheritdoc IFunctionsBilling + /// @dev Only callable by the Coordinator owner function oracleWithdrawAll() external { _onlyOwner(); _disperseFeePool(); @@ -348,8 +338,10 @@ abstract contract FunctionsBilling is Routable, IFunctionsBilling { // Bounded by "maxNumOracles" on OCR2Abstract.sol for (uint256 i = 0; i < transmitters.length; ++i) { uint96 balance = s_withdrawableTokens[transmitters[i]]; - s_withdrawableTokens[transmitters[i]] = 0; - IFunctionsSubscriptions(address(_getRouter())).oracleWithdraw(transmitters[i], balance); + if (balance > 0) { + s_withdrawableTokens[transmitters[i]] = 0; + IFunctionsSubscriptions(address(_getRouter())).oracleWithdraw(transmitters[i], balance); + } } } diff --git a/contracts/src/v0.8/functions/dev/1_0_0/FunctionsClient.sol b/contracts/src/v0.8/functions/dev/1_0_0/FunctionsClient.sol index b7f676c2327..ecbbbd928fe 100644 --- a/contracts/src/v0.8/functions/dev/1_0_0/FunctionsClient.sol +++ b/contracts/src/v0.8/functions/dev/1_0_0/FunctionsClient.sol @@ -6,8 +6,8 @@ import {IFunctionsClient} from "./interfaces/IFunctionsClient.sol"; import {FunctionsRequest} from "./libraries/FunctionsRequest.sol"; -// @title The Chainlink Functions client contract -// @notice Contract developers can inherit this contract in order to make Chainlink Functions requests +/// @title The Chainlink Functions client contract +/// @notice Contract developers can inherit this contract in order to make Chainlink Functions requests abstract contract FunctionsClient is IFunctionsClient { using FunctionsRequest for FunctionsRequest.Request; @@ -22,11 +22,11 @@ abstract contract FunctionsClient is IFunctionsClient { i_router = IFunctionsRouter(router); } - // @notice Sends a Chainlink Functions request - // @param data The CBOR encoded bytes data for a Functions request - // @param subscriptionId The subscription ID that will be charged to service the request - // @param callbackGasLimit the amount of gas that will be available for the fulfillment callback - // @return requestId The generated request ID for this request + /// @notice Sends a Chainlink Functions request + /// @param data The CBOR encoded bytes data for a Functions request + /// @param subscriptionId The subscription ID that will be charged to service the request + /// @param callbackGasLimit the amount of gas that will be available for the fulfillment callback + /// @return requestId The generated request ID for this request function _sendRequest( bytes memory data, uint64 subscriptionId, @@ -44,18 +44,19 @@ abstract contract FunctionsClient is IFunctionsClient { return requestId; } - // @notice User defined function to handle a response from the DON - // @param requestId The request ID, returned by sendRequest() - // @param response Aggregated response from the execution of the user's source code - // @param err Aggregated error from the execution of the user code or from the execution pipeline - // @dev Either response or error parameter will be set, but never both + /// @notice User defined function to handle a response from the DON + /// @param requestId The request ID, returned by sendRequest() + /// @param response Aggregated response from the execution of the user's source code + /// @param err Aggregated error from the execution of the user code or from the execution pipeline + /// @dev Either response or error parameter will be set, but never both function fulfillRequest(bytes32 requestId, bytes memory response, bytes memory err) internal virtual; - // @inheritdoc IFunctionsClient + /// @inheritdoc IFunctionsClient function handleOracleFulfillment(bytes32 requestId, bytes memory response, bytes memory err) external override { if (msg.sender != address(i_router)) { revert OnlyRouterCanFulfill(); } fulfillRequest(requestId, response, err); + emit RequestFulfilled(requestId); } } diff --git a/contracts/src/v0.8/functions/dev/1_0_0/FunctionsCoordinator.sol b/contracts/src/v0.8/functions/dev/1_0_0/FunctionsCoordinator.sol index aa7b1d5c7e1..540b382d652 100644 --- a/contracts/src/v0.8/functions/dev/1_0_0/FunctionsCoordinator.sol +++ b/contracts/src/v0.8/functions/dev/1_0_0/FunctionsCoordinator.sol @@ -9,15 +9,15 @@ import {FunctionsBilling} from "./FunctionsBilling.sol"; import {OCR2Base} from "./ocr/OCR2Base.sol"; import {FunctionsResponse} from "./libraries/FunctionsResponse.sol"; -// @title Functions Coordinator contract -// @notice Contract that nodes of a Decentralized Oracle Network (DON) interact with -// @dev THIS CONTRACT HAS NOT GONE THROUGH ANY SECURITY REVIEW. DO NOT USE IN PROD. +/// @title Functions Coordinator contract +/// @notice Contract that nodes of a Decentralized Oracle Network (DON) interact with +/// @dev THIS CONTRACT HAS NOT GONE THROUGH ANY SECURITY REVIEW. DO NOT USE IN PROD. contract FunctionsCoordinator is OCR2Base, IFunctionsCoordinator, FunctionsBilling { using FunctionsResponse for FunctionsResponse.RequestMeta; using FunctionsResponse for FunctionsResponse.Commitment; using FunctionsResponse for FunctionsResponse.FulfillResult; - // @inheritdoc ITypeAndVersion + /// @inheritdoc ITypeAndVersion string public constant override typeAndVersion = "Functions Coordinator v1.0.0"; event OracleRequest( @@ -47,7 +47,7 @@ contract FunctionsCoordinator is OCR2Base, IFunctionsCoordinator, FunctionsBilli address linkToNativeFeed ) OCR2Base(true) FunctionsBilling(router, config, linkToNativeFeed) {} - // @inheritdoc IFunctionsCoordinator + /// @inheritdoc IFunctionsCoordinator function getThresholdPublicKey() external view override returns (bytes memory) { if (s_thresholdPublicKey.length == 0) { revert EmptyPublicKey(); @@ -55,7 +55,7 @@ contract FunctionsCoordinator is OCR2Base, IFunctionsCoordinator, FunctionsBilli return s_thresholdPublicKey; } - // @inheritdoc IFunctionsCoordinator + /// @inheritdoc IFunctionsCoordinator function setThresholdPublicKey(bytes calldata thresholdPublicKey) external override onlyOwner { if (thresholdPublicKey.length == 0) { revert EmptyPublicKey(); @@ -63,7 +63,7 @@ contract FunctionsCoordinator is OCR2Base, IFunctionsCoordinator, FunctionsBilli s_thresholdPublicKey = thresholdPublicKey; } - // @inheritdoc IFunctionsCoordinator + /// @inheritdoc IFunctionsCoordinator function getDONPublicKey() external view override returns (bytes memory) { if (s_donPublicKey.length == 0) { revert EmptyPublicKey(); @@ -71,7 +71,7 @@ contract FunctionsCoordinator is OCR2Base, IFunctionsCoordinator, FunctionsBilli return s_donPublicKey; } - // @inheritdoc IFunctionsCoordinator + /// @inheritdoc IFunctionsCoordinator function setDONPublicKey(bytes calldata donPublicKey) external override onlyOwner { if (donPublicKey.length == 0) { revert EmptyPublicKey(); @@ -79,7 +79,7 @@ contract FunctionsCoordinator is OCR2Base, IFunctionsCoordinator, FunctionsBilli s_donPublicKey = donPublicKey; } - // @dev check if node is in current transmitter list + /// @dev check if node is in current transmitter list function _isTransmitter(address node) internal view returns (bool) { address[] memory nodes = s_transmitters; // Bounded by "maxNumOracles" on OCR2Abstract.sol @@ -91,7 +91,7 @@ contract FunctionsCoordinator is OCR2Base, IFunctionsCoordinator, FunctionsBilli return false; } - // @inheritdoc IFunctionsCoordinator + /// @inheritdoc IFunctionsCoordinator function startRequest( FunctionsResponse.RequestMeta calldata request ) external override onlyRouter returns (FunctionsResponse.Commitment memory commitment) { @@ -113,19 +113,19 @@ contract FunctionsCoordinator is OCR2Base, IFunctionsCoordinator, FunctionsBilli return commitment; } - // DON fees are pooled together. If the OCR configuration is going to change, these need to be distributed. + /// @dev DON fees are pooled together. If the OCR configuration is going to change, these need to be distributed. function _beforeSetConfig(uint8 /* _f */, bytes memory /* _onchainConfig */) internal override { if (_getTransmitters().length > 0) { _disperseFeePool(); } } - // Used by FunctionsBilling.sol + /// @dev Used by FunctionsBilling.sol function _getTransmitters() internal view override returns (address[] memory) { return s_transmitters; } - // Report hook called within OCR2Base.sol + /// @dev Report hook called within OCR2Base.sol function _report( uint256 /*initialGas*/, address /*transmitter*/, @@ -171,7 +171,7 @@ contract FunctionsCoordinator is OCR2Base, IFunctionsCoordinator, FunctionsBilli } } - // Used in FunctionsBilling.sol + /// @dev Used in FunctionsBilling.sol function _onlyOwner() internal view override { _validateOwnership(); } diff --git a/contracts/src/v0.8/functions/dev/1_0_0/FunctionsRouter.sol b/contracts/src/v0.8/functions/dev/1_0_0/FunctionsRouter.sol index 46f6929fabc..41cd90341f3 100644 --- a/contracts/src/v0.8/functions/dev/1_0_0/FunctionsRouter.sol +++ b/contracts/src/v0.8/functions/dev/1_0_0/FunctionsRouter.sol @@ -62,6 +62,7 @@ contract FunctionsRouter is IFunctionsRouter, FunctionsSubscriptions, Pausable, error SenderMustAcceptTermsOfService(address sender); error InvalidGasFlagValue(uint8 value); error GasLimitTooBig(uint32 limit); + error DuplicateRequestId(bytes32 requestId); struct CallbackResult { bool success; // ══════╸ Whether the callback succeeded or not @@ -84,11 +85,13 @@ contract FunctionsRouter is IFunctionsRouter, FunctionsSubscriptions, Pausable, // | Configuration state | // ================================================================ struct Config { - uint16 maxConsumersPerSubscription; // ══════╗ Maximum number of consumers which can be added to a single subscription. This bound ensures we are able to loop over all subscription consumers as needed, without exceeding gas limits. Should a user require more consumers, they can use multiple subscriptions. - uint72 adminFee; // ║ Flat fee (in Juels of LINK) that will be paid to the Router owner for operation of the network - bytes4 handleOracleFulfillmentSelector; // ║ The function selector that is used when calling back to the Client contract - uint16 gasForCallExactCheck; // ═════════════╝ Used during calling back to the client. Ensures we have at least enough gas to be able to revert if gasAmount > 63//64*gas available. - uint32[] maxCallbackGasLimits; // ═══════════╸ List of max callback gas limits used by flag with GAS_FLAG_INDEX + uint16 maxConsumersPerSubscription; // ═════════╗ Maximum number of consumers which can be added to a single subscription. This bound ensures we are able to loop over all subscription consumers as needed, without exceeding gas limits. Should a user require more consumers, they can use multiple subscriptions. + uint72 adminFee; // ║ Flat fee (in Juels of LINK) that will be paid to the Router owner for operation of the network + bytes4 handleOracleFulfillmentSelector; // ║ The function selector that is used when calling back to the Client contract + uint16 gasForCallExactCheck; // ════════════════╝ Used during calling back to the client. Ensures we have at least enough gas to be able to revert if gasAmount > 63//64*gas available. + uint32[] maxCallbackGasLimits; // ══════════════╸ List of max callback gas limits used by flag with GAS_FLAG_INDEX + uint16 subscriptionDepositMinimumRequests; //═══╗ Amount of requests that must be completed before the full subscription balance will be released when closing a subscription account. + uint72 subscriptionDepositJuels; // ════════════╝ Amount of subscription funds that are held as a deposit until Config.subscriptionDepositMinimumRequests are made using the subscription. } Config private s_config; @@ -134,20 +137,20 @@ contract FunctionsRouter is IFunctionsRouter, FunctionsSubscriptions, Pausable, // | Configuration | // ================================================================ - // @notice The identifier of the route to retrieve the address of the access control contract + /// @notice The identifier of the route to retrieve the address of the access control contract // The access control contract controls which accounts can manage subscriptions - // @return id - bytes32 id that can be passed to the "getContractById" of the Router + /// @return id - bytes32 id that can be passed to the "getContractById" of the Router function getConfig() external view returns (Config memory) { return s_config; } - // @notice The router configuration + /// @notice The router configuration function updateConfig(Config memory config) public onlyOwner { s_config = config; emit ConfigUpdated(config); } - // @inheritdoc IFunctionsRouter + /// @inheritdoc IFunctionsRouter function isValidCallbackGasLimit(uint64 subscriptionId, uint32 callbackGasLimit) public view { uint8 callbackGasLimitsIndexSelector = uint8(getFlags(subscriptionId)[MAX_CALLBACK_GAS_LIMIT_FLAGS_INDEX]); if (callbackGasLimitsIndexSelector >= s_config.maxCallbackGasLimits.length) { @@ -159,31 +162,36 @@ contract FunctionsRouter is IFunctionsRouter, FunctionsSubscriptions, Pausable, } } - // @inheritdoc IFunctionsRouter + /// @inheritdoc IFunctionsRouter function getAdminFee() external view override returns (uint72) { return s_config.adminFee; } - // @inheritdoc IFunctionsRouter + /// @inheritdoc IFunctionsRouter function getAllowListId() external view override returns (bytes32) { return s_allowListId; } - // @inheritdoc IFunctionsRouter + /// @inheritdoc IFunctionsRouter function setAllowListId(bytes32 allowListId) external override onlyOwner { s_allowListId = allowListId; } - // Used within FunctionsSubscriptions.sol + /// @dev Used within FunctionsSubscriptions.sol function _getMaxConsumers() internal view override returns (uint16) { return s_config.maxConsumersPerSubscription; } + /// @dev Used within FunctionsSubscriptions.sol + function _getSubscriptionDepositDetails() internal view override returns (uint16, uint72) { + return (s_config.subscriptionDepositMinimumRequests, s_config.subscriptionDepositJuels); + } + // ================================================================ // | Requests | // ================================================================ - // @inheritdoc IFunctionsRouter + /// @inheritdoc IFunctionsRouter function sendRequest( uint64 subscriptionId, bytes calldata data, @@ -195,7 +203,7 @@ contract FunctionsRouter is IFunctionsRouter, FunctionsSubscriptions, Pausable, return _sendRequest(donId, coordinator, subscriptionId, data, dataVersion, callbackGasLimit); } - // @inheritdoc IFunctionsRouter + /// @inheritdoc IFunctionsRouter function sendRequestToProposed( uint64 subscriptionId, bytes calldata data, @@ -226,6 +234,7 @@ contract FunctionsRouter is IFunctionsRouter, FunctionsSubscriptions, Pausable, Subscription memory subscription = getSubscription(subscriptionId); Consumer memory consumer = getConsumer(msg.sender, subscriptionId); + uint72 adminFee = s_config.adminFee; // Forward request to DON FunctionsResponse.Commitment memory commitment = coordinator.startRequest( @@ -236,7 +245,7 @@ contract FunctionsRouter is IFunctionsRouter, FunctionsSubscriptions, Pausable, dataVersion: dataVersion, flags: getFlags(subscriptionId), callbackGasLimit: callbackGasLimit, - adminFee: s_config.adminFee, + adminFee: adminFee, initiatedRequests: consumer.initiatedRequests, completedRequests: consumer.completedRequests, availableBalance: subscription.balance - subscription.blockedBalance, @@ -244,11 +253,16 @@ contract FunctionsRouter is IFunctionsRouter, FunctionsSubscriptions, Pausable, }) ); + // Do not allow setting a comittment for a requestId that already exists + if (s_requestCommitments[commitment.requestId] != bytes32(0)) { + revert DuplicateRequestId(commitment.requestId); + } + // Store a commitment about the request s_requestCommitments[commitment.requestId] = keccak256( abi.encode( FunctionsResponse.Commitment({ - adminFee: s_config.adminFee, + adminFee: adminFee, coordinator: address(coordinator), client: msg.sender, subscriptionId: subscriptionId, @@ -285,7 +299,7 @@ contract FunctionsRouter is IFunctionsRouter, FunctionsSubscriptions, Pausable, // | Responses | // ================================================================ - // @inheritdoc IFunctionsRouter + /// @inheritdoc IFunctionsRouter function fulfill( bytes memory response, bytes memory err, @@ -300,23 +314,27 @@ contract FunctionsRouter is IFunctionsRouter, FunctionsSubscriptions, Pausable, revert OnlyCallableFromCoordinator(); } - if (s_requestCommitments[commitment.requestId] == bytes32(0)) { - resultCode = FunctionsResponse.FulfillResult.INVALID_REQUEST_ID; - emit RequestNotProcessed(commitment.requestId, commitment.coordinator, transmitter, resultCode); - return (resultCode, 0); - } + { + bytes32 commitmentHash = s_requestCommitments[commitment.requestId]; - if (keccak256(abi.encode(commitment)) != s_requestCommitments[commitment.requestId]) { - resultCode = FunctionsResponse.FulfillResult.INVALID_COMMITMENT; - emit RequestNotProcessed(commitment.requestId, commitment.coordinator, transmitter, resultCode); - return (resultCode, 0); - } + if (commitmentHash == bytes32(0)) { + resultCode = FunctionsResponse.FulfillResult.INVALID_REQUEST_ID; + emit RequestNotProcessed(commitment.requestId, commitment.coordinator, transmitter, resultCode); + return (resultCode, 0); + } + + if (keccak256(abi.encode(commitment)) != commitmentHash) { + resultCode = FunctionsResponse.FulfillResult.INVALID_COMMITMENT; + emit RequestNotProcessed(commitment.requestId, commitment.coordinator, transmitter, resultCode); + return (resultCode, 0); + } - // Check that the transmitter has supplied enough gas for the callback to succeed - if (gasleft() < commitment.callbackGasLimit + commitment.gasOverheadAfterCallback) { - resultCode = FunctionsResponse.FulfillResult.INSUFFICIENT_GAS_PROVIDED; - emit RequestNotProcessed(commitment.requestId, commitment.coordinator, transmitter, resultCode); - return (resultCode, 0); + // Check that the transmitter has supplied enough gas for the callback to succeed + if (gasleft() < commitment.callbackGasLimit + commitment.gasOverheadAfterCallback) { + resultCode = FunctionsResponse.FulfillResult.INSUFFICIENT_GAS_PROVIDED; + emit RequestNotProcessed(commitment.requestId, commitment.coordinator, transmitter, resultCode); + return (resultCode, 0); + } } { @@ -383,6 +401,18 @@ contract FunctionsRouter is IFunctionsRouter, FunctionsSubscriptions, Pausable, uint32 callbackGasLimit, address client ) private returns (CallbackResult memory) { + bool destinationNoLongerExists; + // solhint-disable-next-line no-inline-assembly + assembly { + // solidity calls check that a contract actually exists at the destination, so we do the same + destinationNoLongerExists := iszero(extcodesize(client)) + } + if (destinationNoLongerExists) { + // Return without attempting callback + // The subscription will still be charged to reimburse transmitter's gas overhead + return CallbackResult({success: false, gasUsed: 0, returnData: new bytes(0)}); + } + bytes memory encodedCallback = abi.encodeWithSelector( s_config.handleOracleFulfillmentSelector, requestId, @@ -404,13 +434,6 @@ contract FunctionsRouter is IFunctionsRouter, FunctionsSubscriptions, Pausable, // solhint-disable-next-line no-inline-assembly assembly { - // solidity calls check that a contract actually exists at the destination, so we do the same - // Note we do this check prior to measuring gas so gasForCallExactCheck (our "cushion") - // doesn't need to account for it. - if iszero(extcodesize(client)) { - revert(0, 0) - } - let g := gas() // Compute g -= gasForCallExactCheck and check for underflow // The gas actually passed to the callee is _min(gasAmount, 63//64*gas available). @@ -451,7 +474,7 @@ contract FunctionsRouter is IFunctionsRouter, FunctionsSubscriptions, Pausable, // | Route methods | // ================================================================ - // @inheritdoc IRouterBase + /// @inheritdoc IFunctionsRouter function getContractById(bytes32 id) public view override returns (address) { address currentImplementation = s_route[id]; if (currentImplementation == address(0)) { @@ -460,7 +483,7 @@ contract FunctionsRouter is IFunctionsRouter, FunctionsSubscriptions, Pausable, return currentImplementation; } - // @inheritdoc IRouterBase + /// @inheritdoc IFunctionsRouter function getProposedContractById(bytes32 id) public view override returns (address) { // Iterations will not exceed MAX_PROPOSAL_SET_LENGTH for (uint8 i = 0; i < s_proposedContractSet.ids.length; ++i) { @@ -475,12 +498,12 @@ contract FunctionsRouter is IFunctionsRouter, FunctionsSubscriptions, Pausable, // | Contract Proposal methods | // ================================================================ - // @inheritdoc IRouterBase + /// @inheritdoc IFunctionsRouter function getProposedContractSet() external view override returns (bytes32[] memory, address[] memory) { return (s_proposedContractSet.ids, s_proposedContractSet.to); } - // @inheritdoc IRouterBase + /// @inheritdoc IFunctionsRouter function proposeContractsUpdate( bytes32[] memory proposedContractSetIds, address[] memory proposedContractSetAddresses @@ -501,21 +524,18 @@ contract FunctionsRouter is IFunctionsRouter, FunctionsSubscriptions, Pausable, ) { revert InvalidProposal(); } - } - - s_proposedContractSet = ContractProposalSet({ids: proposedContractSetIds, to: proposedContractSetAddresses}); - // NOTE: iterations of this loop will not exceed MAX_PROPOSAL_SET_LENGTH - for (uint256 i = 0; i < proposedContractSetIds.length; ++i) { emit ContractProposed({ - proposedContractSetId: proposedContractSetIds[i], - proposedContractSetFromAddress: s_route[proposedContractSetIds[i]], - proposedContractSetToAddress: proposedContractSetAddresses[i] + proposedContractSetId: id, + proposedContractSetFromAddress: s_route[id], + proposedContractSetToAddress: proposedContract }); } + + s_proposedContractSet = ContractProposalSet({ids: proposedContractSetIds, to: proposedContractSetAddresses}); } - // @inheritdoc IRouterBase + /// @inheritdoc IFunctionsRouter function updateContracts() external override onlyOwner { // Iterations will not exceed MAX_PROPOSAL_SET_LENGTH for (uint256 i = 0; i < s_proposedContractSet.ids.length; ++i) { @@ -533,17 +553,17 @@ contract FunctionsRouter is IFunctionsRouter, FunctionsSubscriptions, Pausable, // ================================================================ // Favoring internal functions over actual modifiers to reduce contract size - // Used within FunctionsSubscriptions.sol + /// @dev Used within FunctionsSubscriptions.sol function _whenNotPaused() internal view override { _requireNotPaused(); } - // Used within FunctionsSubscriptions.sol + /// @dev Used within FunctionsSubscriptions.sol function _onlyRouterOwner() internal view override { _validateOwnership(); } - // Used within FunctionsSubscriptions.sol + /// @dev Used within FunctionsSubscriptions.sol function _onlySenderThatAcceptedToS() internal view override { address currentImplementation = s_route[s_allowListId]; if (currentImplementation == address(0)) { @@ -555,12 +575,12 @@ contract FunctionsRouter is IFunctionsRouter, FunctionsSubscriptions, Pausable, } } - // @inheritdoc IRouterBase + /// @inheritdoc IFunctionsRouter function pause() external override onlyOwner { _pause(); } - // @inheritdoc IRouterBase + /// @inheritdoc IFunctionsRouter function unpause() external override onlyOwner { _unpause(); } diff --git a/contracts/src/v0.8/functions/dev/1_0_0/FunctionsSubscriptions.sol b/contracts/src/v0.8/functions/dev/1_0_0/FunctionsSubscriptions.sol index cabe8b0d284..864225fd38c 100644 --- a/contracts/src/v0.8/functions/dev/1_0_0/FunctionsSubscriptions.sol +++ b/contracts/src/v0.8/functions/dev/1_0_0/FunctionsSubscriptions.sol @@ -13,9 +13,9 @@ import {IERC20} from "../../../vendor/openzeppelin-solidity/v4.8.0/contracts/tok import {SafeERC20} from "../../../vendor/openzeppelin-solidity/v4.8.0/contracts/token/ERC20/utils/SafeERC20.sol"; import {SafeCast} from "../../../vendor/openzeppelin-solidity/v4.8.0/contracts/utils/math/SafeCast.sol"; -// @title Functions Subscriptions contract -// @notice Contract that coordinates payment from users to the nodes of the Decentralized Oracle Network (DON). -// @dev THIS CONTRACT HAS NOT GONE THROUGH ANY SECURITY REVIEW. DO NOT USE IN PROD. +/// @title Functions Subscriptions contract +/// @notice Contract that coordinates payment from users to the nodes of the Decentralized Oracle Network (DON). +/// @dev THIS CONTRACT HAS NOT GONE THROUGH ANY SECURITY REVIEW. DO NOT USE IN PROD. abstract contract FunctionsSubscriptions is IFunctionsSubscriptions, IERC677Receiver { using SafeERC20 for IERC20; using FunctionsResponse for FunctionsResponse.Commitment; @@ -24,7 +24,7 @@ abstract contract FunctionsSubscriptions is IFunctionsSubscriptions, IERC677Rece // | Balance state | // ================================================================ // link token address - address internal immutable i_linkToken; + IERC20 internal immutable i_linkToken; // s_totalLinkBalance tracks the total LINK sent to/from // this contract through onTokenTransfer, cancelSubscription and oracleWithdraw. @@ -32,7 +32,7 @@ abstract contract FunctionsSubscriptions is IFunctionsSubscriptions, IERC677Rece // sent tokens using transfer and so we may need to use recoverFunds. uint96 private s_totalLinkBalance; - // @dev NOP balances are held as a single amount. The breakdown is held by the Coordinator. + /// @dev NOP balances are held as a single amount. The breakdown is held by the Coordinator. mapping(address coordinator => uint96 balanceJuelsLink) private s_withdrawableTokens; // ================================================================ @@ -42,7 +42,7 @@ abstract contract FunctionsSubscriptions is IFunctionsSubscriptions, IERC677Rece // loop through all the current subscriptions via .getSubscription(). uint64 private s_currentSubscriptionId; - mapping(uint64 subscriptionId => IFunctionsSubscriptions.Subscription) private s_subscriptions; + mapping(uint64 subscriptionId => Subscription) private s_subscriptions; // Maintains the list of keys in s_consumers. // We do this for 2 reasons: @@ -50,7 +50,7 @@ abstract contract FunctionsSubscriptions is IFunctionsSubscriptions, IERC677Rece // 2. To be able to return the list of all consumers in getSubscription. // Note that we need the s_consumers map to be able to directly check if a // consumer is valid without reading all the consumers from storage. - mapping(address consumer => mapping(uint64 subscriptionId => IFunctionsSubscriptions.Consumer)) private s_consumers; + mapping(address consumer => mapping(uint64 subscriptionId => Consumer)) private s_consumers; event SubscriptionCreated(uint64 indexed subscriptionId, address owner); event SubscriptionFunded(uint64 indexed subscriptionId, uint256 oldBalance, uint256 newBalance); @@ -70,7 +70,6 @@ abstract contract FunctionsSubscriptions is IFunctionsSubscriptions, IERC677Rece error MustBeSubscriptionOwner(); error TimeoutNotExceeded(); error MustBeProposedOwner(address proposedOwner); - error TotalBalanceInvariantViolated(uint256 totalBalance, uint256 deductionAttempt); // Should never happen event FundsRecovered(address to, uint256 amount); // ================================================================ @@ -90,15 +89,15 @@ abstract contract FunctionsSubscriptions is IFunctionsSubscriptions, IERC677Rece // | Initialization | // ================================================================ constructor(address link) { - i_linkToken = link; + i_linkToken = IERC20(link); } // ================================================================ // | Request/Response | // ================================================================ - // @notice Sets a request as in-flight - // @dev Only callable within the Router + /// @notice Sets a request as in-flight + /// @dev Only callable within the Router function _markRequestInFlight(address client, uint64 subscriptionId, uint96 estimatedTotalCostJuels) internal { // Earmark subscription funds s_subscriptions[subscriptionId].blockedBalance += estimatedTotalCostJuels; @@ -107,8 +106,8 @@ abstract contract FunctionsSubscriptions is IFunctionsSubscriptions, IERC677Rece s_consumers[client][subscriptionId].initiatedRequests += 1; } - // @notice Moves funds from one subscription account to another. - // @dev Only callable by the Coordinator contract that is saved in the request commitment + /// @notice Moves funds from one subscription account to another. + /// @dev Only callable by the Coordinator contract that is saved in the request commitment function _pay( uint64 subscriptionId, uint96 estimatedTotalCostJuels, @@ -121,16 +120,17 @@ abstract contract FunctionsSubscriptions is IFunctionsSubscriptions, IERC677Rece uint96 callbackGasCostJuels = juelsPerGas * gasUsed; uint96 totalCostJuels = costWithoutCallbackJuels + adminFee + callbackGasCostJuels; - // Charge the subscription - if (s_subscriptions[subscriptionId].balance < totalCostJuels) { + if ( + s_subscriptions[subscriptionId].balance < totalCostJuels || + s_subscriptions[subscriptionId].blockedBalance < estimatedTotalCostJuels + ) { revert InsufficientBalance(s_subscriptions[subscriptionId].balance); } + + // Charge the subscription s_subscriptions[subscriptionId].balance -= totalCostJuels; // Unblock earmarked funds - if (s_subscriptions[subscriptionId].blockedBalance < estimatedTotalCostJuels) { - revert InsufficientBalance(s_subscriptions[subscriptionId].balance); - } s_subscriptions[subscriptionId].blockedBalance -= estimatedTotalCostJuels; // Pay the DON's fees and gas reimbursement @@ -149,21 +149,21 @@ abstract contract FunctionsSubscriptions is IFunctionsSubscriptions, IERC677Rece // | Owner methods | // ================================================================ - // @inheritdoc IFunctionsSubscriptions + /// @inheritdoc IFunctionsSubscriptions function ownerCancelSubscription(uint64 subscriptionId) external override { _onlyRouterOwner(); _isExistingSubscription(subscriptionId); - _cancelSubscriptionHelper(subscriptionId, s_subscriptions[subscriptionId].owner); + _cancelSubscriptionHelper(subscriptionId, s_subscriptions[subscriptionId].owner, false); } - // @inheritdoc IFunctionsSubscriptions + /// @inheritdoc IFunctionsSubscriptions function recoverFunds(address to) external override { _onlyRouterOwner(); - uint256 externalBalance = IERC20(i_linkToken).balanceOf(address(this)); + uint256 externalBalance = i_linkToken.balanceOf(address(this)); uint256 internalBalance = uint256(s_totalLinkBalance); if (internalBalance < externalBalance) { uint256 amount = externalBalance - internalBalance; - IERC20(i_linkToken).safeTransfer(to, amount); + i_linkToken.safeTransfer(to, amount); emit FundsRecovered(to, amount); } // If the balances are equal, nothing to be done. @@ -173,7 +173,7 @@ abstract contract FunctionsSubscriptions is IFunctionsSubscriptions, IERC677Rece // | Fund withdrawal | // ================================================================ - // @inheritdoc IFunctionsSubscriptions + /// @inheritdoc IFunctionsSubscriptions function oracleWithdraw(address recipient, uint96 amount) external override { _whenNotPaused(); @@ -184,18 +184,15 @@ abstract contract FunctionsSubscriptions is IFunctionsSubscriptions, IERC677Rece if (currentBalance < amount) { revert InsufficientBalance(currentBalance); } - if (s_totalLinkBalance < amount) { - revert TotalBalanceInvariantViolated(s_totalLinkBalance, amount); - } s_withdrawableTokens[msg.sender] -= amount; s_totalLinkBalance -= amount; - IERC20(i_linkToken).safeTransfer(recipient, amount); + i_linkToken.safeTransfer(recipient, amount); } - // @notice Owner withdraw LINK earned through admin fees - // @notice If amount is 0 the full balance will be withdrawn - // @param recipient where to send the funds - // @param amount amount to withdraw + /// @notice Owner withdraw LINK earned through admin fees + /// @notice If amount is 0 the full balance will be withdrawn + /// @param recipient where to send the funds + /// @param amount amount to withdraw function ownerWithdraw(address recipient, uint96 amount) external { _onlyRouterOwner(); if (amount == 0) { @@ -205,13 +202,10 @@ abstract contract FunctionsSubscriptions is IFunctionsSubscriptions, IERC677Rece if (currentBalance < amount) { revert InsufficientBalance(currentBalance); } - if (s_totalLinkBalance < amount) { - revert TotalBalanceInvariantViolated(s_totalLinkBalance, amount); - } s_withdrawableTokens[address(this)] -= amount; s_totalLinkBalance -= amount; - IERC20(i_linkToken).safeTransfer(recipient, amount); + i_linkToken.safeTransfer(recipient, amount); } // ================================================================ @@ -219,11 +213,11 @@ abstract contract FunctionsSubscriptions is IFunctionsSubscriptions, IERC677Rece // ================================================================ // This function is to be invoked when using LINK.transferAndCall - // @dev Note to fund the subscription, use transferAndCall. For example - // @dev LINKTOKEN.transferAndCall( - // @dev address(ROUTER), - // @dev amount, - // @dev abi.encode(subscriptionId)); + /// @dev Note to fund the subscription, use transferAndCall. For example + /// @dev LINKTOKEN.transferAndCall( + /// @dev address(ROUTER), + /// @dev amount, + /// @dev abi.encode(subscriptionId)); function onTokenTransfer(address /* sender */, uint256 amount, bytes calldata data) external override { _whenNotPaused(); if (msg.sender != address(i_linkToken)) { @@ -248,42 +242,63 @@ abstract contract FunctionsSubscriptions is IFunctionsSubscriptions, IERC677Rece // | Subscription management | // ================================================================ - // @inheritdoc IFunctionsSubscriptions + /// @inheritdoc IFunctionsSubscriptions function getTotalBalance() external view override returns (uint96) { return s_totalLinkBalance; } - // @inheritdoc IFunctionsSubscriptions + /// @inheritdoc IFunctionsSubscriptions function getSubscriptionCount() external view override returns (uint64) { return s_currentSubscriptionId; } - // @inheritdoc IFunctionsSubscriptions + /// @inheritdoc IFunctionsSubscriptions function getSubscription(uint64 subscriptionId) public view override returns (Subscription memory) { _isExistingSubscription(subscriptionId); return s_subscriptions[subscriptionId]; } - // @inheritdoc IFunctionsSubscriptions + /// @inheritdoc IFunctionsSubscriptions + function getSubscriptionsInRange( + uint64 subscriptionIdStart, + uint64 subscriptionIdEnd + ) external view override returns (Subscription[] memory subscriptions) { + if ( + subscriptionIdStart > subscriptionIdEnd || + subscriptionIdEnd > s_currentSubscriptionId || + s_currentSubscriptionId == 0 + ) { + revert InvalidCalldata(); + } + + subscriptions = new Subscription[]((subscriptionIdEnd - subscriptionIdStart) + 1); + for (uint256 i = 0; i <= subscriptionIdEnd - subscriptionIdStart; ++i) { + subscriptions[i] = s_subscriptions[uint64(subscriptionIdStart + i)]; + } + + return subscriptions; + } + + /// @inheritdoc IFunctionsSubscriptions function getConsumer(address client, uint64 subscriptionId) public view override returns (Consumer memory) { return s_consumers[client][subscriptionId]; } - // Used within this file & FunctionsRouter.sol + /// @dev Used within this file & FunctionsRouter.sol function _isExistingSubscription(uint64 subscriptionId) internal view { if (s_subscriptions[subscriptionId].owner == address(0)) { revert InvalidSubscription(); } } - // Used within FunctionsRouter.sol + /// @dev Used within FunctionsRouter.sol function _isAllowedConsumer(address client, uint64 subscriptionId) internal view { if (!s_consumers[client][subscriptionId].allowed) { revert InvalidConsumer(); } } - // @inheritdoc IFunctionsSubscriptions + /// @inheritdoc IFunctionsSubscriptions function createSubscription() external override returns (uint64 subscriptionId) { _whenNotPaused(); _onlySenderThatAcceptedToS(); @@ -303,7 +318,7 @@ abstract contract FunctionsSubscriptions is IFunctionsSubscriptions, IERC677Rece return subscriptionId; } - // @inheritdoc IFunctionsSubscriptions + /// @inheritdoc IFunctionsSubscriptions function createSubscriptionWithConsumer(address consumer) external override returns (uint64 subscriptionId) { _whenNotPaused(); _onlySenderThatAcceptedToS(); @@ -327,7 +342,7 @@ abstract contract FunctionsSubscriptions is IFunctionsSubscriptions, IERC677Rece return subscriptionId; } - // @inheritdoc IFunctionsSubscriptions + /// @inheritdoc IFunctionsSubscriptions function proposeSubscriptionOwnerTransfer(uint64 subscriptionId, address newOwner) external override { _whenNotPaused(); _onlySubscriptionOwner(subscriptionId); @@ -341,7 +356,7 @@ abstract contract FunctionsSubscriptions is IFunctionsSubscriptions, IERC677Rece emit SubscriptionOwnerTransferRequested(subscriptionId, msg.sender, newOwner); } - // @inheritdoc IFunctionsSubscriptions + /// @inheritdoc IFunctionsSubscriptions function acceptSubscriptionOwnerTransfer(uint64 subscriptionId) external override { _whenNotPaused(); _onlySenderThatAcceptedToS(); @@ -356,16 +371,14 @@ abstract contract FunctionsSubscriptions is IFunctionsSubscriptions, IERC677Rece emit SubscriptionOwnerTransferred(subscriptionId, previousOwner, msg.sender); } - // @inheritdoc IFunctionsSubscriptions + /// @inheritdoc IFunctionsSubscriptions function removeConsumer(uint64 subscriptionId, address consumer) external override { _whenNotPaused(); _onlySubscriptionOwner(subscriptionId); _onlySenderThatAcceptedToS(); Consumer memory consumerData = s_consumers[consumer][subscriptionId]; - if (!consumerData.allowed) { - revert InvalidConsumer(); - } + _isAllowedConsumer(consumer, subscriptionId); if (consumerData.initiatedRequests != consumerData.completedRequests) { revert CannotRemoveWithPendingRequests(); } @@ -384,10 +397,10 @@ abstract contract FunctionsSubscriptions is IFunctionsSubscriptions, IERC677Rece emit SubscriptionConsumerRemoved(subscriptionId, consumer); } - // overriden in FunctionsRouter.sol + /// @dev Overriden in FunctionsRouter.sol function _getMaxConsumers() internal view virtual returns (uint16); - // @inheritdoc IFunctionsSubscriptions + /// @inheritdoc IFunctionsSubscriptions function addConsumer(uint64 subscriptionId, address consumer) external override { _whenNotPaused(); _onlySubscriptionOwner(subscriptionId); @@ -395,7 +408,7 @@ abstract contract FunctionsSubscriptions is IFunctionsSubscriptions, IERC677Rece // Already maxed, cannot add any more consumers. uint16 maximumConsumers = _getMaxConsumers(); - if (s_subscriptions[subscriptionId].consumers.length == maximumConsumers) { + if (s_subscriptions[subscriptionId].consumers.length >= maximumConsumers) { revert TooManyConsumers(maximumConsumers); } if (s_consumers[consumer][subscriptionId].allowed) { @@ -410,36 +423,55 @@ abstract contract FunctionsSubscriptions is IFunctionsSubscriptions, IERC677Rece emit SubscriptionConsumerAdded(subscriptionId, consumer); } - // @inheritdoc IFunctionsSubscriptions - function cancelSubscription(uint64 subscriptionId, address to) external override { - _whenNotPaused(); - _onlySubscriptionOwner(subscriptionId); - _onlySenderThatAcceptedToS(); - - if (pendingRequestExists(subscriptionId)) { - revert CannotRemoveWithPendingRequests(); - } + /// @dev Overriden in FunctionsRouter.sol + function _getSubscriptionDepositDetails() internal virtual returns (uint16, uint72); - _cancelSubscriptionHelper(subscriptionId, to); - } - - function _cancelSubscriptionHelper(uint64 subscriptionId, address to) private { + function _cancelSubscriptionHelper(uint64 subscriptionId, address toAddress, bool checkDepositRefundability) private { Subscription memory subscription = s_subscriptions[subscriptionId]; uint96 balance = subscription.balance; + uint64 completedRequests = 0; + // NOTE: loop iterations are bounded by config.maxConsumers // If no consumers, does nothing. for (uint256 i = 0; i < subscription.consumers.length; ++i) { - delete s_consumers[subscription.consumers[i]][subscriptionId]; + address consumer = subscription.consumers[i]; + completedRequests += s_consumers[consumer][subscriptionId].completedRequests; + delete s_consumers[consumer][subscriptionId]; } delete s_subscriptions[subscriptionId]; - s_totalLinkBalance -= balance; - IERC20(i_linkToken).safeTransfer(to, uint256(balance)); + (uint16 subscriptionDepositMinimumRequests, uint72 subscriptionDepositJuels) = _getSubscriptionDepositDetails(); + + // If subscription has not made enough requests, deposit will be forfeited + if (checkDepositRefundability && completedRequests < subscriptionDepositMinimumRequests) { + uint96 deposit = subscriptionDepositJuels > balance ? balance : subscriptionDepositJuels; + if (deposit > 0) { + s_withdrawableTokens[address(this)] += deposit; + balance -= deposit; + } + } + + if (balance > 0) { + s_totalLinkBalance -= balance; + i_linkToken.safeTransfer(toAddress, uint256(balance)); + } + emit SubscriptionCanceled(subscriptionId, toAddress, balance); + } + + /// @inheritdoc IFunctionsSubscriptions + function cancelSubscription(uint64 subscriptionId, address to) external override { + _whenNotPaused(); + _onlySubscriptionOwner(subscriptionId); + _onlySenderThatAcceptedToS(); + + if (pendingRequestExists(subscriptionId)) { + revert CannotRemoveWithPendingRequests(); + } - emit SubscriptionCanceled(subscriptionId, to, balance); + _cancelSubscriptionHelper(subscriptionId, to, true); } - // @inheritdoc IFunctionsSubscriptions + /// @inheritdoc IFunctionsSubscriptions function pendingRequestExists(uint64 subscriptionId) public view override returns (bool) { address[] memory consumers = s_subscriptions[subscriptionId].consumers; // NOTE: loop iterations are bounded by config.maxConsumers @@ -452,14 +484,14 @@ abstract contract FunctionsSubscriptions is IFunctionsSubscriptions, IERC677Rece return false; } - // @inheritdoc IFunctionsSubscriptions + /// @inheritdoc IFunctionsSubscriptions function setFlags(uint64 subscriptionId, bytes32 flags) external override { _onlyRouterOwner(); _isExistingSubscription(subscriptionId); s_subscriptions[subscriptionId].flags = flags; } - // @inheritdoc IFunctionsSubscriptions + /// @inheritdoc IFunctionsSubscriptions function getFlags(uint64 subscriptionId) public view returns (bytes32) { return s_subscriptions[subscriptionId].flags; } @@ -468,7 +500,7 @@ abstract contract FunctionsSubscriptions is IFunctionsSubscriptions, IERC677Rece // | Request Timeout | // ================================================================ - // @inheritdoc IFunctionsSubscriptions + /// @inheritdoc IFunctionsSubscriptions function timeoutRequests(FunctionsResponse.Commitment[] calldata requestsToTimeoutByCommitment) external override { _whenNotPaused(); @@ -513,12 +545,12 @@ abstract contract FunctionsSubscriptions is IFunctionsSubscriptions, IERC677Rece } } - // Overriden in FunctionsRouter.sol + /// @dev Overriden in FunctionsRouter.sol function _onlySenderThatAcceptedToS() internal virtual; - // Overriden in FunctionsRouter.sol + /// @dev Overriden in FunctionsRouter.sol function _onlyRouterOwner() internal virtual; - // Overriden in FunctionsRouter.sol + /// @dev Overriden in FunctionsRouter.sol function _whenNotPaused() internal virtual; } diff --git a/contracts/src/v0.8/functions/dev/1_0_0/Routable.sol b/contracts/src/v0.8/functions/dev/1_0_0/Routable.sol index 8c09eba5d79..b50b1e603f9 100644 --- a/contracts/src/v0.8/functions/dev/1_0_0/Routable.sol +++ b/contracts/src/v0.8/functions/dev/1_0_0/Routable.sol @@ -4,9 +4,9 @@ pragma solidity ^0.8.19; import {ITypeAndVersion} from "../../../shared/interfaces/ITypeAndVersion.sol"; import {IOwnableFunctionsRouter} from "./interfaces/IOwnableFunctionsRouter.sol"; -// @title This abstract should be inherited by contracts that will be used -// as the destinations to a route (id=>contract) on the Router. -// It provides a Router getter and modifiers +/// @title This abstract should be inherited by contracts that will be used +/// as the destinations to a route (id=>contract) on the Router. +/// It provides a Router getter and modifiers. abstract contract Routable is ITypeAndVersion { IOwnableFunctionsRouter private immutable i_router; @@ -14,7 +14,7 @@ abstract contract Routable is ITypeAndVersion { error OnlyCallableByRouter(); error OnlyCallableByRouterOwner(); - // @dev Initializes the contract. + /// @dev Initializes the contract. constructor(address router) { if (router == address(0)) { revert RouterMustBeSet(); @@ -22,12 +22,12 @@ abstract contract Routable is ITypeAndVersion { i_router = IOwnableFunctionsRouter(router); } - // @notice Return the Router + /// @notice Return the Router function _getRouter() internal view returns (IOwnableFunctionsRouter router) { return i_router; } - // @notice Reverts if called by anyone other than the router. + /// @notice Reverts if called by anyone other than the router. modifier onlyRouter() { if (msg.sender != address(i_router)) { revert OnlyCallableByRouter(); @@ -35,7 +35,7 @@ abstract contract Routable is ITypeAndVersion { _; } - // @notice Reverts if called by anyone other than the router owner. + /// @notice Reverts if called by anyone other than the router owner. modifier onlyRouterOwner() { if (msg.sender != i_router.owner()) { revert OnlyCallableByRouterOwner(); diff --git a/contracts/src/v0.8/functions/dev/1_0_0/accessControl/TermsOfServiceAllowList.sol b/contracts/src/v0.8/functions/dev/1_0_0/accessControl/TermsOfServiceAllowList.sol index 2ce107c9861..c4bd524b522 100644 --- a/contracts/src/v0.8/functions/dev/1_0_0/accessControl/TermsOfServiceAllowList.sol +++ b/contracts/src/v0.8/functions/dev/1_0_0/accessControl/TermsOfServiceAllowList.sol @@ -10,12 +10,12 @@ import {ConfirmedOwner} from "../../../../shared/access/ConfirmedOwner.sol"; import {Address} from "../../../../vendor/openzeppelin-solidity/v4.8.0/contracts/utils/Address.sol"; import {EnumerableSet} from "../../../../vendor/openzeppelin-solidity/v4.8.0/contracts/utils/structs/EnumerableSet.sol"; -// @notice A contract to handle access control of subscription management dependent on signing a Terms of Service +/// @notice A contract to handle access control of subscription management dependent on signing a Terms of Service contract TermsOfServiceAllowList is ITermsOfServiceAllowList, IAccessController, ITypeAndVersion, ConfirmedOwner { using Address for address; using EnumerableSet for EnumerableSet.AddressSet; - // @inheritdoc ITypeAndVersion + /// @inheritdoc ITypeAndVersion string public constant override typeAndVersion = "Functions Terms of Service Allow List v1.0.0"; EnumerableSet.AddressSet private s_allowedSenders; @@ -53,14 +53,14 @@ contract TermsOfServiceAllowList is ITermsOfServiceAllowList, IAccessController, // | Configuration | // ================================================================ - // @notice Gets the contracts's configuration - // @return config + /// @notice Gets the contracts's configuration + /// @return config function getConfig() external view returns (Config memory) { return s_config; } - // @notice Sets the contracts's configuration - // @param config - See the contents of the TermsOfServiceAllowList.Config struct for more information + /// @notice Sets the contracts's configuration + /// @param config - See the contents of the TermsOfServiceAllowList.Config struct for more information function updateConfig(Config memory config) public onlyOwner { s_config = config; emit ConfigUpdated(config); @@ -70,12 +70,12 @@ contract TermsOfServiceAllowList is ITermsOfServiceAllowList, IAccessController, // | Allow methods | // ================================================================ - // @inheritdoc ITermsOfServiceAllowList + /// @inheritdoc ITermsOfServiceAllowList function getMessage(address acceptor, address recipient) public pure override returns (bytes32) { return keccak256(abi.encodePacked(acceptor, recipient)); } - // @inheritdoc ITermsOfServiceAllowList + /// @inheritdoc ITermsOfServiceAllowList function acceptTermsOfService(address acceptor, address recipient, bytes32 r, bytes32 s, uint8 v) external override { if (s_blockedSenders[recipient]) { revert RecipientIsBlocked(); @@ -102,12 +102,12 @@ contract TermsOfServiceAllowList is ITermsOfServiceAllowList, IAccessController, emit AddedAccess(recipient); } - // @inheritdoc ITermsOfServiceAllowList + /// @inheritdoc ITermsOfServiceAllowList function getAllAllowedSenders() external view override returns (address[] memory) { return s_allowedSenders.values(); } - // @inheritdoc IAccessController + /// @inheritdoc IAccessController function hasAccess(address user, bytes calldata /* data */) external view override returns (bool) { if (!s_config.enabled) { return true; @@ -119,7 +119,7 @@ contract TermsOfServiceAllowList is ITermsOfServiceAllowList, IAccessController, // | Block methods | // ================================================================ - // @inheritdoc ITermsOfServiceAllowList + /// @inheritdoc ITermsOfServiceAllowList function isBlockedSender(address sender) external view override returns (bool) { if (!s_config.enabled) { return false; @@ -127,14 +127,14 @@ contract TermsOfServiceAllowList is ITermsOfServiceAllowList, IAccessController, return s_blockedSenders[sender]; } - // @inheritdoc ITermsOfServiceAllowList + /// @inheritdoc ITermsOfServiceAllowList function blockSender(address sender) external override onlyOwner { s_allowedSenders.remove(sender); s_blockedSenders[sender] = true; emit BlockedAccess(sender); } - // @inheritdoc ITermsOfServiceAllowList + /// @inheritdoc ITermsOfServiceAllowList function unblockSender(address sender) external override onlyOwner { s_blockedSenders[sender] = false; emit UnblockedAccess(sender); diff --git a/contracts/src/v0.8/functions/dev/1_0_0/accessControl/interfaces/ITermsOfServiceAllowList.sol b/contracts/src/v0.8/functions/dev/1_0_0/accessControl/interfaces/ITermsOfServiceAllowList.sol index b83375ee01f..af4daa18bc3 100644 --- a/contracts/src/v0.8/functions/dev/1_0_0/accessControl/interfaces/ITermsOfServiceAllowList.sol +++ b/contracts/src/v0.8/functions/dev/1_0_0/accessControl/interfaces/ITermsOfServiceAllowList.sol @@ -1,40 +1,40 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.19; -// @notice A contract to handle access control of subscription management dependent on signing a Terms of Service +/// @notice A contract to handle access control of subscription management dependent on signing a Terms of Service interface ITermsOfServiceAllowList { - // @notice Return the message data for the proof given to accept the Terms of Service - // @param acceptor - The wallet address that has accepted the Terms of Service on the UI - // @param recipient - The recipient address that the acceptor is taking responsibility for - // @return Hash of the message data + /// @notice Return the message data for the proof given to accept the Terms of Service + /// @param acceptor - The wallet address that has accepted the Terms of Service on the UI + /// @param recipient - The recipient address that the acceptor is taking responsibility for + /// @return Hash of the message data function getMessage(address acceptor, address recipient) external pure returns (bytes32); - // @notice Check if the address is blocked for usage - // @param sender The transaction sender's address - // @return True or false + /// @notice Check if the address is blocked for usage + /// @param sender The transaction sender's address + /// @return True or false function isBlockedSender(address sender) external returns (bool); - // @notice Get a list of all allowed senders - // @dev WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed - // to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that - // this function has an unbounded cost, and using it as part of a state-changing function may render the function - // uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block. - // @return addresses - all allowed addresses + /// @notice Get a list of all allowed senders + /// @dev WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed + /// to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that + /// this function has an unbounded cost, and using it as part of a state-changing function may render the function + /// uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block. + /// @return addresses - all allowed addresses function getAllAllowedSenders() external view returns (address[] memory); - // @notice Allows access to the sender based on acceptance of the Terms of Service - // @param acceptor - The wallet address that has accepted the Terms of Service on the UI - // @param recipient - The recipient address that the acceptor is taking responsibility for - // @param r - ECDSA signature r data produced by the Chainlink Functions Subscription UI - // @param s - ECDSA signature s produced by the Chainlink Functions Subscription UI - // @param v - ECDSA signature v produced by the Chainlink Functions Subscription UI + /// @notice Allows access to the sender based on acceptance of the Terms of Service + /// @param acceptor - The wallet address that has accepted the Terms of Service on the UI + /// @param recipient - The recipient address that the acceptor is taking responsibility for + /// @param r - ECDSA signature r data produced by the Chainlink Functions Subscription UI + /// @param s - ECDSA signature s produced by the Chainlink Functions Subscription UI + /// @param v - ECDSA signature v produced by the Chainlink Functions Subscription UI function acceptTermsOfService(address acceptor, address recipient, bytes32 r, bytes32 s, uint8 v) external; - // @notice Removes a sender's access if already authorized, and disallows re-accepting the Terms of Service - // @param sender - Address of the sender to block + /// @notice Removes a sender's access if already authorized, and disallows re-accepting the Terms of Service + /// @param sender - Address of the sender to block function blockSender(address sender) external; - // @notice Re-allows a previously blocked sender to accept the Terms of Service - // @param sender - Address of the sender to unblock + /// @notice Re-allows a previously blocked sender to accept the Terms of Service + /// @param sender - Address of the sender to unblock function unblockSender(address sender) external; } diff --git a/contracts/src/v0.8/functions/dev/1_0_0/example/FunctionsClientExample.sol b/contracts/src/v0.8/functions/dev/1_0_0/example/FunctionsClientExample.sol index 5feee704ef5..f0f154c07b2 100644 --- a/contracts/src/v0.8/functions/dev/1_0_0/example/FunctionsClientExample.sol +++ b/contracts/src/v0.8/functions/dev/1_0_0/example/FunctionsClientExample.sol @@ -5,9 +5,7 @@ import {FunctionsClient} from "../FunctionsClient.sol"; import {ConfirmedOwner} from "../../../../shared/access/ConfirmedOwner.sol"; import {FunctionsRequest} from "../libraries/FunctionsRequest.sol"; -/** - * @title Chainlink Functions example Client contract implementation - */ +/// @title Chainlink Functions example Client contract implementation contract FunctionsClientExample is FunctionsClient, ConfirmedOwner { using FunctionsRequest for FunctionsRequest.Request; @@ -23,13 +21,11 @@ contract FunctionsClientExample is FunctionsClient, ConfirmedOwner { constructor(address router) FunctionsClient(router) ConfirmedOwner(msg.sender) {} - /** - * @notice Send a simple request - * @param source JavaScript source code - * @param encryptedSecretsReferences Encrypted secrets payload - * @param args List of arguments accessible from within the source code - * @param subscriptionId Billing ID - */ + /// @notice Send a simple request + /// @param source JavaScript source code + /// @param encryptedSecretsReferences Encrypted secrets payload + /// @param args List of arguments accessible from within the source code + /// @param subscriptionId Billing ID function sendRequest( string calldata source, bytes calldata encryptedSecretsReferences, @@ -44,13 +40,11 @@ contract FunctionsClientExample is FunctionsClient, ConfirmedOwner { s_lastRequestId = _sendRequest(req.encodeCBOR(), subscriptionId, MAX_CALLBACK_GAS, jobId); } - /** - * @notice Store latest result/error - * @param requestId The request ID, returned by sendRequest() - * @param response Aggregated response from the user code - * @param err Aggregated error from the user code or from the execution pipeline - * Either response or error parameter will be set, but never both - */ + /// @notice Store latest result/error + /// @param requestId The request ID, returned by sendRequest() + /// @param response Aggregated response from the user code + /// @param err Aggregated error from the user code or from the execution pipeline + /// @dev Either response or error parameter will be set, but never both function fulfillRequest(bytes32 requestId, bytes memory response, bytes memory err) internal override { if (s_lastRequestId != requestId) { revert UnexpectedRequestID(requestId); diff --git a/contracts/src/v0.8/functions/dev/1_0_0/interfaces/IFunctionsBilling.sol b/contracts/src/v0.8/functions/dev/1_0_0/interfaces/IFunctionsBilling.sol index 00ff17ee14d..6291d05e57c 100644 --- a/contracts/src/v0.8/functions/dev/1_0_0/interfaces/IFunctionsBilling.sol +++ b/contracts/src/v0.8/functions/dev/1_0_0/interfaces/IFunctionsBilling.sol @@ -1,44 +1,44 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.19; -// @title Chainlink Functions DON billing interface. +/// @title Chainlink Functions DON billing interface. interface IFunctionsBilling { - // @notice Return the current conversion from WEI of ETH to LINK from the configured Chainlink data feed - // @return weiPerUnitLink - The amount of WEI in one LINK + /// @notice Return the current conversion from WEI of ETH to LINK from the configured Chainlink data feed + /// @return weiPerUnitLink - The amount of WEI in one LINK function getWeiPerUnitLink() external view returns (uint256); - // @notice Determine the fee that will be split between Node Operators for servicing a request - // @param requestCBOR - CBOR encoded Chainlink Functions request data, use FunctionsRequest library to encode a request - // @return fee - Cost in Juels (1e18) of LINK + /// @notice Determine the fee that will be split between Node Operators for servicing a request + /// @param requestCBOR - CBOR encoded Chainlink Functions request data, use FunctionsRequest library to encode a request + /// @return fee - Cost in Juels (1e18) of LINK function getDONFee(bytes memory requestCBOR) external view returns (uint72); - // @notice Determine the fee that will be paid to the Router owner for operating the network - // @return fee - Cost in Juels (1e18) of LINK + /// @notice Determine the fee that will be paid to the Router owner for operating the network + /// @return fee - Cost in Juels (1e18) of LINK function getAdminFee() external view returns (uint72); - // @notice Estimate the total cost that will be charged to a subscription to make a request: transmitter gas re-reimbursement, plus DON fee, plus Registry fee - // @param - subscriptionId An identifier of the billing account - // @param - data Encoded Chainlink Functions request data, use FunctionsClient API to encode a request - // @param - callbackGasLimit Gas limit for the fulfillment callback - // @param - gasPriceGwei The blockchain's gas price to estimate with - // @return - billedCost Cost in Juels (1e18) of LINK + /// @notice Estimate the total cost that will be charged to a subscription to make a request: transmitter gas re-reimbursement, plus DON fee, plus Registry fee + /// @param - subscriptionId An identifier of the billing account + /// @param - data Encoded Chainlink Functions request data, use FunctionsClient API to encode a request + /// @param - callbackGasLimit Gas limit for the fulfillment callback + /// @param - gasPriceWei The blockchain's gas price to estimate with + /// @return - billedCost Cost in Juels (1e18) of LINK function estimateCost( uint64 subscriptionId, bytes calldata data, uint32 callbackGasLimit, - uint256 gasPriceGwei + uint256 gasPriceWei ) external view returns (uint96); - // @notice Remove a request commitment that the Router has determined to be stale - // @param requestId - The request ID to remove - function deleteCommitment(bytes32 requestId) external returns (bool); + /// @notice Remove a request commitment that the Router has determined to be stale + /// @param requestId - The request ID to remove + function deleteCommitment(bytes32 requestId) external; - // @notice Oracle withdraw LINK earned through fulfilling requests - // @notice If amount is 0 the full balance will be withdrawn - // @param recipient where to send the funds - // @param amount amount to withdraw + /// @notice Oracle withdraw LINK earned through fulfilling requests + /// @notice If amount is 0 the full balance will be withdrawn + /// @param recipient where to send the funds + /// @param amount amount to withdraw function oracleWithdraw(address recipient, uint96 amount) external; - // @notice Withdraw all LINK earned by Oracles through fulfilling requests + /// @notice Withdraw all LINK earned by Oracles through fulfilling requests function oracleWithdrawAll() external; } diff --git a/contracts/src/v0.8/functions/dev/1_0_0/interfaces/IFunctionsClient.sol b/contracts/src/v0.8/functions/dev/1_0_0/interfaces/IFunctionsClient.sol index 5fbee58274e..f28a41666b5 100644 --- a/contracts/src/v0.8/functions/dev/1_0_0/interfaces/IFunctionsClient.sol +++ b/contracts/src/v0.8/functions/dev/1_0_0/interfaces/IFunctionsClient.sol @@ -1,13 +1,13 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.19; -// @title Chainlink Functions client interface. +/// @title Chainlink Functions client interface. interface IFunctionsClient { - // @notice Chainlink Functions response handler called by the Functions Router - // during fullilment from the designated transmitter node in an OCR round. - // @param requestId The requestId returned by FunctionsClient.sendRequest(). - // @param response Aggregated response from the request's source code. - // @param err Aggregated error either from the request's source code or from the execution pipeline. - // @dev Either response or error parameter will be set, but never both. + /// @notice Chainlink Functions response handler called by the Functions Router + /// during fullilment from the designated transmitter node in an OCR round. + /// @param requestId The requestId returned by FunctionsClient.sendRequest(). + /// @param response Aggregated response from the request's source code. + /// @param err Aggregated error either from the request's source code or from the execution pipeline. + /// @dev Either response or error parameter will be set, but never both. function handleOracleFulfillment(bytes32 requestId, bytes memory response, bytes memory err) external; } diff --git a/contracts/src/v0.8/functions/dev/1_0_0/interfaces/IFunctionsCoordinator.sol b/contracts/src/v0.8/functions/dev/1_0_0/interfaces/IFunctionsCoordinator.sol index 5a0d07415bd..4e2bd703dc4 100644 --- a/contracts/src/v0.8/functions/dev/1_0_0/interfaces/IFunctionsCoordinator.sol +++ b/contracts/src/v0.8/functions/dev/1_0_0/interfaces/IFunctionsCoordinator.sol @@ -3,34 +3,34 @@ pragma solidity ^0.8.19; import {FunctionsResponse} from "../libraries/FunctionsResponse.sol"; -// @title Chainlink Functions DON Coordinator interface. +/// @title Chainlink Functions DON Coordinator interface. interface IFunctionsCoordinator { - // @notice Returns the DON's threshold encryption public key used to encrypt secrets - // @dev All nodes on the DON have separate key shares of the threshold decryption key - // and nodes must participate in a threshold decryption OCR round to decrypt secrets - // @return thresholdPublicKey the DON's threshold encryption public key + /// @notice Returns the DON's threshold encryption public key used to encrypt secrets + /// @dev All nodes on the DON have separate key shares of the threshold decryption key + /// and nodes must participate in a threshold decryption OCR round to decrypt secrets + /// @return thresholdPublicKey the DON's threshold encryption public key function getThresholdPublicKey() external view returns (bytes memory); - // @notice Sets the DON's threshold encryption public key used to encrypt secrets - // @dev Used to rotate the key - // @param thresholdPublicKey The new public key + /// @notice Sets the DON's threshold encryption public key used to encrypt secrets + /// @dev Used to rotate the key + /// @param thresholdPublicKey The new public key function setThresholdPublicKey(bytes calldata thresholdPublicKey) external; - // @notice Returns the DON's secp256k1 public key that is used to encrypt secrets - // @dev All nodes on the DON have the corresponding private key - // needed to decrypt the secrets encrypted with the public key - // @return publicKey the DON's public key + /// @notice Returns the DON's secp256k1 public key that is used to encrypt secrets + /// @dev All nodes on the DON have the corresponding private key + /// needed to decrypt the secrets encrypted with the public key + /// @return publicKey the DON's public key function getDONPublicKey() external view returns (bytes memory); - // @notice Sets DON's secp256k1 public key used to encrypt secrets - // @dev Used to rotate the key - // @param donPublicKey The new public key + /// @notice Sets DON's secp256k1 public key used to encrypt secrets + /// @dev Used to rotate the key + /// @param donPublicKey The new public key function setDONPublicKey(bytes calldata donPublicKey) external; - // @notice Receives a request to be emitted to the DON for processing - // @param request The request metadata - // @dev see the struct for field descriptions - // @return commitment - The parameters of the request that must be held consistent at response time + /// @notice Receives a request to be emitted to the DON for processing + /// @param request The request metadata + /// @dev see the struct for field descriptions + /// @return commitment - The parameters of the request that must be held consistent at response time function startRequest( FunctionsResponse.RequestMeta calldata request ) external returns (FunctionsResponse.Commitment memory commitment); diff --git a/contracts/src/v0.8/functions/dev/1_0_0/interfaces/IFunctionsRouter.sol b/contracts/src/v0.8/functions/dev/1_0_0/interfaces/IFunctionsRouter.sol index ebc1dbd4538..5f93aac873e 100644 --- a/contracts/src/v0.8/functions/dev/1_0_0/interfaces/IFunctionsRouter.sol +++ b/contracts/src/v0.8/functions/dev/1_0_0/interfaces/IFunctionsRouter.sol @@ -3,29 +3,29 @@ pragma solidity ^0.8.19; import {FunctionsResponse} from "../libraries/FunctionsResponse.sol"; -// @title Chainlink Functions Router interface. +/// @title Chainlink Functions Router interface. interface IFunctionsRouter { - // @notice The identifier of the route to retrieve the address of the access control contract - // The access control contract controls which accounts can manage subscriptions - // @return id - bytes32 id that can be passed to the "getContractById" of the Router + /// @notice The identifier of the route to retrieve the address of the access control contract + /// The access control contract controls which accounts can manage subscriptions + /// @return id - bytes32 id that can be passed to the "getContractById" of the Router function getAllowListId() external view returns (bytes32); - // @notice Set the identifier of the route to retrieve the address of the access control contract - // The access control contract controls which accounts can manage subscriptions + /// @notice Set the identifier of the route to retrieve the address of the access control contract + /// The access control contract controls which accounts can manage subscriptions function setAllowListId(bytes32 allowListId) external; - // @notice Get the flat fee (in Juels of LINK) that will be paid to the Router owner for operation of the network - // @return adminFee + /// @notice Get the flat fee (in Juels of LINK) that will be paid to the Router owner for operation of the network + /// @return adminFee function getAdminFee() external view returns (uint72 adminFee); - // @notice Sends a request using the provided subscriptionId - // @param subscriptionId - A unique subscription ID allocated by billing system, - // a client can make requests from different contracts referencing the same subscription - // @param data - CBOR encoded Chainlink Functions request data, use FunctionsClient API to encode a request - // @param dataVersion - Gas limit for the fulfillment callback - // @param callbackGasLimit - Gas limit for the fulfillment callback - // @param donId - An identifier used to determine which route to send the request along - // @return requestId - A unique request identifier + /// @notice Sends a request using the provided subscriptionId + /// @param subscriptionId - A unique subscription ID allocated by billing system, + /// a client can make requests from different contracts referencing the same subscription + /// @param data - CBOR encoded Chainlink Functions request data, use FunctionsClient API to encode a request + /// @param dataVersion - Gas limit for the fulfillment callback + /// @param callbackGasLimit - Gas limit for the fulfillment callback + /// @param donId - An identifier used to determine which route to send the request along + /// @return requestId - A unique request identifier function sendRequest( uint64 subscriptionId, bytes calldata data, @@ -34,14 +34,14 @@ interface IFunctionsRouter { bytes32 donId ) external returns (bytes32); - // @notice Sends a request to the proposed contracts - // @param subscriptionId - A unique subscription ID allocated by billing system, - // a client can make requests from different contracts referencing the same subscription - // @param data - CBOR encoded Chainlink Functions request data, use FunctionsClient API to encode a request - // @param dataVersion - Gas limit for the fulfillment callback - // @param callbackGasLimit - Gas limit for the fulfillment callback - // @param donId - An identifier used to determine which route to send the request along - // @return requestId - A unique request identifier + /// @notice Sends a request to the proposed contracts + /// @param subscriptionId - A unique subscription ID allocated by billing system, + /// a client can make requests from different contracts referencing the same subscription + /// @param data - CBOR encoded Chainlink Functions request data, use FunctionsClient API to encode a request + /// @param dataVersion - Gas limit for the fulfillment callback + /// @param callbackGasLimit - Gas limit for the fulfillment callback + /// @param donId - An identifier used to determine which route to send the request along + /// @return requestId - A unique request identifier function sendRequestToProposed( uint64 subscriptionId, bytes calldata data, @@ -50,18 +50,18 @@ interface IFunctionsRouter { bytes32 donId ) external returns (bytes32); - // @notice Fulfill the request by: - // - calling back the data that the Oracle returned to the client contract - // - pay the DON for processing the request - // @dev Only callable by the Coordinator contract that is saved in the commitment - // @param response response data from DON consensus - // @param err error from DON consensus - // @param juelsPerGas - current rate of juels/gas - // @param costWithoutFulfillment - The cost of processing the request (in Juels of LINK ), without fulfillment - // @param transmitter - The Node that transmitted the OCR report - // @param commitment - The parameters of the request that must be held consistent between request and response time - // @return fulfillResult - - // @return callbackGasCostJuels - + /// @notice Fulfill the request by: + /// - calling back the data that the Oracle returned to the client contract + /// - pay the DON for processing the request + /// @dev Only callable by the Coordinator contract that is saved in the commitment + /// @param response response data from DON consensus + /// @param err error from DON consensus + /// @param juelsPerGas - current rate of juels/gas + /// @param costWithoutFulfillment - The cost of processing the request (in Juels of LINK ), without fulfillment + /// @param transmitter - The Node that transmitted the OCR report + /// @param commitment - The parameters of the request that must be held consistent between request and response time + /// @return fulfillResult - + /// @return callbackGasCostJuels - function fulfill( bytes memory response, bytes memory err, @@ -71,39 +71,39 @@ interface IFunctionsRouter { FunctionsResponse.Commitment memory commitment ) external returns (FunctionsResponse.FulfillResult, uint96); - // @notice Validate requested gas limit is below the subscription max. - // @param subscriptionId subscription ID - // @param callbackGasLimit desired callback gas limit + /// @notice Validate requested gas limit is below the subscription max. + /// @param subscriptionId subscription ID + /// @param callbackGasLimit desired callback gas limit function isValidCallbackGasLimit(uint64 subscriptionId, uint32 callbackGasLimit) external view; - // @notice Get the current contract given an ID - // @param id A bytes32 identifier for the route - // @return contract The current contract address + /// @notice Get the current contract given an ID + /// @param id A bytes32 identifier for the route + /// @return contract The current contract address function getContractById(bytes32 id) external view returns (address); - // @notice Get the proposed next contract given an ID - // @param id A bytes32 identifier for the route - // @return contract The current or proposed contract address + /// @notice Get the proposed next contract given an ID + /// @param id A bytes32 identifier for the route + /// @return contract The current or proposed contract address function getProposedContractById(bytes32 id) external view returns (address); - // @notice Return the latest proprosal set - // @return ids The identifiers of the contracts to update - // @return to The addresses of the contracts that will be updated to + /// @notice Return the latest proprosal set + /// @return ids The identifiers of the contracts to update + /// @return to The addresses of the contracts that will be updated to function getProposedContractSet() external view returns (bytes32[] memory, address[] memory); - // @notice Proposes one or more updates to the contract routes - // @dev Only callable by owner + /// @notice Proposes one or more updates to the contract routes + /// @dev Only callable by owner function proposeContractsUpdate(bytes32[] memory proposalSetIds, address[] memory proposalSetAddresses) external; - // @notice Updates the current contract routes to the proposed contracts - // @dev Only callable by owner + /// @notice Updates the current contract routes to the proposed contracts + /// @dev Only callable by owner function updateContracts() external; - // @dev Puts the system into an emergency stopped state. - // @dev Only callable by owner + /// @dev Puts the system into an emergency stopped state. + /// @dev Only callable by owner function pause() external; - // @dev Takes the system out of an emergency stopped state. - // @dev Only callable by owner + /// @dev Takes the system out of an emergency stopped state. + /// @dev Only callable by owner function unpause() external; } diff --git a/contracts/src/v0.8/functions/dev/1_0_0/interfaces/IFunctionsSubscriptions.sol b/contracts/src/v0.8/functions/dev/1_0_0/interfaces/IFunctionsSubscriptions.sol index 4072307edb8..eafd6f4fe99 100644 --- a/contracts/src/v0.8/functions/dev/1_0_0/interfaces/IFunctionsSubscriptions.sol +++ b/contracts/src/v0.8/functions/dev/1_0_0/interfaces/IFunctionsSubscriptions.sol @@ -3,7 +3,7 @@ pragma solidity ^0.8.19; import {FunctionsResponse} from "../libraries/FunctionsResponse.sol"; -// @title Chainlink Functions Subscription interface. +/// @title Chainlink Functions Subscription interface. interface IFunctionsSubscriptions { struct Subscription { uint96 balance; // ═════════╗ Common LINK balance that is controlled by the Router to be used for all consumer requests. @@ -20,114 +20,121 @@ interface IFunctionsSubscriptions { uint64 completedRequests; // ══╝ The number of requests that have successfully completed or timed out } - // @notice Get details about a subscription. - // @param subscriptionId - the ID of the subscription - // @return subscription - see IFunctionsSubscriptions.Subscription for more information on the structure + /// @notice Get details about a subscription. + /// @param subscriptionId - the ID of the subscription + /// @return subscription - see IFunctionsSubscriptions.Subscription for more information on the structure function getSubscription(uint64 subscriptionId) external view returns (Subscription memory); - // @notice Get details about a consumer of a subscription. - // @param client - the consumer contract address - // @param subscriptionId - the ID of the subscription - // @return consumer - see IFunctionsSubscriptions.Consumer for more information on the structure + /// @notice Retrieve details about multiple subscriptions using an inclusive range + /// @param subscriptionIdStart - the ID of the subscription to start the range at + /// @param subscriptionIdEnd - the ID of the subscription to end the range at + /// @return subscriptions - see IFunctionsSubscriptions.Subscription for more information on the structure + function getSubscriptionsInRange( + uint64 subscriptionIdStart, + uint64 subscriptionIdEnd + ) external view returns (Subscription[] memory); + + /// @notice Get details about a consumer of a subscription. + /// @param client - the consumer contract address + /// @param subscriptionId - the ID of the subscription + /// @return consumer - see IFunctionsSubscriptions.Consumer for more information on the structure function getConsumer(address client, uint64 subscriptionId) external view returns (Consumer memory); - // @notice Get details about the total amount of LINK within the system - // @return totalBalance - total Juels of LINK held by the contract + /// @notice Get details about the total amount of LINK within the system + /// @return totalBalance - total Juels of LINK held by the contract function getTotalBalance() external view returns (uint96); - // @notice Get details about the total number of subscription accounts - // @return count - total number of subscriptions in the system + /// @notice Get details about the total number of subscription accounts + /// @return count - total number of subscriptions in the system function getSubscriptionCount() external view returns (uint64); - // @notice Time out all expired requests: unlocks funds and removes the ability for the request to be fulfilled - // @param requestsToTimeoutByCommitment - A list of request commitments to time out - // @dev The commitment can be found on the "OracleRequest" event created when sending the request. + /// @notice Time out all expired requests: unlocks funds and removes the ability for the request to be fulfilled + /// @param requestsToTimeoutByCommitment - A list of request commitments to time out + /// @dev The commitment can be found on the "OracleRequest" event created when sending the request. function timeoutRequests(FunctionsResponse.Commitment[] calldata requestsToTimeoutByCommitment) external; - // @notice Oracle withdraw LINK earned through fulfilling requests - // @notice If amount is 0 the full balance will be withdrawn - // @notice Both signing and transmitting wallets will have a balance to withdraw - // @param recipient where to send the funds - // @param amount amount to withdraw + /// @notice Oracle withdraw LINK earned through fulfilling requests + /// @notice If amount is 0 the full balance will be withdrawn + /// @notice Both signing and transmitting wallets will have a balance to withdraw + /// @param recipient where to send the funds + /// @param amount amount to withdraw function oracleWithdraw(address recipient, uint96 amount) external; - // @notice Owner cancel subscription, sends remaining link directly to the subscription owner. - // @dev Only callable by the Router Owner - // @param subscriptionId subscription id - // @dev notably can be called even if there are pending requests, outstanding ones may fail onchain + /// @notice Owner cancel subscription, sends remaining link directly to the subscription owner. + /// @dev Only callable by the Router Owner + /// @param subscriptionId subscription id + /// @dev notably can be called even if there are pending requests, outstanding ones may fail onchain function ownerCancelSubscription(uint64 subscriptionId) external; - // @notice Recover link sent with transfer instead of transferAndCall. - // @dev Only callable by the Router Owner - // @param to address to send link to + /// @notice Recover link sent with transfer instead of transferAndCall. + /// @dev Only callable by the Router Owner + /// @param to address to send link to function recoverFunds(address to) external; - // @notice Create a new subscription. - // @return subscriptionId - A unique subscription id. - // @dev You can manage the consumer set dynamically with addConsumer/removeConsumer. - // @dev Note to fund the subscription, use transferAndCall. For example - // @dev LINKTOKEN.transferAndCall( - // @dev address(ROUTER), - // @dev amount, - // @dev abi.encode(subscriptionId)); + /// @notice Create a new subscription. + /// @return subscriptionId - A unique subscription id. + /// @dev You can manage the consumer set dynamically with addConsumer/removeConsumer. + /// @dev Note to fund the subscription, use transferAndCall. For example + /// @dev LINKTOKEN.transferAndCall( + /// @dev address(ROUTER), + /// @dev amount, + /// @dev abi.encode(subscriptionId)); function createSubscription() external returns (uint64); - // @notice Create a new subscription and add a consumer. - // @return subscriptionId - A unique subscription id. - // @dev You can manage the consumer set dynamically with addConsumer/removeConsumer. - // @dev Note to fund the subscription, use transferAndCall. For example - // @dev LINKTOKEN.transferAndCall( - // @dev address(ROUTER), - // @dev amount, - // @dev abi.encode(subscriptionId)); + /// @notice Create a new subscription and add a consumer. + /// @return subscriptionId - A unique subscription id. + /// @dev You can manage the consumer set dynamically with addConsumer/removeConsumer. + /// @dev Note to fund the subscription, use transferAndCall. For example + /// @dev LINKTOKEN.transferAndCall( + /// @dev address(ROUTER), + /// @dev amount, + /// @dev abi.encode(subscriptionId)); function createSubscriptionWithConsumer(address consumer) external returns (uint64 subscriptionId); - // @notice Propose a new owner for a subscription. - // @dev Only callable by the Subscription's owner - // @param subscriptionId - ID of the subscription - // @param newOwner - proposed new owner of the subscription + /// @notice Propose a new owner for a subscription. + /// @dev Only callable by the Subscription's owner + /// @param subscriptionId - ID of the subscription + /// @param newOwner - proposed new owner of the subscription function proposeSubscriptionOwnerTransfer(uint64 subscriptionId, address newOwner) external; - // @notice Accept an ownership transfer. - // @param subscriptionId - ID of the subscription - // @dev will revert if original owner of subscriptionId has - // not requested that msg.sender become the new owner. + /// @notice Accept an ownership transfer. + /// @param subscriptionId - ID of the subscription + /// @dev will revert if original owner of subscriptionId has not requested that msg.sender become the new owner. function acceptSubscriptionOwnerTransfer(uint64 subscriptionId) external; - // @notice Remove a consumer from a Chainlink Functions subscription. - // @dev Only callable by the Subscription's owner - // @param subscriptionId - ID of the subscription - // @param consumer - Consumer to remove from the subscription + /// @notice Remove a consumer from a Chainlink Functions subscription. + /// @dev Only callable by the Subscription's owner + /// @param subscriptionId - ID of the subscription + /// @param consumer - Consumer to remove from the subscription function removeConsumer(uint64 subscriptionId, address consumer) external; - // @notice Add a consumer to a Chainlink Functions subscription. - // @dev Only callable by the Subscription's owner - // @param subscriptionId - ID of the subscription - // @param consumer - New consumer which can use the subscription + /// @notice Add a consumer to a Chainlink Functions subscription. + /// @dev Only callable by the Subscription's owner + /// @param subscriptionId - ID of the subscription + /// @param consumer - New consumer which can use the subscription function addConsumer(uint64 subscriptionId, address consumer) external; - // @notice Cancel a subscription - // @dev Only callable by the Subscription's owner - // @param subscriptionId - ID of the subscription - // @param to - Where to send the remaining LINK to + /// @notice Cancel a subscription + /// @dev Only callable by the Subscription's owner + /// @param subscriptionId - ID of the subscription + /// @param to - Where to send the remaining LINK to function cancelSubscription(uint64 subscriptionId, address to) external; - // @notice Check to see if there exists a request commitment for all consumers for a given sub. - // @param subscriptionId - ID of the subscription - // @return true if there exists at least one unfulfilled request for the subscription, false - // otherwise. - // @dev Looping is bounded to MAX_CONSUMERS*(number of DONs). - // @dev Used to disable subscription canceling while outstanding request are present. + /// @notice Check to see if there exists a request commitment for all consumers for a given sub. + /// @param subscriptionId - ID of the subscription + /// @return true if there exists at least one unfulfilled request for the subscription, false otherwise. + /// @dev Looping is bounded to MAX_CONSUMERS*(number of DONs). + /// @dev Used to disable subscription canceling while outstanding request are present. function pendingRequestExists(uint64 subscriptionId) external view returns (bool); - // @notice Set subscription specific flags for a subscription. - // Each byte of the flag is used to represent a resource tier that the subscription can utilize. - // @param subscriptionId - ID of the subscription - // @param flags - desired flag values + /// @notice Set subscription specific flags for a subscription. + /// Each byte of the flag is used to represent a resource tier that the subscription can utilize. + /// @param subscriptionId - ID of the subscription + /// @param flags - desired flag values function setFlags(uint64 subscriptionId, bytes32 flags) external; - // @notice Get flags for a given subscription. - // @param subscriptionId - ID of the subscription - // @return flags - current flag values + /// @notice Get flags for a given subscription. + /// @param subscriptionId - ID of the subscription + /// @return flags - current flag values function getFlags(uint64 subscriptionId) external view returns (bytes32); } diff --git a/contracts/src/v0.8/functions/dev/1_0_0/interfaces/IOwnableFunctionsRouter.sol b/contracts/src/v0.8/functions/dev/1_0_0/interfaces/IOwnableFunctionsRouter.sol index 5a2f85fd32e..39b84a930aa 100644 --- a/contracts/src/v0.8/functions/dev/1_0_0/interfaces/IOwnableFunctionsRouter.sol +++ b/contracts/src/v0.8/functions/dev/1_0_0/interfaces/IOwnableFunctionsRouter.sol @@ -4,7 +4,7 @@ pragma solidity ^0.8.19; import {IFunctionsRouter} from "./IFunctionsRouter.sol"; import {IOwnable} from "../../../../shared/interfaces/IOwnable.sol"; -// @title Chainlink Functions Router interface with Ownability. +/// @title Chainlink Functions Router interface with Ownability. interface IOwnableFunctionsRouter is IOwnable, IFunctionsRouter { } diff --git a/contracts/src/v0.8/functions/dev/1_0_0/libraries/FunctionsRequest.sol b/contracts/src/v0.8/functions/dev/1_0_0/libraries/FunctionsRequest.sol index 0a669588ed0..efc3a811e6a 100644 --- a/contracts/src/v0.8/functions/dev/1_0_0/libraries/FunctionsRequest.sol +++ b/contracts/src/v0.8/functions/dev/1_0_0/libraries/FunctionsRequest.sol @@ -3,7 +3,7 @@ pragma solidity ^0.8.19; import {CBOR} from "../../../../vendor/solidity-cborutils/v2.0.0/CBOR.sol"; -// @title Library for encoding the input data of a Functions request into CBOR +/// @title Library for encoding the input data of a Functions request into CBOR library FunctionsRequest { using CBOR for CBOR.CBORBuffer; @@ -27,7 +27,6 @@ library FunctionsRequest { CodeLanguage language; // ════════════╸ The coding language that the source code is written in string source; // ════════════════════╸ Raw source code for Request.codeLocation of Location.Inline, URL for Request.codeLocation of Location.Remote, or slot decimal number for Request.codeLocation of Location.DONHosted bytes encryptedSecretsReference; // ══╸ Encrypted URLs for Request.secretsLocation of Location.Remote (use addSecretsReference()), or CBOR encoded slotid+version for Request.secretsLocation of Location.DONHosted (use addDONHostedSecrets()) - bytes requestSignature; // ═══════════╸ Signature generated by the subscription owner's EOA string[] args; // ════════════════════╸ String arguments that will be passed into the source code bytes[] bytesArgs; // ════════════════╸ Bytes arguments that will be passed into the source code } @@ -37,9 +36,9 @@ library FunctionsRequest { error EmptyArgs(); error NoInlineSecrets(); - // @notice Encodes a Request to CBOR encoded bytes - // @param self The request to encode - // @return CBOR encoded bytes + /// @notice Encodes a Request to CBOR encoded bytes + /// @param self The request to encode + /// @return CBOR encoded bytes function encodeCBOR(Request memory self) internal pure returns (bytes memory) { CBOR.CBORBuffer memory buffer = CBOR.create(DEFAULT_BUFFER_SIZE); @@ -52,11 +51,6 @@ library FunctionsRequest { buffer.writeString("source"); buffer.writeString(self.source); - if (self.requestSignature.length > 0) { - buffer.writeString("requestSignature"); - buffer.writeBytes(self.requestSignature); - } - if (self.args.length > 0) { buffer.writeString("args"); buffer.startArray(); @@ -88,12 +82,12 @@ library FunctionsRequest { return buffer.buf.buf; } - // @notice Initializes a Chainlink Functions Request - // @dev Sets the codeLocation and code on the request - // @param self The uninitialized request - // @param codeLocation The user provided source code location - // @param language The programming language of the user code - // @param source The user provided source code or a url + /// @notice Initializes a Chainlink Functions Request + /// @dev Sets the codeLocation and code on the request + /// @param self The uninitialized request + /// @param codeLocation The user provided source code location + /// @param language The programming language of the user code + /// @param source The user provided source code or a url function initializeRequest( Request memory self, Location codeLocation, @@ -107,17 +101,17 @@ library FunctionsRequest { self.source = source; } - // @notice Initializes a Chainlink Functions Request - // @dev Simplified version of initializeRequest for PoC - // @param self The uninitialized request - // @param javaScriptSource The user provided JS code (must not be empty) + /// @notice Initializes a Chainlink Functions Request + /// @dev Simplified version of initializeRequest for PoC + /// @param self The uninitialized request + /// @param javaScriptSource The user provided JS code (must not be empty) function initializeRequestForInlineJavaScript(Request memory self, string memory javaScriptSource) internal pure { initializeRequest(self, Location.Inline, CodeLanguage.JavaScript, javaScriptSource); } - // @notice Adds Remote user encrypted secrets to a Request - // @param self The initialized request - // @param encryptedSecretsReference Encrypted comma-separated string of URLs pointing to off-chain secrets + /// @notice Adds Remote user encrypted secrets to a Request + /// @param self The initialized request + /// @param encryptedSecretsReference Encrypted comma-separated string of URLs pointing to off-chain secrets function addSecretsReference(Request memory self, bytes memory encryptedSecretsReference) internal pure { if (encryptedSecretsReference.length == 0) revert EmptySecrets(); @@ -125,10 +119,10 @@ library FunctionsRequest { self.encryptedSecretsReference = encryptedSecretsReference; } - // @notice Adds DON-hosted secrets reference to a Request - // @param self The initialized request - // @param slotID Slot ID of the user's secrets hosted on DON - // @param version User data version (for the slotID) + /// @notice Adds DON-hosted secrets reference to a Request + /// @param self The initialized request + /// @param slotID Slot ID of the user's secrets hosted on DON + /// @param version User data version (for the slotID) function addDONHostedSecrets(Request memory self, uint8 slotID, uint64 version) internal pure { CBOR.CBORBuffer memory buffer = CBOR.create(DEFAULT_BUFFER_SIZE); @@ -141,18 +135,18 @@ library FunctionsRequest { self.encryptedSecretsReference = buffer.buf.buf; } - // @notice Sets args for the user run function - // @param self The initialized request - // @param args The array of string args (must not be empty) + /// @notice Sets args for the user run function + /// @param self The initialized request + /// @param args The array of string args (must not be empty) function setArgs(Request memory self, string[] memory args) internal pure { if (args.length == 0) revert EmptyArgs(); self.args = args; } - // @notice Sets bytes args for the user run function - // @param self The initialized request - // @param args The array of bytes args (must not be empty) + /// @notice Sets bytes args for the user run function + /// @param self The initialized request + /// @param args The array of bytes args (must not be empty) function setBytesArgs(Request memory self, bytes[] memory args) internal pure { if (args.length == 0) revert EmptyArgs(); diff --git a/contracts/src/v0.8/functions/dev/1_0_0/libraries/FunctionsResponse.sol b/contracts/src/v0.8/functions/dev/1_0_0/libraries/FunctionsResponse.sol index 71e731b2e33..31a33169226 100644 --- a/contracts/src/v0.8/functions/dev/1_0_0/libraries/FunctionsResponse.sol +++ b/contracts/src/v0.8/functions/dev/1_0_0/libraries/FunctionsResponse.sol @@ -3,7 +3,7 @@ pragma solidity ^0.8.19; import {IFunctionsSubscriptions} from "../interfaces/IFunctionsSubscriptions.sol"; -// @title Library of types that are used for fulfillment of a Functions request +/// @title Library of types that are used for fulfillment of a Functions request library FunctionsResponse { // Used to send request information from the Router to the Coordinator struct RequestMeta { diff --git a/contracts/src/v0.8/functions/tests/1_0_0/BaseTest.t.sol b/contracts/src/v0.8/functions/tests/1_0_0/BaseTest.t.sol index 13994f88f71..d01e438a92a 100644 --- a/contracts/src/v0.8/functions/tests/1_0_0/BaseTest.t.sol +++ b/contracts/src/v0.8/functions/tests/1_0_0/BaseTest.t.sol @@ -16,6 +16,6 @@ contract BaseTest is Test { if (s_baseTestInitialized) return; s_baseTestInitialized = true; // Set msg.sender to OWNER until stopPrank is called - vm.startPrank(OWNER_ADDRESS); + vm.startPrank(OWNER_ADDRESS, OWNER_ADDRESS); } } diff --git a/contracts/src/v0.8/functions/tests/1_0_0/FunctionsCoordinator.t.sol b/contracts/src/v0.8/functions/tests/1_0_0/FunctionsCoordinator.t.sol index c6d560fffc6..cf3a86cce41 100644 --- a/contracts/src/v0.8/functions/tests/1_0_0/FunctionsCoordinator.t.sol +++ b/contracts/src/v0.8/functions/tests/1_0_0/FunctionsCoordinator.t.sol @@ -1,6 +1,12 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.19; +import {FunctionsCoordinator} from "../../dev/1_0_0/FunctionsCoordinator.sol"; +import {FunctionsBilling} from "../../dev/1_0_0/FunctionsBilling.sol"; +import {FunctionsRequest} from "../../dev/1_0_0/libraries/FunctionsRequest.sol"; + +import {FunctionsSubscriptionSetup, FunctionsMultipleFulfillmentsSetup} from "./Setup.t.sol"; + // ================================================================ // | Functions Coordinator | // ================================================================ @@ -115,8 +121,61 @@ contract FunctionsBilling__GetJuelsPerGas { } /// @notice #estimateCost -contract FunctionsBilling_EstimateCost { - +contract FunctionsBilling_EstimateCost is FunctionsSubscriptionSetup { + function setUp() public virtual override { + FunctionsSubscriptionSetup.setUp(); + + // Get cost estimate as stranger + vm.stopPrank(); + vm.startPrank(STRANGER_ADDRESS); + } + + uint256 private constant REASONABLE_GAS_PRICE_CEILING = 1_000_000_000_000_000; // 1 million gwei + + function test_EstimateCost_RevertsIfGasPriceAboveCeiling() public { + // Build minimal valid request data + string memory sourceCode = "return 'hello world';"; + FunctionsRequest.Request memory request; + FunctionsRequest.initializeRequest( + request, + FunctionsRequest.Location.Inline, + FunctionsRequest.CodeLanguage.JavaScript, + sourceCode + ); + bytes memory requestData = FunctionsRequest.encodeCBOR(request); + + uint32 callbackGasLimit = 5_500; + uint256 gasPriceWei = REASONABLE_GAS_PRICE_CEILING + 1; + + vm.expectRevert(FunctionsBilling.InvalidCalldata.selector); + + s_functionsCoordinator.estimateCost(s_subscriptionId, requestData, callbackGasLimit, gasPriceWei); + } + + function test_EstimateCost_Success() public { + // Build minimal valid request data + string memory sourceCode = "return 'hello world';"; + FunctionsRequest.Request memory request; + FunctionsRequest.initializeRequest( + request, + FunctionsRequest.Location.Inline, + FunctionsRequest.CodeLanguage.JavaScript, + sourceCode + ); + bytes memory requestData = FunctionsRequest.encodeCBOR(request); + + uint32 callbackGasLimit = 5_500; + uint256 gasPriceWei = 1; + + uint96 costEstimate = s_functionsCoordinator.estimateCost( + s_subscriptionId, + requestData, + callbackGasLimit, + gasPriceWei + ); + uint96 expectedCostEstimate = 15725380; + assertEq(costEstimate, expectedCostEstimate); + } } /// @notice #_calculateCostEstimate @@ -150,8 +209,47 @@ contract FunctionsBilling_OracleWithdraw { } /// @notice #oracleWithdrawAll -contract FunctionsBilling_OracleWithdrawAll { - +contract FunctionsBilling_OracleWithdrawAll is FunctionsMultipleFulfillmentsSetup { + function setUp() public virtual override { + // Use no DON fee so that a transmitter has a balance of 0 + s_donFee = 0; + + FunctionsMultipleFulfillmentsSetup.setUp(); + } + + function test_OracleWithdrawAll_RevertIfNotOwner() public { + // Send as stranger + vm.stopPrank(); + vm.startPrank(STRANGER_ADDRESS); + + vm.expectRevert("Only callable by owner"); + s_functionsCoordinator.oracleWithdrawAll(); + } + + function test_OracleWithdrawAll_SuccessPaysTransmittersWithBalance() public { + uint256 transmitter1BalanceBefore = s_linkToken.balanceOf(NOP_TRANSMITTER_ADDRESS_1); + assertEq(transmitter1BalanceBefore, 0); + uint256 transmitter2BalanceBefore = s_linkToken.balanceOf(NOP_TRANSMITTER_ADDRESS_2); + assertEq(transmitter2BalanceBefore, 0); + uint256 transmitter3BalanceBefore = s_linkToken.balanceOf(NOP_TRANSMITTER_ADDRESS_3); + assertEq(transmitter3BalanceBefore, 0); + uint256 transmitter4BalanceBefore = s_linkToken.balanceOf(NOP_TRANSMITTER_ADDRESS_4); + assertEq(transmitter4BalanceBefore, 0); + + s_functionsCoordinator.oracleWithdrawAll(); + + uint96 expectedTransmitterBalance = s_fulfillmentCoordinatorBalance / 3; + + uint256 transmitter1BalanceAfter = s_linkToken.balanceOf(NOP_TRANSMITTER_ADDRESS_1); + assertEq(transmitter1BalanceAfter, expectedTransmitterBalance); + uint256 transmitter2BalanceAfter = s_linkToken.balanceOf(NOP_TRANSMITTER_ADDRESS_2); + assertEq(transmitter2BalanceAfter, expectedTransmitterBalance); + uint256 transmitter3BalanceAfter = s_linkToken.balanceOf(NOP_TRANSMITTER_ADDRESS_3); + assertEq(transmitter3BalanceAfter, expectedTransmitterBalance); + // Transmitter 4 has no balance + uint256 transmitter4BalanceAfter = s_linkToken.balanceOf(NOP_TRANSMITTER_ADDRESS_4); + assertEq(transmitter4BalanceAfter, 0); + } } /// @notice #_getTransmitters diff --git a/contracts/src/v0.8/functions/tests/1_0_0/FunctionsRouter.t.sol b/contracts/src/v0.8/functions/tests/1_0_0/FunctionsRouter.t.sol index 649c06f9eed..4d6e5a1fe0e 100644 --- a/contracts/src/v0.8/functions/tests/1_0_0/FunctionsRouter.t.sol +++ b/contracts/src/v0.8/functions/tests/1_0_0/FunctionsRouter.t.sol @@ -3,116 +3,1574 @@ pragma solidity ^0.8.19; import {FunctionsRouter} from "../../dev/1_0_0/FunctionsRouter.sol"; import {FunctionsSubscriptions} from "../../dev/1_0_0/FunctionsSubscriptions.sol"; +import {FunctionsCoordinator} from "../../dev/1_0_0/FunctionsCoordinator.sol"; +import {FunctionsBilling} from "../../dev/1_0_0/FunctionsBilling.sol"; +import {FunctionsRequest} from "../../dev/1_0_0/libraries/FunctionsRequest.sol"; +import {FunctionsResponse} from "../../dev/1_0_0/libraries/FunctionsResponse.sol"; +import {FunctionsCoordinatorTestHelper} from "./testhelpers/FunctionsCoordinatorTestHelper.sol"; +import {FunctionsClientTestHelper} from "./testhelpers/FunctionsClientTestHelper.sol"; -import {FunctionsRouterSetup, FunctionsOwnerAcceptTermsOfService} from "./Setup.t.sol"; +import {FunctionsRouterSetup, FunctionsRoutesSetup, FunctionsSubscriptionSetup, FunctionsClientRequestSetup} from "./Setup.t.sol"; + +import "forge-std/Vm.sol"; // ================================================================ // | Functions Router | // ================================================================ /// @notice #constructor -contract FunctionsRouter_Constructor { - +contract FunctionsRouter_Constructor is FunctionsRouterSetup { + function test_Constructor_Success() public { + assertEq(s_functionsRouter.typeAndVersion(), "Functions Router v1.0.0"); + assertEq(s_functionsRouter.owner(), OWNER_ADDRESS); + } } /// @notice #getConfig -contract FunctionsRouter_GetConfig { +contract FunctionsRouter_GetConfig is FunctionsRouterSetup { + function test_GetConfig_Success() public { + // Send as stranger + vm.stopPrank(); + vm.startPrank(STRANGER_ADDRESS); + FunctionsRouter.Config memory config = s_functionsRouter.getConfig(); + assertEq(config.maxConsumersPerSubscription, getRouterConfig().maxConsumersPerSubscription); + assertEq(config.adminFee, getRouterConfig().adminFee); + assertEq(config.handleOracleFulfillmentSelector, getRouterConfig().handleOracleFulfillmentSelector); + assertEq(config.maxCallbackGasLimits[0], getRouterConfig().maxCallbackGasLimits[0]); + assertEq(config.maxCallbackGasLimits[1], getRouterConfig().maxCallbackGasLimits[1]); + assertEq(config.maxCallbackGasLimits[2], getRouterConfig().maxCallbackGasLimits[2]); + assertEq(config.gasForCallExactCheck, getRouterConfig().gasForCallExactCheck); + assertEq(config.subscriptionDepositMinimumRequests, getRouterConfig().subscriptionDepositMinimumRequests); + assertEq(config.subscriptionDepositJuels, getRouterConfig().subscriptionDepositJuels); + } } /// @notice #updateConfig -contract FunctionsRouter_UpdateConfig { +contract FunctionsRouter_UpdateConfig is FunctionsRouterSetup { + FunctionsRouter.Config internal configToSet; + + function setUp() public virtual override { + FunctionsRouterSetup.setUp(); + + uint32[] memory maxCallbackGasLimits = new uint32[](4); + maxCallbackGasLimits[0] = 300_000; + maxCallbackGasLimits[1] = 500_000; + maxCallbackGasLimits[2] = 1_000_000; + maxCallbackGasLimits[3] = 3_000_000; + + configToSet = FunctionsRouter.Config({ + maxConsumersPerSubscription: s_maxConsumersPerSubscription, + adminFee: s_adminFee, + handleOracleFulfillmentSelector: s_handleOracleFulfillmentSelector, + maxCallbackGasLimits: maxCallbackGasLimits, + gasForCallExactCheck: 5000, + subscriptionDepositMinimumRequests: 10, + subscriptionDepositJuels: 5 * 1e18 + }); + } + + function test_UpdateConfig_RevertIfNotOwner() public { + // Send as stranger + vm.stopPrank(); + vm.startPrank(STRANGER_ADDRESS); + + vm.expectRevert("Only callable by owner"); + s_functionsRouter.updateConfig(configToSet); + } + + event ConfigUpdated(FunctionsRouter.Config config); + + function test_UpdateConfig_Success() public { + // topic0 (function signature, always checked), NOT topic1 (false), NOT topic2 (false), NOT topic3 (false), and data (true). + bool checkTopic1 = false; + bool checkTopic2 = false; + bool checkTopic3 = false; + bool checkData = true; + vm.expectEmit(checkTopic1, checkTopic2, checkTopic3, checkData); + emit ConfigUpdated(configToSet); + s_functionsRouter.updateConfig(configToSet); + + FunctionsRouter.Config memory config = s_functionsRouter.getConfig(); + assertEq(config.maxConsumersPerSubscription, configToSet.maxConsumersPerSubscription); + assertEq(config.adminFee, configToSet.adminFee); + assertEq(config.handleOracleFulfillmentSelector, configToSet.handleOracleFulfillmentSelector); + assertEq(config.maxCallbackGasLimits[0], configToSet.maxCallbackGasLimits[0]); + assertEq(config.maxCallbackGasLimits[1], configToSet.maxCallbackGasLimits[1]); + assertEq(config.maxCallbackGasLimits[2], configToSet.maxCallbackGasLimits[2]); + assertEq(config.maxCallbackGasLimits[3], configToSet.maxCallbackGasLimits[3]); + assertEq(config.gasForCallExactCheck, configToSet.gasForCallExactCheck); + } } /// @notice #isValidCallbackGasLimit -contract FunctionsRouter_IsValidCallbackGasLimit { +contract FunctionsRouter_IsValidCallbackGasLimit is FunctionsSubscriptionSetup { + function test_IsValidCallbackGasLimit_RevertInvalidConfig() public { + // Set an invalid maxCallbackGasLimit flag + bytes32 flagsToSet = 0x5a00000000000000000000000000000000000000000000000000000000000000; + s_functionsRouter.setFlags(s_subscriptionId, flagsToSet); + + vm.expectRevert(abi.encodeWithSelector(FunctionsRouter.InvalidGasFlagValue.selector, 90)); + s_functionsRouter.isValidCallbackGasLimit(s_subscriptionId, 0); + } + + function test_IsValidCallbackGasLimit_RevertGasLimitTooBig() public { + uint8 MAX_CALLBACK_GAS_LIMIT_FLAGS_INDEX = 0; + bytes32 subscriptionFlags = s_functionsRouter.getFlags(s_subscriptionId); + uint8 callbackGasLimitsIndexSelector = uint8(subscriptionFlags[MAX_CALLBACK_GAS_LIMIT_FLAGS_INDEX]); + + FunctionsRouter.Config memory config = s_functionsRouter.getConfig(); + uint32[] memory _maxCallbackGasLimits = config.maxCallbackGasLimits; + uint32 maxCallbackGasLimit = _maxCallbackGasLimits[callbackGasLimitsIndexSelector]; + vm.expectRevert(abi.encodeWithSelector(FunctionsRouter.GasLimitTooBig.selector, maxCallbackGasLimit)); + s_functionsRouter.isValidCallbackGasLimit(s_subscriptionId, maxCallbackGasLimit + 1); + } + + function test_IsValidCallbackGasLimit_Success() public view { + uint8 MAX_CALLBACK_GAS_LIMIT_FLAGS_INDEX = 0; + bytes32 subscriptionFlags = s_functionsRouter.getFlags(s_subscriptionId); + uint8 callbackGasLimitsIndexSelector = uint8(subscriptionFlags[MAX_CALLBACK_GAS_LIMIT_FLAGS_INDEX]); + + FunctionsRouter.Config memory config = s_functionsRouter.getConfig(); + uint32[] memory _maxCallbackGasLimits = config.maxCallbackGasLimits; + uint32 maxCallbackGasLimit = _maxCallbackGasLimits[callbackGasLimitsIndexSelector]; + + s_functionsRouter.isValidCallbackGasLimit(s_subscriptionId, maxCallbackGasLimit); + } } /// @notice #getAdminFee -contract FunctionsRouter_GetAdminFee { +contract FunctionsRouter_GetAdminFee is FunctionsRouterSetup { + function test_GetAdminFee_Success() public { + // Send as stranger + vm.stopPrank(); + vm.startPrank(STRANGER_ADDRESS); + uint72 adminFee = s_functionsRouter.getAdminFee(); + assertEq(adminFee, getRouterConfig().adminFee); + } } /// @notice #getAllowListId -contract FunctionsRouter_GetAllowListId { +contract FunctionsRouter_GetAllowListId is FunctionsRouterSetup { + function test_GetAllowListId_Success() public { + // Send as stranger + vm.stopPrank(); + vm.startPrank(STRANGER_ADDRESS); + + bytes32 defaultAllowListId = bytes32(0); + bytes32 allowListId = s_functionsRouter.getAllowListId(); + assertEq(allowListId, defaultAllowListId); + } } /// @notice #setAllowListId -contract FunctionsRouter_SetAllowListId { +contract FunctionsRouter_SetAllowListId is FunctionsRouterSetup { + function test_UpdateConfig_RevertIfNotOwner() public { + // Send as stranger + vm.stopPrank(); + vm.startPrank(STRANGER_ADDRESS); + + bytes32 routeIdToSet = bytes32("allowList"); + + vm.expectRevert("Only callable by owner"); + s_functionsRouter.setAllowListId(routeIdToSet); + } + function test_SetAllowListId_Success() public { + bytes32 routeIdToSet = bytes32("allowList"); + s_functionsRouter.setAllowListId(routeIdToSet); + bytes32 allowListId = s_functionsRouter.getAllowListId(); + assertEq(allowListId, routeIdToSet); + } } /// @notice #_getMaxConsumers -contract FunctionsRouter__GetMaxConsumers { - +contract FunctionsRouter__GetMaxConsumers is FunctionsRouterSetup { + // TODO: make contract internal function helper } /// @notice #sendRequest -contract FunctionsRouter_SendRequest { +contract FunctionsRouter_SendRequest is FunctionsSubscriptionSetup { + function setUp() public virtual override { + FunctionsSubscriptionSetup.setUp(); + + // Add sending wallet as a subscription consumer + s_functionsRouter.addConsumer(s_subscriptionId, OWNER_ADDRESS); + } + + function test_SendRequest_RevertIfInvalidDonId() public { + // Build minimal valid request data + string memory sourceCode = "return 'hello world';"; + FunctionsRequest.Request memory request; + FunctionsRequest.initializeRequest( + request, + FunctionsRequest.Location.Inline, + FunctionsRequest.CodeLanguage.JavaScript, + sourceCode + ); + bytes memory requestData = FunctionsRequest.encodeCBOR(request); + + bytes32 invalidDonId = bytes32("this does not exist"); + + vm.expectRevert(abi.encodeWithSelector(FunctionsRouter.RouteNotFound.selector, invalidDonId)); + s_functionsRouter.sendRequest( + s_subscriptionId, + requestData, + FunctionsRequest.REQUEST_DATA_VERSION, + 5_000, + invalidDonId + ); + } + + function test_SendRequest_RevertIfIncorrectDonId() public { + // Build minimal valid request data + string memory sourceCode = "return 'hello world';"; + FunctionsRequest.Request memory request; + FunctionsRequest.initializeRequest( + request, + FunctionsRequest.Location.Inline, + FunctionsRequest.CodeLanguage.JavaScript, + sourceCode + ); + bytes memory requestData = FunctionsRequest.encodeCBOR(request); + + bytes32 incorrectDonId = s_functionsRouter.getAllowListId(); + + // Low level revert from incorrect call + vm.expectRevert(); + s_functionsRouter.sendRequest( + s_subscriptionId, + requestData, + FunctionsRequest.REQUEST_DATA_VERSION, + 5_000, + incorrectDonId + ); + } + + function test_SendRequest_RevertIfPaused() public { + s_functionsRouter.pause(); + + // Build minimal valid request data + string memory sourceCode = "return 'hello world';"; + FunctionsRequest.Request memory request; + FunctionsRequest.initializeRequest( + request, + FunctionsRequest.Location.Inline, + FunctionsRequest.CodeLanguage.JavaScript, + sourceCode + ); + bytes memory requestData = FunctionsRequest.encodeCBOR(request); + + vm.expectRevert("Pausable: paused"); + s_functionsRouter.sendRequest(s_subscriptionId, requestData, FunctionsRequest.REQUEST_DATA_VERSION, 5000, s_donId); + } + + function test_SendRequest_RevertIfNoSubscription() public { + // Build minimal valid request data + string memory sourceCode = "return 'hello world';"; + FunctionsRequest.Request memory request; + FunctionsRequest.initializeRequest( + request, + FunctionsRequest.Location.Inline, + FunctionsRequest.CodeLanguage.JavaScript, + sourceCode + ); + bytes memory requestData = FunctionsRequest.encodeCBOR(request); + + uint64 invalidSubscriptionId = 123456789; + + vm.expectRevert(FunctionsSubscriptions.InvalidSubscription.selector); + s_functionsRouter.sendRequest( + invalidSubscriptionId, + requestData, + FunctionsRequest.REQUEST_DATA_VERSION, + 5000, + s_donId + ); + } + + function test_SendRequest_RevertIfConsumerNotAllowed() public { + // Remove sending wallet as a subscription consumer + s_functionsRouter.removeConsumer(s_subscriptionId, OWNER_ADDRESS); + + // Build minimal valid request data + string memory sourceCode = "return 'hello world';"; + FunctionsRequest.Request memory request; + FunctionsRequest.initializeRequest( + request, + FunctionsRequest.Location.Inline, + FunctionsRequest.CodeLanguage.JavaScript, + sourceCode + ); + bytes memory requestData = FunctionsRequest.encodeCBOR(request); + + vm.expectRevert(FunctionsSubscriptions.InvalidConsumer.selector); + s_functionsRouter.sendRequest(s_subscriptionId, requestData, FunctionsRequest.REQUEST_DATA_VERSION, 5000, s_donId); + } + + function test_SendRequest_RevertIfInvalidCallbackGasLimit() public { + // Build minimal valid request data + string memory sourceCode = "return 'hello world';"; + FunctionsRequest.Request memory request; + FunctionsRequest.initializeRequest( + request, + FunctionsRequest.Location.Inline, + FunctionsRequest.CodeLanguage.JavaScript, + sourceCode + ); + bytes memory requestData = FunctionsRequest.encodeCBOR(request); + + uint8 MAX_CALLBACK_GAS_LIMIT_FLAGS_INDEX = 0; + bytes32 subscriptionFlags = s_functionsRouter.getFlags(s_subscriptionId); + uint8 callbackGasLimitsIndexSelector = uint8(subscriptionFlags[MAX_CALLBACK_GAS_LIMIT_FLAGS_INDEX]); + + FunctionsRouter.Config memory config = s_functionsRouter.getConfig(); + uint32[] memory _maxCallbackGasLimits = config.maxCallbackGasLimits; + uint32 maxCallbackGasLimit = _maxCallbackGasLimits[callbackGasLimitsIndexSelector]; + + vm.expectRevert(abi.encodeWithSelector(FunctionsRouter.GasLimitTooBig.selector, maxCallbackGasLimit)); + s_functionsRouter.sendRequest( + s_subscriptionId, + requestData, + FunctionsRequest.REQUEST_DATA_VERSION, + 500_000, + s_donId + ); + } + + function test_SendRequest_RevertIfEmptyData() public { + // Build invalid request data + bytes memory emptyRequestData = new bytes(0); + + vm.expectRevert(FunctionsRouter.EmptyRequestData.selector); + s_functionsRouter.sendRequest( + s_subscriptionId, + emptyRequestData, + FunctionsRequest.REQUEST_DATA_VERSION, + 5_000, + s_donId + ); + } + + function test_SendRequest_RevertIfInsufficientSubscriptionBalance() public { + // Create new subscription that does not have any funding + uint64 subscriptionId = s_functionsRouter.createSubscription(); + s_functionsRouter.addConsumer(subscriptionId, address(OWNER_ADDRESS)); + // Build minimal valid request data + string memory sourceCode = "return 'hello world';"; + FunctionsRequest.Request memory request; + FunctionsRequest.initializeRequest( + request, + FunctionsRequest.Location.Inline, + FunctionsRequest.CodeLanguage.JavaScript, + sourceCode + ); + bytes memory requestData = FunctionsRequest.encodeCBOR(request); + + uint32 callbackGasLimit = 5000; + vm.expectRevert(FunctionsBilling.InsufficientBalance.selector); + + s_functionsRouter.sendRequest( + subscriptionId, + requestData, + FunctionsRequest.REQUEST_DATA_VERSION, + callbackGasLimit, + s_donId + ); + } + + function test_SendRequest_RevertIfDuplicateRequestId() public { + // Build minimal valid request data + string memory sourceCode = "return 'hello world';"; + FunctionsRequest.Request memory request; + FunctionsRequest.initializeRequest( + request, + FunctionsRequest.Location.Inline, + FunctionsRequest.CodeLanguage.JavaScript, + sourceCode + ); + uint32 callbackGasLimit = 5_000; + bytes memory requestData = FunctionsRequest.encodeCBOR(request); + + // Send a first request that will remain pending + bytes32 requestId = s_functionsRouter.sendRequest( + s_subscriptionId, + requestData, + FunctionsRequest.REQUEST_DATA_VERSION, + callbackGasLimit, + s_donId + ); + + // Mock the Coordinator to always give back the first requestId + FunctionsResponse.Commitment memory mockCommitment = FunctionsResponse.Commitment({ + adminFee: s_adminFee, + coordinator: address(s_functionsCoordinator), + client: OWNER_ADDRESS, + subscriptionId: s_subscriptionId, + callbackGasLimit: callbackGasLimit, + estimatedTotalCostJuels: 0, + timeoutTimestamp: uint32(block.timestamp + getCoordinatorConfig().requestTimeoutSeconds), + requestId: requestId, + donFee: s_donFee, + gasOverheadBeforeCallback: getCoordinatorConfig().gasOverheadBeforeCallback, + gasOverheadAfterCallback: getCoordinatorConfig().gasOverheadAfterCallback + }); + + vm.mockCall( + address(s_functionsCoordinator), + abi.encodeWithSelector(FunctionsCoordinator.startRequest.selector), + abi.encode(mockCommitment) + ); + + vm.expectRevert(abi.encodeWithSelector(FunctionsRouter.DuplicateRequestId.selector, requestId)); + s_functionsRouter.sendRequest( + s_subscriptionId, + requestData, + FunctionsRequest.REQUEST_DATA_VERSION, + callbackGasLimit, + s_donId + ); + } + + event RequestStart( + bytes32 indexed requestId, + bytes32 indexed donId, + uint64 indexed subscriptionId, + address subscriptionOwner, + address requestingContract, + address requestInitiator, + bytes data, + uint16 dataVersion, + uint32 callbackGasLimit, + uint96 estimatedTotalCostJuels + ); + + function test_SendRequest_Success() public { + // Build minimal valid request data + string memory sourceCode = "return 'hello world';"; + FunctionsRequest.Request memory request; + FunctionsRequest.initializeRequest( + request, + FunctionsRequest.Location.Inline, + FunctionsRequest.CodeLanguage.JavaScript, + sourceCode + ); + bytes memory requestData = FunctionsRequest.encodeCBOR(request); + + uint32 callbackGasLimit = 5000; + + bytes32 expectedRequestId = keccak256( + abi.encode(address(s_functionsCoordinator), OWNER_ADDRESS, s_subscriptionId, 1) + ); + + uint96 costEstimate = s_functionsCoordinator.estimateCost( + s_subscriptionId, + requestData, + callbackGasLimit, + tx.gasprice + ); + + vm.recordLogs(); + + // topic0 (function signature, always checked), topic1 (true), topic2 (true), topic3 (true), and data (true). + bool checkTopic1 = true; + bool checkTopic2 = true; + bool checkTopic3 = true; + bool checkData = true; + vm.expectEmit(checkTopic1, checkTopic2, checkTopic3, checkData); + emit RequestStart({ + requestId: expectedRequestId, + donId: s_donId, + subscriptionId: s_subscriptionId, + subscriptionOwner: OWNER_ADDRESS, + requestingContract: OWNER_ADDRESS, + requestInitiator: OWNER_ADDRESS, + data: requestData, + dataVersion: FunctionsRequest.REQUEST_DATA_VERSION, + callbackGasLimit: callbackGasLimit, + estimatedTotalCostJuels: costEstimate + }); + + bytes32 requestIdFromReturn = s_functionsRouter.sendRequest( + s_subscriptionId, + requestData, + FunctionsRequest.REQUEST_DATA_VERSION, + callbackGasLimit, + s_donId + ); + + // Get requestId from RequestStart event log topic 1 + Vm.Log[] memory entries = vm.getRecordedLogs(); + bytes32 requestIdFromEvent = entries[2].topics[1]; + + assertEq(requestIdFromReturn, requestIdFromEvent); + } } /// @notice #sendRequestToProposed -contract FunctionsRouter_SendRequestToProposed { +contract FunctionsRouter_SendRequestToProposed is FunctionsSubscriptionSetup { + FunctionsCoordinatorTestHelper internal s_functionsCoordinator2; // TODO: use actual FunctionsCoordinator instead of helper + + function setUp() public virtual override { + FunctionsSubscriptionSetup.setUp(); + + // Add sending wallet as a subscription consumer + s_functionsRouter.addConsumer(s_subscriptionId, OWNER_ADDRESS); + + // Deploy new Coordinator contract + s_functionsCoordinator2 = new FunctionsCoordinatorTestHelper( + address(s_functionsRouter), + getCoordinatorConfig(), + address(s_linkEthFeed) + ); + + // Propose new Coordinator contract + bytes32[] memory proposedContractSetIds = new bytes32[](1); + proposedContractSetIds[0] = s_donId; + address[] memory proposedContractSetAddresses = new address[](1); + proposedContractSetAddresses[0] = address(s_functionsCoordinator2); + + s_functionsRouter.proposeContractsUpdate(proposedContractSetIds, proposedContractSetAddresses); + } + + function test_SendRequestToProposed_RevertIfInvalidDonId() public { + // Build minimal valid request data + string memory sourceCode = "return 'hello world';"; + FunctionsRequest.Request memory request; + FunctionsRequest.initializeRequest( + request, + FunctionsRequest.Location.Inline, + FunctionsRequest.CodeLanguage.JavaScript, + sourceCode + ); + bytes memory requestData = FunctionsRequest.encodeCBOR(request); + + bytes32 invalidDonId = bytes32("this does not exist"); + + vm.expectRevert(abi.encodeWithSelector(FunctionsRouter.RouteNotFound.selector, invalidDonId)); + s_functionsRouter.sendRequestToProposed( + s_subscriptionId, + requestData, + FunctionsRequest.REQUEST_DATA_VERSION, + 5_000, + invalidDonId + ); + } + + function test_SendRequestToProposed_RevertIfIncorrectDonId() public { + // Build minimal valid request data + string memory sourceCode = "return 'hello world';"; + FunctionsRequest.Request memory request; + FunctionsRequest.initializeRequest( + request, + FunctionsRequest.Location.Inline, + FunctionsRequest.CodeLanguage.JavaScript, + sourceCode + ); + bytes memory requestData = FunctionsRequest.encodeCBOR(request); + + bytes32 incorrectDonId = s_functionsRouter.getAllowListId(); + + // Low level revert from incorrect call + vm.expectRevert(); + s_functionsRouter.sendRequestToProposed( + s_subscriptionId, + requestData, + FunctionsRequest.REQUEST_DATA_VERSION, + 5_000, + incorrectDonId + ); + } + + function test_SendRequestToProposed_RevertIfPaused() public { + s_functionsRouter.pause(); + + // Build minimal valid request data + string memory sourceCode = "return 'hello world';"; + FunctionsRequest.Request memory request; + FunctionsRequest.initializeRequest( + request, + FunctionsRequest.Location.Inline, + FunctionsRequest.CodeLanguage.JavaScript, + sourceCode + ); + bytes memory requestData = FunctionsRequest.encodeCBOR(request); + + vm.expectRevert("Pausable: paused"); + s_functionsRouter.sendRequestToProposed( + s_subscriptionId, + requestData, + FunctionsRequest.REQUEST_DATA_VERSION, + 5000, + s_donId + ); + } + + function test_SendRequestToProposed_RevertIfNoSubscription() public { + // Build minimal valid request data + string memory sourceCode = "return 'hello world';"; + FunctionsRequest.Request memory request; + FunctionsRequest.initializeRequest( + request, + FunctionsRequest.Location.Inline, + FunctionsRequest.CodeLanguage.JavaScript, + sourceCode + ); + bytes memory requestData = FunctionsRequest.encodeCBOR(request); + uint64 invalidSubscriptionId = 123456789; + + vm.expectRevert(FunctionsSubscriptions.InvalidSubscription.selector); + s_functionsRouter.sendRequestToProposed( + invalidSubscriptionId, + requestData, + FunctionsRequest.REQUEST_DATA_VERSION, + 5000, + s_donId + ); + } + + function test_SendRequestToProposed_RevertIfConsumerNotAllowed() public { + // Remove sending wallet as a subscription consumer + s_functionsRouter.removeConsumer(s_subscriptionId, OWNER_ADDRESS); + + // Build minimal valid request data + string memory sourceCode = "return 'hello world';"; + FunctionsRequest.Request memory request; + FunctionsRequest.initializeRequest( + request, + FunctionsRequest.Location.Inline, + FunctionsRequest.CodeLanguage.JavaScript, + sourceCode + ); + bytes memory requestData = FunctionsRequest.encodeCBOR(request); + + vm.expectRevert(FunctionsSubscriptions.InvalidConsumer.selector); + s_functionsRouter.sendRequestToProposed( + s_subscriptionId, + requestData, + FunctionsRequest.REQUEST_DATA_VERSION, + 5000, + s_donId + ); + } + + function test_SendRequestToProposed_RevertIfInvalidCallbackGasLimit() public { + // Build minimal valid request data + string memory sourceCode = "return 'hello world';"; + FunctionsRequest.Request memory request; + FunctionsRequest.initializeRequest( + request, + FunctionsRequest.Location.Inline, + FunctionsRequest.CodeLanguage.JavaScript, + sourceCode + ); + bytes memory requestData = FunctionsRequest.encodeCBOR(request); + + uint8 MAX_CALLBACK_GAS_LIMIT_FLAGS_INDEX = 0; + bytes32 subscriptionFlags = s_functionsRouter.getFlags(s_subscriptionId); + uint8 callbackGasLimitsIndexSelector = uint8(subscriptionFlags[MAX_CALLBACK_GAS_LIMIT_FLAGS_INDEX]); + + FunctionsRouter.Config memory config = s_functionsRouter.getConfig(); + uint32[] memory _maxCallbackGasLimits = config.maxCallbackGasLimits; + uint32 maxCallbackGasLimit = _maxCallbackGasLimits[callbackGasLimitsIndexSelector]; + + vm.expectRevert(abi.encodeWithSelector(FunctionsRouter.GasLimitTooBig.selector, maxCallbackGasLimit)); + s_functionsRouter.sendRequestToProposed( + s_subscriptionId, + requestData, + FunctionsRequest.REQUEST_DATA_VERSION, + 500_000, + s_donId + ); + } + + function test_SendRequestToProposed_RevertIfEmptyData() public { + // Build invalid request data + bytes memory emptyRequestData = new bytes(0); + + vm.expectRevert(FunctionsRouter.EmptyRequestData.selector); + s_functionsRouter.sendRequestToProposed( + s_subscriptionId, + emptyRequestData, + FunctionsRequest.REQUEST_DATA_VERSION, + 5_000, + s_donId + ); + } + + function test_SendRequest_RevertIfInsufficientSubscriptionBalance() public { + // Create new subscription that does not have any funding + uint64 subscriptionId = s_functionsRouter.createSubscription(); + s_functionsRouter.addConsumer(subscriptionId, address(OWNER_ADDRESS)); + + // Build minimal valid request data + string memory sourceCode = "return 'hello world';"; + FunctionsRequest.Request memory request; + FunctionsRequest.initializeRequest( + request, + FunctionsRequest.Location.Inline, + FunctionsRequest.CodeLanguage.JavaScript, + sourceCode + ); + bytes memory requestData = FunctionsRequest.encodeCBOR(request); + + uint32 callbackGasLimit = 5000; + vm.expectRevert(FunctionsBilling.InsufficientBalance.selector); + + s_functionsRouter.sendRequestToProposed( + subscriptionId, + requestData, + FunctionsRequest.REQUEST_DATA_VERSION, + callbackGasLimit, + s_donId + ); + } + + event RequestStart( + bytes32 indexed requestId, + bytes32 indexed donId, + uint64 indexed subscriptionId, + address subscriptionOwner, + address requestingContract, + address requestInitiator, + bytes data, + uint16 dataVersion, + uint32 callbackGasLimit, + uint96 estimatedTotalCostJuels + ); + + function test_SendRequestToProposed_Success() public { + // Build minimal valid request data + string memory sourceCode = "return 'hello world';"; + FunctionsRequest.Request memory request; + FunctionsRequest.initializeRequest( + request, + FunctionsRequest.Location.Inline, + FunctionsRequest.CodeLanguage.JavaScript, + sourceCode + ); + bytes memory requestData = FunctionsRequest.encodeCBOR(request); + + uint32 callbackGasLimit = 5000; + + bytes32 expectedRequestId = keccak256( + abi.encode(address(s_functionsCoordinator2), OWNER_ADDRESS, s_subscriptionId, 1) + ); + + uint96 costEstimate = s_functionsCoordinator2.estimateCost( + s_subscriptionId, + requestData, + callbackGasLimit, + tx.gasprice + ); + + vm.recordLogs(); + + // topic0 (function signature, always checked), topic1 (true), topic2 (true), topic3 (true), and data (true). + bool checkTopic1 = true; + bool checkTopic2 = true; + bool checkTopic3 = true; + bool checkData = true; + vm.expectEmit(checkTopic1, checkTopic2, checkTopic3, checkData); + emit RequestStart({ + requestId: expectedRequestId, + donId: s_donId, + subscriptionId: s_subscriptionId, + subscriptionOwner: OWNER_ADDRESS, + requestingContract: OWNER_ADDRESS, + requestInitiator: OWNER_ADDRESS, + data: requestData, + dataVersion: FunctionsRequest.REQUEST_DATA_VERSION, + callbackGasLimit: callbackGasLimit, + estimatedTotalCostJuels: costEstimate + }); + + bytes32 requestIdFromReturn = s_functionsRouter.sendRequestToProposed( + s_subscriptionId, + requestData, + FunctionsRequest.REQUEST_DATA_VERSION, + callbackGasLimit, + s_donId + ); + + // Get requestId from RequestStart event log topic 1 + Vm.Log[] memory entries = vm.getRecordedLogs(); + bytes32 requestIdFromEvent = entries[2].topics[1]; + + assertEq(requestIdFromReturn, requestIdFromEvent); + } } /// @notice #_sendRequest -contract FunctionsRouter__SendRequest { - +contract FunctionsRouter__SendRequest is FunctionsRouterSetup { + // TODO: make contract internal function helper } /// @notice #fulfill -contract FunctionsRouter_Fulfill { +contract FunctionsRouter_Fulfill is FunctionsClientRequestSetup { + function test_Fulfill_RevertIfPaused() public { + s_functionsRouter.pause(); + + // Send as committed Coordinator + vm.stopPrank(); + vm.startPrank(address(s_functionsCoordinator)); + + bytes memory response = bytes("hello world!"); + bytes memory err = new bytes(0); + uint96 juelsPerGas = 0; + uint96 costWithoutCallback = 0; + address transmitter = NOP_TRANSMITTER_ADDRESS_1; + FunctionsResponse.Commitment memory commitment = s_requestCommitment; + + vm.expectRevert("Pausable: paused"); + s_functionsRouter.fulfill(response, err, juelsPerGas, costWithoutCallback, transmitter, commitment); + } + + function test_Fulfill_RevertIfNotCommittedCoordinator() public { + // Send as stranger + vm.stopPrank(); + vm.startPrank(STRANGER_ADDRESS); + bytes memory response = bytes("hello world!"); + bytes memory err = new bytes(0); + uint96 juelsPerGas = 0; + uint96 costWithoutCallback = 0; + address transmitter = NOP_TRANSMITTER_ADDRESS_1; + FunctionsResponse.Commitment memory commitment = s_requestCommitment; + + vm.expectRevert(FunctionsRouter.OnlyCallableFromCoordinator.selector); + s_functionsRouter.fulfill(response, err, juelsPerGas, costWithoutCallback, transmitter, commitment); + } + + event RequestNotProcessed( + bytes32 indexed requestId, + address coordinator, + address transmitter, + FunctionsResponse.FulfillResult resultCode + ); + + function test_Fulfill_RequestNotProcessedInvalidRequestId() public { + // Send as committed Coordinator + vm.stopPrank(); + vm.startPrank(address(s_functionsCoordinator)); + + bytes memory response = bytes("hello world!"); + bytes memory err = new bytes(0); + uint96 juelsPerGas = 0; + uint96 costWithoutCallback = 0; + address transmitter = NOP_TRANSMITTER_ADDRESS_1; + FunctionsResponse.Commitment memory commitment = s_requestCommitment; + // Modify request commitment to have a invalid requestId + bytes32 invalidRequestId = bytes32("this does not exist"); + commitment.requestId = invalidRequestId; + + // topic0 (function signature, always checked), NOT topic1 (false), NOT topic2 (false), NOT topic3 (false), and data (true). + bool checkTopic1 = false; + bool checkTopic2 = false; + bool checkTopic3 = false; + bool checkData = true; + vm.expectEmit(checkTopic1, checkTopic2, checkTopic3, checkData); + emit RequestNotProcessed({ + requestId: s_requestCommitment.requestId, + coordinator: address(s_functionsCoordinator), + transmitter: NOP_TRANSMITTER_ADDRESS_1, + resultCode: FunctionsResponse.FulfillResult.INVALID_REQUEST_ID + }); + + (FunctionsResponse.FulfillResult resultCode, uint96 callbackGasCostJuels) = s_functionsRouter.fulfill( + response, + err, + juelsPerGas, + costWithoutCallback, + transmitter, + commitment + ); + + assertEq(uint(resultCode), uint(FunctionsResponse.FulfillResult.INVALID_REQUEST_ID)); + assertEq(callbackGasCostJuels, 0); + } + + function test_Fulfill_RequestNotProcessedInvalidCommitment() public { + // Send as committed Coordinator + vm.stopPrank(); + vm.startPrank(address(s_functionsCoordinator)); + + bytes memory response = bytes("hello world!"); + bytes memory err = new bytes(0); + uint96 juelsPerGas = 0; + uint96 costWithoutCallback = 0; + address transmitter = NOP_TRANSMITTER_ADDRESS_1; + FunctionsResponse.Commitment memory commitment = s_requestCommitment; + // Modify request commitment to have charge more than quoted + commitment.estimatedTotalCostJuels = 10 * JUELS_PER_LINK; // 10 LINK + + // topic0 (function signature, always checked), NOT topic1 (false), NOT topic2 (false), NOT topic3 (false), and data (true). + bool checkTopic1 = false; + bool checkTopic2 = false; + bool checkTopic3 = false; + bool checkData = true; + vm.expectEmit(checkTopic1, checkTopic2, checkTopic3, checkData); + emit RequestNotProcessed({ + requestId: s_requestCommitment.requestId, + coordinator: address(s_functionsCoordinator), + transmitter: NOP_TRANSMITTER_ADDRESS_1, + resultCode: FunctionsResponse.FulfillResult.INVALID_COMMITMENT + }); + + (FunctionsResponse.FulfillResult resultCode, uint96 callbackGasCostJuels) = s_functionsRouter.fulfill( + response, + err, + juelsPerGas, + costWithoutCallback, + transmitter, + commitment + ); + + assertEq(uint(resultCode), uint(FunctionsResponse.FulfillResult.INVALID_COMMITMENT)); + assertEq(callbackGasCostJuels, 0); + } + + function test_Fulfill_RequestNotProcessedInsufficientGas() public { + // Send as committed Coordinator + vm.stopPrank(); + vm.startPrank(address(s_functionsCoordinator)); + + bytes memory response = bytes("hello world!"); + bytes memory err = new bytes(0); + uint96 juelsPerGas = 0; + uint96 costWithoutCallback = 0; + address transmitter = NOP_TRANSMITTER_ADDRESS_1; + + vm.txGasPrice(1); + + // topic0 (function signature, always checked), NOT topic1 (false), NOT topic2 (false), NOT topic3 (false), and data (true). + bool checkTopic1 = false; + bool checkTopic2 = false; + bool checkTopic3 = false; + bool checkData = true; + vm.expectEmit(checkTopic1, checkTopic2, checkTopic3, checkData); + emit RequestNotProcessed({ + requestId: s_requestCommitment.requestId, + coordinator: address(s_functionsCoordinator), + transmitter: NOP_TRANSMITTER_ADDRESS_1, + resultCode: FunctionsResponse.FulfillResult.INSUFFICIENT_GAS_PROVIDED + }); + + // Coordinator sends enough gas that would get through callback and payment, but fail after + uint32 callbackGasLimit = 5000; + uint256 gasToUse = getCoordinatorConfig().gasOverheadBeforeCallback + callbackGasLimit; + (FunctionsResponse.FulfillResult resultCode, uint96 callbackGasCostJuels) = s_functionsRouter.fulfill{ + gas: gasToUse + }(response, err, juelsPerGas, costWithoutCallback, transmitter, s_requestCommitment); + + assertEq(uint(resultCode), uint(FunctionsResponse.FulfillResult.INSUFFICIENT_GAS_PROVIDED)); + assertEq(callbackGasCostJuels, 0); + } + + function test_Fulfill_RequestNotProcessedSubscriptionBalanceInvariant() public { + // // Send as committed Coordinator + // vm.stopPrank(); + // vm.startPrank(address(s_functionsCoordinator)); + // bytes memory response = bytes("hello world!"); + // bytes memory err = new bytes(0); + // uint96 juelsPerGas = 0; + // uint96 costWithoutCallback = 0; + // address transmitter = NOP_TRANSMITTER_ADDRESS_1; + // FunctionsResponse.Commitment memory commitment = s_requestCommitment; + // TODO: use contract helper to change subscription balance + // // topic0 (function signature, always checked), NOT topic1 (false), NOT topic2 (false), NOT topic3 (false), and data (true). + // bool checkTopic1 = false; + // bool checkTopic2 = false; + // bool checkTopic3 = false; + // bool checkData = true; + // vm.expectEmit(checkTopic1, checkTopic2, checkTopic3, checkData); + // emit RequestNotProcessed({ + // requestId: s_requestCommitment.requestId, + // coordinator: address(s_functionsCoordinator), + // transmitter: NOP_TRANSMITTER_ADDRESS_1, + // resultCode: FunctionsResponse.FulfillResult.SUBSCRIPTION_BALANCE_INVARIANT_VIOLATION + // }); + // (FunctionsResponse.FulfillResult resultCode, uint96 callbackGasCostJuels) = s_functionsRouter.fulfill( + // response, + // err, + // juelsPerGas, + // costWithoutCallback, + // transmitter, + // commitment + // ); + // assertEq(uint(resultCode), uint(FunctionsResponse.FulfillResult.SUBSCRIPTION_BALANCE_INVARIANT_VIOLATION)); + // assertEq(callbackGasCostJuels, 0); + } + + function test_Fulfill_RequestNotProcessedCostExceedsCommitment() public { + // Send as committed Coordinator + vm.stopPrank(); + vm.startPrank(address(s_functionsCoordinator)); + + bytes memory response = bytes("hello world!"); + bytes memory err = new bytes(0); + // Use higher juelsPerGas than request time + uint96 juelsPerGas = 100000; + uint96 costWithoutCallback = 1; + address transmitter = NOP_TRANSMITTER_ADDRESS_1; + FunctionsResponse.Commitment memory commitment = s_requestCommitment; + + // topic0 (function signature, always checked), NOT topic1 (false), NOT topic2 (false), NOT topic3 (false), and data (true). + bool checkTopic1 = false; + bool checkTopic2 = false; + bool checkTopic3 = false; + bool checkData = true; + vm.expectEmit(checkTopic1, checkTopic2, checkTopic3, checkData); + emit RequestNotProcessed({ + requestId: s_requestCommitment.requestId, + coordinator: address(s_functionsCoordinator), + transmitter: NOP_TRANSMITTER_ADDRESS_1, + resultCode: FunctionsResponse.FulfillResult.COST_EXCEEDS_COMMITMENT + }); + + (FunctionsResponse.FulfillResult resultCode, uint96 callbackGasCostJuels) = s_functionsRouter.fulfill( + response, + err, + juelsPerGas, + costWithoutCallback, + transmitter, + commitment + ); + + assertEq(uint(resultCode), uint(FunctionsResponse.FulfillResult.COST_EXCEEDS_COMMITMENT)); + assertEq(callbackGasCostJuels, 0); + } + + event RequestProcessed( + bytes32 indexed requestId, + uint64 indexed subscriptionId, + uint96 totalCostJuels, + address transmitter, + FunctionsResponse.FulfillResult resultCode, + bytes response, + bytes err, + bytes callbackReturnData + ); + + FunctionsClientTestHelper internal s_clientWithFailingCallback; + + function test_Fulfill_SuccessUserCallbackReverts() public { + // Deploy Client with failing callback + s_clientWithFailingCallback = new FunctionsClientTestHelper(address(s_functionsRouter)); + s_clientWithFailingCallback.setRevertFulfillRequest(true); + + // Add Client as a subscription consumer + s_functionsRouter.addConsumer(s_subscriptionId, address(s_clientWithFailingCallback)); + + // Send a minimal request + string memory sourceCode = "return 'hello world';"; + + vm.recordLogs(); + bytes32 requestId = s_clientWithFailingCallback.sendSimpleRequestWithJavaScript( + sourceCode, + s_subscriptionId, + s_donId, + 5000 + ); + + // Get commitment data from OracleRequest event log + Vm.Log[] memory entries = vm.getRecordedLogs(); + (, , , , , , , FunctionsResponse.Commitment memory _commitment) = abi.decode( + entries[0].data, + (address, uint64, address, bytes, uint16, bytes32, uint64, FunctionsResponse.Commitment) + ); + s_requestCommitment = _commitment; + + // Send as committed Coordinator + vm.stopPrank(); + vm.startPrank(address(s_functionsCoordinator)); + + bytes memory response = bytes("hello world!"); + bytes memory err = new bytes(0); + uint96 juelsPerGas = 0; + uint96 costWithoutCallback = 0; + address transmitter = NOP_TRANSMITTER_ADDRESS_1; + FunctionsResponse.Commitment memory commitment = s_requestCommitment; + + // topic0 (function signature, always checked), NOT topic1 (false), NOT topic2 (false), NOT topic3 (false), and data (true). + bool checkTopic1 = false; + bool checkTopic2 = false; + bool checkTopic3 = false; + bool checkData = true; + vm.expectEmit(checkTopic1, checkTopic2, checkTopic3, checkData); + emit RequestProcessed({ + requestId: requestId, + subscriptionId: s_subscriptionId, + totalCostJuels: s_adminFee + costWithoutCallback, + transmitter: transmitter, + resultCode: FunctionsResponse.FulfillResult.USER_CALLBACK_ERROR, + response: response, + err: err, + callbackReturnData: vm.parseBytes( + "0x08c379a00000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000f61736b656420746f207265766572740000000000000000000000000000000000" + ) // TODO: build this + }); + + (FunctionsResponse.FulfillResult resultCode, uint96 callbackGasCostJuels) = s_functionsRouter.fulfill( + response, + err, + juelsPerGas, + costWithoutCallback, + transmitter, + commitment + ); + + assertEq(uint(resultCode), uint(FunctionsResponse.FulfillResult.USER_CALLBACK_ERROR)); + assertEq(callbackGasCostJuels, 0); + } + + function test_Fulfill_SuccessUserCallbackRunsOutOfGas() public { + string memory sourceCode = "return 'hello world';"; + bytes memory secrets; + string[] memory args = new string[](0); + bytes[] memory bytesArgs = new bytes[](0); + uint32 callbackGasLimit = 0; + + vm.recordLogs(); + // Send a request with no gas for the callback + bytes32 requestId = s_functionsClient.sendRequest( + s_donId, + sourceCode, + secrets, + args, + bytesArgs, + s_subscriptionId, + callbackGasLimit + ); + + // Get commitment data from OracleRequest event log + Vm.Log[] memory entries = vm.getRecordedLogs(); + (, , , , , , , FunctionsResponse.Commitment memory commitment) = abi.decode( + entries[0].data, + (address, uint64, address, bytes, uint16, bytes32, uint64, FunctionsResponse.Commitment) + ); + + // Send as committed Coordinator + vm.stopPrank(); + vm.startPrank(address(s_functionsCoordinator)); + + bytes memory response = bytes("hello world!"); + bytes memory err = new bytes(0); + uint96 juelsPerGas = 0; + uint96 costWithoutCallback = 0; + address transmitter = NOP_TRANSMITTER_ADDRESS_1; + + // topic0 (function signature, always checked), NOT topic1 (false), NOT topic2 (false), NOT topic3 (false), and data (true). + vm.expectEmit(false, false, false, true); + emit RequestProcessed({ + requestId: requestId, + subscriptionId: s_subscriptionId, + totalCostJuels: s_adminFee + costWithoutCallback, // NOTE: tx.gasprice is at 0, so no callback gas used + transmitter: transmitter, + resultCode: FunctionsResponse.FulfillResult.USER_CALLBACK_ERROR, + response: response, + err: err, + callbackReturnData: new bytes(0) + }); + + vm.recordLogs(); + + (FunctionsResponse.FulfillResult resultCode, uint96 callbackGasCostJuels) = s_functionsRouter.fulfill( + response, + err, + juelsPerGas, + costWithoutCallback, + transmitter, + commitment + ); + + assertEq(uint(resultCode), uint(FunctionsResponse.FulfillResult.USER_CALLBACK_ERROR)); + assertEq(callbackGasCostJuels, 0); + } + + function test_Fulfill_SuccessClientNoLongerExists() public { + // Delete the Client contract in the time between request and fulfillment + vm.etch(address(s_functionsClient), new bytes(0)); + + // Send as committed Coordinator + vm.stopPrank(); + vm.startPrank(address(s_functionsCoordinator)); + + bytes memory response = bytes("hello world!"); + bytes memory err = new bytes(0); + uint96 juelsPerGas = 0; + uint96 costWithoutCallback = 0; + address transmitter = NOP_TRANSMITTER_ADDRESS_1; + FunctionsResponse.Commitment memory commitment = s_requestCommitment; + + // topic0 (function signature, always checked), topic1 (true), topic2 (true), NOT topic3 (false), and data (true). + bool checkTopic1RequestId = true; + bool checkTopic2SubscriptionId = true; + bool checkTopic3 = false; + bool checkData = true; + vm.expectEmit(checkTopic1RequestId, checkTopic2SubscriptionId, checkTopic3, checkData); + emit RequestProcessed({ + requestId: s_requestId, + subscriptionId: s_subscriptionId, + totalCostJuels: s_adminFee + costWithoutCallback, // NOTE: tx.gasprice is at 0, so no callback gas used + transmitter: transmitter, + resultCode: FunctionsResponse.FulfillResult.USER_CALLBACK_ERROR, + response: response, + err: err, + callbackReturnData: new bytes(0) + }); + + vm.recordLogs(); + + (FunctionsResponse.FulfillResult resultCode, uint96 callbackGasCostJuels) = s_functionsRouter.fulfill( + response, + err, + juelsPerGas, + costWithoutCallback, + transmitter, + commitment + ); + + assertEq(uint(resultCode), uint(FunctionsResponse.FulfillResult.USER_CALLBACK_ERROR)); + assertEq(callbackGasCostJuels, 0); + } + + function test_Fulfill_SuccessFulfilled() public { + // Send as committed Coordinator + vm.stopPrank(); + vm.startPrank(address(s_functionsCoordinator)); + + bytes memory response = bytes("hello world!"); + bytes memory err = new bytes(0); + uint96 juelsPerGas = 0; + uint96 costWithoutCallback = 0; + address transmitter = NOP_TRANSMITTER_ADDRESS_1; + + // topic0 (function signature, always checked), NOT topic1 (false), NOT topic2 (false), NOT topic3 (false), and data (true). + bool checkTopic1 = false; + bool checkTopic2 = false; + bool checkTopic3 = false; + bool checkData = true; + vm.expectEmit(checkTopic1, checkTopic2, checkTopic3, checkData); + emit RequestProcessed({ + requestId: s_requestId, + subscriptionId: s_subscriptionId, + totalCostJuels: s_adminFee + costWithoutCallback, // NOTE: tx.gasprice is at 0, so no callback gas used + transmitter: transmitter, + resultCode: FunctionsResponse.FulfillResult.FULFILLED, + response: response, + err: err, + callbackReturnData: new bytes(0) + }); + + vm.recordLogs(); + + (FunctionsResponse.FulfillResult resultCode, uint96 callbackGasCostJuels) = s_functionsRouter.fulfill( + response, + err, + juelsPerGas, + costWithoutCallback, + transmitter, + s_requestCommitment + ); + + assertEq(uint(resultCode), uint(FunctionsResponse.FulfillResult.FULFILLED)); + assertEq(callbackGasCostJuels, 0); + } } /// @notice #_callback -contract FunctionsRouter__Callback { - +contract FunctionsRouter__Callback is FunctionsRouterSetup { + // TODO: make contract internal function helper } /// @notice #getContractById -contract FunctionsRouter_GetContractById { +contract FunctionsRouter_GetContractById is FunctionsRoutesSetup { + function test_GetContractById_RevertIfRouteDoesNotExist() public { + // Send as stranger + vm.stopPrank(); + vm.startPrank(STRANGER_ADDRESS); + + bytes32 invalidRouteId = bytes32("this does not exist"); + + vm.expectRevert(abi.encodeWithSelector(FunctionsRouter.RouteNotFound.selector, invalidRouteId)); + s_functionsRouter.getContractById(invalidRouteId); + } + function test_GetContractById_SuccessIfRouteExists() public { + // Send as stranger + vm.stopPrank(); + vm.startPrank(STRANGER_ADDRESS); + + address routeDestination = s_functionsRouter.getContractById(s_donId); + assertEq(routeDestination, address(s_functionsCoordinator)); + } } /// @notice #getProposedContractById -contract FunctionsRouter_GetProposedContractById { +contract FunctionsRouter_GetProposedContractById is FunctionsRoutesSetup { + FunctionsCoordinatorTestHelper internal s_functionsCoordinator2; // TODO: use actual FunctionsCoordinator instead of helper + + function setUp() public virtual override { + FunctionsRoutesSetup.setUp(); + + // Deploy new Coordinator contract + s_functionsCoordinator2 = new FunctionsCoordinatorTestHelper( + address(s_functionsRouter), + getCoordinatorConfig(), + address(s_linkEthFeed) + ); + + // Propose new Coordinator contract + bytes32[] memory proposedContractSetIds = new bytes32[](1); + proposedContractSetIds[0] = s_donId; + address[] memory proposedContractSetAddresses = new address[](1); + proposedContractSetAddresses[0] = address(s_functionsCoordinator2); + + s_functionsRouter.proposeContractsUpdate(proposedContractSetIds, proposedContractSetAddresses); + } + + function test_GetProposedContractById_RevertIfRouteDoesNotExist() public { + // Send as stranger + vm.stopPrank(); + vm.startPrank(STRANGER_ADDRESS); + + bytes32 invalidRouteId = bytes32("this does not exist"); + + vm.expectRevert(abi.encodeWithSelector(FunctionsRouter.RouteNotFound.selector, invalidRouteId)); + s_functionsRouter.getProposedContractById(invalidRouteId); + } + + function test_GetProposedContractById_SuccessIfRouteExists() public { + // Send as stranger + vm.stopPrank(); + vm.startPrank(STRANGER_ADDRESS); + address routeDestination = s_functionsRouter.getProposedContractById(s_donId); + assertEq(routeDestination, address(s_functionsCoordinator2)); + } } /// @notice #getProposedContractSet -contract FunctionsRouter_GetProposedContractSet { +contract FunctionsRouter_GetProposedContractSet is FunctionsRoutesSetup { + FunctionsCoordinatorTestHelper internal s_functionsCoordinator2; // TODO: use actual FunctionsCoordinator instead of helper + bytes32[] s_proposedContractSetIds; + address[] s_proposedContractSetAddresses; + + function setUp() public virtual override { + FunctionsRoutesSetup.setUp(); + + // Deploy new Coordinator contract + s_functionsCoordinator2 = new FunctionsCoordinatorTestHelper( + address(s_functionsRouter), + getCoordinatorConfig(), + address(s_linkEthFeed) + ); + + // Propose new Coordinator contract + s_proposedContractSetIds = new bytes32[](1); + s_proposedContractSetIds[0] = s_donId; + s_proposedContractSetAddresses = new address[](1); + s_proposedContractSetAddresses[0] = address(s_functionsCoordinator2); + s_functionsRouter.proposeContractsUpdate(s_proposedContractSetIds, s_proposedContractSetAddresses); + } + + function test_GetProposedContractSet_Success() public { + // Send as stranger + vm.stopPrank(); + vm.startPrank(STRANGER_ADDRESS); + + (bytes32[] memory proposedContractSetIds, address[] memory proposedContractSetAddresses) = s_functionsRouter + .getProposedContractSet(); + + assertEq(proposedContractSetIds.length, 1); + assertEq(proposedContractSetIds[0], s_donId); + assertEq(proposedContractSetIds.length, 1); + assertEq(proposedContractSetAddresses[0], address(s_functionsCoordinator2)); + } } /// @notice #proposeContractsUpdate -contract FunctionsRouter_ProposeContractsUpdate { +contract FunctionsRouter_ProposeContractsUpdate is FunctionsRoutesSetup { + FunctionsCoordinatorTestHelper internal s_functionsCoordinator2; // TODO: use actual FunctionsCoordinator instead of helper + bytes32[] s_proposedContractSetIds; + address[] s_proposedContractSetAddresses; + + function setUp() public virtual override { + FunctionsRoutesSetup.setUp(); + + // Deploy new Coordinator contract + s_functionsCoordinator2 = new FunctionsCoordinatorTestHelper( + address(s_functionsRouter), + getCoordinatorConfig(), + address(s_linkEthFeed) + ); + + // Propose new Coordinator contract + s_proposedContractSetIds = new bytes32[](1); + s_proposedContractSetIds[0] = s_donId; + s_proposedContractSetAddresses = new address[](1); + s_proposedContractSetAddresses[0] = address(s_functionsCoordinator2); + } + + function test_ProposeContractsUpdate_RevertIfNotOwner() public { + // Send as stranger + vm.stopPrank(); + vm.startPrank(STRANGER_ADDRESS); + + vm.expectRevert("Only callable by owner"); + s_functionsRouter.proposeContractsUpdate(s_proposedContractSetIds, s_proposedContractSetAddresses); + } + + function test_ProposeContractsUpdate_RevertIfLengthMismatch() public { + bytes32[] memory proposedContractSetIds = new bytes32[](1); + proposedContractSetIds[0] = s_donId; + address[] memory proposedContractSetAddresses = new address[](1); + vm.expectRevert(FunctionsRouter.InvalidProposal.selector); + s_functionsRouter.proposeContractsUpdate(proposedContractSetIds, proposedContractSetAddresses); + } + + function test_ProposeContractsUpdate_RevertIfExceedsMaxProposal() public { + uint8 MAX_PROPOSAL_SET_LENGTH = 8; + uint8 INVALID_PROPOSAL_SET_LENGTH = MAX_PROPOSAL_SET_LENGTH + 1; + + // Generate some mock data + bytes32[] memory proposedContractSetIds = new bytes32[](INVALID_PROPOSAL_SET_LENGTH); + for (uint8 i = 0; i < INVALID_PROPOSAL_SET_LENGTH; ++i) { + proposedContractSetIds[i] = bytes32(uint256(i + 111)); + } + address[] memory proposedContractSetAddresses = new address[](INVALID_PROPOSAL_SET_LENGTH); + for (uint8 i = 0; i < INVALID_PROPOSAL_SET_LENGTH; ++i) { + proposedContractSetAddresses[i] = address(uint160(uint(keccak256(abi.encodePacked(i + 111))))); + } + + vm.expectRevert(FunctionsRouter.InvalidProposal.selector); + s_functionsRouter.proposeContractsUpdate(proposedContractSetIds, proposedContractSetAddresses); + } + + function test_ProposeContractsUpdate_RevertIfEmptyAddress() public { + bytes32[] memory proposedContractSetIds = new bytes32[](1); + proposedContractSetIds[0] = s_donId; + address[] memory proposedContractSetAddresses = new address[](1); + proposedContractSetAddresses[0] = address(0); + + vm.expectRevert(FunctionsRouter.InvalidProposal.selector); + s_functionsRouter.proposeContractsUpdate(proposedContractSetIds, proposedContractSetAddresses); + } + + function test_ProposeContractsUpdate_RevertIfNotNewContract() public { + bytes32[] memory proposedContractSetIds = new bytes32[](1); + proposedContractSetIds[0] = s_donId; + address[] memory proposedContractSetAddresses = new address[](1); + proposedContractSetAddresses[0] = address(s_functionsCoordinator); + + vm.expectRevert(FunctionsRouter.InvalidProposal.selector); + s_functionsRouter.proposeContractsUpdate(proposedContractSetIds, proposedContractSetAddresses); + } + + event ContractProposed( + bytes32 proposedContractSetId, + address proposedContractSetFromAddress, + address proposedContractSetToAddress + ); + + function test_ProposeContractsUpdate_Success() public { + // topic0 (function signature, always checked), NOT topic1 (false), NOT topic2 (false), NOT topic3 (false), and data (true). + bool checkTopic1 = false; + bool checkTopic2 = false; + bool checkTopic3 = false; + bool checkData = true; + vm.expectEmit(checkTopic1, checkTopic2, checkTopic3, checkData); + emit ContractProposed({ + proposedContractSetId: s_proposedContractSetIds[0], + proposedContractSetFromAddress: address(s_functionsCoordinator), + proposedContractSetToAddress: s_proposedContractSetAddresses[0] + }); + + s_functionsRouter.proposeContractsUpdate(s_proposedContractSetIds, s_proposedContractSetAddresses); + } } /// @notice #updateContracts -contract FunctionsRouter_UpdateContracts { +contract FunctionsRouter_UpdateContracts is FunctionsRoutesSetup { + FunctionsCoordinatorTestHelper internal s_functionsCoordinator2; // TODO: use actual FunctionsCoordinator instead of helper + bytes32[] s_proposedContractSetIds; + address[] s_proposedContractSetAddresses; + function setUp() public virtual override { + FunctionsRoutesSetup.setUp(); + + // Deploy new Coordinator contract + s_functionsCoordinator2 = new FunctionsCoordinatorTestHelper( + address(s_functionsRouter), + getCoordinatorConfig(), + address(s_linkEthFeed) + ); + + // Propose new Coordinator contract + s_proposedContractSetIds = new bytes32[](1); + s_proposedContractSetIds[0] = s_donId; + s_proposedContractSetAddresses = new address[](1); + s_proposedContractSetAddresses[0] = address(s_functionsCoordinator2); + + s_functionsRouter.proposeContractsUpdate(s_proposedContractSetIds, s_proposedContractSetAddresses); + } + + function test_UpdateContracts_RevertIfNotOwner() public { + // Send as stranger + vm.stopPrank(); + vm.startPrank(STRANGER_ADDRESS); + + vm.expectRevert("Only callable by owner"); + s_functionsRouter.updateContracts(); + } + + event ContractUpdated(bytes32 id, address from, address to); + + function test_UpdateContracts_Success() public { + // topic0 (function signature, always checked), NOT topic1 (false), NOT topic2 (false), NOT topic3 (false), and data (true). + bool checkTopic1 = false; + bool checkTopic2 = false; + bool checkTopic3 = false; + bool checkData = true; + vm.expectEmit(checkTopic1, checkTopic2, checkTopic3, checkData); + emit ContractUpdated({ + id: s_proposedContractSetIds[0], + from: address(s_functionsCoordinator), + to: s_proposedContractSetAddresses[0] + }); + + s_functionsRouter.updateContracts(); + + (bytes32[] memory proposedContractSetIds, address[] memory proposedContractSetAddresses) = s_functionsRouter + .getProposedContractSet(); + + assertEq(proposedContractSetIds.length, 0); + assertEq(proposedContractSetAddresses.length, 0); + } } /// @notice #_whenNotPaused -contract FunctionsRouter__WhenNotPaused { - +contract FunctionsRouter__WhenNotPaused is FunctionsRouterSetup { + // TODO: make contract internal function helper } /// @notice #_onlyRouterOwner -contract FunctionsRouter__OnlyRouterOwner { - +contract FunctionsRouter__OnlyRouterOwner is FunctionsRouterSetup { + // TODO: make contract internal function helper } /// @notice #_onlySenderThatAcceptedToS -contract FunctionsRouter__OnlySenderThatAcceptedToS { - +contract FunctionsRouter__OnlySenderThatAcceptedToS is FunctionsRouterSetup { + // TODO: make contract internal function helper } /// @notice #pause diff --git a/contracts/src/v0.8/functions/tests/1_0_0/FunctionsSubscriptions.t.sol b/contracts/src/v0.8/functions/tests/1_0_0/FunctionsSubscriptions.t.sol index ab77a33691d..928ede95bf2 100644 --- a/contracts/src/v0.8/functions/tests/1_0_0/FunctionsSubscriptions.t.sol +++ b/contracts/src/v0.8/functions/tests/1_0_0/FunctionsSubscriptions.t.sol @@ -1,105 +1,504 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.19; +import {BaseTest} from "./BaseTest.t.sol"; import {FunctionsRouter} from "../../dev/1_0_0/FunctionsRouter.sol"; import {FunctionsSubscriptions} from "../../dev/1_0_0/FunctionsSubscriptions.sol"; +import {FunctionsResponse} from "../../dev/1_0_0/libraries/FunctionsResponse.sol"; -import {FunctionsRouterSetup, FunctionsOwnerAcceptTermsOfService} from "./Setup.t.sol"; +import {IERC20} from "../../../vendor/openzeppelin-solidity/v4.8.0/contracts/token/ERC20/IERC20.sol"; + +import {FunctionsRouterSetup, FunctionsOwnerAcceptTermsOfServiceSetup, FunctionsClientSetup, FunctionsSubscriptionSetup, FunctionsClientRequestSetup, FunctionsFulfillmentSetup} from "./Setup.t.sol"; + +import "forge-std/Vm.sol"; // ================================================================ // | Functions Subscriptions | // ================================================================ +contract FunctionsSubscriptions_Constructor_Helper is FunctionsSubscriptions { + constructor(address link) FunctionsSubscriptions(link) {} + + function getLinkToken() public view returns (IERC20) { + return IERC20(i_linkToken); + } + + // overrides + function _getMaxConsumers() internal pure override returns (uint16) { + return 0; + } + + function _getSubscriptionDepositDetails() internal pure override returns (uint16, uint72) { + return (0, 0); + } + + function _onlySenderThatAcceptedToS() internal override {} + + function _onlyRouterOwner() internal override {} + + function _whenNotPaused() internal override {} +} + /// @notice #constructor -contract FunctionsSubscriptions_Constructor { +contract FunctionsSubscriptions_Constructor is BaseTest { + FunctionsSubscriptions_Constructor_Helper s_subscriptionsHelper; + address internal s_linkToken = 0x01BE23585060835E02B77ef475b0Cc51aA1e0709; + + function setUp() public virtual override { + BaseTest.setUp(); + s_subscriptionsHelper = new FunctionsSubscriptions_Constructor_Helper(s_linkToken); + } + function test_Constructor_Success() public { + assertEq(address(s_linkToken), address(s_subscriptionsHelper.getLinkToken())); + } } /// @notice #_markRequestInFlight contract FunctionsSubscriptions__MarkRequestInFlight { - + // TODO: make contract internal function helper } /// @notice #_pay contract FunctionsSubscriptions__Pay { - + // TODO: make contract internal function helper } /// @notice #ownerCancelSubscription -contract FunctionsSubscriptions_OwnerCancelSubscription { +contract FunctionsSubscriptions_OwnerCancelSubscription is FunctionsSubscriptionSetup { + function test_OwnerCancelSubscription_RevertIfNotOwner() public { + // Send as stranger + vm.stopPrank(); + vm.startPrank(STRANGER_ADDRESS); + + vm.expectRevert("Only callable by owner"); + s_functionsRouter.ownerCancelSubscription(s_subscriptionId); + } + + function test_OwnerCancelSubscription_RevertIfNoSubscription() public { + vm.expectRevert(FunctionsSubscriptions.InvalidSubscription.selector); + uint64 invalidSubscriptionId = 123456789; + s_functionsRouter.ownerCancelSubscription(invalidSubscriptionId); + } + + function test_OwnerCancelSubscription_SuccessSubOwnerRefunded() public { + uint256 subscriptionOwnerBalanceBefore = s_linkToken.balanceOf(OWNER_ADDRESS); + s_functionsRouter.ownerCancelSubscription(s_subscriptionId); + uint256 subscriptionOwnerBalanceAfter = s_linkToken.balanceOf(OWNER_ADDRESS); + assertEq(subscriptionOwnerBalanceBefore + s_subscriptionInitialFunding, subscriptionOwnerBalanceAfter); + } + + function test_OwnerCancelSubscription_SuccessWhenRequestInFlight() public { + // send request + string memory sourceCode = "return 'hello world';"; + bytes memory secrets; + string[] memory args = new string[](0); + bytes[] memory bytesArgs = new bytes[](0); + + s_functionsClient.sendRequest(s_donId, sourceCode, secrets, args, bytesArgs, s_subscriptionId, 5000); + s_functionsRouter.ownerCancelSubscription(s_subscriptionId); + } + + function test_OwnerCancelSubscription_SuccessDeletesSubscription() public { + s_functionsRouter.ownerCancelSubscription(s_subscriptionId); + // Subscription should no longer exist + vm.expectRevert(FunctionsSubscriptions.InvalidSubscription.selector); + s_functionsRouter.getSubscription(s_subscriptionId); + } + + event SubscriptionCanceled(uint64 indexed subscriptionId, address fundsRecipient, uint256 fundsAmount); + function test_OwnerCancelSubscription_Success() public { + uint256 subscriptionOwnerBalanceBefore = s_linkToken.balanceOf(OWNER_ADDRESS); + + // topic0 (function signature, always checked), topic1 (true), NOT topic2 (false), NOT topic3 (false), and data (true). + bool checkTopic1SubscriptionId = true; + bool checkTopic2 = false; + bool checkTopic3 = false; + bool checkData = true; + vm.expectEmit(checkTopic1SubscriptionId, checkTopic2, checkTopic3, checkData); + emit SubscriptionCanceled(s_subscriptionId, OWNER_ADDRESS, s_subscriptionInitialFunding); + + s_functionsRouter.ownerCancelSubscription(s_subscriptionId); + + uint256 subscriptionOwnerBalanceAfter = s_linkToken.balanceOf(OWNER_ADDRESS); + assertEq(subscriptionOwnerBalanceBefore + s_subscriptionInitialFunding, subscriptionOwnerBalanceAfter); + } } /// @notice #recoverFunds -contract FunctionsSubscriptions_RecoverFunds { +contract FunctionsSubscriptions_RecoverFunds is FunctionsRouterSetup { + event FundsRecovered(address to, uint256 amount); + + function test_RecoverFunds_Success() public { + uint256 fundsTransferred = 1 * 1e18; // 1 LINK + s_linkToken.transfer(address(s_functionsRouter), fundsTransferred); + + // topic0 (function signature, always checked), NOT topic1 (false), NOT topic2 (false), NOT topic3 (false), and data (true). + bool checkTopic1 = false; + bool checkTopic2 = false; + bool checkTopic3 = false; + bool checkData = true; + vm.expectEmit(checkTopic1, checkTopic2, checkTopic3, checkData); + emit FundsRecovered(OWNER_ADDRESS, fundsTransferred); + + uint256 subscriptionOwnerBalanceBefore = s_linkToken.balanceOf(OWNER_ADDRESS); + s_functionsRouter.recoverFunds(OWNER_ADDRESS); + uint256 subscriptionOwnerBalanceAfter = s_linkToken.balanceOf(OWNER_ADDRESS); + assertEq(subscriptionOwnerBalanceBefore + fundsTransferred, subscriptionOwnerBalanceAfter); + } + function test_OwnerCancelSubscription_RevertIfNotOwner() public { + // Send as stranger + vm.stopPrank(); + vm.startPrank(STRANGER_ADDRESS); + + vm.expectRevert("Only callable by owner"); + s_functionsRouter.recoverFunds(OWNER_ADDRESS); + } } /// @notice #oracleWithdraw -contract FunctionsSubscriptions_OracleWithdraw { +contract FunctionsSubscriptions_OracleWithdraw is FunctionsFulfillmentSetup { + function test_OracleWithdraw_RevertIfPaused() public { + s_functionsRouter.pause(); + // Subscription payable balances are set to the Coordinator + // Send as Coordinator contract + vm.stopPrank(); + vm.startPrank(address(s_functionsCoordinator)); + + vm.expectRevert("Pausable: paused"); + + uint96 amountToWithdraw = 1; // more than 0 + s_functionsRouter.oracleWithdraw(NOP_TRANSMITTER_ADDRESS_1, amountToWithdraw); + } + + function test_OracleWithdraw_RevertIfNoAmount() public { + // Subscription payable balances are set to the Coordinator + // Send as Coordinator contract + vm.stopPrank(); + vm.startPrank(address(s_functionsCoordinator)); + + vm.expectRevert(FunctionsSubscriptions.InvalidCalldata.selector); + + uint96 amountToWithdraw = 0; + s_functionsRouter.oracleWithdraw(NOP_TRANSMITTER_ADDRESS_1, amountToWithdraw); + } + + function test_OracleWithdraw_RevertIfAmountMoreThanBalance() public { + // Subscription payable balances are set to the Coordinator + // Send as Coordinator contract + vm.stopPrank(); + vm.startPrank(address(s_functionsCoordinator)); + + vm.expectRevert( + abi.encodeWithSelector(FunctionsSubscriptions.InsufficientBalance.selector, s_fulfillmentCoordinatorBalance) + ); + + uint96 amountToWithdraw = s_fulfillmentCoordinatorBalance + 1; + s_functionsRouter.oracleWithdraw(NOP_TRANSMITTER_ADDRESS_1, amountToWithdraw); + } + + function test_OracleWithdraw_RevertIfBalanceInvariant() public { + // Subscription payable balances are set to the Coordinator + // Send as Coordinator contract + // vm.stopPrank(); + // vm.startPrank(address(s_functionsCoordinator)); + // TODO: Use internal function helper contract to modify s_totalLinkBalance + // uint96 amountToWithdraw = s_fulfillmentCoordinatorBalance; + // vm.expectRevert(abi.encodeWithSelector(FunctionsSubscriptions.TotalBalanceInvariantViolated.selector, 0, amountToWithdraw)); + // s_functionsRouter.oracleWithdraw(NOP_TRANSMITTER_ADDRESS_1, amountToWithdraw); + } + + function test_OracleWithdraw_SuccessPaysRecipient() public { + // Subscription payable balances are set to the Coordinator + // Send as Coordinator contract + vm.stopPrank(); + vm.startPrank(address(s_functionsCoordinator)); + + uint256 transmitterBalanceBefore = s_linkToken.balanceOf(NOP_TRANSMITTER_ADDRESS_1); + + uint96 amountToWithdraw = s_fulfillmentCoordinatorBalance; + s_functionsRouter.oracleWithdraw(NOP_TRANSMITTER_ADDRESS_1, amountToWithdraw); + + uint256 transmitterBalanceAfter = s_linkToken.balanceOf(NOP_TRANSMITTER_ADDRESS_1); + assertEq(transmitterBalanceBefore + s_fulfillmentCoordinatorBalance, transmitterBalanceAfter); + } + + function test_OracleWithdraw_SuccessSetsBalanceToZero() public { + // Subscription payable balances are set to the Coordinator + // Send as Coordinator contract + vm.stopPrank(); + vm.startPrank(address(s_functionsCoordinator)); + + uint96 amountToWithdraw = s_fulfillmentCoordinatorBalance; + s_functionsRouter.oracleWithdraw(NOP_TRANSMITTER_ADDRESS_1, amountToWithdraw); + + // Attempt to withdraw 1 Juel after withdrawing full balance + vm.expectRevert(abi.encodeWithSelector(FunctionsSubscriptions.InsufficientBalance.selector, 0)); + s_functionsRouter.oracleWithdraw(NOP_TRANSMITTER_ADDRESS_1, 1); + } } /// @notice #ownerWithdraw -contract FunctionsSubscriptions_OwnerWithdraw { +contract FunctionsSubscriptions_OwnerWithdraw is FunctionsFulfillmentSetup { + function test_OwnerWithdraw_RevertIfNotOwner() public { + // Send as stranger + vm.stopPrank(); + vm.startPrank(STRANGER_ADDRESS); + + vm.expectRevert("Only callable by owner"); + s_functionsRouter.recoverFunds(OWNER_ADDRESS); + } + + function test_OwnerWithdraw_RevertIfAmountMoreThanBalance() public { + vm.expectRevert( + abi.encodeWithSelector(FunctionsSubscriptions.InsufficientBalance.selector, s_fulfillmentRouterOwnerBalance) + ); + + uint96 amountToWithdraw = s_fulfillmentRouterOwnerBalance + 1; + s_functionsRouter.ownerWithdraw(OWNER_ADDRESS, amountToWithdraw); + } + + function test_OwnerWithdraw_RevertIfBalanceInvariant() public { + // TODO: Use internal function helper contract to modify s_totalLinkBalance + // uint96 amountToWithdraw = s_fulfillmentRouterOwnerBalance; + // vm.expectRevert(abi.encodeWithSelector(FunctionsSubscriptions.TotalBalanceInvariantViolated.selector, 0, amountToWithdraw)); + // s_functionsRouter.ownerWithdraw(OWNER_ADDRESS, amountToWithdraw); + } + + function test_OwnerWithdraw_SuccessIfNoAmount() public { + uint256 balanceBefore = s_linkToken.balanceOf(OWNER_ADDRESS); + uint96 amountToWithdraw = 0; + s_functionsRouter.ownerWithdraw(OWNER_ADDRESS, amountToWithdraw); + uint256 balanceAfter = s_linkToken.balanceOf(OWNER_ADDRESS); + assertEq(balanceBefore + s_fulfillmentRouterOwnerBalance, balanceAfter); + } + + function test_OwnerWithdraw_SuccessPaysRecipient() public { + uint256 balanceBefore = s_linkToken.balanceOf(STRANGER_ADDRESS); + + uint96 amountToWithdraw = s_fulfillmentRouterOwnerBalance; + s_functionsRouter.ownerWithdraw(STRANGER_ADDRESS, amountToWithdraw); + + uint256 balanceAfter = s_linkToken.balanceOf(STRANGER_ADDRESS); + assertEq(balanceBefore + s_fulfillmentRouterOwnerBalance, balanceAfter); + } + + function test_OwnerWithdraw_SuccessSetsBalanceToZero() public { + uint96 amountToWithdraw = s_fulfillmentRouterOwnerBalance; + s_functionsRouter.ownerWithdraw(OWNER_ADDRESS, amountToWithdraw); + // Attempt to withdraw 1 Juel after withdrawing full balance + vm.expectRevert(abi.encodeWithSelector(FunctionsSubscriptions.InsufficientBalance.selector, 0)); + s_functionsRouter.ownerWithdraw(OWNER_ADDRESS, 1); + } } /// @notice #onTokenTransfer -contract FunctionsSubscriptions_OnTokenTransfer { +contract FunctionsSubscriptions_OnTokenTransfer is FunctionsSubscriptionSetup { + function test_OnTokenTransfer_RevertIfPaused() public { + s_functionsRouter.pause(); + vm.expectRevert("Pausable: paused"); + uint96 fundingAmount = 100; + s_linkToken.transferAndCall(address(s_functionsRouter), fundingAmount, abi.encode(s_subscriptionId)); + } + + function test_OnTokenTransfer_RevertIfCallerIsNotLink() public { + vm.expectRevert(FunctionsSubscriptions.OnlyCallableFromLink.selector); + uint96 fundingAmount = 100; + s_functionsRouter.onTokenTransfer(address(s_functionsRouter), fundingAmount, abi.encode(s_subscriptionId)); + } + function test_OnTokenTransfer_RevertIfCallerIsNoCalldata() public { + vm.expectRevert(FunctionsSubscriptions.InvalidCalldata.selector); + uint96 fundingAmount = 100; + s_linkToken.transferAndCall(address(s_functionsRouter), fundingAmount, new bytes(0)); + } + + function test_OnTokenTransfer_RevertIfCallerIsNoSubscription() public { + vm.expectRevert(FunctionsSubscriptions.InvalidSubscription.selector); + uint96 fundingAmount = 100; + uint64 invalidSubscriptionId = 123456789; + s_linkToken.transferAndCall(address(s_functionsRouter), fundingAmount, abi.encode(invalidSubscriptionId)); + } + + function test_OnTokenTransfer_Success() public { + uint96 fundingAmount = 100; + uint96 subscriptionBalanceBefore = s_functionsRouter.getSubscription(s_subscriptionId).balance; + s_linkToken.transferAndCall(address(s_functionsRouter), fundingAmount, abi.encode(s_subscriptionId)); + uint96 subscriptionBalanceAfter = s_functionsRouter.getSubscription(s_subscriptionId).balance; + assertEq(subscriptionBalanceBefore + fundingAmount, subscriptionBalanceAfter); + } } /// @notice #getTotalBalance -contract FunctionsSubscriptions_GetTotalBalance { +contract FunctionsSubscriptions_GetTotalBalance is FunctionsSubscriptionSetup { + function test_GetTotalBalance_Success() public { + // Send as stranger + vm.stopPrank(); + vm.startPrank(STRANGER_ADDRESS); + uint96 totalBalance = s_functionsRouter.getTotalBalance(); + assertEq(totalBalance, s_subscriptionInitialFunding); + } } /// @notice #getSubscriptionCount -contract FunctionsSubscriptions_GetSubscriptionCount { +contract FunctionsSubscriptions_GetSubscriptionCount is FunctionsSubscriptionSetup { + function test_GetSubscriptionCount_Success() public { + // Send as stranger + vm.stopPrank(); + vm.startPrank(STRANGER_ADDRESS); + uint96 subscriptionCount = s_functionsRouter.getSubscriptionCount(); + // One subscription was made during setup + assertEq(subscriptionCount, 1); + } +} + +/// @notice #getSubscriptionsInRange +contract FunctionsSubscriptions_GetSubscriptionsInRange is FunctionsSubscriptionSetup { + function setUp() public virtual override { + FunctionsSubscriptionSetup.setUp(); + + // Create 2 more subscriptions + /* uint64 subscriptionId2 = */ s_functionsRouter.createSubscription(); + uint64 subscriptionId3 = s_functionsRouter.createSubscription(); + + // Give each one unique state + // #1 subscriptionId for requests, #2 empty, #3 proposedOwner of stranger + s_functionsRouter.proposeSubscriptionOwnerTransfer(subscriptionId3, STRANGER_ADDRESS); + } + + function test_GetSubscriptionsInRange_RevertIfStartIsAfterEnd() public { + // Send as stranger + vm.stopPrank(); + vm.startPrank(STRANGER_ADDRESS); + + vm.expectRevert(FunctionsSubscriptions.InvalidCalldata.selector); + + s_functionsRouter.getSubscriptionsInRange(1, 0); + } + + function test_GetSubscriptionsInRange_RevertIfEndIsAfterLastSubscription() public { + // Send as stranger + vm.stopPrank(); + vm.startPrank(STRANGER_ADDRESS); + + uint64 lastSubscriptionId = s_functionsRouter.getSubscriptionCount(); + vm.expectRevert(FunctionsSubscriptions.InvalidCalldata.selector); + s_functionsRouter.getSubscriptionsInRange(1, lastSubscriptionId + 1); + } + + function test_GetSubscriptionsInRange_Success() public { + // Send as stranger + vm.stopPrank(); + vm.startPrank(STRANGER_ADDRESS); + + uint64 lastSubscriptionId = s_functionsRouter.getSubscriptionCount(); + FunctionsSubscriptions.Subscription[] memory subscriptions = s_functionsRouter.getSubscriptionsInRange( + s_subscriptionId, + lastSubscriptionId + ); + + assertEq(subscriptions.length, 3); + + // Check subscription 1 + assertEq(subscriptions[0].balance, s_subscriptionInitialFunding); + assertEq(subscriptions[0].owner, OWNER_ADDRESS); + assertEq(subscriptions[0].blockedBalance, 0); + assertEq(subscriptions[0].proposedOwner, address(0)); + assertEq(subscriptions[0].consumers[0], address(s_functionsClient)); + assertEq(subscriptions[0].flags, bytes32(0)); + + // Check subscription 2 + assertEq(subscriptions[1].balance, 0); + assertEq(subscriptions[1].owner, OWNER_ADDRESS); + assertEq(subscriptions[1].blockedBalance, 0); + assertEq(subscriptions[1].proposedOwner, address(0)); + assertEq(subscriptions[1].consumers.length, 0); + assertEq(subscriptions[1].flags, bytes32(0)); + + // Check subscription 3 + assertEq(subscriptions[2].balance, 0); + assertEq(subscriptions[2].owner, OWNER_ADDRESS); + assertEq(subscriptions[2].blockedBalance, 0); + assertEq(subscriptions[2].proposedOwner, address(STRANGER_ADDRESS)); + assertEq(subscriptions[2].consumers.length, 0); + assertEq(subscriptions[2].flags, bytes32(0)); + } } /// @notice #getSubscription -contract FunctionsSubscriptions_GetSubscription { +contract FunctionsSubscriptions_GetSubscription is FunctionsSubscriptionSetup { + function test_GetSubscription_Success() public { + // Send as stranger + vm.stopPrank(); + vm.startPrank(STRANGER_ADDRESS); + FunctionsSubscriptions.Subscription memory subscription = s_functionsRouter.getSubscription(s_subscriptionId); + + assertEq(subscription.balance, s_subscriptionInitialFunding); + assertEq(subscription.owner, OWNER_ADDRESS); + assertEq(subscription.blockedBalance, 0); + assertEq(subscription.proposedOwner, address(0)); + assertEq(subscription.consumers[0], address(s_functionsClient)); + assertEq(subscription.flags, bytes32(0)); + } } /// @notice #getConsumer -contract FunctionsSubscriptions_GetConsumer { +contract FunctionsSubscriptions_GetConsumer is FunctionsSubscriptionSetup { + function test_GetConsumer_Success() public { + // Send as stranger + vm.stopPrank(); + vm.startPrank(STRANGER_ADDRESS); + + FunctionsSubscriptions.Consumer memory consumer = s_functionsRouter.getConsumer( + address(s_functionsClient), + s_subscriptionId + ); + assertEq(consumer.allowed, true); + assertEq(consumer.initiatedRequests, 0); + assertEq(consumer.completedRequests, 0); + } } /// @notice #_isExistingSubscription -contract FunctionsSubscriptions__IsExistingSubscription { - +contract FunctionsSubscriptions__IsExistingSubscription is FunctionsSubscriptionSetup { + // TODO: make contract internal function helper } /// @notice #_isAllowedConsumer contract FunctionsSubscriptions__IsAllowedConsumer { - + // TODO: make contract internal function helper } /// @notice #createSubscription -contract FunctionsSubscriptions_createSubscription is FunctionsOwnerAcceptTermsOfService { - function setUp() public virtual override { - FunctionsOwnerAcceptTermsOfService.setUp(); - } - +contract FunctionsSubscriptions_createSubscription is FunctionsOwnerAcceptTermsOfServiceSetup { event SubscriptionCreated(uint64 indexed subscriptionId, address owner); function test_CreateSubscription_Success() public { - vm.expectEmit(true, false, false, true); + // topic0 (function signature, always checked), topic1 (true), NOT topic2 (false), NOT topic3 (false), and data (true). + bool checkTopic1 = true; + bool checkTopic2 = false; + bool checkTopic3 = false; + bool checkData = true; + + vm.expectEmit(checkTopic1, checkTopic2, checkTopic3, checkData); emit SubscriptionCreated(1, OWNER_ADDRESS); uint64 firstCallSubscriptionId = s_functionsRouter.createSubscription(); assertEq(firstCallSubscriptionId, 1); - vm.expectEmit(true, false, false, true); + vm.expectEmit(checkTopic1, checkTopic2, checkTopic3, checkData); emit SubscriptionCreated(2, OWNER_ADDRESS); uint64 secondCallSubscriptionId = s_functionsRouter.createSubscription(); assertEq(secondCallSubscriptionId, 2); - vm.expectEmit(true, false, false, true); + vm.expectEmit(checkTopic1, checkTopic2, checkTopic3, checkData); emit SubscriptionCreated(3, OWNER_ADDRESS); uint64 thirdCallSubscriptionId = s_functionsRouter.createSubscription(); assertEq(thirdCallSubscriptionId, 3); @@ -123,66 +522,742 @@ contract FunctionsSubscriptions_createSubscription is FunctionsOwnerAcceptTermsO } /// @notice #createSubscriptionWithConsumer -contract FunctionsSubscriptions_CreateSubscriptionWithConsumer { +contract FunctionsSubscriptions_CreateSubscriptionWithConsumer is FunctionsClientSetup { + event SubscriptionCreated(uint64 indexed subscriptionId, address owner); + event SubscriptionConsumerAdded(uint64 indexed subscriptionId, address consumer); + + function test_CreateSubscriptionWithConsumer_Success() public { + // topic0 (function signature, always checked), topic1 (true), NOT topic2 (false), NOT topic3 (false), and data (true). + bool checkTopic1 = true; + bool checkTopic2 = false; + bool checkTopic3 = false; + bool checkData = true; + + vm.expectEmit(checkTopic1, checkTopic2, checkTopic3, checkData); + emit SubscriptionCreated(1, OWNER_ADDRESS); + vm.expectEmit(checkTopic1, checkTopic2, checkTopic3, checkData); + emit SubscriptionConsumerAdded(1, address(s_functionsClient)); + uint64 firstCallSubscriptionId = s_functionsRouter.createSubscriptionWithConsumer(address(s_functionsClient)); + assertEq(firstCallSubscriptionId, 1); + assertEq(s_functionsRouter.getSubscription(firstCallSubscriptionId).consumers[0], address(s_functionsClient)); + + vm.expectEmit(checkTopic1, checkTopic2, checkTopic3, checkData); + emit SubscriptionCreated(2, OWNER_ADDRESS); + vm.expectEmit(checkTopic1, checkTopic2, checkTopic3, checkData); + emit SubscriptionConsumerAdded(2, address(s_functionsClient)); + uint64 secondCallSubscriptionId = s_functionsRouter.createSubscriptionWithConsumer(address(s_functionsClient)); + assertEq(secondCallSubscriptionId, 2); + assertEq(s_functionsRouter.getSubscription(secondCallSubscriptionId).consumers[0], address(s_functionsClient)); + + vm.expectEmit(checkTopic1, checkTopic2, checkTopic3, checkData); + emit SubscriptionCreated(3, OWNER_ADDRESS); + vm.expectEmit(checkTopic1, checkTopic2, checkTopic3, checkData); + emit SubscriptionConsumerAdded(3, address(s_functionsClient)); + uint64 thirdCallSubscriptionId = s_functionsRouter.createSubscriptionWithConsumer(address(s_functionsClient)); + assertEq(thirdCallSubscriptionId, 3); + assertEq(s_functionsRouter.getSubscription(thirdCallSubscriptionId).consumers[0], address(s_functionsClient)); + } + function test_CreateSubscriptionWithConsumer_RevertIfPaused() public { + s_functionsRouter.pause(); + + vm.expectRevert("Pausable: paused"); + s_functionsRouter.createSubscriptionWithConsumer(address(s_functionsClient)); + } + + function test_CreateSubscriptionWithConsumer_RevertIfNotAllowedSender() public { + // Send as stranger, who has not accepted Terms of Service + vm.stopPrank(); + vm.startPrank(STRANGER_ADDRESS); + + vm.expectRevert(abi.encodeWithSelector(FunctionsRouter.SenderMustAcceptTermsOfService.selector, STRANGER_ADDRESS)); + s_functionsRouter.createSubscriptionWithConsumer(address(s_functionsClient)); + } } /// @notice #proposeSubscriptionOwnerTransfer -contract FunctionsSubscriptions_ProposeSubscriptionOwnerTransfer { +contract FunctionsSubscriptions_ProposeSubscriptionOwnerTransfer is FunctionsSubscriptionSetup { + uint256 internal NEW_OWNER_PRIVATE_KEY_WITH_TOS = 0x3; + address internal NEW_OWNER_ADDRESS_WITH_TOS = vm.addr(NEW_OWNER_PRIVATE_KEY_WITH_TOS); + uint256 internal NEW_OWNER_PRIVATE_KEY_WITHOUT_TOS = 0x4; + address internal NEW_OWNER_ADDRESS_WITHOUT_TOS = vm.addr(NEW_OWNER_PRIVATE_KEY_WITHOUT_TOS); + function setUp() public virtual override { + FunctionsSubscriptionSetup.setUp(); + + // Accept ToS as new owner + vm.stopPrank(); + vm.startPrank(NEW_OWNER_ADDRESS_WITH_TOS); + bytes32 message = s_termsOfServiceAllowList.getMessage(NEW_OWNER_ADDRESS_WITH_TOS, NEW_OWNER_ADDRESS_WITH_TOS); + bytes32 prefixedMessage = keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", message)); + (uint8 v, bytes32 r, bytes32 s) = vm.sign(TOS_SIGNER_PRIVATE_KEY, prefixedMessage); + s_termsOfServiceAllowList.acceptTermsOfService(NEW_OWNER_ADDRESS_WITH_TOS, NEW_OWNER_ADDRESS_WITH_TOS, r, s, v); + + vm.stopPrank(); + vm.startPrank(OWNER_ADDRESS); + } + + function test_ProposeSubscriptionOwnerTransfer_RevertIfPaused() public { + s_functionsRouter.pause(); + + vm.expectRevert("Pausable: paused"); + s_functionsRouter.proposeSubscriptionOwnerTransfer(s_subscriptionId, NEW_OWNER_ADDRESS_WITH_TOS); + } + + function test_ProposeSubscriptionOwnerTransfer_RevertIfNoSubscription() public { + vm.expectRevert(FunctionsSubscriptions.InvalidSubscription.selector); + uint64 invalidSubscriptionId = 123456789; + s_functionsRouter.proposeSubscriptionOwnerTransfer(invalidSubscriptionId, NEW_OWNER_ADDRESS_WITH_TOS); + } + + function test_ProposeSubscriptionOwnerTransfer_RevertIfNotSubscriptionOwner() public { + // Send as non-owner, who has accepted Terms of Service + vm.stopPrank(); + vm.startPrank(NEW_OWNER_ADDRESS_WITH_TOS); + + vm.expectRevert(FunctionsSubscriptions.MustBeSubscriptionOwner.selector); + s_functionsRouter.proposeSubscriptionOwnerTransfer(s_subscriptionId, NEW_OWNER_ADDRESS_WITH_TOS); + } + + function test_ProposeSubscriptionOwnerTransfer_RevertIfNotAllowedSender() public { + // Remove owner from Allow List + s_termsOfServiceAllowList.blockSender(OWNER_ADDRESS); + + vm.expectRevert(abi.encodeWithSelector(FunctionsRouter.SenderMustAcceptTermsOfService.selector, OWNER_ADDRESS)); + s_functionsRouter.proposeSubscriptionOwnerTransfer(s_subscriptionId, NEW_OWNER_ADDRESS_WITH_TOS); + } + + function test_ProposeSubscriptionOwnerTransfer_RevertIfEmptyNewOwner() public { + address EMPTY_ADDRESS = address(0); + vm.expectRevert(FunctionsSubscriptions.InvalidCalldata.selector); + s_functionsRouter.proposeSubscriptionOwnerTransfer(s_subscriptionId, EMPTY_ADDRESS); + } + + function test_ProposeSubscriptionOwnerTransfer_RevertIfInvalidNewOwner() public { + s_functionsRouter.proposeSubscriptionOwnerTransfer(s_subscriptionId, NEW_OWNER_ADDRESS_WITH_TOS); + vm.expectRevert(FunctionsSubscriptions.InvalidCalldata.selector); + s_functionsRouter.proposeSubscriptionOwnerTransfer(s_subscriptionId, NEW_OWNER_ADDRESS_WITH_TOS); + } + + event SubscriptionOwnerTransferRequested(uint64 indexed subscriptionId, address from, address to); + + function test_ProposeSubscriptionOwnerTransfer_Success() public { + // topic0 (function signature, always checked), topic1 (true), NOT topic2 (false), NOT topic3 (false), and data (true). + bool checkTopic1 = true; + bool checkTopic2 = false; + bool checkTopic3 = false; + bool checkData = true; + + vm.expectEmit(checkTopic1, checkTopic2, checkTopic3, checkData); + emit SubscriptionOwnerTransferRequested(s_subscriptionId, OWNER_ADDRESS, NEW_OWNER_ADDRESS_WITH_TOS); + s_functionsRouter.proposeSubscriptionOwnerTransfer(s_subscriptionId, NEW_OWNER_ADDRESS_WITH_TOS); + assertEq(s_functionsRouter.getSubscription(s_subscriptionId).proposedOwner, NEW_OWNER_ADDRESS_WITH_TOS); + } } /// @notice #acceptSubscriptionOwnerTransfer -contract FunctionsSubscriptions_AcceptSubscriptionOwnerTransfer { +contract FunctionsSubscriptions_AcceptSubscriptionOwnerTransfer is FunctionsSubscriptionSetup { + uint256 internal NEW_OWNER_PRIVATE_KEY_WITH_TOS = 0x3; + address internal NEW_OWNER_ADDRESS_WITH_TOS = vm.addr(NEW_OWNER_PRIVATE_KEY_WITH_TOS); + uint256 internal NEW_OWNER_PRIVATE_KEY_WITHOUT_TOS = 0x4; + address internal NEW_OWNER_ADDRESS_WITHOUT_TOS = vm.addr(NEW_OWNER_PRIVATE_KEY_WITHOUT_TOS); + + function setUp() public virtual override { + FunctionsSubscriptionSetup.setUp(); + + // Accept ToS as new owner + vm.stopPrank(); + vm.startPrank(NEW_OWNER_ADDRESS_WITH_TOS); + bytes32 message = s_termsOfServiceAllowList.getMessage(NEW_OWNER_ADDRESS_WITH_TOS, NEW_OWNER_ADDRESS_WITH_TOS); + bytes32 prefixedMessage = keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", message)); + (uint8 v, bytes32 r, bytes32 s) = vm.sign(TOS_SIGNER_PRIVATE_KEY, prefixedMessage); + s_termsOfServiceAllowList.acceptTermsOfService(NEW_OWNER_ADDRESS_WITH_TOS, NEW_OWNER_ADDRESS_WITH_TOS, r, s, v); + + vm.stopPrank(); + vm.startPrank(OWNER_ADDRESS); + } + + function test_AcceptSubscriptionOwnerTransfer_RevertIfPaused() public { + s_functionsRouter.proposeSubscriptionOwnerTransfer(s_subscriptionId, NEW_OWNER_ADDRESS_WITH_TOS); + s_functionsRouter.pause(); + + // Send as new owner, who has accepted Terms of Service + vm.stopPrank(); + vm.startPrank(NEW_OWNER_ADDRESS_WITH_TOS); + + vm.expectRevert("Pausable: paused"); + s_functionsRouter.acceptSubscriptionOwnerTransfer(s_subscriptionId); + } + + function test_AcceptSubscriptionOwnerTransfer_RevertIfNotAllowedSender() public { + s_functionsRouter.proposeSubscriptionOwnerTransfer(s_subscriptionId, NEW_OWNER_ADDRESS_WITHOUT_TOS); + + // Send as new owner, who has NOT accepted Terms of Service + vm.stopPrank(); + vm.startPrank(NEW_OWNER_ADDRESS_WITHOUT_TOS); + + vm.expectRevert( + abi.encodeWithSelector(FunctionsRouter.SenderMustAcceptTermsOfService.selector, NEW_OWNER_ADDRESS_WITHOUT_TOS) + ); + s_functionsRouter.acceptSubscriptionOwnerTransfer(s_subscriptionId); + } + + function test_AcceptSubscriptionOwnerTransfer_RevertIfSenderBecomesBlocked() public { + // Propose an address that is allowed to accept ownership + s_functionsRouter.proposeSubscriptionOwnerTransfer(s_subscriptionId, NEW_OWNER_ADDRESS_WITH_TOS); + bool hasAccess = s_termsOfServiceAllowList.hasAccess(NEW_OWNER_ADDRESS_WITH_TOS, new bytes(0)); + assertEq(hasAccess, true); + + // Revoke access + s_termsOfServiceAllowList.blockSender(NEW_OWNER_ADDRESS_WITH_TOS); + + // Send as blocked address + vm.stopPrank(); + vm.startPrank(NEW_OWNER_ADDRESS_WITH_TOS); + + vm.expectRevert( + abi.encodeWithSelector(FunctionsRouter.SenderMustAcceptTermsOfService.selector, NEW_OWNER_ADDRESS_WITH_TOS) + ); + s_functionsRouter.acceptSubscriptionOwnerTransfer(s_subscriptionId); + } + function test_AcceptSubscriptionOwnerTransfer_RevertIfSenderIsNotNewOwner() public { + s_functionsRouter.proposeSubscriptionOwnerTransfer(s_subscriptionId, STRANGER_ADDRESS); + + // Send as someone who is not hte proposed new owner + vm.stopPrank(); + vm.startPrank(NEW_OWNER_ADDRESS_WITH_TOS); + + vm.expectRevert(abi.encodeWithSelector(FunctionsSubscriptions.MustBeProposedOwner.selector, STRANGER_ADDRESS)); + s_functionsRouter.acceptSubscriptionOwnerTransfer(s_subscriptionId); + } + + event SubscriptionOwnerTransferred(uint64 indexed subscriptionId, address from, address to); + + function test_AcceptSubscriptionOwnerTransfer_Success() public { + s_functionsRouter.proposeSubscriptionOwnerTransfer(s_subscriptionId, NEW_OWNER_ADDRESS_WITH_TOS); + + // Send as new owner, who has accepted Terms of Service + vm.stopPrank(); + vm.startPrank(NEW_OWNER_ADDRESS_WITH_TOS); + + // topic0 (function signature, always checked), NOT topic1 (false), NOT topic2 (false), NOT topic3 (false), and data (true). + bool checkTopic1 = false; + bool checkTopic2 = false; + bool checkTopic3 = false; + bool checkData = true; + vm.expectEmit(checkTopic1, checkTopic2, checkTopic3, checkData); + emit SubscriptionOwnerTransferred(s_subscriptionId, OWNER_ADDRESS, NEW_OWNER_ADDRESS_WITH_TOS); + + s_functionsRouter.acceptSubscriptionOwnerTransfer(s_subscriptionId); + + FunctionsSubscriptions.Subscription memory subscription = s_functionsRouter.getSubscription(s_subscriptionId); + assertEq(subscription.owner, NEW_OWNER_ADDRESS_WITH_TOS); + assertEq(subscription.proposedOwner, address(0)); + } } /// @notice #removeConsumer -contract FunctionsSubscriptions_RemoveConsumer { +contract FunctionsSubscriptions_RemoveConsumer is FunctionsSubscriptionSetup { + function test_RemoveConsumer_RevertIfPaused() public { + s_functionsRouter.pause(); + + vm.expectRevert("Pausable: paused"); + s_functionsRouter.removeConsumer(s_subscriptionId, address(s_functionsClient)); + } + function test_RemoveConsumer_RevertIfNoSubscription() public { + vm.expectRevert(FunctionsSubscriptions.InvalidSubscription.selector); + uint64 invalidSubscriptionId = 123456789; + s_functionsRouter.removeConsumer(invalidSubscriptionId, address(s_functionsClient)); + } + + function test_RemoveConsumer_RevertIfNotSubscriptionOwner() public { + // Accept ToS as stranger + vm.stopPrank(); + vm.startPrank(STRANGER_ADDRESS); + bytes32 message = s_termsOfServiceAllowList.getMessage(STRANGER_ADDRESS, STRANGER_ADDRESS); + bytes32 prefixedMessage = keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", message)); + (uint8 v, bytes32 r, bytes32 s) = vm.sign(TOS_SIGNER_PRIVATE_KEY, prefixedMessage); + s_termsOfServiceAllowList.acceptTermsOfService(STRANGER_ADDRESS, STRANGER_ADDRESS, r, s, v); + + // Send as non-subscription owner, who has accepted Terms of Service + vm.stopPrank(); + vm.startPrank(STRANGER_ADDRESS); + + vm.expectRevert(FunctionsSubscriptions.MustBeSubscriptionOwner.selector); + s_functionsRouter.removeConsumer(s_subscriptionId, address(s_functionsClient)); + } + + function test_RemoveConsumer_RevertIfNotAllowedSender() public { + // Remove owner from Allow List + s_termsOfServiceAllowList.blockSender(OWNER_ADDRESS); + + vm.expectRevert(abi.encodeWithSelector(FunctionsRouter.SenderMustAcceptTermsOfService.selector, OWNER_ADDRESS)); + s_functionsRouter.removeConsumer(s_subscriptionId, address(s_functionsClient)); + } + + function test_RemoveConsumer_RevertIfInvalidConsumer() public { + vm.expectRevert(FunctionsSubscriptions.InvalidConsumer.selector); + s_functionsRouter.removeConsumer(s_subscriptionId, address(0)); + } + + function test_RemoveConsumer_RevertIfPendingRequests() public { + // Send a minimal request + string memory sourceCode = "return 'hello world';"; + bytes memory secrets; + string[] memory args = new string[](0); + bytes[] memory bytesArgs = new bytes[](0); + + s_functionsClient.sendRequest(s_donId, sourceCode, secrets, args, bytesArgs, s_subscriptionId, 5000); + + vm.expectRevert(FunctionsSubscriptions.CannotRemoveWithPendingRequests.selector); + s_functionsRouter.removeConsumer(s_subscriptionId, address(s_functionsClient)); + } + + event SubscriptionConsumerRemoved(uint64 indexed subscriptionId, address consumer); + + function test_RemoveConsumer_Success() public { + // topic0 (function signature, always checked), NOT topic1 (false), NOT topic2 (false), NOT topic3 (false), and data (true). + bool checkTopic1 = false; + bool checkTopic2 = false; + bool checkTopic3 = false; + bool checkData = true; + vm.expectEmit(checkTopic1, checkTopic2, checkTopic3, checkData); + emit SubscriptionConsumerRemoved(s_subscriptionId, address(s_functionsClient)); + s_functionsRouter.removeConsumer(s_subscriptionId, address(s_functionsClient)); + + FunctionsSubscriptions.Subscription memory subscription = s_functionsRouter.getSubscription(s_subscriptionId); + assertEq(subscription.consumers, new address[](0)); + } } /// @notice #_getMaxConsumers -contract FunctionsSubscriptions__GetMaxConsumers { - +contract FunctionsSubscriptions__GetMaxConsumers is FunctionsRouterSetup { + // TODO: make contract internal function helper } /// @notice #addConsumer -contract FunctionsSubscriptions_AddConsumer { +contract FunctionsSubscriptions_AddConsumer is FunctionsSubscriptionSetup { + function test_AddConsumer_RevertIfPaused() public { + s_functionsRouter.pause(); + + vm.expectRevert("Pausable: paused"); + s_functionsRouter.addConsumer(s_subscriptionId, address(1)); + } + function test_AddConsumer_RevertIfNoSubscription() public { + vm.expectRevert(FunctionsSubscriptions.InvalidSubscription.selector); + uint64 invalidSubscriptionId = 123456789; + s_functionsRouter.addConsumer(invalidSubscriptionId, address(1)); + } + + function test_AddConsumer_RevertIfNotSubscriptionOwner() public { + // Accept ToS as stranger + vm.stopPrank(); + vm.startPrank(STRANGER_ADDRESS); + bytes32 message = s_termsOfServiceAllowList.getMessage(STRANGER_ADDRESS, STRANGER_ADDRESS); + bytes32 prefixedMessage = keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", message)); + (uint8 v, bytes32 r, bytes32 s) = vm.sign(TOS_SIGNER_PRIVATE_KEY, prefixedMessage); + s_termsOfServiceAllowList.acceptTermsOfService(STRANGER_ADDRESS, STRANGER_ADDRESS, r, s, v); + + // Send as non-subscription owner, who has accepted Terms of Service + vm.stopPrank(); + vm.startPrank(STRANGER_ADDRESS); + + vm.expectRevert(FunctionsSubscriptions.MustBeSubscriptionOwner.selector); + s_functionsRouter.addConsumer(s_subscriptionId, address(1)); + } + + function test_AddConsumer_RevertIfNotAllowedSender() public { + // Remove owner from Allow List + s_termsOfServiceAllowList.blockSender(OWNER_ADDRESS); + + vm.expectRevert(abi.encodeWithSelector(FunctionsRouter.SenderMustAcceptTermsOfService.selector, OWNER_ADDRESS)); + s_functionsRouter.addConsumer(s_subscriptionId, address(1)); + } + + function test_AddConsumer_RevertIfMaximumConsumers() public { + // Fill Consumers to s_maxConsumersPerSubscription + // Already has one from setup + s_functionsRouter.addConsumer(s_subscriptionId, address(1)); + s_functionsRouter.addConsumer(s_subscriptionId, address(2)); + + vm.expectRevert( + abi.encodeWithSelector(FunctionsSubscriptions.TooManyConsumers.selector, s_maxConsumersPerSubscription) + ); + s_functionsRouter.addConsumer(s_subscriptionId, address(3)); + } + + function test_AddConsumer_RevertIfMaximumConsumersAfterConfigUpdate() public { + // Fill Consumers to s_maxConsumersPerSubscription + // Already has one from setup + s_functionsRouter.addConsumer(s_subscriptionId, address(1)); + s_functionsRouter.addConsumer(s_subscriptionId, address(2)); + + // Lower maxConsumersPerSubscription + s_maxConsumersPerSubscription = 1; + FunctionsRouter.Config memory newRouterConfig = getRouterConfig(); + s_functionsRouter.updateConfig(newRouterConfig); + + // .AddConsumer should still revert + vm.expectRevert( + abi.encodeWithSelector(FunctionsSubscriptions.TooManyConsumers.selector, s_maxConsumersPerSubscription) + ); + s_functionsRouter.addConsumer(s_subscriptionId, address(3)); + } + + event SubscriptionConsumerAdded(uint64 indexed subscriptionId, address consumer); + + function test_AddConsumer_Success() public { + // topic0 (function signature, always checked), NOT topic1 (false), NOT topic2 (false), NOT topic3 (false), and data (true). + bool checkTopic1 = false; + bool checkTopic2 = false; + bool checkTopic3 = false; + bool checkData = true; + vm.expectEmit(checkTopic1, checkTopic2, checkTopic3, checkData); + emit SubscriptionConsumerAdded(s_subscriptionId, address(1)); + s_functionsRouter.addConsumer(s_subscriptionId, address(1)); + + FunctionsSubscriptions.Subscription memory subscription = s_functionsRouter.getSubscription(s_subscriptionId); + assertEq(subscription.consumers[1], address(1)); + FunctionsSubscriptions.Consumer memory consumer = s_functionsRouter.getConsumer(address(1), s_subscriptionId); + assertEq(consumer.allowed, true); + } } /// @notice #cancelSubscription -contract FunctionsSubscriptions_CancelSubscription { +contract FunctionsSubscriptions_CancelSubscription is FunctionsSubscriptionSetup { + function test_CancelSubscription_RevertIfPaused() public { + s_functionsRouter.pause(); + + vm.expectRevert("Pausable: paused"); + s_functionsRouter.cancelSubscription(s_subscriptionId, OWNER_ADDRESS); + } + + function test_CancelSubscription_RevertIfNoSubscription() public { + vm.expectRevert(FunctionsSubscriptions.InvalidSubscription.selector); + uint64 invalidSubscriptionId = 123456789; + s_functionsRouter.cancelSubscription(invalidSubscriptionId, OWNER_ADDRESS); + } + + function test_CancelSubscription_RevertIfNotSubscriptionOwner() public { + // Accept ToS as stranger + vm.stopPrank(); + vm.startPrank(STRANGER_ADDRESS); + bytes32 message = s_termsOfServiceAllowList.getMessage(STRANGER_ADDRESS, STRANGER_ADDRESS); + bytes32 prefixedMessage = keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", message)); + (uint8 v, bytes32 r, bytes32 s) = vm.sign(TOS_SIGNER_PRIVATE_KEY, prefixedMessage); + s_termsOfServiceAllowList.acceptTermsOfService(STRANGER_ADDRESS, STRANGER_ADDRESS, r, s, v); + + // Send as non-subscription owner, who has accepted Terms of Service + vm.stopPrank(); + vm.startPrank(STRANGER_ADDRESS); + + vm.expectRevert(FunctionsSubscriptions.MustBeSubscriptionOwner.selector); + s_functionsRouter.cancelSubscription(s_subscriptionId, OWNER_ADDRESS); + } + + function test_CancelSubscription_RevertIfNotAllowedSender() public { + // Remove owner from Allow List + s_termsOfServiceAllowList.blockSender(OWNER_ADDRESS); + + vm.expectRevert(abi.encodeWithSelector(FunctionsRouter.SenderMustAcceptTermsOfService.selector, OWNER_ADDRESS)); + s_functionsRouter.cancelSubscription(s_subscriptionId, OWNER_ADDRESS); + } + + function test_CancelSubscription_RevertIfPendingRequests() public { + // Send a minimal request + string memory sourceCode = "return 'hello world';"; + bytes memory secrets; + string[] memory args = new string[](0); + bytes[] memory bytesArgs = new bytes[](0); + + s_functionsClient.sendRequest(s_donId, sourceCode, secrets, args, bytesArgs, s_subscriptionId, 5000); + + vm.expectRevert(FunctionsSubscriptions.CannotRemoveWithPendingRequests.selector); + s_functionsRouter.cancelSubscription(s_subscriptionId, OWNER_ADDRESS); + } + + event SubscriptionCanceled(uint64 indexed subscriptionId, address fundsRecipient, uint256 fundsAmount); + + function test_CancelSubscription_SuccessForfeitAllBalanceAsDeposit() public { + // No requests have been completed + assertEq(s_functionsRouter.getConsumer(address(s_functionsClient), s_subscriptionId).completedRequests, 0); + // Subscription balance is less than deposit amount + assertLe(s_functionsRouter.getSubscription(s_subscriptionId).balance, s_subscriptionDepositJuels); + + uint256 subscriptionOwnerBalanceBefore = s_linkToken.balanceOf(OWNER_ADDRESS); + uint96 expectedRefund = 0; + + // topic0 (function signature, always checked), NOT topic1 (false), NOT topic2 (false), NOT topic3 (false), and data (true). + bool checkTopic1 = false; + bool checkTopic2 = false; + bool checkTopic3 = false; + bool checkData = true; + vm.expectEmit(checkTopic1, checkTopic2, checkTopic3, checkData); + emit SubscriptionCanceled(s_subscriptionId, OWNER_ADDRESS, expectedRefund); + + s_functionsRouter.cancelSubscription(s_subscriptionId, OWNER_ADDRESS); + + uint256 subscriptionOwnerBalanceAfter = s_linkToken.balanceOf(OWNER_ADDRESS); + assertEq(subscriptionOwnerBalanceBefore + expectedRefund, subscriptionOwnerBalanceAfter); + + // Subscription should no longer exist + vm.expectRevert(FunctionsSubscriptions.InvalidSubscription.selector); + s_functionsRouter.getSubscription(s_subscriptionId); + + // Router owner should have expectedDepositWithheld to withdraw + uint96 expectedDepositWithheld = s_subscriptionInitialFunding; + uint256 balanceBeforeWithdraw = s_linkToken.balanceOf(STRANGER_ADDRESS); + s_functionsRouter.ownerWithdraw(STRANGER_ADDRESS, 0); + uint256 balanceAfterWithdraw = s_linkToken.balanceOf(STRANGER_ADDRESS); + assertEq(balanceBeforeWithdraw + expectedDepositWithheld, balanceAfterWithdraw); + } + + function test_CancelSubscription_SuccessForfeitSomeBalanceAsDeposit() public { + // No requests have been completed + assertEq(s_functionsRouter.getConsumer(address(s_functionsClient), s_subscriptionId).completedRequests, 0); + // Subscription balance is more than deposit amount, double fund the subscription + s_linkToken.transferAndCall(address(s_functionsRouter), s_subscriptionInitialFunding, abi.encode(s_subscriptionId)); + assertGe(s_functionsRouter.getSubscription(s_subscriptionId).balance, s_subscriptionDepositJuels); + + uint256 subscriptionOwnerBalanceBefore = s_linkToken.balanceOf(OWNER_ADDRESS); + + uint96 expectedRefund = (s_subscriptionInitialFunding * 2) - s_subscriptionDepositJuels; + // topic0 (function signature, always checked), NOT topic1 (false), NOT topic2 (false), NOT topic3 (false), and data (true). + bool checkTopic1 = false; + bool checkTopic2 = false; + bool checkTopic3 = false; + bool checkData = true; + vm.expectEmit(checkTopic1, checkTopic2, checkTopic3, checkData); + emit SubscriptionCanceled(s_subscriptionId, OWNER_ADDRESS, expectedRefund); + + s_functionsRouter.cancelSubscription(s_subscriptionId, OWNER_ADDRESS); + + uint256 subscriptionOwnerBalanceAfter = s_linkToken.balanceOf(OWNER_ADDRESS); + assertEq(subscriptionOwnerBalanceBefore + expectedRefund, subscriptionOwnerBalanceAfter); + + // Subscription should no longer exist + vm.expectRevert(FunctionsSubscriptions.InvalidSubscription.selector); + s_functionsRouter.getSubscription(s_subscriptionId); + + // Router owner should have expectedDepositWithheld to withdraw + uint96 expectedDepositWithheld = s_subscriptionDepositJuels; + uint256 balanceBeforeWithdraw = s_linkToken.balanceOf(STRANGER_ADDRESS); + s_functionsRouter.ownerWithdraw(STRANGER_ADDRESS, 0); + uint256 balanceAfterWithdraw = s_linkToken.balanceOf(STRANGER_ADDRESS); + assertEq(balanceBeforeWithdraw + expectedDepositWithheld, balanceAfterWithdraw); + } + + function test_CancelSubscription_SuccessRecieveDeposit() public { + // Complete 1 request = subscriptionDepositMinimumRequests + vm.recordLogs(); + bytes32 requestId = s_functionsClient.sendRequest( + s_donId, + "return 'hello world';", + new bytes(0), + new string[](0), + new bytes[](0), + s_subscriptionId, + 5500 + ); + + // Get commitment data from OracleRequest event log + Vm.Log[] memory entries = vm.getRecordedLogs(); + (, , , , , , , FunctionsResponse.Commitment memory commitment) = abi.decode( + entries[0].data, + (address, uint64, address, bytes, uint16, bytes32, uint64, FunctionsResponse.Commitment) + ); + + // Send as transmitter 1 + vm.stopPrank(); + vm.startPrank(NOP_TRANSMITTER_ADDRESS_1); + + // Build report + bytes32[] memory requestIds = new bytes32[](1); + requestIds[0] = requestId; + bytes[] memory results = new bytes[](1); + results[0] = bytes("hello world!"); + bytes[] memory errors = new bytes[](1); + // No error + bytes[] memory onchainMetadata = new bytes[](1); + onchainMetadata[0] = abi.encode(commitment); + bytes[] memory offchainMetadata = new bytes[](1); + // No offchain metadata + bytes memory report = abi.encode(requestIds, results, errors, onchainMetadata, offchainMetadata); + + // Build signers + address[31] memory signers; + signers[0] = NOP_SIGNER_ADDRESS_1; + + // Send report + vm.recordLogs(); + s_functionsCoordinator.callReportWithSigners(report, signers); + + // Get actual cost from RequestProcessed event log + Vm.Log[] memory entries2 = vm.getRecordedLogs(); + (uint96 totalCostJuels, , , , , ) = abi.decode( + entries2[2].data, + (uint96, address, FunctionsResponse.FulfillResult, bytes, bytes, bytes) + ); + + // Return to sending as owner + vm.stopPrank(); + vm.startPrank(OWNER_ADDRESS); + + uint256 subscriptionOwnerBalanceBefore = s_linkToken.balanceOf(OWNER_ADDRESS); + + uint96 expectedRefund = s_subscriptionInitialFunding - totalCostJuels; + // topic0 (function signature, always checked), NOT topic1 (false), NOT topic2 (false), NOT topic3 (false), and data (true). + bool checkTopic1 = false; + bool checkTopic2 = false; + bool checkTopic3 = false; + bool checkData = true; + vm.expectEmit(checkTopic1, checkTopic2, checkTopic3, checkData); + emit SubscriptionCanceled(s_subscriptionId, OWNER_ADDRESS, expectedRefund); + + s_functionsRouter.cancelSubscription(s_subscriptionId, OWNER_ADDRESS); + + uint256 subscriptionOwnerBalanceAfter = s_linkToken.balanceOf(OWNER_ADDRESS); + assertEq(subscriptionOwnerBalanceBefore + expectedRefund, subscriptionOwnerBalanceAfter); + + // Subscription should no longer exist + vm.expectRevert(FunctionsSubscriptions.InvalidSubscription.selector); + s_functionsRouter.getSubscription(s_subscriptionId); + } } /// @notice #_cancelSubscriptionHelper contract FunctionsSubscriptions__CancelSubscriptionHelper { - + // TODO: make contract internal function helper } /// @notice #pendingRequestExists -contract FunctionsSubscriptions_PendingRequestExists { +contract FunctionsSubscriptions_PendingRequestExists is FunctionsFulfillmentSetup { + function test_PendingRequestExists_SuccessFalseIfNoPendingRequests() public { + bool hasPendingRequests = s_functionsRouter.pendingRequestExists(s_subscriptionId); + assertEq(hasPendingRequests, false); + } + + function test_PendingRequestExists_SuccessTrueIfPendingRequests() public { + // Send a minimal request + string memory sourceCode = "return 'hello world';"; + bytes memory secrets; + string[] memory args = new string[](0); + bytes[] memory bytesArgs = new bytes[](0); + s_functionsClient.sendRequest(s_donId, sourceCode, secrets, args, bytesArgs, s_subscriptionId, 5000); + + bool hasPendingRequests = s_functionsRouter.pendingRequestExists(s_subscriptionId); + assertEq(hasPendingRequests, true); + } } /// @notice #setFlags -contract FunctionsSubscriptions_SetFlags { +contract FunctionsSubscriptions_SetFlags is FunctionsSubscriptionSetup { + function test_SetFlags_RevertIfNotOwner() public { + // Send as stranger + vm.stopPrank(); + vm.startPrank(STRANGER_ADDRESS); + + vm.expectRevert("Only callable by owner"); + bytes32 flagsToSet = bytes32("1"); + s_functionsRouter.setFlags(s_subscriptionId, flagsToSet); + } + + function test_SetFlags_RevertIfNoSubscription() public { + vm.expectRevert(FunctionsSubscriptions.InvalidSubscription.selector); + uint64 invalidSubscriptionId = 123456789; + bytes32 flagsToSet = bytes32("1"); + s_functionsRouter.setFlags(invalidSubscriptionId, flagsToSet); + } + function test_SetFlags_Success() public { + bytes32 flagsToSet = bytes32("1"); + s_functionsRouter.setFlags(s_subscriptionId, flagsToSet); + bytes32 flags = s_functionsRouter.getFlags(s_subscriptionId); + assertEq(flags, flagsToSet); + } } /// @notice #getFlags -contract FunctionsSubscriptions_GetFlags { +contract FunctionsSubscriptions_GetFlags is FunctionsSubscriptionSetup { + function test_GetFlags_Success() public { + // Set flags + bytes32 flagsToSet = bytes32("1"); + s_functionsRouter.setFlags(s_subscriptionId, flagsToSet); + // Send as stranger + vm.stopPrank(); + vm.startPrank(STRANGER_ADDRESS); + + bytes32 flags = s_functionsRouter.getFlags(s_subscriptionId); + assertEq(flags, flagsToSet); + } } /// @notice #timeoutRequests -contract FunctionsSubscriptions_TimeoutRequests { +contract FunctionsSubscriptions_TimeoutRequests is FunctionsClientRequestSetup { + function test_TimeoutRequests_RevertIfPaused() public { + s_functionsRouter.pause(); + + vm.expectRevert("Pausable: paused"); + FunctionsResponse.Commitment[] memory commitments = new FunctionsResponse.Commitment[](1); + commitments[0] = s_requestCommitment; + s_functionsRouter.timeoutRequests(commitments); + } + + function test_TimeoutRequests_RevertInvalidRequest() public { + // Modify the commitment so that it doesn't match + s_requestCommitment.donFee = 123456789; + FunctionsResponse.Commitment[] memory commitments = new FunctionsResponse.Commitment[](1); + commitments[0] = s_requestCommitment; + vm.expectRevert(FunctionsSubscriptions.InvalidCalldata.selector); + s_functionsRouter.timeoutRequests(commitments); + } + + function test_TimeoutRequests_RevertIfTimeoutNotExceeded() public { + vm.expectRevert(FunctionsSubscriptions.TimeoutNotExceeded.selector); + FunctionsResponse.Commitment[] memory commitments = new FunctionsResponse.Commitment[](1); + commitments[0] = s_requestCommitment; + s_functionsRouter.timeoutRequests(commitments); + } + event RequestTimedOut(bytes32 indexed requestId); + + function test_TimeoutRequests_Success() public { + uint64 consumerCompletedRequestsBefore = s_functionsRouter + .getConsumer(address(s_functionsClient), s_subscriptionId) + .completedRequests; + + // topic0 (function signature, always checked), NOT topic1 (false), NOT topic2 (false), NOT topic3 (false), and data (true). + bool checkTopic1 = false; + bool checkTopic2 = false; + bool checkTopic3 = false; + bool checkData = true; + vm.expectEmit(checkTopic1, checkTopic2, checkTopic3, checkData); + emit RequestTimedOut(s_requestId); + + // Jump ahead in time past timeout timestamp + vm.warp(s_requestCommitment.timeoutTimestamp + 1); + + FunctionsResponse.Commitment[] memory commitments = new FunctionsResponse.Commitment[](1); + commitments[0] = s_requestCommitment; + s_functionsRouter.timeoutRequests(commitments); + + // Releases blocked balance and increments completed requests + uint96 subscriptionBlockedBalanceAfter = s_functionsRouter.getSubscription(s_subscriptionId).blockedBalance; + assertEq(0, subscriptionBlockedBalanceAfter); + uint64 consumerCompletedRequestsAfter = s_functionsRouter + .getConsumer(address(s_functionsClient), s_subscriptionId) + .completedRequests; + assertEq(consumerCompletedRequestsBefore + 1, consumerCompletedRequestsAfter); + } } -/// @notice #_onlySubscriptionOwner +// @notice #_onlySubscriptionOwner contract FunctionsSubscriptions__OnlySubscriptionOwner { - + // TODO: make contract internal function helper } diff --git a/contracts/src/v0.8/functions/tests/1_0_0/FunctionsTermsOfServiceAllowList.t.sol b/contracts/src/v0.8/functions/tests/1_0_0/FunctionsTermsOfServiceAllowList.t.sol index af6fa6dcca5..d4a18e207b4 100644 --- a/contracts/src/v0.8/functions/tests/1_0_0/FunctionsTermsOfServiceAllowList.t.sol +++ b/contracts/src/v0.8/functions/tests/1_0_0/FunctionsTermsOfServiceAllowList.t.sol @@ -1,52 +1,343 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.19; -/// @notice #constructor -contract FunctionsTermsOfServiceAllowList_Constructor { +import {TermsOfServiceAllowList} from "../../dev/1_0_0/accessControl/TermsOfServiceAllowList.sol"; +import {FunctionsClientTestHelper} from "./testhelpers/FunctionsClientTestHelper.sol"; + +import {FunctionsRoutesSetup, FunctionsOwnerAcceptTermsOfServiceSetup} from "./Setup.t.sol"; +/// @notice #constructor +contract FunctionsTermsOfServiceAllowList_Constructor is FunctionsRoutesSetup { + function test_Constructor_Success() public { + assertEq(s_termsOfServiceAllowList.typeAndVersion(), "Functions Terms of Service Allow List v1.0.0"); + assertEq(s_termsOfServiceAllowList.owner(), OWNER_ADDRESS); + } } /// @notice #getConfig -contract FunctionsTermsOfServiceAllowList_GetConfig { +contract FunctionsTermsOfServiceAllowList_GetConfig is FunctionsRoutesSetup { + function test_GetConfig_Success() public { + // Send as stranger + vm.stopPrank(); + vm.startPrank(STRANGER_ADDRESS); + TermsOfServiceAllowList.Config memory config = s_termsOfServiceAllowList.getConfig(); + assertEq(config.enabled, getTermsOfServiceConfig().enabled); + assertEq(config.signerPublicKey, getTermsOfServiceConfig().signerPublicKey); + } } /// @notice #updateConfig -contract FunctionsTermsOfServiceAllowList_UpdateConfig { +contract FunctionsTermsOfServiceAllowList_UpdateConfig is FunctionsRoutesSetup { + function test_UpdateConfig_RevertIfNotOwner() public { + // Send as stranger + vm.stopPrank(); + vm.startPrank(STRANGER_ADDRESS); + + vm.expectRevert("Only callable by owner"); + s_termsOfServiceAllowList.updateConfig( + TermsOfServiceAllowList.Config({enabled: true, signerPublicKey: STRANGER_ADDRESS}) + ); + } + + event ConfigUpdated(TermsOfServiceAllowList.Config config); + + function test_UpdateConfig_Success() public { + TermsOfServiceAllowList.Config memory configToSet = TermsOfServiceAllowList.Config({ + enabled: false, + signerPublicKey: TOS_SIGNER + }); + + // topic0 (function signature, always checked), NOT topic1 (false), NOT topic2 (false), NOT topic3 (false), and data (true). + bool checkTopic1 = false; + bool checkTopic2 = false; + bool checkTopic3 = false; + bool checkData = true; + vm.expectEmit(checkTopic1, checkTopic2, checkTopic3, checkData); + emit ConfigUpdated(configToSet); + + s_termsOfServiceAllowList.updateConfig(configToSet); + TermsOfServiceAllowList.Config memory config = s_termsOfServiceAllowList.getConfig(); + assertEq(config.enabled, configToSet.enabled); + assertEq(config.signerPublicKey, configToSet.signerPublicKey); + } } /// @notice #getMessage -contract FunctionsTermsOfServiceAllowList_GetMessage { +contract FunctionsTermsOfServiceAllowList_GetMessage is FunctionsRoutesSetup { + function test_GetMessage_Success() public { + // Send as stranger + vm.stopPrank(); + vm.startPrank(STRANGER_ADDRESS); + bytes32 message = s_termsOfServiceAllowList.getMessage(STRANGER_ADDRESS, STRANGER_ADDRESS); + + assertEq(message, keccak256(abi.encodePacked(STRANGER_ADDRESS, STRANGER_ADDRESS))); + } } /// @notice #acceptTermsOfService -contract FunctionsTermsOfServiceAllowList_AcceptTermsOfService { +contract FunctionsTermsOfServiceAllowList_AcceptTermsOfService is FunctionsRoutesSetup { + function test_AcceptTermsOfService_RevertIfBlockedSender() public { + s_termsOfServiceAllowList.blockSender(STRANGER_ADDRESS); + + // Send as stranger + vm.stopPrank(); + vm.startPrank(STRANGER_ADDRESS); + + bytes32 message = s_termsOfServiceAllowList.getMessage(STRANGER_ADDRESS, STRANGER_ADDRESS); + bytes32 prefixedMessage = keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", message)); + (uint8 v, bytes32 r, bytes32 s) = vm.sign(TOS_SIGNER_PRIVATE_KEY, prefixedMessage); + + vm.expectRevert(TermsOfServiceAllowList.RecipientIsBlocked.selector); + + s_termsOfServiceAllowList.acceptTermsOfService(STRANGER_ADDRESS, STRANGER_ADDRESS, r, s, v); + } + + function test_AcceptTermsOfService_RevertIfInvalidSigner() public { + // Send as stranger + vm.stopPrank(); + vm.startPrank(STRANGER_ADDRESS); + + bytes32 message = s_termsOfServiceAllowList.getMessage(STRANGER_ADDRESS, STRANGER_ADDRESS); + bytes32 prefixedMessage = keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", message)); + (uint8 v, bytes32 r, bytes32 s) = vm.sign(STRANGER_PRIVATE_KEY, prefixedMessage); + + vm.expectRevert(TermsOfServiceAllowList.InvalidSignature.selector); + + s_termsOfServiceAllowList.acceptTermsOfService(STRANGER_ADDRESS, STRANGER_ADDRESS, r, s, v); + } + + function test_AcceptTermsOfService_RevertIfRecipientIsNotSender() public { + // Send as stranger + vm.stopPrank(); + vm.startPrank(STRANGER_ADDRESS); + + bytes32 message = s_termsOfServiceAllowList.getMessage(OWNER_ADDRESS, STRANGER_ADDRESS); + bytes32 prefixedMessage = keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", message)); + (uint8 v, bytes32 r, bytes32 s) = vm.sign(TOS_SIGNER_PRIVATE_KEY, prefixedMessage); + + vm.expectRevert(TermsOfServiceAllowList.InvalidUsage.selector); + + s_termsOfServiceAllowList.acceptTermsOfService(OWNER_ADDRESS, STRANGER_ADDRESS, r, s, v); + } + + function test_AcceptTermsOfService_RevertIfAcceptorIsNotSender() public { + // Send as stranger + vm.stopPrank(); + vm.startPrank(STRANGER_ADDRESS); + + bytes32 message = s_termsOfServiceAllowList.getMessage(STRANGER_ADDRESS, OWNER_ADDRESS); + bytes32 prefixedMessage = keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", message)); + (uint8 v, bytes32 r, bytes32 s) = vm.sign(TOS_SIGNER_PRIVATE_KEY, prefixedMessage); + + vm.expectRevert(TermsOfServiceAllowList.InvalidUsage.selector); + + s_termsOfServiceAllowList.acceptTermsOfService(STRANGER_ADDRESS, OWNER_ADDRESS, r, s, v); + } + + function test_AcceptTermsOfService_RevertIfRecipientContractIsNotSender() public { + FunctionsClientTestHelper s_functionsClientHelper = new FunctionsClientTestHelper(address(s_functionsRouter)); + + // Send as externally owned account + vm.stopPrank(); + vm.startPrank(STRANGER_ADDRESS); + + // Attempt to accept for a contract account + bytes32 message = s_termsOfServiceAllowList.getMessage(STRANGER_ADDRESS, address(s_functionsClientHelper)); + bytes32 prefixedMessage = keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", message)); + (uint8 v, bytes32 r, bytes32 s) = vm.sign(TOS_SIGNER_PRIVATE_KEY, prefixedMessage); + + vm.expectRevert(TermsOfServiceAllowList.InvalidUsage.selector); + + s_termsOfServiceAllowList.acceptTermsOfService(STRANGER_ADDRESS, address(s_functionsClientHelper), r, s, v); + } + event AddedAccess(address user); + + function test_AcceptTermsOfService_SuccessIfAcceptingForSelf() public { + // Send as stranger + vm.stopPrank(); + vm.startPrank(STRANGER_ADDRESS); + + bytes32 message = s_termsOfServiceAllowList.getMessage(STRANGER_ADDRESS, STRANGER_ADDRESS); + bytes32 prefixedMessage = keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", message)); + (uint8 v, bytes32 r, bytes32 s) = vm.sign(TOS_SIGNER_PRIVATE_KEY, prefixedMessage); + + // topic0 (function signature, always checked), NOT topic1 (false), NOT topic2 (false), NOT topic3 (false), and data (true). + bool checkTopic1 = false; + bool checkTopic2 = false; + bool checkTopic3 = false; + bool checkData = true; + vm.expectEmit(checkTopic1, checkTopic2, checkTopic3, checkData); + emit AddedAccess(STRANGER_ADDRESS); + + s_termsOfServiceAllowList.acceptTermsOfService(STRANGER_ADDRESS, STRANGER_ADDRESS, r, s, v); + + assertEq(s_termsOfServiceAllowList.hasAccess(STRANGER_ADDRESS, new bytes(0)), true); + } + + function test_AcceptTermsOfService_SuccessIfAcceptingForContract() public { + FunctionsClientTestHelper s_functionsClientHelper = new FunctionsClientTestHelper(address(s_functionsRouter)); + + // Send as stranger + vm.stopPrank(); + vm.startPrank(STRANGER_ADDRESS); + + bytes32 message = s_termsOfServiceAllowList.getMessage(STRANGER_ADDRESS, address(s_functionsClientHelper)); + bytes32 prefixedMessage = keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", message)); + (uint8 v, bytes32 r, bytes32 s) = vm.sign(TOS_SIGNER_PRIVATE_KEY, prefixedMessage); + + // topic0 (function signature, always checked), NOT topic1 (false), NOT topic2 (false), NOT topic3 (false), and data (true). + bool checkTopic1 = false; + bool checkTopic2 = false; + bool checkTopic3 = false; + bool checkData = true; + vm.expectEmit(checkTopic1, checkTopic2, checkTopic3, checkData); + emit AddedAccess(address(s_functionsClientHelper)); + + s_functionsClientHelper.acceptTermsOfService(STRANGER_ADDRESS, address(s_functionsClientHelper), r, s, v); + + assertEq(s_termsOfServiceAllowList.hasAccess(address(s_functionsClientHelper), new bytes(0)), true); + } } /// @notice #getAllAllowedSenders -contract FunctionsTermsOfServiceAllowList_GetAllAllowedSenders { +contract FunctionsTermsOfServiceAllowList_GetAllAllowedSenders is FunctionsOwnerAcceptTermsOfServiceSetup { + function test_GetAllAllowedSenders_Success() public { + // Send as stranger + vm.stopPrank(); + vm.startPrank(STRANGER_ADDRESS); + + address[] memory expectedSenders = new address[](1); + expectedSenders[0] = OWNER_ADDRESS; + assertEq(s_termsOfServiceAllowList.getAllAllowedSenders(), expectedSenders); + } } /// @notice #hasAccess -contract FunctionsTermsOfServiceAllowList_HasAccess { +contract FunctionsTermsOfServiceAllowList_HasAccess is FunctionsRoutesSetup { + function test_HasAccess_FalseWhenEnabled() public { + // Send as stranger + vm.stopPrank(); + vm.startPrank(STRANGER_ADDRESS); + + // Check access of account that is not on the allow list + assertEq(s_termsOfServiceAllowList.hasAccess(STRANGER_ADDRESS, new bytes(0)), false); + } + + function test_HasAccess_TrueWhenDisabled() public { + // Disable allow list, which opens all access + s_termsOfServiceAllowList.updateConfig( + TermsOfServiceAllowList.Config({enabled: false, signerPublicKey: TOS_SIGNER}) + ); + + // Send as stranger + vm.stopPrank(); + vm.startPrank(STRANGER_ADDRESS); + // Check access of account that is not on the allow list + assertEq(s_termsOfServiceAllowList.hasAccess(STRANGER_ADDRESS, new bytes(0)), true); + } } /// @notice #isBlockedSender -contract FunctionsTermsOfServiceAllowList_IsBlockedSender { +contract FunctionsTermsOfServiceAllowList_IsBlockedSender is FunctionsRoutesSetup { + function test_IsBlockedSender_SuccessFalse() public { + // Send as stranger + vm.stopPrank(); + vm.startPrank(STRANGER_ADDRESS); + assertEq(s_termsOfServiceAllowList.isBlockedSender(STRANGER_ADDRESS), false); + } + + function test_IsBlockedSender_SuccessTrue() public { + // Block sender + s_termsOfServiceAllowList.blockSender(STRANGER_ADDRESS); + + // Send as stranger + vm.stopPrank(); + vm.startPrank(STRANGER_ADDRESS); + + assertEq(s_termsOfServiceAllowList.isBlockedSender(STRANGER_ADDRESS), true); + } } /// @notice #blockSender -contract FunctionsTermsOfServiceAllowList_BlockSender { +contract FunctionsTermsOfServiceAllowList_BlockSender is FunctionsRoutesSetup { + function test_BlockSender_RevertIfNotOwner() public { + // Send as stranger + vm.stopPrank(); + vm.startPrank(STRANGER_ADDRESS); + + vm.expectRevert("Only callable by owner"); + s_termsOfServiceAllowList.blockSender(OWNER_ADDRESS); + } + + event BlockedAccess(address user); + + function test_BlockSender_Success() public { + // topic0 (function signature, always checked), NOT topic1 (false), NOT topic2 (false), NOT topic3 (false), and data (true). + bool checkTopic1 = false; + bool checkTopic2 = false; + bool checkTopic3 = false; + bool checkData = true; + vm.expectEmit(checkTopic1, checkTopic2, checkTopic3, checkData); + emit BlockedAccess(STRANGER_ADDRESS); + + s_termsOfServiceAllowList.blockSender(STRANGER_ADDRESS); + assertEq(s_termsOfServiceAllowList.hasAccess(STRANGER_ADDRESS, new bytes(0)), false); + assertEq(s_termsOfServiceAllowList.isBlockedSender(STRANGER_ADDRESS), true); + // Account can no longer accept Terms of Service + bytes32 message = s_termsOfServiceAllowList.getMessage(STRANGER_ADDRESS, STRANGER_ADDRESS); + bytes32 prefixedMessage = keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", message)); + (uint8 v, bytes32 r, bytes32 s) = vm.sign(TOS_SIGNER_PRIVATE_KEY, prefixedMessage); + vm.expectRevert(TermsOfServiceAllowList.RecipientIsBlocked.selector); + s_termsOfServiceAllowList.acceptTermsOfService(STRANGER_ADDRESS, STRANGER_ADDRESS, r, s, v); + } } /// @notice #unblockSender -contract FunctionsTermsOfServiceAllowList_UnblockSender { +contract FunctionsTermsOfServiceAllowList_UnblockSender is FunctionsRoutesSetup { + function setUp() public virtual override { + FunctionsRoutesSetup.setUp(); + + s_termsOfServiceAllowList.blockSender(STRANGER_ADDRESS); + } + + function test_UnblockSender_RevertIfNotOwner() public { + // Send as stranger + vm.stopPrank(); + vm.startPrank(STRANGER_ADDRESS); + + vm.expectRevert("Only callable by owner"); + s_termsOfServiceAllowList.unblockSender(STRANGER_ADDRESS); + } + + event UnblockedAccess(address user); + + function test_UnblockSender_Success() public { + // topic0 (function signature, always checked), NOT topic1 (false), NOT topic2 (false), NOT topic3 (false), and data (true). + bool checkTopic1 = false; + bool checkTopic2 = false; + bool checkTopic3 = false; + bool checkData = true; + vm.expectEmit(checkTopic1, checkTopic2, checkTopic3, checkData); + emit UnblockedAccess(STRANGER_ADDRESS); + + s_termsOfServiceAllowList.unblockSender(STRANGER_ADDRESS); + + // Send as stranger + vm.stopPrank(); + vm.startPrank(STRANGER_ADDRESS); + // Account can now accept the Terms of Service + bytes32 message = s_termsOfServiceAllowList.getMessage(STRANGER_ADDRESS, STRANGER_ADDRESS); + bytes32 prefixedMessage = keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", message)); + (uint8 v, bytes32 r, bytes32 s) = vm.sign(TOS_SIGNER_PRIVATE_KEY, prefixedMessage); + s_termsOfServiceAllowList.acceptTermsOfService(STRANGER_ADDRESS, STRANGER_ADDRESS, r, s, v); + } } diff --git a/contracts/src/v0.8/functions/tests/1_0_0/OCR2.t.sol b/contracts/src/v0.8/functions/tests/1_0_0/OCR2.t.sol new file mode 100644 index 00000000000..e69de29bb2d diff --git a/contracts/src/v0.8/functions/tests/1_0_0/README.md b/contracts/src/v0.8/functions/tests/1_0_0/README.md new file mode 100644 index 00000000000..bbbf33dbe96 --- /dev/null +++ b/contracts/src/v0.8/functions/tests/1_0_0/README.md @@ -0,0 +1,22 @@ +## Usage + +First set the foundry profile to Functions: +``` +export FOUNDRY_PROFILE=functions +``` + +To run all test files use: +``` +forge test -vv +``` + +To run a specific file use: +``` +forge test -vv --mp src/v0.8/functions/tests/1_0_0/[File Name].t.sol +``` + +To see coverage: +First ensure that the correct files are being evaluated. For example, if only v1 contracts are, then temporarily change the Functions profile in `./foundry.toml`. +``` +forge coverage +``` \ No newline at end of file diff --git a/contracts/src/v0.8/functions/tests/1_0_0/Setup.t.sol b/contracts/src/v0.8/functions/tests/1_0_0/Setup.t.sol index 56addcabd79..7a911c3bd60 100644 --- a/contracts/src/v0.8/functions/tests/1_0_0/Setup.t.sol +++ b/contracts/src/v0.8/functions/tests/1_0_0/Setup.t.sol @@ -3,22 +3,29 @@ pragma solidity ^0.8.19; import {BaseTest} from "./BaseTest.t.sol"; import {FunctionsRouter} from "../../dev/1_0_0/FunctionsRouter.sol"; -import {FunctionsCoordinator} from "../../dev/1_0_0/FunctionsCoordinator.sol"; +import {FunctionsCoordinatorTestHelper} from "./testhelpers/FunctionsCoordinatorTestHelper.sol"; import {FunctionsBilling} from "../../dev/1_0_0/FunctionsBilling.sol"; +import {FunctionsResponse} from "../../dev/1_0_0/libraries/FunctionsResponse.sol"; import {MockV3Aggregator} from "../../../tests/MockV3Aggregator.sol"; import {TermsOfServiceAllowList} from "../../dev/1_0_0/accessControl/TermsOfServiceAllowList.sol"; +import {FunctionsClientUpgradeHelper} from "./testhelpers/FunctionsClientUpgradeHelper.sol"; +import {MockLinkToken} from "../../../mocks/MockLinkToken.sol"; + +import "forge-std/Vm.sol"; contract FunctionsRouterSetup is BaseTest { FunctionsRouter internal s_functionsRouter; - FunctionsCoordinator internal s_functionsCoordinator; + FunctionsCoordinatorTestHelper internal s_functionsCoordinator; // TODO: use actual FunctionsCoordinator instead of helper MockV3Aggregator internal s_linkEthFeed; TermsOfServiceAllowList internal s_termsOfServiceAllowList; + MockLinkToken internal s_linkToken; - uint16 internal s_maxConsumersPerSubscription = 100; + uint16 internal s_maxConsumersPerSubscription = 3; uint72 internal s_adminFee = 100; + uint72 internal s_donFee = 100; bytes4 internal s_handleOracleFulfillmentSelector = 0x0ca76175; - - address internal s_linkToken = 0x01BE23585060835E02B77ef475b0Cc51aA1e0709; + uint16 s_subscriptionDepositMinimumRequests = 1; + uint72 s_subscriptionDepositJuels = 11 * 1e18; int256 internal LINK_ETH_RATE = 6000000000000000; @@ -27,9 +34,10 @@ contract FunctionsRouterSetup is BaseTest { function setUp() public virtual override { BaseTest.setUp(); - s_functionsRouter = new FunctionsRouter(s_linkToken, getRouterConfig()); + s_linkToken = new MockLinkToken(); + s_functionsRouter = new FunctionsRouter(address(s_linkToken), getRouterConfig()); s_linkEthFeed = new MockV3Aggregator(0, LINK_ETH_RATE); - s_functionsCoordinator = new FunctionsCoordinator( + s_functionsCoordinator = new FunctionsCoordinatorTestHelper( address(s_functionsRouter), getCoordinatorConfig(), address(s_linkEthFeed) @@ -49,19 +57,20 @@ contract FunctionsRouterSetup is BaseTest { adminFee: s_adminFee, handleOracleFulfillmentSelector: s_handleOracleFulfillmentSelector, maxCallbackGasLimits: maxCallbackGasLimits, - gasForCallExactCheck: 5000 + gasForCallExactCheck: 5000, + subscriptionDepositMinimumRequests: s_subscriptionDepositMinimumRequests, + subscriptionDepositJuels: s_subscriptionDepositJuels }); } - function getCoordinatorConfig() public pure returns (FunctionsBilling.Config memory) { + function getCoordinatorConfig() public view returns (FunctionsBilling.Config memory) { return FunctionsBilling.Config({ - maxCallbackGasLimit: 0, // NOTE: unused , TODO: remove feedStalenessSeconds: 24 * 60 * 60, // 1 day gasOverheadAfterCallback: 44_615, // TODO: update gasOverheadBeforeCallback: 44_615, // TODO: update requestTimeoutSeconds: 60 * 5, // 5 minutes - donFee: 100, + donFee: s_donFee, maxSupportedRequestDataVersion: 1, fulfillmentGasPriceOverEstimationBP: 5000, fallbackNativePerUnitLink: 5000000000000000 @@ -73,13 +82,63 @@ contract FunctionsRouterSetup is BaseTest { } } -contract FunctionsSetupRoutes is FunctionsRouterSetup { +contract FunctionsDONSetup is FunctionsRouterSetup { + uint256 internal NOP_SIGNER_PRIVATE_KEY_1 = 0x100; + address internal NOP_SIGNER_ADDRESS_1 = vm.addr(NOP_SIGNER_PRIVATE_KEY_1); + uint256 internal NOP_SIGNER_PRIVATE_KEY_2 = 0x101; + address internal NOP_SIGNER_ADDRESS_2 = vm.addr(NOP_SIGNER_PRIVATE_KEY_2); + uint256 internal NOP_SIGNER_PRIVATE_KEY_3 = 0x102; + address internal NOP_SIGNER_ADDRESS_3 = vm.addr(NOP_SIGNER_PRIVATE_KEY_3); + uint256 internal NOP_SIGNER_PRIVATE_KEY_4 = 0x103; + address internal NOP_SIGNER_ADDRESS_4 = vm.addr(NOP_SIGNER_PRIVATE_KEY_4); + + uint256 internal NOP_TRANSMITTER_PRIVATE_KEY_1 = 0x104; + address internal NOP_TRANSMITTER_ADDRESS_1 = vm.addr(NOP_TRANSMITTER_PRIVATE_KEY_1); + uint256 internal NOP_TRANSMITTER_PRIVATE_KEY_2 = 0x105; + address internal NOP_TRANSMITTER_ADDRESS_2 = vm.addr(NOP_TRANSMITTER_PRIVATE_KEY_2); + uint256 internal NOP_TRANSMITTER_PRIVATE_KEY_3 = 0x106; + address internal NOP_TRANSMITTER_ADDRESS_3 = vm.addr(NOP_TRANSMITTER_PRIVATE_KEY_3); + uint256 internal NOP_TRANSMITTER_PRIVATE_KEY_4 = 0x107; + address internal NOP_TRANSMITTER_ADDRESS_4 = vm.addr(NOP_TRANSMITTER_PRIVATE_KEY_4); + function setUp() public virtual override { FunctionsRouterSetup.setUp(); + address[] memory _signers = new address[](4); + _signers[0] = NOP_SIGNER_ADDRESS_1; + _signers[1] = NOP_SIGNER_ADDRESS_2; + _signers[2] = NOP_SIGNER_ADDRESS_3; + _signers[3] = NOP_SIGNER_ADDRESS_4; + address[] memory _transmitters = new address[](4); + _transmitters[0] = NOP_TRANSMITTER_ADDRESS_1; + _transmitters[1] = NOP_TRANSMITTER_ADDRESS_2; + _transmitters[2] = NOP_TRANSMITTER_ADDRESS_3; + _transmitters[3] = NOP_TRANSMITTER_ADDRESS_4; + uint8 _f = 1; + bytes memory _onchainConfig = new bytes(0); + uint64 _offchainConfigVersion = 1; + bytes memory _offchainConfig = new bytes(0); + // set OCR config + s_functionsCoordinator.setConfig( + _signers, + _transmitters, + _f, + _onchainConfig, + _offchainConfigVersion, + _offchainConfig + ); + } +} + +contract FunctionsRoutesSetup is FunctionsDONSetup { + bytes32 s_donId = bytes32("1"); + + function setUp() public virtual override { + FunctionsDONSetup.setUp(); + bytes32 allowListId = s_functionsRouter.getAllowListId(); bytes32[] memory proposedContractSetIds = new bytes32[](2); - proposedContractSetIds[0] = bytes32("1"); + proposedContractSetIds[0] = s_donId; proposedContractSetIds[1] = allowListId; address[] memory proposedContractSetAddresses = new address[](2); proposedContractSetAddresses[0] = address(s_functionsCoordinator); @@ -90,9 +149,9 @@ contract FunctionsSetupRoutes is FunctionsRouterSetup { } } -contract FunctionsOwnerAcceptTermsOfService is FunctionsSetupRoutes { +contract FunctionsOwnerAcceptTermsOfServiceSetup is FunctionsRoutesSetup { function setUp() public virtual override { - FunctionsSetupRoutes.setUp(); + FunctionsRoutesSetup.setUp(); bytes32 message = s_termsOfServiceAllowList.getMessage(OWNER_ADDRESS, OWNER_ADDRESS); bytes32 prefixedMessage = keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", message)); @@ -100,3 +159,243 @@ contract FunctionsOwnerAcceptTermsOfService is FunctionsSetupRoutes { s_termsOfServiceAllowList.acceptTermsOfService(OWNER_ADDRESS, OWNER_ADDRESS, r, s, v); } } + +contract FunctionsClientSetup is FunctionsOwnerAcceptTermsOfServiceSetup { + FunctionsClientUpgradeHelper internal s_functionsClient; + + function setUp() public virtual override { + FunctionsOwnerAcceptTermsOfServiceSetup.setUp(); + + s_functionsClient = new FunctionsClientUpgradeHelper(address(s_functionsRouter)); + } +} + +contract FunctionsSubscriptionSetup is FunctionsClientSetup { + uint96 constant JUELS_PER_LINK = 1e18; + uint64 s_subscriptionId; + uint96 s_subscriptionInitialFunding = 10 * JUELS_PER_LINK; // 10 LINK + + function setUp() public virtual override { + FunctionsClientSetup.setUp(); + + // Create subscription + s_subscriptionId = s_functionsRouter.createSubscription(); + s_functionsRouter.addConsumer(s_subscriptionId, address(s_functionsClient)); + + // Fund subscription + s_linkToken.transferAndCall(address(s_functionsRouter), s_subscriptionInitialFunding, abi.encode(s_subscriptionId)); + } +} + +contract FunctionsClientRequestSetup is FunctionsSubscriptionSetup { + bytes32 s_requestId; + FunctionsResponse.Commitment s_requestCommitment; + + function setUp() public virtual override { + FunctionsSubscriptionSetup.setUp(); + + // Send a minimal request + string memory sourceCode = "return 'hello world';"; + bytes memory secrets; + string[] memory args = new string[](0); + bytes[] memory bytesArgs = new bytes[](0); + uint32 callbackGasLimit = 5500; + + vm.recordLogs(); + s_requestId = s_functionsClient.sendRequest( + s_donId, + sourceCode, + secrets, + args, + bytesArgs, + s_subscriptionId, + callbackGasLimit + ); + + // Get commitment data from OracleRequest event log + Vm.Log[] memory entries = vm.getRecordedLogs(); + (, , , , , , , FunctionsResponse.Commitment memory commitment) = abi.decode( + entries[0].data, + (address, uint64, address, bytes, uint16, bytes32, uint64, FunctionsResponse.Commitment) + ); + s_requestCommitment = commitment; + } +} + +contract FunctionsFulfillmentSetup is FunctionsClientRequestSetup { + uint96 s_fulfillmentRouterOwnerBalance = s_adminFee; + uint96 s_fulfillmentCoordinatorBalance; + + function setUp() public virtual override { + FunctionsClientRequestSetup.setUp(); + + // Send as transmitter 1 + vm.stopPrank(); + vm.startPrank(NOP_TRANSMITTER_ADDRESS_1); + + // Build report + bytes32[] memory requestIds = new bytes32[](1); + requestIds[0] = s_requestId; + bytes[] memory results = new bytes[](1); + results[0] = bytes("hello world!"); + bytes[] memory errors = new bytes[](1); + // No error + bytes[] memory onchainMetadata = new bytes[](1); + onchainMetadata[0] = abi.encode(s_requestCommitment); + bytes[] memory offchainMetadata = new bytes[](1); + // No offchain metadata + bytes memory report = abi.encode(requestIds, results, errors, onchainMetadata, offchainMetadata); + + // Build signers + address[31] memory signers; + signers[0] = NOP_SIGNER_ADDRESS_1; + + // Send report + vm.recordLogs(); + s_functionsCoordinator.callReportWithSigners(report, signers); + + // Get actual cost from RequestProcessed event log + Vm.Log[] memory entries = vm.getRecordedLogs(); + (uint96 totalCostJuels, , , , , ) = abi.decode( + entries[2].data, + (uint96, address, FunctionsResponse.FulfillResult, bytes, bytes, bytes) + ); + // totalCostJuels = costWithoutCallbackJuels + adminFee + callbackGasCostJuels + s_fulfillmentCoordinatorBalance = totalCostJuels - s_adminFee; + + // Return prank to Owner + vm.stopPrank(); + vm.startPrank(OWNER_ADDRESS); + } +} + +contract FunctionsMultipleFulfillmentsSetup is FunctionsFulfillmentSetup { + bytes32 s_requestId2; + FunctionsResponse.Commitment s_requestCommitment2; + bytes32 s_requestId3; + FunctionsResponse.Commitment s_requestCommitment3; + + function setUp() public virtual override { + FunctionsFulfillmentSetup.setUp(); + + // Make 2 additional requests (1 already complete) + + // *** Request #2 *** + vm.recordLogs(); + s_requestId2 = s_functionsClient.sendRequest( + s_donId, + "return 'hello world';", + new bytes(0), + new string[](0), + new bytes[](0), + s_subscriptionId, + 5500 + ); + + // Get commitment data from OracleRequest event log + Vm.Log[] memory entriesAfterRequest2 = vm.getRecordedLogs(); + (, , , , , , , FunctionsResponse.Commitment memory commitment2) = abi.decode( + entriesAfterRequest2[0].data, + (address, uint64, address, bytes, uint16, bytes32, uint64, FunctionsResponse.Commitment) + ); + s_requestCommitment2 = commitment2; + + // Transmit as transmitter 2 + vm.stopPrank(); + vm.startPrank(NOP_TRANSMITTER_ADDRESS_2); + + // Build report + bytes32[] memory requestIds2 = new bytes32[](1); + requestIds2[0] = s_requestId2; + bytes[] memory results2 = new bytes[](1); + results2[0] = bytes("hello world!"); + bytes[] memory errors2 = new bytes[](1); + // No error + bytes[] memory onchainMetadata2 = new bytes[](1); + onchainMetadata2[0] = abi.encode(s_requestCommitment2); + bytes[] memory offchainMetadata2 = new bytes[](1); + // No offchain metadata + bytes memory report2 = abi.encode(requestIds2, results2, errors2, onchainMetadata2, offchainMetadata2); + + // Build signers + address[31] memory signers2; + signers2[0] = NOP_SIGNER_ADDRESS_2; + + // Send report + vm.recordLogs(); + s_functionsCoordinator.callReportWithSigners(report2, signers2); + + // Get actual cost from RequestProcessed event log + Vm.Log[] memory entriesAfterFulfill2 = vm.getRecordedLogs(); + (uint96 totalCostJuels2, , , , , ) = abi.decode( + entriesAfterFulfill2[2].data, + (uint96, address, FunctionsResponse.FulfillResult, bytes, bytes, bytes) + ); + // totalCostJuels = costWithoutCallbackJuels + adminFee + callbackGasCostJuels + s_fulfillmentCoordinatorBalance += totalCostJuels2 - s_adminFee; + s_fulfillmentRouterOwnerBalance += s_adminFee; + + // Return prank to Owner + vm.stopPrank(); + vm.startPrank(OWNER_ADDRESS); + + // *** Request #3 *** + vm.recordLogs(); + s_requestId3 = s_functionsClient.sendRequest( + s_donId, + "return 'hello world';", + new bytes(0), + new string[](0), + new bytes[](0), + s_subscriptionId, + 5500 + ); + + // Get commitment data from OracleRequest event log + Vm.Log[] memory entriesAfterRequest3 = vm.getRecordedLogs(); + (, , , , , , , FunctionsResponse.Commitment memory commitment3) = abi.decode( + entriesAfterRequest3[0].data, + (address, uint64, address, bytes, uint16, bytes32, uint64, FunctionsResponse.Commitment) + ); + s_requestCommitment3 = commitment3; + + // Transmit as transmitter 3 + vm.stopPrank(); + vm.startPrank(NOP_TRANSMITTER_ADDRESS_3); + + // Build report + bytes32[] memory requestIds3 = new bytes32[](1); + requestIds3[0] = s_requestId3; + bytes[] memory results3 = new bytes[](1); + results3[0] = bytes("hello world!"); + bytes[] memory errors3 = new bytes[](1); + // No error + bytes[] memory onchainMetadata3 = new bytes[](1); + onchainMetadata3[0] = abi.encode(s_requestCommitment3); + bytes[] memory offchainMetadata3 = new bytes[](1); + // No offchain metadata + bytes memory report3 = abi.encode(requestIds3, results3, errors3, onchainMetadata3, offchainMetadata3); + + // Build signers + address[31] memory signers3; + signers3[0] = NOP_SIGNER_ADDRESS_3; + + // Send report + vm.recordLogs(); + s_functionsCoordinator.callReportWithSigners(report3, signers3); + + // Get actual cost from RequestProcessed event log + Vm.Log[] memory entriesAfterFulfill3 = vm.getRecordedLogs(); + (uint96 totalCostJuels3, , , , , ) = abi.decode( + entriesAfterFulfill3[2].data, + (uint96, address, FunctionsResponse.FulfillResult, bytes, bytes, bytes) + ); + + // totalCostJuels = costWithoutCallbackJuels + adminFee + callbackGasCostJuels + s_fulfillmentCoordinatorBalance += totalCostJuels3 - s_adminFee; + + // Return prank to Owner + vm.stopPrank(); + vm.startPrank(OWNER_ADDRESS); + } +} diff --git a/contracts/src/v0.8/functions/tests/1_0_0/testhelpers/FunctionsCoordinatorTestHelper.sol b/contracts/src/v0.8/functions/tests/1_0_0/testhelpers/FunctionsCoordinatorTestHelper.sol index 0bf7adb7a25..c612f47644f 100644 --- a/contracts/src/v0.8/functions/tests/1_0_0/testhelpers/FunctionsCoordinatorTestHelper.sol +++ b/contracts/src/v0.8/functions/tests/1_0_0/testhelpers/FunctionsCoordinatorTestHelper.sol @@ -23,4 +23,8 @@ contract FunctionsCoordinatorTestHelper is FunctionsCoordinator { signers[1] = secondSigner; _report(gasleft(), msg.sender, 2, signers, report); } + + function callReportWithSigners(bytes calldata report, address[MAX_NUM_ORACLES] memory signers) external { + _report(gasleft(), msg.sender, 2, signers, report); + } } diff --git a/contracts/src/v0.8/functions/tests/1_0_0/testhelpers/FunctionsLoadTestClient.sol b/contracts/src/v0.8/functions/tests/1_0_0/testhelpers/FunctionsLoadTestClient.sol index 047b45e9562..7327dc26f78 100644 --- a/contracts/src/v0.8/functions/tests/1_0_0/testhelpers/FunctionsLoadTestClient.sol +++ b/contracts/src/v0.8/functions/tests/1_0_0/testhelpers/FunctionsLoadTestClient.sol @@ -11,11 +11,11 @@ import {FunctionsRequest} from "../../../dev/1_0_0/libraries/FunctionsRequest.so contract FunctionsLoadTestClient is FunctionsClient, ConfirmedOwner { using FunctionsRequest for FunctionsRequest.Request; - uint32 public constant MAX_CALLBACK_GAS = 70_000; + uint32 public constant MAX_CALLBACK_GAS = 250_000; bytes32 public lastRequestID; - bytes32 public lastResponse; - bytes32 public lastError; + bytes public lastResponse; + bytes public lastError; uint32 public totalRequests; uint32 public totalEmptyResponses; uint32 public totalSucceededResponses; @@ -25,10 +25,12 @@ contract FunctionsLoadTestClient is FunctionsClient, ConfirmedOwner { /** * @notice Send a simple request + * @param times Number of times to send the request * @param source JavaScript source code * @param encryptedSecretsReferences Encrypted secrets payload * @param args List of arguments accessible from within the source code * @param subscriptionId Billing ID + * @param donId DON ID */ function sendRequest( uint32 times, @@ -36,7 +38,7 @@ contract FunctionsLoadTestClient is FunctionsClient, ConfirmedOwner { bytes calldata encryptedSecretsReferences, string[] calldata args, uint64 subscriptionId, - bytes32 jobId + bytes32 donId ) external onlyOwner { FunctionsRequest.Request memory req; req.initializeRequestForInlineJavaScript(source); @@ -44,7 +46,57 @@ contract FunctionsLoadTestClient is FunctionsClient, ConfirmedOwner { if (args.length > 0) req.setArgs(args); uint i = 0; for (i = 0; i < times; i++) { - lastRequestID = _sendRequest(req.encodeCBOR(), subscriptionId, MAX_CALLBACK_GAS, jobId); + lastRequestID = _sendRequest(req.encodeCBOR(), subscriptionId, MAX_CALLBACK_GAS, donId); + totalRequests += 1; + } + } + + /** + * @notice Same as sendRequest but for DONHosted secrets + * @param times Number of times to send the request + * @param source JavaScript source code + * @param slotId DON hosted secrets slot ID + * @param slotVersion DON hosted secrets slot version + * @param args List of arguments accessible from within the source code + * @param subscriptionId Billing ID + * @param donId DON ID + */ + function sendRequestWithDONHostedSecrets( + uint32 times, + string calldata source, + uint8 slotId, + uint64 slotVersion, + string[] calldata args, + uint64 subscriptionId, + bytes32 donId + ) public onlyOwner { + FunctionsRequest.Request memory req; + req.initializeRequestForInlineJavaScript(source); + req.addDONHostedSecrets(slotId, slotVersion); + if (args.length > 0) req.setArgs(args); + uint i = 0; + for (i = 0; i < times; i++) { + lastRequestID = _sendRequest(req.encodeCBOR(), subscriptionId, MAX_CALLBACK_GAS, donId); + totalRequests += 1; + } + } + + /** + * @notice Sends a Chainlink Functions request that has already been CBOR encoded + * @param times Number of times to send the request + * @param cborEncodedRequest The CBOR encoded bytes data for a Functions request + * @param subscriptionId The subscription ID that will be charged to service the request + * @param donId DON ID + */ + function sendEncodedRequest( + uint32 times, + bytes memory cborEncodedRequest, + uint64 subscriptionId, + bytes32 donId + ) public onlyOwner { + uint i = 0; + for (i = 0; i < times; i++) { + lastRequestID = _sendRequest(cborEncodedRequest, subscriptionId, MAX_CALLBACK_GAS, donId); totalRequests += 1; } } @@ -59,7 +111,12 @@ contract FunctionsLoadTestClient is FunctionsClient, ConfirmedOwner { totalEmptyResponses = 0; } - function getStats() public view onlyOwner returns (bytes32, bytes32, bytes32, uint32, uint32, uint32, uint32) { + function getStats() + public + view + onlyOwner + returns (bytes32, bytes memory, bytes memory, uint32, uint32, uint32, uint32) + { return ( lastRequestID, lastResponse, @@ -79,10 +136,9 @@ contract FunctionsLoadTestClient is FunctionsClient, ConfirmedOwner { * Either response or error parameter will be set, but never both */ function fulfillRequest(bytes32 requestId, bytes memory response, bytes memory err) internal override { - // Save only the first 32 bytes of response/error to always fit within MAX_CALLBACK_GAS lastRequestID = requestId; - lastResponse = bytesToBytes32(response); - lastError = bytesToBytes32(err); + lastResponse = response; + lastError = err; if (response.length == 0) { totalEmptyResponses += 1; } @@ -93,15 +149,4 @@ contract FunctionsLoadTestClient is FunctionsClient, ConfirmedOwner { totalSucceededResponses += 1; } } - - function bytesToBytes32(bytes memory b) private pure returns (bytes32 out) { - uint256 maxLen = 32; - if (b.length < 32) { - maxLen = b.length; - } - for (uint256 i = 0; i < maxLen; ++i) { - out |= bytes32(b[i]) >> (i * 8); - } - return out; - } } diff --git a/contracts/src/v0.8/functions/tests/1_0_0/testhelpers/FunctionsTestHelper.sol b/contracts/src/v0.8/functions/tests/1_0_0/testhelpers/FunctionsTestHelper.sol index 57ae6e0bbad..73f10071dbc 100644 --- a/contracts/src/v0.8/functions/tests/1_0_0/testhelpers/FunctionsTestHelper.sol +++ b/contracts/src/v0.8/functions/tests/1_0_0/testhelpers/FunctionsTestHelper.sol @@ -41,12 +41,6 @@ contract FunctionsTestHelper { storeRequest(r); } - function addSignature(bytes memory signature) public { - FunctionsRequest.Request memory r = s_req; - r.requestSignature = signature; - storeRequest(r); - } - function storeRequest(FunctionsRequest.Request memory r) private { s_req.codeLocation = r.codeLocation; s_req.language = r.language; @@ -54,6 +48,5 @@ contract FunctionsTestHelper { s_req.args = r.args; s_req.secretsLocation = r.secretsLocation; s_req.encryptedSecretsReference = r.encryptedSecretsReference; - s_req.requestSignature = r.requestSignature; } } diff --git a/contracts/src/v0.8/llo-feeds/VerifierProxy.sol b/contracts/src/v0.8/llo-feeds/VerifierProxy.sol index be2f411c0e9..4df6691b6ac 100644 --- a/contracts/src/v0.8/llo-feeds/VerifierProxy.sol +++ b/contracts/src/v0.8/llo-feeds/VerifierProxy.sol @@ -7,7 +7,7 @@ import {IVerifier} from "./interfaces/IVerifier.sol"; import {TypeAndVersionInterface} from "../interfaces/TypeAndVersionInterface.sol"; import {AccessControllerInterface} from "../shared/interfaces/AccessControllerInterface.sol"; import {IERC165} from "../vendor/openzeppelin-solidity/v4.8.0/contracts/interfaces/IERC165.sol"; -import {IVerifierFeeManager} from "./interfaces/IVerifierFeeManager.sol"; +import {IVerifierFeeManager} from "./dev/interfaces/IVerifierFeeManager.sol"; import {Common} from "../libraries/Common.sol"; /** @@ -65,6 +65,10 @@ contract VerifierProxy is IVerifierProxy, ConfirmedOwner, TypeAndVersionInterfac /// not conform to the verifier interface error VerifierInvalid(); + /// @notice This error is thrown when the fee manager at an address does + /// not conform to the fee manager interface + error FeeManagerInvalid(); + /// @notice This error is thrown whenever a verifier is not found /// @param configDigest The digest for which a verifier is not found error VerifierNotFound(bytes32 configDigest); @@ -117,7 +121,7 @@ contract VerifierProxy is IVerifierProxy, ConfirmedOwner, TypeAndVersionInterfac } /// @inheritdoc IVerifierProxy - function verify(bytes calldata payload) external payable checkAccess returns (bytes memory verifiedReport) { + function verify(bytes calldata payload) external payable checkAccess returns (bytes memory) { IVerifierFeeManager feeManager = s_feeManager; // Bill the verifier @@ -192,7 +196,7 @@ contract VerifierProxy is IVerifierProxy, ConfirmedOwner, TypeAndVersionInterfac } /// @inheritdoc IVerifierProxy - function getVerifier(bytes32 configDigest) external view override returns (address verifierAddress) { + function getVerifier(bytes32 configDigest) external view override returns (address) { return s_verifiersByConfig[configDigest]; } @@ -207,6 +211,11 @@ contract VerifierProxy is IVerifierProxy, ConfirmedOwner, TypeAndVersionInterfac function setFeeManager(IVerifierFeeManager feeManager) external onlyOwner { if (address(feeManager) == address(0)) revert ZeroAddress(); + if ( + !IERC165(feeManager).supportsInterface(IVerifierFeeManager.processFee.selector) || + !IERC165(feeManager).supportsInterface(IVerifierFeeManager.processFeeBulk.selector) + ) revert FeeManagerInvalid(); + address oldFeeManager = address(s_feeManager); s_feeManager = IVerifierFeeManager(feeManager); emit FeeManagerSet(oldFeeManager, address(feeManager)); diff --git a/contracts/src/v0.8/llo-feeds/dev/FeeManager.sol b/contracts/src/v0.8/llo-feeds/dev/FeeManager.sol index 341ac19762e..2e5d060dca6 100644 --- a/contracts/src/v0.8/llo-feeds/dev/FeeManager.sol +++ b/contracts/src/v0.8/llo-feeds/dev/FeeManager.sol @@ -11,6 +11,7 @@ import {IWERC20} from "../../shared/interfaces/IWERC20.sol"; import {IERC20} from "../../vendor/openzeppelin-solidity/v4.8.0/contracts/interfaces/IERC20.sol"; import {Math} from "../../vendor/openzeppelin-solidity/v4.8.0/contracts/utils/math/Math.sol"; import {SafeERC20} from "../../vendor/openzeppelin-solidity/v4.8.0/contracts/token/ERC20/utils/SafeERC20.sol"; +import {IVerifierFeeManager} from "./interfaces/IVerifierFeeManager.sol"; /** * @title FeeManager @@ -75,6 +76,9 @@ contract FeeManager is IFeeManager, ConfirmedOwner, TypeAndVersionInterface { // @notice thrown when trying to clear a zero deficit error ZeroDeficit(); + /// @notice thrown when trying to pay an address that cannot except funds + error InvalidReceivingAddress(); + /// @notice Emitted whenever a subscriber's discount is updated /// @param subscriber address of the subscriber to update discounts for /// @param feedId Feed ID for the discount @@ -91,15 +95,31 @@ contract FeeManager is IFeeManager, ConfirmedOwner, TypeAndVersionInterface { event InsufficientLink(IRewardManager.FeePayment[] rewards); /// @notice Emitted when funds are withdrawn + /// @param adminAddress Address of the admin + /// @param recipient Address of the recipient /// @param assetAddress Address of the asset withdrawn /// @param quantity Amount of the asset withdrawn - event Withdraw(address adminAddress, address assetAddress, uint192 quantity); + event Withdraw(address adminAddress, address recipient, address assetAddress, uint192 quantity); /// @notice Emits when a deficit has been cleared for a particular config digest /// @param configDigest Config digest of the deficit cleared /// @param linkQuantity Amount of LINK required to pay the deficit event LinkDeficitCleared(bytes32 indexed configDigest, uint256 linkQuantity); + /// @notice Emits when a fee has been processed + /// @param configDigest Config digest of the fee processed + /// @param subscriber Address of the subscriber who paid the fee + /// @param fee Fee paid + /// @param reward Reward paid + /// @param appliedDiscount Discount applied to the fee + event DiscountApplied( + bytes32 indexed configDigest, + address indexed subscriber, + Common.Asset fee, + Common.Asset reward, + uint256 appliedDiscount + ); + /** * @notice Construct the FeeManager contract * @param _linkAddress The address of the LINK token @@ -133,9 +153,14 @@ contract FeeManager is IFeeManager, ConfirmedOwner, TypeAndVersionInterface { _; } + modifier onlyProxy() { + if (msg.sender != i_proxyAddress) revert Unauthorized(); + _; + } + /// @inheritdoc TypeAndVersionInterface function typeAndVersion() external pure override returns (string memory) { - return "FeeManager 0.0.1"; + return "FeeManager 1.0.0"; } /// @inheritdoc IERC165 @@ -143,9 +168,9 @@ contract FeeManager is IFeeManager, ConfirmedOwner, TypeAndVersionInterface { return interfaceId == this.processFee.selector || interfaceId == this.processFeeBulk.selector; } - /// @inheritdoc IFeeManager - function processFee(bytes calldata payload, address subscriber) external payable override onlyOwnerOrProxy { - (Common.Asset memory fee, Common.Asset memory reward) = _processFee(payload, subscriber); + /// @inheritdoc IVerifierFeeManager + function processFee(bytes calldata payload, address subscriber) external payable override onlyProxy { + (Common.Asset memory fee, Common.Asset memory reward, uint256 appliedDiscount) = _processFee(payload, subscriber); if (fee.amount == 0) { _tryReturnChange(subscriber, msg.value); @@ -153,7 +178,7 @@ contract FeeManager is IFeeManager, ConfirmedOwner, TypeAndVersionInterface { } IFeeManager.FeeAndReward[] memory feeAndReward = new IFeeManager.FeeAndReward[](1); - feeAndReward[0] = IFeeManager.FeeAndReward(bytes32(payload), fee, reward); + feeAndReward[0] = IFeeManager.FeeAndReward(bytes32(payload), fee, reward, appliedDiscount); if (fee.assetAddress == i_linkAddress) { _handleFeesAndRewards(subscriber, feeAndReward, 1, 0); @@ -162,8 +187,8 @@ contract FeeManager is IFeeManager, ConfirmedOwner, TypeAndVersionInterface { } } - /// @inheritdoc IFeeManager - function processFeeBulk(bytes[] calldata payloads, address subscriber) external payable override onlyOwnerOrProxy { + /// @inheritdoc IVerifierFeeManager + function processFeeBulk(bytes[] calldata payloads, address subscriber) external payable override onlyProxy { FeeAndReward[] memory feesAndRewards = new IFeeManager.FeeAndReward[](payloads.length); //keep track of the number of fees to prevent over initialising the FeePayment array within _convertToLinkAndNativeFees @@ -172,10 +197,18 @@ contract FeeManager is IFeeManager, ConfirmedOwner, TypeAndVersionInterface { uint256 feesAndRewardsIndex; for (uint256 i; i < payloads.length; ++i) { - (Common.Asset memory fee, Common.Asset memory reward) = _processFee(payloads[i], subscriber); + (Common.Asset memory fee, Common.Asset memory reward, uint256 appliedDiscount) = _processFee( + payloads[i], + subscriber + ); if (fee.amount != 0) { - feesAndRewards[feesAndRewardsIndex++] = IFeeManager.FeeAndReward(bytes32(payloads[i]), fee, reward); + feesAndRewards[feesAndRewardsIndex++] = IFeeManager.FeeAndReward( + bytes32(payloads[i]), + fee, + reward, + appliedDiscount + ); unchecked { //keep track of some tallys to make downstream calculations more efficient @@ -200,7 +233,7 @@ contract FeeManager is IFeeManager, ConfirmedOwner, TypeAndVersionInterface { address subscriber, bytes memory report, Quote memory quote - ) public view returns (Common.Asset memory, Common.Asset memory) { + ) public view returns (Common.Asset memory, Common.Asset memory, uint256) { Common.Asset memory fee; Common.Asset memory reward; @@ -214,7 +247,7 @@ contract FeeManager is IFeeManager, ConfirmedOwner, TypeAndVersionInterface { if (reportVersion == REPORT_V1) { fee.assetAddress = i_nativeAddress; reward.assetAddress = i_linkAddress; - return (fee, reward); + return (fee, reward, 0); } //verify the quote payload is a supported token @@ -255,10 +288,10 @@ contract FeeManager is IFeeManager, ConfirmedOwner, TypeAndVersionInterface { } //return the fee - return (fee, reward); + return (fee, reward, discount); } - /// @inheritdoc IFeeManager + /// @inheritdoc IVerifierFeeManager function setFeeRecipients( bytes32 configDigest, Common.AddressAndWeight[] calldata rewardRecipientAndWeights @@ -293,18 +326,20 @@ contract FeeManager is IFeeManager, ConfirmedOwner, TypeAndVersionInterface { } /// @inheritdoc IFeeManager - function withdraw(address assetAddress, uint192 quantity) external onlyOwner { + function withdraw(address assetAddress, address recipient, uint192 quantity) external onlyOwner { //address 0 is used to withdraw native in the context of withdrawing if (assetAddress == address(0)) { - payable(owner()).transfer(quantity); + (bool success, ) = payable(recipient).call{value: quantity}(""); + + if (!success) revert InvalidReceivingAddress(); return; } //withdraw the requested asset - IERC20(assetAddress).safeTransfer(owner(), quantity); + IERC20(assetAddress).safeTransfer(recipient, quantity); //emit event when funds are withdrawn - emit Withdraw(msg.sender, assetAddress, quantity); + emit Withdraw(msg.sender, recipient, assetAddress, uint192(quantity)); } /// @inheritdoc IFeeManager @@ -324,7 +359,7 @@ contract FeeManager is IFeeManager, ConfirmedOwner, TypeAndVersionInterface { function _processFee( bytes calldata payload, address subscriber - ) internal view returns (Common.Asset memory, Common.Asset memory) { + ) internal view returns (Common.Asset memory, Common.Asset memory, uint256) { if (subscriber == address(this)) revert InvalidAddress(); //decode the report from the payload @@ -381,6 +416,16 @@ contract FeeManager is IFeeManager, ConfirmedOwner, TypeAndVersionInterface { totalNativeFee += feesAndRewards[i].fee.amount; totalNativeFeeLinkValue += feesAndRewards[i].reward.amount; } + + if (feesAndRewards[i].appliedDiscount != 0) { + emit DiscountApplied( + feesAndRewards[i].configDigest, + subscriber, + feesAndRewards[i].fee, + feesAndRewards[i].reward, + feesAndRewards[i].appliedDiscount + ); + } } //keep track of change in case of any over payment @@ -390,7 +435,7 @@ contract FeeManager is IFeeManager, ConfirmedOwner, TypeAndVersionInterface { //there must be enough to cover the fee if (totalNativeFee > msg.value) revert InvalidDeposit(); - //wrap the amount required to pay the fee & approve as the subscriber paid in unwrapped native + //wrap the amount required to pay the fee & approve as the subscriber paid in wrapped native IWERC20(i_nativeAddress).deposit{value: totalNativeFee}(); unchecked { @@ -413,7 +458,10 @@ contract FeeManager is IFeeManager, ConfirmedOwner, TypeAndVersionInterface { if (totalNativeFeeLinkValue > IERC20(i_linkAddress).balanceOf(address(this))) { // If not enough LINK on this contract to forward for rewards, tally the deficit to be paid by out-of-band LINK for (uint256 i; i < nativeFeeLinkRewards.length; ++i) { - s_linkDeficit[nativeFeeLinkRewards[i].poolId] += nativeFeeLinkRewards[i].amount; + unchecked { + //we have previously tallied the fees, any overflows would have already reverted + s_linkDeficit[nativeFeeLinkRewards[i].poolId] += nativeFeeLinkRewards[i].amount; + } } emit InsufficientLink(nativeFeeLinkRewards); diff --git a/contracts/src/v0.8/llo-feeds/dev/RewardManager.sol b/contracts/src/v0.8/llo-feeds/dev/RewardManager.sol index 8858f82c958..3f7e524c02b 100644 --- a/contracts/src/v0.8/llo-feeds/dev/RewardManager.sol +++ b/contracts/src/v0.8/llo-feeds/dev/RewardManager.sol @@ -54,11 +54,14 @@ contract RewardManager is IRewardManager, ConfirmedOwner, TypeAndVersionInterfac // @notice Thrown when the calling contract is not within the authorized contracts error Unauthorized(); + // @notice Thrown when getAvailableRewardPoolIds parameters are incorrectly set + error InvalidPoolLength(); + // Events emitted upon state change event RewardRecipientsUpdated(bytes32 indexed poolId, Common.AddressAndWeight[] newRewardRecipients); event RewardsClaimed(bytes32 indexed poolId, address indexed recipient, uint192 quantity); event FeeManagerUpdated(address newFeeManagerAddress); - event FeePaid(FeePayment[] payments, address payee); + event FeePaid(FeePayment[] payments, address payer); /** * @notice Constructor @@ -73,7 +76,7 @@ contract RewardManager is IRewardManager, ConfirmedOwner, TypeAndVersionInterfac // @inheritdoc TypeAndVersionInterface function typeAndVersion() external pure override returns (string memory) { - return "RewardManager 0.0.1"; + return "RewardManager 1.0.0"; } // @inheritdoc IERC165 @@ -91,8 +94,13 @@ contract RewardManager is IRewardManager, ConfirmedOwner, TypeAndVersionInterfac _; } + modifier onlyFeeManager() { + if (msg.sender != s_feeManagerAddress) revert Unauthorized(); + _; + } + /// @inheritdoc IRewardManager - function onFeePaid(FeePayment[] calldata payments, address payee) external override onlyOwnerOrFeeManager { + function onFeePaid(FeePayment[] calldata payments, address payer) external override onlyFeeManager { uint256 totalFeeAmount; for (uint256 i; i < payments.length; ++i) { unchecked { @@ -105,9 +113,9 @@ contract RewardManager is IRewardManager, ConfirmedOwner, TypeAndVersionInterfac } //transfer the fees to this contract - IERC20(i_linkAddress).safeTransferFrom(payee, address(this), totalFeeAmount); + IERC20(i_linkAddress).safeTransferFrom(payer, address(this), totalFeeAmount); - emit FeePaid(payments, payee); + emit FeePaid(payments, payer); } /// @inheritdoc IRewardManager @@ -276,19 +284,28 @@ contract RewardManager is IRewardManager, ConfirmedOwner, TypeAndVersionInterfac } /// @inheritdoc IRewardManager - function getAvailableRewardPoolIds(address recipient) external view returns (bytes32[] memory) { + function getAvailableRewardPoolIds( + address recipient, + uint256 startIndex, + uint256 endIndex + ) external view returns (bytes32[] memory) { //get the length of the pool ids which we will loop through and potentially return uint256 registeredPoolIdsLength = s_registeredPoolIds.length; + uint256 lastIndex = endIndex > registeredPoolIdsLength ? registeredPoolIdsLength : endIndex; + + if (startIndex > lastIndex) revert InvalidPoolLength(); + //create a new array with the maximum amount of potential pool ids - bytes32[] memory claimablePoolIds = new bytes32[](registeredPoolIdsLength); + bytes32[] memory claimablePoolIds = new bytes32[](lastIndex - startIndex); //we want the pools which a recipient has funds for to be sequential, so we need to keep track of the index uint256 poolIdArrayIndex; //loop all the pool ids, and check if the recipient has a registered weight and a claimable amount - for (uint256 i; i < registeredPoolIdsLength; ++i) { + for (uint256 i = startIndex; i < lastIndex; ++i) { //get the poolId bytes32 poolId = s_registeredPoolIds[i]; + //if the recipient has a weight, they are a recipient of this poolId if (s_rewardRecipientWeights[poolId][recipient] != 0) { //get the total in this pool diff --git a/contracts/src/v0.8/llo-feeds/dev/interfaces/IFeeManager.sol b/contracts/src/v0.8/llo-feeds/dev/interfaces/IFeeManager.sol index ff81aafe5d3..49fd7f95587 100644 --- a/contracts/src/v0.8/llo-feeds/dev/interfaces/IFeeManager.sol +++ b/contracts/src/v0.8/llo-feeds/dev/interfaces/IFeeManager.sol @@ -3,49 +3,21 @@ pragma solidity 0.8.16; import {IERC165} from "../../../vendor/openzeppelin-solidity/v4.8.0/contracts/interfaces/IERC165.sol"; import {Common} from "../../../libraries/Common.sol"; -import {IVerifierFeeManager} from "../../interfaces/IVerifierFeeManager.sol"; +import {IVerifierFeeManager} from "./IVerifierFeeManager.sol"; interface IFeeManager is IERC165, IVerifierFeeManager { - struct Quote { - address quoteAddress; - } - - /** - * @notice Processes the fee for a report, billing the subscriber and paying the reward manager - * @param payload report and quote data to process the fee for - * @param subscriber address of the user to process fee for - */ - function processFee(bytes calldata payload, address subscriber) external payable; - - /** - * @notice Processes the fees for each report in the payload, billing the subscriber and paying the reward manager - * @param payloads reports and quotes to process - * @param subscriber address of the user to process fee for - */ - function processFeeBulk(bytes[] calldata payloads, address subscriber) external payable; - /** * @notice Calculate the applied fee and the reward from a report. If the sender is a subscriber, they will receive a discount. * @param subscriber address trying to verify * @param report report to calculate the fee for * @param quote any metadata required to fetch the fee - * @return (fee, reward) fee and the reward data + * @return (fee, reward, totalDiscount) fee and the reward data with the discount applied */ function getFeeAndReward( address subscriber, bytes memory report, Quote memory quote - ) external returns (Common.Asset memory, Common.Asset memory); - - /** - * @notice Sets the fee recipients within the reward manager - * @param configDigest digest of the configuration - * @param rewardRecipientAndWeights the address and weights of all the recipients to receive rewards - */ - function setFeeRecipients( - bytes32 configDigest, - Common.AddressAndWeight[] calldata rewardRecipientAndWeights - ) external; + ) external returns (Common.Asset memory, Common.Asset memory, uint256); /** * @notice Sets the native surcharge @@ -64,10 +36,11 @@ interface IFeeManager is IERC165, IVerifierFeeManager { /** * @notice Withdraws any native or LINK rewards to the owner address - * @param quantity quantity of tokens to withdraw, address(0) is native + * @param assetAddress address of the asset to withdraw + * @param recipientAddress address to withdraw to * @param quantity quantity to withdraw */ - function withdraw(address assetAddress, uint192 quantity) external; + function withdraw(address assetAddress, address recipientAddress, uint192 quantity) external; /** * @notice Returns the link balance of the fee manager @@ -86,10 +59,20 @@ interface IFeeManager is IERC165, IVerifierFeeManager { * @param digest the digest linked to the fee and reward * @param fee the fee paid to verify the report * @param reward the reward paid upon verification + & @param appliedDiscount the discount applied to the reward */ struct FeeAndReward { bytes32 configDigest; Common.Asset fee; Common.Asset reward; + uint256 appliedDiscount; + } + + /** + * @notice The structure to hold quote metadata + * @param quoteAddress the address of the quote + */ + struct Quote { + address quoteAddress; } } diff --git a/contracts/src/v0.8/llo-feeds/dev/interfaces/IRewardManager.sol b/contracts/src/v0.8/llo-feeds/dev/interfaces/IRewardManager.sol index e9b351c935c..8f6b1921e94 100644 --- a/contracts/src/v0.8/llo-feeds/dev/interfaces/IRewardManager.sol +++ b/contracts/src/v0.8/llo-feeds/dev/interfaces/IRewardManager.sol @@ -48,8 +48,14 @@ interface IRewardManager is IERC165 { /** * @notice Gets a list of pool ids which have reward for a specific recipient. * @param recipient address of the recipient to get pool ids for + * @param startIndex the index to start from + * @param endIndex the index to stop at */ - function getAvailableRewardPoolIds(address recipient) external view returns (bytes32[] memory); + function getAvailableRewardPoolIds( + address recipient, + uint256 startIndex, + uint256 endIndex + ) external view returns (bytes32[] memory); /** * @notice The structure to hold a fee payment notice diff --git a/contracts/src/v0.8/llo-feeds/interfaces/IVerifierFeeManager.sol b/contracts/src/v0.8/llo-feeds/dev/interfaces/IVerifierFeeManager.sol similarity index 87% rename from contracts/src/v0.8/llo-feeds/interfaces/IVerifierFeeManager.sol rename to contracts/src/v0.8/llo-feeds/dev/interfaces/IVerifierFeeManager.sol index 92220582ba4..c9b1a821746 100644 --- a/contracts/src/v0.8/llo-feeds/interfaces/IVerifierFeeManager.sol +++ b/contracts/src/v0.8/llo-feeds/dev/interfaces/IVerifierFeeManager.sol @@ -1,8 +1,8 @@ // SPDX-License-Identifier: MIT pragma solidity 0.8.16; -import {IERC165} from "../../vendor/openzeppelin-solidity/v4.8.0/contracts/interfaces/IERC165.sol"; -import {Common} from "../../libraries/Common.sol"; +import {IERC165} from "../../../vendor/openzeppelin-solidity/v4.8.0/contracts/interfaces/IERC165.sol"; +import {Common} from "../../../libraries/Common.sol"; interface IVerifierFeeManager is IERC165 { /** diff --git a/contracts/src/v0.8/llo-feeds/interfaces/IVerifierProxy.sol b/contracts/src/v0.8/llo-feeds/interfaces/IVerifierProxy.sol index be221263c56..82ac492f5c3 100644 --- a/contracts/src/v0.8/llo-feeds/interfaces/IVerifierProxy.sol +++ b/contracts/src/v0.8/llo-feeds/interfaces/IVerifierProxy.sol @@ -3,7 +3,7 @@ pragma solidity 0.8.16; import {Common} from "../../libraries/Common.sol"; import {AccessControllerInterface} from "../../shared/interfaces/AccessControllerInterface.sol"; -import {IVerifierFeeManager} from "./IVerifierFeeManager.sol"; +import {IVerifierFeeManager} from "./../dev/interfaces/IVerifierFeeManager.sol"; interface IVerifierProxy { /** diff --git a/contracts/src/v0.8/llo-feeds/test/fee-manager/BaseFeeManager.t.sol b/contracts/src/v0.8/llo-feeds/test/fee-manager/BaseFeeManager.t.sol index 10bd89331f1..6b8858fc93f 100644 --- a/contracts/src/v0.8/llo-feeds/test/fee-manager/BaseFeeManager.t.sol +++ b/contracts/src/v0.8/llo-feeds/test/fee-manager/BaseFeeManager.t.sol @@ -75,8 +75,15 @@ contract BaseFeeManagerTest is Test { event SubscriberDiscountUpdated(address indexed subscriber, bytes32 indexed feedId, address token, uint64 discount); event NativeSurchargeUpdated(uint64 newSurcharge); event InsufficientLink(IRewardManager.FeePayment[] feesAndRewards); - event Withdraw(address adminAddress, address assetAddress, uint192 quantity); + event Withdraw(address adminAddress, address recipient, address assetAddress, uint192 quantity); event LinkDeficitCleared(bytes32 indexed configDigest, uint256 linkQuantity); + event DiscountApplied( + bytes32 indexed configDigest, + address indexed subscriber, + Common.Asset fee, + Common.Asset reward, + uint256 appliedDiscountQuantity + ); function setUp() public virtual { //change to admin user @@ -153,7 +160,7 @@ contract BaseFeeManagerTest is Test { address subscriber ) public view returns (Common.Asset memory) { //get the fee - (Common.Asset memory fee, ) = feeManager.getFeeAndReward(subscriber, report, quote); + (Common.Asset memory fee, , ) = feeManager.getFeeAndReward(subscriber, report, quote); return fee; } @@ -164,11 +171,22 @@ contract BaseFeeManagerTest is Test { address subscriber ) public view returns (Common.Asset memory) { //get the reward - (, Common.Asset memory reward) = feeManager.getFeeAndReward(subscriber, report, quote); + (, Common.Asset memory reward, ) = feeManager.getFeeAndReward(subscriber, report, quote); return reward; } + function getAppliedDiscount( + bytes memory report, + IFeeManager.Quote memory quote, + address subscriber + ) public view returns (uint256) { + //get the reward + (, , uint256 appliedDiscount) = feeManager.getFeeAndReward(subscriber, report, quote); + + return appliedDiscount; + } + function getV1Report(bytes32 feedId) public pure returns (bytes memory) { return abi.encode(feedId, uint32(0), int192(0), int192(0), int192(0), uint64(0), bytes32(0), uint64(0), uint64(0)); } @@ -229,13 +247,13 @@ contract BaseFeeManagerTest is Test { return IFeeManager.Quote(getNativeAddress()); } - function withdraw(address assetAddress, uint256 amount, address sender) public { + function withdraw(address assetAddress, address recipient, uint256 amount, address sender) public { //record the current address and switch to the recipient address originalAddr = msg.sender; changePrank(sender); //set the surcharge - feeManager.withdraw(assetAddress, uint192(amount)); + feeManager.withdraw(assetAddress, recipient, uint192(amount)); //change back to the original address changePrank(originalAddr); diff --git a/contracts/src/v0.8/llo-feeds/test/fee-manager/FeeManager.general.t.sol b/contracts/src/v0.8/llo-feeds/test/fee-manager/FeeManager.general.t.sol index 2e5d6cf15e7..d776c54eb36 100644 --- a/contracts/src/v0.8/llo-feeds/test/fee-manager/FeeManager.general.t.sol +++ b/contracts/src/v0.8/llo-feeds/test/fee-manager/FeeManager.general.t.sol @@ -28,7 +28,7 @@ contract FeeManagerProcessFeeTest is BaseFeeManagerTest { uint256 withdrawAmount = contractBalance / 2; //withdraw some balance - withdraw(getLinkAddress(), withdrawAmount, ADMIN); + withdraw(getLinkAddress(), ADMIN, withdrawAmount, ADMIN); //check the balance has been reduced uint256 newContractBalance = getLinkBalance(address(feeManager)); @@ -54,7 +54,7 @@ contract FeeManagerProcessFeeTest is BaseFeeManagerTest { uint256 withdrawAmount = contractBalance / 2; //withdraw some balance - withdraw(NATIVE_WITHDRAW_ADDRESS, withdrawAmount, ADMIN); + withdraw(NATIVE_WITHDRAW_ADDRESS, ADMIN, withdrawAmount, ADMIN); //check the balance has been reduced uint256 newContractBalance = getNativeUnwrappedBalance(address(feeManager)); @@ -76,7 +76,7 @@ contract FeeManagerProcessFeeTest is BaseFeeManagerTest { vm.expectRevert(ONLY_CALLABLE_BY_OWNER_ERROR); //withdraw some balance - withdraw(getLinkAddress(), DEFAULT_LINK_MINT_QUANTITY, USER); + withdraw(getLinkAddress(), ADMIN, DEFAULT_LINK_MINT_QUANTITY, USER); } function test_eventIsEmittedAfterSurchargeIsSet() public { @@ -118,10 +118,10 @@ contract FeeManagerProcessFeeTest is BaseFeeManagerTest { vm.expectEmit(); //the event to be emitted - emit Withdraw(ADMIN, getLinkAddress(), withdrawAmount); + emit Withdraw(ADMIN, ADMIN, getLinkAddress(), withdrawAmount); //withdraw some balance - withdraw(getLinkAddress(), withdrawAmount, ADMIN); + withdraw(getLinkAddress(), ADMIN, withdrawAmount, ADMIN); } function test_linkAvailableForPaymentReturnsLinkBalance() public { diff --git a/contracts/src/v0.8/llo-feeds/test/fee-manager/FeeManager.getFeeAndReward.t.sol b/contracts/src/v0.8/llo-feeds/test/fee-manager/FeeManager.getFeeAndReward.t.sol index d59ced1a237..f31c06bd41e 100644 --- a/contracts/src/v0.8/llo-feeds/test/fee-manager/FeeManager.getFeeAndReward.t.sol +++ b/contracts/src/v0.8/llo-feeds/test/fee-manager/FeeManager.getFeeAndReward.t.sol @@ -570,4 +570,40 @@ contract FeeManagerProcessFeeTest is BaseFeeManagerTest { USER ); } + + function test_discountIsReturnedForLink() public { + //set the subscriber discount to 50% + setSubscriberDiscount(USER, DEFAULT_FEED_1_V3, getLinkAddress(), FEE_SCALAR / 2, ADMIN); + + //get the fee applied + uint256 discount = getAppliedDiscount(getV3Report(DEFAULT_FEED_1_V3), getLinkQuote(), USER); + + //fee should be half the default + assertEq(discount, FEE_SCALAR / 2); + } + + function test_DiscountIsReturnedForNative() public { + //set the subscriber discount to 50% + setSubscriberDiscount(USER, DEFAULT_FEED_1_V3, getNativeAddress(), FEE_SCALAR / 2, ADMIN); + + //get the discount applied + uint256 discount = getAppliedDiscount(getV3Report(DEFAULT_FEED_1_V3), getNativeQuote(), USER); + + //fee should be half the default + assertEq(discount, FEE_SCALAR / 2); + } + + function test_DiscountIsReturnedForNativeWithSurcharge() public { + //set the subscriber discount to 50% + setSubscriberDiscount(USER, DEFAULT_FEED_1_V3, getNativeAddress(), FEE_SCALAR / 2, ADMIN); + + //set the surcharge + setNativeSurcharge(FEE_SCALAR / 5, ADMIN); + + //get the discount applied + uint256 discount = getAppliedDiscount(getV3Report(DEFAULT_FEED_1_V3), getNativeQuote(), USER); + + //fee should be half the default + assertEq(discount, FEE_SCALAR / 2); + } } diff --git a/contracts/src/v0.8/llo-feeds/test/fee-manager/FeeManager.processFee.t.sol b/contracts/src/v0.8/llo-feeds/test/fee-manager/FeeManager.processFee.t.sol index ab13a60c371..aa0ca063d85 100644 --- a/contracts/src/v0.8/llo-feeds/test/fee-manager/FeeManager.processFee.t.sol +++ b/contracts/src/v0.8/llo-feeds/test/fee-manager/FeeManager.processFee.t.sol @@ -455,4 +455,46 @@ contract FeeManagerProcessFeeTest is BaseFeeManagerTest { //check the unused native passed in is returned assertEq(USER.balance, DEFAULT_NATIVE_MINT_QUANTITY); } + + function test_processFeeWithDiscountEmitsEvent() public { + //simulate a deposit of link for the conversion pool + mintLink(address(feeManager), DEFAULT_REPORT_LINK_FEE); + + //set the subscriber discount to 50% + setSubscriberDiscount(USER, DEFAULT_FEED_1_V3, getNativeAddress(), FEE_SCALAR / 2, ADMIN); + + //approve the native to be transferred from the user + approveNative(address(feeManager), DEFAULT_REPORT_NATIVE_FEE / 2, USER); + + //get the default payload + bytes memory payload = getPayload(getV3Report(DEFAULT_FEED_1_V3), getQuotePayload(getNativeAddress())); + + Common.Asset memory fee = getFee(getV3Report(DEFAULT_FEED_1_V3), getNativeQuote(), USER); + Common.Asset memory reward = getReward(getV3Report(DEFAULT_FEED_1_V3), getNativeQuote(), USER); + uint256 appliedDiscount = getAppliedDiscount(getV3Report(DEFAULT_FEED_1_V3), getNativeQuote(), USER); + + vm.expectEmit(); + + emit DiscountApplied(DEFAULT_CONFIG_DIGEST, USER, fee, reward, appliedDiscount); + + //call processFee should not revert as the fee is 0 + processFee(payload, USER, 0); + } + + function test_processFeeWithNoDiscountDoesNotEmitEvent() public { + //simulate a deposit of link for the conversion pool + mintLink(address(feeManager), DEFAULT_REPORT_LINK_FEE); + + //approve the native to be transferred from the user + approveNative(address(feeManager), DEFAULT_REPORT_NATIVE_FEE, USER); + + //get the default payload + bytes memory payload = getPayload(getV3Report(DEFAULT_FEED_1_V3), getQuotePayload(getNativeAddress())); + + //call processFee should not revert as the fee is 0 + processFee(payload, USER, 0); + + //no logs should have been emitted + assertEq(vm.getRecordedLogs().length, 0); + } } diff --git a/contracts/src/v0.8/llo-feeds/test/reward-manager/BaseRewardManager.t.sol b/contracts/src/v0.8/llo-feeds/test/reward-manager/BaseRewardManager.t.sol index a54431b64a2..a82859df624 100644 --- a/contracts/src/v0.8/llo-feeds/test/reward-manager/BaseRewardManager.t.sol +++ b/contracts/src/v0.8/llo-feeds/test/reward-manager/BaseRewardManager.t.sol @@ -67,6 +67,7 @@ contract BaseRewardManagerTest is Test { bytes4 internal immutable INVALID_WEIGHT_ERROR_SELECTOR = RewardManager.InvalidWeights.selector; bytes4 internal immutable INVALID_POOL_ID_ERROR_SELECTOR = RewardManager.InvalidPoolId.selector; bytes internal constant ONLY_CALLABLE_BY_OWNER_ERROR = "Only callable by owner"; + bytes4 internal immutable INVALID_POOL_LENGTH_SELECTOR = RewardManager.InvalidPoolLength.selector; // Events emitted within the reward manager event RewardRecipientsUpdated(bytes32 indexed poolId, Common.AddressAndWeight[] newRewardRecipients); diff --git a/contracts/src/v0.8/llo-feeds/test/reward-manager/RewardManager.claim.t.sol b/contracts/src/v0.8/llo-feeds/test/reward-manager/RewardManager.claim.t.sol index db514c5dd8a..9a3749d1dde 100644 --- a/contracts/src/v0.8/llo-feeds/test/reward-manager/RewardManager.claim.t.sol +++ b/contracts/src/v0.8/llo-feeds/test/reward-manager/RewardManager.claim.t.sol @@ -550,7 +550,11 @@ contract RewardManagerRecipientClaimMultiplePoolsTest is BaseRewardManagerTest { function test_getRewardsAvailableToRecipientInBothPools() public { //get index 0 as this recipient is in both default pools - bytes32[] memory poolIds = rewardManager.getAvailableRewardPoolIds(getPrimaryRecipients()[0].addr); + bytes32[] memory poolIds = rewardManager.getAvailableRewardPoolIds( + getPrimaryRecipients()[0].addr, + 0, + type(uint256).max + ); //check the recipient is in both pools assertEq(poolIds[0], PRIMARY_POOL_ID); @@ -559,7 +563,11 @@ contract RewardManagerRecipientClaimMultiplePoolsTest is BaseRewardManagerTest { function test_getRewardsAvailableToRecipientInSinglePool() public { //get index 0 as this recipient is in both default pools - bytes32[] memory poolIds = rewardManager.getAvailableRewardPoolIds(getPrimaryRecipients()[1].addr); + bytes32[] memory poolIds = rewardManager.getAvailableRewardPoolIds( + getPrimaryRecipients()[1].addr, + 0, + type(uint256).max + ); //check the recipient is in both pools assertEq(poolIds[0], PRIMARY_POOL_ID); @@ -568,7 +576,7 @@ contract RewardManagerRecipientClaimMultiplePoolsTest is BaseRewardManagerTest { function test_getRewardsAvailableToRecipientInNoPools() public { //get index 0 as this recipient is in both default pools - bytes32[] memory poolIds = rewardManager.getAvailableRewardPoolIds(FEE_MANAGER); + bytes32[] memory poolIds = rewardManager.getAvailableRewardPoolIds(FEE_MANAGER, 0, type(uint256).max); //check the recipient is in neither pool assertEq(poolIds[0], ZERO_POOL_ID); @@ -577,7 +585,11 @@ contract RewardManagerRecipientClaimMultiplePoolsTest is BaseRewardManagerTest { function test_getRewardsAvailableToRecipientInBothPoolsWhereAlreadyClaimed() public { //get index 0 as this recipient is in both default pools - bytes32[] memory poolIds = rewardManager.getAvailableRewardPoolIds(getPrimaryRecipients()[0].addr); + bytes32[] memory poolIds = rewardManager.getAvailableRewardPoolIds( + getPrimaryRecipients()[0].addr, + 0, + type(uint256).max + ); //check the recipient is in both pools assertEq(poolIds[0], PRIMARY_POOL_ID); @@ -588,12 +600,30 @@ contract RewardManagerRecipientClaimMultiplePoolsTest is BaseRewardManagerTest { claimRewards(SECONDARY_POOL_ARRAY, getSecondaryRecipients()[0].addr); //get the available pools again - poolIds = rewardManager.getAvailableRewardPoolIds(getPrimaryRecipients()[0].addr); + poolIds = rewardManager.getAvailableRewardPoolIds(getPrimaryRecipients()[0].addr, 0, type(uint256).max); //user should not be in any pool assertEq(poolIds[0], ZERO_POOL_ID); assertEq(poolIds[1], ZERO_POOL_ID); } + + function test_getAvailableRewardsCursorCannotBeGreaterThanTotalPools() public { + vm.expectRevert(INVALID_POOL_LENGTH_SELECTOR); + + rewardManager.getAvailableRewardPoolIds(FEE_MANAGER, type(uint256).max, 0); + } + + function test_getAvailableRewardsCursorAndTotalPoolsEqual() public { + bytes32[] memory poolIds = rewardManager.getAvailableRewardPoolIds(getPrimaryRecipients()[0].addr, 2, 2); + + assertEq(poolIds.length, 0); + } + + function test_getAvailableRewardsCursorSingleResult() public { + bytes32[] memory poolIds = rewardManager.getAvailableRewardPoolIds(getPrimaryRecipients()[0].addr, 0, 1); + + assertEq(poolIds[0], PRIMARY_POOL_ID); + } } contract RewardManagerRecipientClaimDifferentWeightsTest is BaseRewardManagerTest { diff --git a/contracts/src/v0.8/llo-feeds/test/verifier/VerifierProxyTest.t.sol b/contracts/src/v0.8/llo-feeds/test/verifier/VerifierProxyTest.t.sol index 4d1c57cd822..0aae95b3da2 100644 --- a/contracts/src/v0.8/llo-feeds/test/verifier/VerifierProxyTest.t.sol +++ b/contracts/src/v0.8/llo-feeds/test/verifier/VerifierProxyTest.t.sol @@ -14,4 +14,14 @@ contract VerifierProxyInitializeVerifierTest is BaseTestWithConfiguredVerifierAn vm.expectRevert(abi.encodeWithSelector(VerifierProxy.ZeroAddress.selector)); s_verifierProxy.setFeeManager(FeeManager(address(0))); } + + function test_setFeeManagerWhichDoesntHonourInterface() public { + vm.expectRevert(abi.encodeWithSelector(VerifierProxy.FeeManagerInvalid.selector)); + s_verifierProxy.setFeeManager(FeeManager(address(s_verifier))); + } + + function test_setFeeManagerWhichDoesntHonourIERC165Interface() public { + vm.expectRevert(); + s_verifierProxy.setFeeManager(FeeManager(address(1))); + } } diff --git a/contracts/src/v0.8/mocks/VRFCoordinatorV2Mock.sol b/contracts/src/v0.8/mocks/VRFCoordinatorV2Mock.sol index 8dfb0dca7c5..34a3334189d 100644 --- a/contracts/src/v0.8/mocks/VRFCoordinatorV2Mock.sol +++ b/contracts/src/v0.8/mocks/VRFCoordinatorV2Mock.sol @@ -5,8 +5,9 @@ pragma solidity ^0.8.4; import "../shared/interfaces/LinkTokenInterface.sol"; import "../interfaces/VRFCoordinatorV2Interface.sol"; import "../vrf/VRFConsumerBaseV2.sol"; +import "../shared/access/ConfirmedOwner.sol"; -contract VRFCoordinatorV2Mock is VRFCoordinatorV2Interface { +contract VRFCoordinatorV2Mock is VRFCoordinatorV2Interface, ConfirmedOwner { uint96 public immutable BASE_FEE; uint96 public immutable GAS_PRICE_LINK; uint16 public immutable MAX_CONSUMERS = 100; @@ -17,6 +18,7 @@ contract VRFCoordinatorV2Mock is VRFCoordinatorV2Interface { error TooManyConsumers(); error InvalidConsumer(); error InvalidRandomWords(); + error Reentrant(); event RandomWordsRequested( bytes32 indexed keyHash, @@ -34,7 +36,13 @@ contract VRFCoordinatorV2Mock is VRFCoordinatorV2Interface { event SubscriptionCanceled(uint64 indexed subId, address to, uint256 amount); event ConsumerAdded(uint64 indexed subId, address consumer); event ConsumerRemoved(uint64 indexed subId, address consumer); + event ConfigSet(); + struct Config { + // Reentrancy protection. + bool reentrancyLock; + } + Config private s_config; uint64 s_currentSubId; uint256 s_nextRequestId = 1; uint256 s_nextPreSeed = 100; @@ -52,9 +60,18 @@ contract VRFCoordinatorV2Mock is VRFCoordinatorV2Interface { } mapping(uint256 => Request) s_requests; /* requestId */ /* request */ - constructor(uint96 _baseFee, uint96 _gasPriceLink) { + constructor(uint96 _baseFee, uint96 _gasPriceLink) ConfirmedOwner(msg.sender) { BASE_FEE = _baseFee; GAS_PRICE_LINK = _gasPriceLink; + setConfig(); + } + + /** + * @notice Sets the configuration of the vrfv2 mock coordinator + */ + function setConfig() public onlyOwner { + s_config = Config({reentrancyLock: false}); + emit ConfigSet(); } function consumerIsAdded(uint64 _subId, address _consumer) public view returns (bool) { @@ -85,7 +102,7 @@ contract VRFCoordinatorV2Mock is VRFCoordinatorV2Interface { * @param _requestId the request to fulfill * @param _consumer the VRF randomness consumer to send the result to */ - function fulfillRandomWords(uint256 _requestId, address _consumer) external { + function fulfillRandomWords(uint256 _requestId, address _consumer) external nonReentrant { fulfillRandomWordsWithOverride(_requestId, _consumer, new uint256[](0)); } @@ -114,7 +131,9 @@ contract VRFCoordinatorV2Mock is VRFCoordinatorV2Interface { VRFConsumerBaseV2 v; bytes memory callReq = abi.encodeWithSelector(v.rawFulfillRandomWords.selector, _requestId, _words); + s_config.reentrancyLock = true; (bool success, ) = _consumer.call{gas: req.callbackGasLimit}(callReq); + s_config.reentrancyLock = false; uint96 payment = uint96(BASE_FEE + ((startGas - gasleft()) * GAS_PRICE_LINK)); if (s_subscriptions[req.subId].balance < payment) { @@ -146,7 +165,7 @@ contract VRFCoordinatorV2Mock is VRFCoordinatorV2Interface { uint16 _minimumRequestConfirmations, uint32 _callbackGasLimit, uint32 _numWords - ) external override onlyValidConsumer(_subId, msg.sender) returns (uint256) { + ) external override nonReentrant onlyValidConsumer(_subId, msg.sender) returns (uint256) { if (s_subscriptions[_subId].owner == address(0)) { revert InvalidSubscription(); } @@ -185,7 +204,7 @@ contract VRFCoordinatorV2Mock is VRFCoordinatorV2Interface { return (s_subscriptions[_subId].balance, 0, s_subscriptions[_subId].owner, s_consumers[_subId]); } - function cancelSubscription(uint64 _subId, address _to) external override onlySubOwner(_subId) { + function cancelSubscription(uint64 _subId, address _to) external override onlySubOwner(_subId) nonReentrant { emit SubscriptionCanceled(_subId, _to, s_subscriptions[_subId].balance); delete (s_subscriptions[_subId]); } @@ -221,7 +240,7 @@ contract VRFCoordinatorV2Mock is VRFCoordinatorV2Interface { function removeConsumer( uint64 _subId, address _consumer - ) external override onlySubOwner(_subId) onlyValidConsumer(_subId, _consumer) { + ) external override onlySubOwner(_subId) onlyValidConsumer(_subId, _consumer) nonReentrant { address[] storage consumers = s_consumers[_subId]; for (uint256 i = 0; i < consumers.length; i++) { if (consumers[i] == _consumer) { @@ -276,6 +295,13 @@ contract VRFCoordinatorV2Mock is VRFCoordinatorV2Interface { ); } + modifier nonReentrant() { + if (s_config.reentrancyLock) { + revert Reentrant(); + } + _; + } + function getFallbackWeiPerUnitLink() external view returns (int256) { return 4000000000000000; // 0.004 Ether } diff --git a/contracts/src/v0.8/tests/StreamsLookupUpkeep.sol b/contracts/src/v0.8/tests/StreamsLookupUpkeep.sol index 8cdcf71178d..9b28875020d 100644 --- a/contracts/src/v0.8/tests/StreamsLookupUpkeep.sol +++ b/contracts/src/v0.8/tests/StreamsLookupUpkeep.sol @@ -15,15 +15,7 @@ interface IVerifierProxy { } contract StreamsLookupUpkeep is AutomationCompatibleInterface, StreamsLookupCompatibleInterface { - event MercuryPerformEvent( - address indexed sender, - uint256 indexed blockNumber, - bytes v0, - bytes v1, - bytes verifiedV0, - bytes verifiedV1, - bytes ed - ); + event MercuryPerformEvent(address indexed sender, uint256 indexed blockNumber, bytes v0, bytes verifiedV0, bytes ed); ArbSys internal constant ARB_SYS = ArbSys(0x0000000000000000000000000000000000000064); // keep these in sync with verifier proxy in RDD @@ -53,12 +45,13 @@ contract StreamsLookupUpkeep is AutomationCompatibleInterface, StreamsLookupComp initialBlock = 0; counter = 0; useArbBlock = _useArbBlock; - feedParamKey = "feedIdHex"; // feedIDs for v0.3 - timeParamKey = "blockNumber"; // timestamp + feedParamKey = "feedIDs"; // feedIDs for v0.3 + timeParamKey = "timestamp"; // timestamp // search feeds in notion: "Schema and Feed ID Registry" feeds = [ - "0x4554482d5553442d415242495452554d2d544553544e45540000000000000000", // ETH / USD in production testnet - "0x4254432d5553442d415242495452554d2d544553544e45540000000000000000" // BTC / USD in production testnet + //"0x4554482d5553442d415242495452554d2d544553544e45540000000000000000", // ETH / USD in production testnet v0.2 + //"0x4254432d5553442d415242495452554d2d544553544e45540000000000000000" // BTC / USD in production testnet v0.2 + "0x00028c915d6af0fd66bba2d0fc9405226bca8d6806333121a7d9832103d1563c" // ETH / USD in staging testnet v0.3 ]; staging = _staging; verify = _verify; @@ -99,15 +92,21 @@ contract StreamsLookupUpkeep is AutomationCompatibleInterface, StreamsLookupComp if (!eligible()) { return (false, data); } - uint256 blockNumber; - if (useArbBlock) { - blockNumber = ARB_SYS.arbBlockNumber(); + uint256 timeParam; + if (keccak256(abi.encodePacked(timeParamKey)) == keccak256(abi.encodePacked("feedIdHex"))) { + if (useArbBlock) { + timeParam = ARB_SYS.arbBlockNumber(); + } else { + timeParam = block.number; + } } else { - blockNumber = block.number; + // assume this will be feedIDs for v0.3 + timeParam = block.timestamp; } + // encode ARB_SYS as extraData to verify that it is provided to checkCallback correctly. // in reality, this can be any data or empty - revert StreamsLookup(feedParamKey, feeds, timeParamKey, blockNumber, abi.encodePacked(address(ARB_SYS))); + revert StreamsLookup(feedParamKey, feeds, timeParamKey, timeParam, abi.encodePacked(address(ARB_SYS))); } function performUpkeep(bytes calldata performData) external { @@ -129,13 +128,11 @@ contract StreamsLookupUpkeep is AutomationCompatibleInterface, StreamsLookupComp if (verify) { if (staging) { v0 = STAGING_TESTNET_VERIFIER_PROXY.verify(values[0]); - v1 = STAGING_TESTNET_VERIFIER_PROXY.verify(values[1]); } else { v0 = PRODUCTION_TESTNET_VERIFIER_PROXY.verify(values[0]); - v1 = PRODUCTION_TESTNET_VERIFIER_PROXY.verify(values[1]); } } - emit MercuryPerformEvent(msg.sender, blockNumber, values[0], values[1], v0, v1, extraData); + emit MercuryPerformEvent(msg.sender, blockNumber, values[0], v0, extraData); } function eligible() public view returns (bool) { diff --git a/contracts/src/v0.8/tests/VerifiableLoadLogTriggerUpkeep.sol b/contracts/src/v0.8/tests/VerifiableLoadLogTriggerUpkeep.sol index 355be69d250..02ad2ef2d45 100644 --- a/contracts/src/v0.8/tests/VerifiableLoadLogTriggerUpkeep.sol +++ b/contracts/src/v0.8/tests/VerifiableLoadLogTriggerUpkeep.sol @@ -54,12 +54,20 @@ contract VerifiableLoadLogTriggerUpkeep is VerifiableLoadBase, StreamsLookupComp dummyMap[blockhash(blockNum)] = false; } + uint256 timeParam; + if (keccak256(abi.encodePacked(timeParamKey)) == keccak256(abi.encodePacked("feedIdHex"))) { + timeParam = blockNum; + } else { + // assume this will be feedIDs for v0.3 + timeParam = block.timestamp; + } + if (useMercury) { - revert StreamsLookup(feedParamKey, feedsHex, timeParamKey, blockNum, abi.encode(upkeepId, blockNum, addr)); + revert StreamsLookup(feedParamKey, feedsHex, timeParamKey, timeParam, abi.encode(upkeepId, blockNum, addr)); } // if we don't use mercury, create a perform data which resembles the output of checkCallback - bytes[] memory values = new bytes[](2); + bytes[] memory values = new bytes[](feedsHex.length); bytes memory extraData = abi.encode(upkeepId, blockNum, addr); return (true, abi.encode(values, extraData)); } diff --git a/contracts/src/v0.8/tests/VerifiableLoadStreamsLookupUpkeep.sol b/contracts/src/v0.8/tests/VerifiableLoadStreamsLookupUpkeep.sol index 63dd813e1cd..451de7aebdb 100644 --- a/contracts/src/v0.8/tests/VerifiableLoadStreamsLookupUpkeep.sol +++ b/contracts/src/v0.8/tests/VerifiableLoadStreamsLookupUpkeep.sol @@ -34,7 +34,15 @@ contract VerifiableLoadStreamsLookupUpkeep is VerifiableLoadBase, StreamsLookupC return (false, pData); } - revert StreamsLookup(feedParamKey, feedsHex, timeParamKey, blockNum, abi.encode(upkeepId)); + uint256 timeParam; + if (keccak256(abi.encodePacked(timeParamKey)) == keccak256(abi.encodePacked("feedIdHex"))) { + timeParam = blockNum; + } else { + // assume this will be feedIDs for v0.3 + timeParam = block.timestamp; + } + + revert StreamsLookup(feedParamKey, feedsHex, timeParamKey, timeParam, abi.encode(upkeepId)); } function performUpkeep(bytes calldata performData) external { diff --git a/contracts/test/v0.7/Operator.test.ts b/contracts/test/v0.7/Operator.test.ts index 251ee65a7ae..4af846576b3 100644 --- a/contracts/test/v0.7/Operator.test.ts +++ b/contracts/test/v0.7/Operator.test.ts @@ -1024,9 +1024,8 @@ describe('Operator', () => { .deploy(link.address, operator.address, specId) const paymentAmount = toWei('1') await link.transfer(gasGuzzlingConsumer.address, paymentAmount) - const tx = await gasGuzzlingConsumer.gassyRequestEthereumPrice( - paymentAmount, - ) + const tx = + await gasGuzzlingConsumer.gassyRequestEthereumPrice(paymentAmount) const receipt = await tx.wait() request = decodeRunRequest(receipt.logs?.[3]) }) @@ -1480,9 +1479,8 @@ describe('Operator', () => { .deploy(link.address, operator.address, specId) const paymentAmount = toWei('1') await link.transfer(gasGuzzlingConsumer.address, paymentAmount) - const tx = await gasGuzzlingConsumer.gassyRequestEthereumPrice( - paymentAmount, - ) + const tx = + await gasGuzzlingConsumer.gassyRequestEthereumPrice(paymentAmount) const receipt = await tx.wait() request = decodeRunRequest(receipt.logs?.[3]) }) @@ -2087,9 +2085,8 @@ describe('Operator', () => { .deploy(link.address, operator.address, specId) const paymentAmount = toWei('1') await link.transfer(gasGuzzlingConsumer.address, paymentAmount) - const tx = await gasGuzzlingConsumer.gassyMultiWordRequest( - paymentAmount, - ) + const tx = + await gasGuzzlingConsumer.gassyMultiWordRequest(paymentAmount) const receipt = await tx.wait() request = decodeRunRequest(receipt.logs?.[3]) }) @@ -2604,9 +2601,8 @@ describe('Operator', () => { .deploy(link.address, operator.address, specId) const paymentAmount = toWei('1') await link.transfer(gasGuzzlingConsumer.address, paymentAmount) - const tx = await gasGuzzlingConsumer.gassyMultiWordRequest( - paymentAmount, - ) + const tx = + await gasGuzzlingConsumer.gassyMultiWordRequest(paymentAmount) const receipt = await tx.wait() request = decodeRunRequest(receipt.logs?.[3]) }) diff --git a/contracts/test/v0.8/automation/CronUpkeep.test.ts b/contracts/test/v0.8/automation/CronUpkeep.test.ts index 755b4494c81..f153345b570 100644 --- a/contracts/test/v0.8/automation/CronUpkeep.test.ts +++ b/contracts/test/v0.8/automation/CronUpkeep.test.ts @@ -321,12 +321,10 @@ describe('CronUpkeep', () => { it('creates jobs with sequential IDs', async () => { const cronString1 = '0 * * * *' const cronString2 = '0 1,2,3 */4 5-6 1-2' - const encodedSpec1 = await cronFactoryContract.encodeCronString( - cronString1, - ) - const encodedSpec2 = await cronFactoryContract.encodeCronString( - cronString2, - ) + const encodedSpec1 = + await cronFactoryContract.encodeCronString(cronString1) + const encodedSpec2 = + await cronFactoryContract.encodeCronString(cronString2) const nextTick1 = ( await cronTestHelper.calculateNextTick(cronString1) ).toNumber() diff --git a/contracts/test/v0.8/automation/KeeperRegistry2_1.test.ts b/contracts/test/v0.8/automation/KeeperRegistry2_1.test.ts index a14946a06a9..2f83c133705 100644 --- a/contracts/test/v0.8/automation/KeeperRegistry2_1.test.ts +++ b/contracts/test/v0.8/automation/KeeperRegistry2_1.test.ts @@ -64,7 +64,7 @@ describe('KeeperRegistry2_1 - Frozen [ @skip-coverage ]', () => { it('has not changed', () => { assert.equal( ethers.utils.id(KeeperRegistryFactory.bytecode), - '0xd94f351a1cd64aa81dd7238301f680f4bfc2a0f84c4b5451525f3f879488f033', + '0xd8dfe20e746039e8420349326becc0a15dcd8fa3cd6aa0924d214328a7c45206', 'KeeperRegistry bytecode has changed', ) assert.equal( @@ -474,9 +474,8 @@ describe('KeeperRegistry2_1', () => { 'src/v0.8/tests/MockV3Aggregator.sol:MockV3Aggregator', )) as unknown as MockV3AggregatorFactory upkeepMockFactory = await ethers.getContractFactory('UpkeepMock') - upkeepAutoFunderFactory = await ethers.getContractFactory( - 'UpkeepAutoFunder', - ) + upkeepAutoFunderFactory = + await ethers.getContractFactory('UpkeepAutoFunder') mockArbGasInfoFactory = await ethers.getContractFactory('MockArbGasInfo') mockOVMGasPriceOracleFactory = await ethers.getContractFactory( 'MockOVMGasPriceOracle', @@ -741,6 +740,7 @@ describe('KeeperRegistry2_1', () => { performData?: string checkBlockNum?: number checkBlockHash?: string + logBlockHash?: BytesLike txHash?: BytesLike logIndex?: number timestamp?: number @@ -763,6 +763,7 @@ describe('KeeperRegistry2_1', () => { checkBlockHash: latestBlock.hash, logIndex: 0, txHash: undefined, // assigned uniquely below + logBlockHash: undefined, // assigned uniquely below timestamp: now(), gasLimit: undefined, gasPrice: undefined, @@ -780,6 +781,7 @@ describe('KeeperRegistry2_1', () => { 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, @@ -1238,18 +1240,19 @@ describe('KeeperRegistry2_1', () => { }) 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', 'uint32'], - [logUpkeepId, txHash, logIndex], + ['uint256', 'bytes32', 'bytes32', 'uint32'], + [logUpkeepId, logBlockHash, txHash, logIndex], ) assert.isFalse(await registry.hasDedupKey(expectedDedupKey)) const tx = await getTransmitTx( registry, keeper1, [logUpkeepId, logUpkeepId], - { txHash, logIndex }, // will result in the same dedup key + { logBlockHash, txHash, logIndex }, // will result in the same dedup key ) const receipt = await tx.wait() const staleUpkeepReport = parseStaleUpkeepReportLogs(receipt) diff --git a/contracts/test/v0.8/automation/UpkeepTranscoder3_0.test.ts b/contracts/test/v0.8/automation/UpkeepTranscoder3_0.test.ts index 8bad7f63873..2f0f169ab1f 100644 --- a/contracts/test/v0.8/automation/UpkeepTranscoder3_0.test.ts +++ b/contracts/test/v0.8/automation/UpkeepTranscoder3_0.test.ts @@ -164,9 +164,8 @@ async function deployLegacyRegistry1_2( ) { const mock = await upkeepMockFactory.deploy() // @ts-ignore bug in autogen file - const keeperRegistryFactory = await ethers.getContractFactory( - 'KeeperRegistry1_2', - ) + const keeperRegistryFactory = + await ethers.getContractFactory('KeeperRegistry1_2') transcoder = await upkeepTranscoderFactory.connect(owner).deploy() const legacyRegistry = await keeperRegistryFactory .connect(owner) diff --git a/contracts/test/v0.8/automation/UpkeepTranscoder4_0.test.ts b/contracts/test/v0.8/automation/UpkeepTranscoder4_0.test.ts index e6b74d41bd9..970054893d2 100644 --- a/contracts/test/v0.8/automation/UpkeepTranscoder4_0.test.ts +++ b/contracts/test/v0.8/automation/UpkeepTranscoder4_0.test.ts @@ -140,9 +140,8 @@ const encodeUpkeepV12 = (ids: number[], upkeeps: any[], checkDatas: any[]) => { } async function deployRegistry1_2(): Promise<[BigNumber, KeeperRegistry1_2]> { - const keeperRegistryFactory = await ethers.getContractFactory( - 'KeeperRegistry1_2', - ) + const keeperRegistryFactory = + await ethers.getContractFactory('KeeperRegistry1_2') const registry12 = await keeperRegistryFactory .connect(owner) .deploy(linkToken.address, linkEthFeed.address, gasPriceFeed.address, { diff --git a/contracts/test/v0.8/dev/OptimismCrossDomainForwarder.test.ts b/contracts/test/v0.8/dev/OptimismCrossDomainForwarder.test.ts index 76f0e6ddf0a..3b75b412bfd 100644 --- a/contracts/test/v0.8/dev/OptimismCrossDomainForwarder.test.ts +++ b/contracts/test/v0.8/dev/OptimismCrossDomainForwarder.test.ts @@ -40,9 +40,8 @@ before(async () => { describe('OptimismCrossDomainForwarder', () => { beforeEach(async () => { - crossDomainMessenger = await crossDomainMessengerFactory.deploy( - l1OwnerAddress, - ) + crossDomainMessenger = + await crossDomainMessengerFactory.deploy(l1OwnerAddress) forwarder = await forwarderFactory.deploy( crossDomainMessenger.address, l1OwnerAddress, diff --git a/contracts/test/v0.8/dev/OptimismCrossDomainGovernor.test.ts b/contracts/test/v0.8/dev/OptimismCrossDomainGovernor.test.ts index cedc90ab9a9..9ea425bb995 100644 --- a/contracts/test/v0.8/dev/OptimismCrossDomainGovernor.test.ts +++ b/contracts/test/v0.8/dev/OptimismCrossDomainGovernor.test.ts @@ -46,9 +46,8 @@ before(async () => { describe('OptimismCrossDomainGovernor', () => { beforeEach(async () => { - crossDomainMessenger = await crossDomainMessengerFactory.deploy( - l1OwnerAddress, - ) + crossDomainMessenger = + await crossDomainMessengerFactory.deploy(l1OwnerAddress) governor = await governorFactory.deploy( crossDomainMessenger.address, l1OwnerAddress, diff --git a/contracts/test/v0.8/dev/OptimismSequencerUptimeFeed.test.ts b/contracts/test/v0.8/dev/OptimismSequencerUptimeFeed.test.ts index e6b44041a71..2856568793a 100644 --- a/contracts/test/v0.8/dev/OptimismSequencerUptimeFeed.test.ts +++ b/contracts/test/v0.8/dev/OptimismSequencerUptimeFeed.test.ts @@ -108,8 +108,7 @@ describe('OptimismSequencerUptimeFeed', () => { .updateStatus(true, timestamp.add(200)) // Submit another status update with the same status - const currentBlock = await ethers.provider.getBlockNumber() - const latestBlock = await ethers.provider.getBlock(currentBlock) + const latestBlock = await ethers.provider.getBlock('latest') await expect(tx) .to.emit(optimismUptimeFeed, 'RoundUpdated') diff --git a/contracts/test/v0.8/dev/OptimismValidator.test.ts b/contracts/test/v0.8/dev/OptimismValidator.test.ts index a63780a3f3e..120b1057d14 100644 --- a/contracts/test/v0.8/dev/OptimismValidator.test.ts +++ b/contracts/test/v0.8/dev/OptimismValidator.test.ts @@ -75,8 +75,7 @@ describe('OptimismValidator', () => { it('posts sequencer status when there is not status change', async () => { await optimismValidator.addAccess(eoaValidator.address) - const currentBlockNum = await ethers.provider.getBlockNumber() - const currentBlock = await ethers.provider.getBlock(currentBlockNum) + const currentBlock = await ethers.provider.getBlock('latest') const futureTimestamp = currentBlock.timestamp + 5000 await ethers.provider.send('evm_setNextBlockTimestamp', [futureTimestamp]) @@ -100,8 +99,7 @@ describe('OptimismValidator', () => { it('post sequencer offline', async () => { await optimismValidator.addAccess(eoaValidator.address) - const currentBlockNum = await ethers.provider.getBlockNumber() - const currentBlock = await ethers.provider.getBlock(currentBlockNum) + const currentBlock = await ethers.provider.getBlock('latest') const futureTimestamp = currentBlock.timestamp + 10000 await ethers.provider.send('evm_setNextBlockTimestamp', [futureTimestamp]) diff --git a/contracts/test/v0.8/dev/VRFCoordinatorV2Mock.test.ts b/contracts/test/v0.8/dev/VRFCoordinatorV2Mock.test.ts index b3446ddb154..b0a2a10b201 100644 --- a/contracts/test/v0.8/dev/VRFCoordinatorV2Mock.test.ts +++ b/contracts/test/v0.8/dev/VRFCoordinatorV2Mock.test.ts @@ -262,7 +262,7 @@ describe('VRFCoordinatorV2Mock', () => { expect(receipt.events[0].args['success']).to.equal(true) assert( receipt.events[0].args['payment'] - .sub(BigNumber.from('100119017000000000')) + .sub(BigNumber.from('100119403000000000')) .lt(BigNumber.from('10000000000')), ) @@ -315,7 +315,7 @@ describe('VRFCoordinatorV2Mock', () => { expect(receipt.events[0].args['success']).to.equal(true) assert( receipt.events[0].args['payment'] - .sub(BigNumber.from('100119017000000000')) + .sub(BigNumber.from('100120516000000000')) .lt(BigNumber.from('10000000000')), ) diff --git a/contracts/test/v0.8/foundry/vrf/TrustedBlockhashStore.t.sol b/contracts/test/v0.8/foundry/vrf/TrustedBlockhashStore.t.sol index d2f52552e43..47fff7ea900 100644 --- a/contracts/test/v0.8/foundry/vrf/TrustedBlockhashStore.t.sol +++ b/contracts/test/v0.8/foundry/vrf/TrustedBlockhashStore.t.sol @@ -48,6 +48,7 @@ contract TrustedBlockhashStoreTest is BaseTest { assertEq(blockhash(unreachableBlock), 0); // Store blockhash from whitelisted address; + uint256[] memory invalidBlockNums = new uint256[](0); uint256[] memory blockNums = new uint256[](1); blockNums[0] = unreachableBlock; bytes32[] memory blockhashes = new bytes32[](1); @@ -64,9 +65,25 @@ contract TrustedBlockhashStoreTest is BaseTest { vm.expectRevert("Only callable by owner"); bhs.setWhitelist(new address[](0)); - // Should store unreachable blocks via whitelisted address. + // Should not store for a mismatched list of block numbers and hashes. changePrank(LINK_WHALE); + vm.expectRevert(TrustedBlockhashStore.InvalidTrustedBlockhashes.selector); + bhs.storeTrusted(invalidBlockNums, blockhashes, recentBlockNumber, blockhash(recentBlockNumber)); + + // Should store unreachable blocks via whitelisted address. bhs.storeTrusted(blockNums, blockhashes, recentBlockNumber, blockhash(recentBlockNumber)); assertEq(bhs.getBlockhash(unreachableBlock), unreachableBlockhash); + + // Change whitelist. Assert that the old whitelisted address can no longer store, + // but the new one can. + address[] memory newWhitelist = new address[](1); + newWhitelist[0] = LINK_WHALE_2; + bhs.setWhitelist(newWhitelist); + + vm.expectRevert(TrustedBlockhashStore.NotInWhitelist.selector); + bhs.storeTrusted(blockNums, blockhashes, recentBlockNumber, blockhash(recentBlockNumber)); + + changePrank(LINK_WHALE_2); + bhs.storeTrusted(blockNums, blockhashes, recentBlockNumber, blockhash(recentBlockNumber)); } } diff --git a/contracts/test/v0.8/foundry/vrf/VRFV2PlusSubscriptionAPI.t.sol b/contracts/test/v0.8/foundry/vrf/VRFV2PlusSubscriptionAPI.t.sol new file mode 100644 index 00000000000..813b3d4c808 --- /dev/null +++ b/contracts/test/v0.8/foundry/vrf/VRFV2PlusSubscriptionAPI.t.sol @@ -0,0 +1,605 @@ +pragma solidity 0.8.6; + +import "../BaseTest.t.sol"; +import {ExposedVRFCoordinatorV2Plus} from "../../../../src/v0.8/dev/vrf/testhelpers/ExposedVRFCoordinatorV2Plus.sol"; +import {SubscriptionAPI} from "../../../../src/v0.8/dev/vrf/SubscriptionAPI.sol"; +import {MockLinkToken} from "../../../../src/v0.8/mocks/MockLinkToken.sol"; +import {MockV3Aggregator} from "../../../../src/v0.8/tests/MockV3Aggregator.sol"; +import "@openzeppelin/contracts/utils/Strings.sol"; // for Strings.toString + +contract VRFV2PlusSubscriptionAPITest is BaseTest { + event SubscriptionFunded(uint256 indexed subId, uint256 oldBalance, uint256 newBalance); + event SubscriptionFundedWithEth(uint256 indexed subId, uint256 oldEthBalance, uint256 newEthBalance); + event SubscriptionCanceled(uint256 indexed subId, address to, uint256 amountLink, uint256 amountEth); + event FundsRecovered(address to, uint256 amountLink); + event EthFundsRecovered(address to, uint256 amountEth); + event SubscriptionOwnerTransferRequested(uint256 indexed subId, address from, address to); + event SubscriptionOwnerTransferred(uint256 indexed subId, address from, address to); + event SubscriptionConsumerAdded(uint256 indexed subId, address consumer); + + ExposedVRFCoordinatorV2Plus s_subscriptionAPI; + + function setUp() public override { + BaseTest.setUp(); + address bhs = makeAddr("bhs"); + s_subscriptionAPI = new ExposedVRFCoordinatorV2Plus(bhs); + } + + function testDefaultState() public { + assertEq(address(s_subscriptionAPI.LINK()), address(0)); + assertEq(address(s_subscriptionAPI.LINK_ETH_FEED()), address(0)); + assertEq(s_subscriptionAPI.s_currentSubNonce(), 0); + assertEq(s_subscriptionAPI.getActiveSubscriptionIdsLength(), 0); + assertEq(s_subscriptionAPI.s_totalBalance(), 0); + assertEq(s_subscriptionAPI.s_totalEthBalance(), 0); + } + + function testSetLINKAndLINKETHFeed() public { + address link = makeAddr("link"); + address linkEthFeed = makeAddr("linkEthFeed"); + s_subscriptionAPI.setLINKAndLINKETHFeed(link, linkEthFeed); + assertEq(address(s_subscriptionAPI.LINK()), link); + assertEq(address(s_subscriptionAPI.LINK_ETH_FEED()), linkEthFeed); + + // try setting it again, should revert + vm.expectRevert(SubscriptionAPI.LinkAlreadySet.selector); + s_subscriptionAPI.setLINKAndLINKETHFeed(link, linkEthFeed); + } + + function testOwnerCancelSubscriptionNoFunds() public { + // CASE: new subscription w/ no funds at all + // Should cancel trivially + + // Note that the link token is not set, but this should still + // not fail in that case. + + // Create the subscription from a separate address + address subOwner = makeAddr("subOwner"); + changePrank(subOwner); + uint64 nonceBefore = s_subscriptionAPI.s_currentSubNonce(); + uint256 subId = s_subscriptionAPI.createSubscription(); + assertEq(s_subscriptionAPI.s_currentSubNonce(), nonceBefore + 1); + + // change back to owner and cancel the subscription + changePrank(OWNER); + vm.expectEmit(true, false, false, true); + emit SubscriptionCanceled(subId, subOwner, 0, 0); + s_subscriptionAPI.ownerCancelSubscription(subId); + + // assert that the subscription no longer exists + assertEq(s_subscriptionAPI.getActiveSubscriptionIdsLength(), 0); + assertEq(s_subscriptionAPI.getSubscriptionConfig(subId).owner, address(0)); + // no point in checking s_subscriptions because all fields are zeroed out + // due to no balance and no requests made + } + + function testOwnerCancelSubscriptionNativeFundsOnly() public { + // CASE: new subscription with native funds only + // no link funds. + // should cancel and return the native funds + + // Create the subscription from a separate address + address subOwner = makeAddr("subOwner"); + changePrank(subOwner); + uint64 nonceBefore = s_subscriptionAPI.s_currentSubNonce(); + uint256 subId = s_subscriptionAPI.createSubscription(); + assertEq(s_subscriptionAPI.s_currentSubNonce(), nonceBefore + 1); + + // fund the subscription with ether + vm.deal(subOwner, 10 ether); + vm.expectEmit(true, false, false, true); + emit SubscriptionFundedWithEth(subId, 0, 5 ether); + s_subscriptionAPI.fundSubscriptionWithEth{value: 5 ether}(subId); + + // change back to owner and cancel the subscription + changePrank(OWNER); + vm.expectEmit(true, false, false, true); + emit SubscriptionCanceled(subId, subOwner, 0 /* link balance */, 5 ether /* native balance */); + s_subscriptionAPI.ownerCancelSubscription(subId); + + // assert that the subscription no longer exists + assertEq(s_subscriptionAPI.getActiveSubscriptionIdsLength(), 0); + assertEq(s_subscriptionAPI.getSubscriptionConfig(subId).owner, address(0)); + assertEq(s_subscriptionAPI.getSubscriptionStruct(subId).ethBalance, 0); + + // check the ether balance of the subOwner, should be 10 ether + assertEq(address(subOwner).balance, 10 ether); + } + + function testOwnerCancelSubscriptionLinkFundsOnly() public { + // CASE: new subscription with link funds only + // no native funds. + // should cancel and return the link funds + + // Create link token and set the link token on the subscription api object + MockLinkToken linkToken = new MockLinkToken(); + s_subscriptionAPI.setLINKAndLINKETHFeed(address(linkToken), address(0)); + assertEq(address(s_subscriptionAPI.LINK()), address(linkToken)); + + // Create the subscription from a separate address + address subOwner = makeAddr("subOwner"); + changePrank(subOwner); + uint64 nonceBefore = s_subscriptionAPI.s_currentSubNonce(); + uint256 subId = s_subscriptionAPI.createSubscription(); + assertEq(s_subscriptionAPI.s_currentSubNonce(), nonceBefore + 1); + + // fund the subscription with link + // can do it from the owner acct because anyone can fund a subscription + changePrank(OWNER); + vm.expectEmit(true, false, false, true); + emit SubscriptionFunded(subId, 0, 5 ether); + bool success = linkToken.transferAndCall(address(s_subscriptionAPI), 5 ether, abi.encode(subId)); + assertTrue(success, "failed link transfer and call"); + + // change back to owner and cancel the subscription + vm.expectEmit(true, false, false, true); + emit SubscriptionCanceled(subId, subOwner, 5 ether /* link balance */, 0 /* native balance */); + s_subscriptionAPI.ownerCancelSubscription(subId); + + // assert that the subscription no longer exists + assertEq(s_subscriptionAPI.getActiveSubscriptionIdsLength(), 0); + assertEq(s_subscriptionAPI.getSubscriptionConfig(subId).owner, address(0)); + assertEq(s_subscriptionAPI.getSubscriptionStruct(subId).balance, 0); + + // check the link balance of the sub owner, should be 5 LINK + assertEq(linkToken.balanceOf(subOwner), 5 ether); + } + + function testOwnerCancelSubscriptionNativeAndLinkFunds() public { + // CASE: new subscription with link and native funds + // should cancel and return both link and native funds + + // Create link token and set the link token on the subscription api object + MockLinkToken linkToken = new MockLinkToken(); + s_subscriptionAPI.setLINKAndLINKETHFeed(address(linkToken), address(0)); + assertEq(address(s_subscriptionAPI.LINK()), address(linkToken)); + + // Create the subscription from a separate address + address subOwner = makeAddr("subOwner"); + changePrank(subOwner); + uint64 nonceBefore = s_subscriptionAPI.s_currentSubNonce(); + uint256 subId = s_subscriptionAPI.createSubscription(); + assertEq(s_subscriptionAPI.s_currentSubNonce(), nonceBefore + 1); + + // fund the subscription with link + changePrank(OWNER); + vm.expectEmit(true, false, false, true); + emit SubscriptionFunded(subId, 0, 5 ether); + bool success = linkToken.transferAndCall(address(s_subscriptionAPI), 5 ether, abi.encode(subId)); + assertTrue(success, "failed link transfer and call"); + + // fund the subscription with ether + vm.deal(subOwner, 10 ether); + changePrank(subOwner); + vm.expectEmit(true, false, false, true); + emit SubscriptionFundedWithEth(subId, 0, 5 ether); + s_subscriptionAPI.fundSubscriptionWithEth{value: 5 ether}(subId); + + // change back to owner and cancel the subscription + changePrank(OWNER); + vm.expectEmit(true, false, false, true); + emit SubscriptionCanceled(subId, subOwner, 5 ether /* link balance */, 5 ether /* native balance */); + s_subscriptionAPI.ownerCancelSubscription(subId); + + // assert that the subscription no longer exists + assertEq(s_subscriptionAPI.getActiveSubscriptionIdsLength(), 0); + assertEq(s_subscriptionAPI.getSubscriptionConfig(subId).owner, address(0)); + assertEq(s_subscriptionAPI.getSubscriptionStruct(subId).balance, 0); + assertEq(s_subscriptionAPI.getSubscriptionStruct(subId).ethBalance, 0); + + // check the link balance of the sub owner, should be 5 LINK + assertEq(linkToken.balanceOf(subOwner), 5 ether, "link balance incorrect"); + // check the ether balance of the sub owner, should be 10 ether + assertEq(address(subOwner).balance, 10 ether, "eth balance incorrect"); + } + + function testRecoverFundsLINKNotSet() public { + // CASE: link token not set + // should revert with error LinkNotSet + + // call recoverFunds + vm.expectRevert(SubscriptionAPI.LinkNotSet.selector); + s_subscriptionAPI.recoverFunds(OWNER); + } + + function testRecoverFundsBalanceInvariantViolated() public { + // CASE: link token set + // and internal balance is greater than external balance + + // Create link token and set the link token on the subscription api object + MockLinkToken linkToken = new MockLinkToken(); + s_subscriptionAPI.setLINKAndLINKETHFeed(address(linkToken), address(0)); + assertEq(address(s_subscriptionAPI.LINK()), address(linkToken)); + + // set the total balance to be greater than the external balance + // so that we trigger the invariant violation + // note that this field is not modifiable in the actual contracts + // other than through onTokenTransfer or similar functions + s_subscriptionAPI.setTotalBalanceTestingOnlyXXX(100 ether); + + // call recoverFunds + vm.expectRevert(abi.encodeWithSelector(SubscriptionAPI.BalanceInvariantViolated.selector, 100 ether, 0)); + s_subscriptionAPI.recoverFunds(OWNER); + } + + function testRecoverFundsAmountToTransfer() public { + // CASE: link token set + // and internal balance is less than external balance + // (i.e invariant is not violated) + // should recover funds successfully + + // Create link token and set the link token on the subscription api object + MockLinkToken linkToken = new MockLinkToken(); + s_subscriptionAPI.setLINKAndLINKETHFeed(address(linkToken), address(0)); + assertEq(address(s_subscriptionAPI.LINK()), address(linkToken)); + + // transfer 10 LINK to the contract to recover + bool success = linkToken.transfer(address(s_subscriptionAPI), 10 ether); + assertTrue(success, "failed link transfer"); + + // call recoverFunds + vm.expectEmit(true, false, false, true); + emit FundsRecovered(OWNER, 10 ether); + s_subscriptionAPI.recoverFunds(OWNER); + } + + function testRecoverFundsNothingToTransfer() public { + // CASE: link token set + // and there is nothing to transfer + // should do nothing at all + + // Create link token and set the link token on the subscription api object + MockLinkToken linkToken = new MockLinkToken(); + s_subscriptionAPI.setLINKAndLINKETHFeed(address(linkToken), address(0)); + assertEq(address(s_subscriptionAPI.LINK()), address(linkToken)); + + // create a subscription and fund it with 5 LINK + address subOwner = makeAddr("subOwner"); + changePrank(subOwner); + uint64 nonceBefore = s_subscriptionAPI.s_currentSubNonce(); + uint256 subId = s_subscriptionAPI.createSubscription(); + assertEq(s_subscriptionAPI.s_currentSubNonce(), nonceBefore + 1); + + // fund the subscription with link + changePrank(OWNER); + vm.expectEmit(true, false, false, true); + emit SubscriptionFunded(subId, 0, 5 ether); + bool success = linkToken.transferAndCall(address(s_subscriptionAPI), 5 ether, abi.encode(subId)); + assertTrue(success, "failed link transfer and call"); + + // call recoverFunds, nothing should happen because external balance == internal balance + s_subscriptionAPI.recoverFunds(OWNER); + assertEq(linkToken.balanceOf(address(s_subscriptionAPI)), s_subscriptionAPI.s_totalBalance()); + } + + function testRecoverEthFundsBalanceInvariantViolated() public { + // set the total balance to be greater than the external balance + // so that we trigger the invariant violation + // note that this field is not modifiable in the actual contracts + // other than through onTokenTransfer or similar functions + s_subscriptionAPI.setTotalEthBalanceTestingOnlyXXX(100 ether); + + // call recoverFunds + vm.expectRevert(abi.encodeWithSelector(SubscriptionAPI.BalanceInvariantViolated.selector, 100 ether, 0)); + s_subscriptionAPI.recoverEthFunds(payable(OWNER)); + } + + function testRecoverEthFundsAmountToTransfer() public { + // transfer 10 LINK to the contract to recover + vm.deal(address(s_subscriptionAPI), 10 ether); + + // call recoverFunds + vm.expectEmit(true, false, false, true); + emit EthFundsRecovered(OWNER, 10 ether); + s_subscriptionAPI.recoverEthFunds(payable(OWNER)); + } + + function testRecoverEthFundsNothingToTransfer() public { + // create a subscription and fund it with 5 ether + address subOwner = makeAddr("subOwner"); + changePrank(subOwner); + uint64 nonceBefore = s_subscriptionAPI.s_currentSubNonce(); + uint256 subId = s_subscriptionAPI.createSubscription(); + assertEq(s_subscriptionAPI.s_currentSubNonce(), nonceBefore + 1); + + // fund the subscription with ether + vm.deal(subOwner, 5 ether); + changePrank(subOwner); + vm.expectEmit(true, false, false, true); + emit SubscriptionFundedWithEth(subId, 0, 5 ether); + s_subscriptionAPI.fundSubscriptionWithEth{value: 5 ether}(subId); + + // call recoverEthFunds, nothing should happen because external balance == internal balance + changePrank(OWNER); + s_subscriptionAPI.recoverEthFunds(payable(OWNER)); + assertEq(address(s_subscriptionAPI).balance, s_subscriptionAPI.s_totalEthBalance()); + } + + function testOracleWithdrawNoLink() public { + // CASE: no link token set + vm.expectRevert(SubscriptionAPI.LinkNotSet.selector); + s_subscriptionAPI.oracleWithdraw(OWNER, 1 ether); + } + + function testOracleWithdrawInsufficientBalance() public { + // CASE: link token set, trying to withdraw + // more than balance + MockLinkToken linkToken = new MockLinkToken(); + s_subscriptionAPI.setLINKAndLINKETHFeed(address(linkToken), address(0)); + assertEq(address(s_subscriptionAPI.LINK()), address(linkToken)); + + // call oracleWithdraw + vm.expectRevert(SubscriptionAPI.InsufficientBalance.selector); + s_subscriptionAPI.oracleWithdraw(OWNER, 1 ether); + } + + function testOracleWithdrawSufficientBalanceLinkSet() public { + // CASE: link token set, trying to withdraw + // less than balance + MockLinkToken linkToken = new MockLinkToken(); + s_subscriptionAPI.setLINKAndLINKETHFeed(address(linkToken), address(0)); + assertEq(address(s_subscriptionAPI.LINK()), address(linkToken)); + + // transfer 10 LINK to the contract to withdraw + bool success = linkToken.transfer(address(s_subscriptionAPI), 10 ether); + assertTrue(success, "failed link transfer"); + + // set the withdrawable tokens of the oracle to be 1 ether + address oracle = makeAddr("oracle"); + s_subscriptionAPI.setWithdrawableTokensTestingOnlyXXX(oracle, 1 ether); + assertEq(s_subscriptionAPI.getWithdrawableTokensTestingOnlyXXX(oracle), 1 ether); + + // set the total balance to be the same as the link balance for consistency + // (this is not necessary for the test, but just to be sane) + s_subscriptionAPI.setTotalBalanceTestingOnlyXXX(10 ether); + + // call oracleWithdraw from oracle address + changePrank(oracle); + s_subscriptionAPI.oracleWithdraw(oracle, 1 ether); + // assert link balance of oracle + assertEq(linkToken.balanceOf(oracle), 1 ether, "oracle link balance incorrect"); + // assert state of subscription api + assertEq(s_subscriptionAPI.getWithdrawableTokensTestingOnlyXXX(oracle), 0, "oracle withdrawable tokens incorrect"); + // assert that total balance is changed by the withdrawn amount + assertEq(s_subscriptionAPI.s_totalBalance(), 9 ether, "total balance incorrect"); + } + + function testOracleWithdrawEthInsufficientBalance() public { + // CASE: trying to withdraw more than balance + // should revert with InsufficientBalance + + // call oracleWithdrawEth + vm.expectRevert(SubscriptionAPI.InsufficientBalance.selector); + s_subscriptionAPI.oracleWithdrawEth(payable(OWNER), 1 ether); + } + + function testOracleWithdrawEthSufficientBalance() public { + // CASE: trying to withdraw less than balance + // should withdraw successfully + + // transfer 10 ether to the contract to withdraw + vm.deal(address(s_subscriptionAPI), 10 ether); + + // set the withdrawable eth of the oracle to be 1 ether + address oracle = makeAddr("oracle"); + s_subscriptionAPI.setWithdrawableEthTestingOnlyXXX(oracle, 1 ether); + assertEq(s_subscriptionAPI.getWithdrawableEthTestingOnlyXXX(oracle), 1 ether); + + // set the total balance to be the same as the eth balance for consistency + // (this is not necessary for the test, but just to be sane) + s_subscriptionAPI.setTotalEthBalanceTestingOnlyXXX(10 ether); + + // call oracleWithdrawEth from oracle address + changePrank(oracle); + s_subscriptionAPI.oracleWithdrawEth(payable(oracle), 1 ether); + // assert eth balance of oracle + assertEq(address(oracle).balance, 1 ether, "oracle eth balance incorrect"); + // assert state of subscription api + assertEq(s_subscriptionAPI.getWithdrawableEthTestingOnlyXXX(oracle), 0, "oracle withdrawable eth incorrect"); + // assert that total balance is changed by the withdrawn amount + assertEq(s_subscriptionAPI.s_totalEthBalance(), 9 ether, "total eth balance incorrect"); + } + + function testOnTokenTransferCallerNotLink() public { + vm.expectRevert(SubscriptionAPI.OnlyCallableFromLink.selector); + s_subscriptionAPI.onTokenTransfer(makeAddr("someaddress"), 1 ether, abi.encode(uint256(1))); + } + + function testOnTokenTransferInvalidCalldata() public { + // create and set link token on subscription api + MockLinkToken linkToken = new MockLinkToken(); + s_subscriptionAPI.setLINKAndLINKETHFeed(address(linkToken), address(0)); + assertEq(address(s_subscriptionAPI.LINK()), address(linkToken)); + + // call link.transferAndCall with invalid calldata + vm.expectRevert(SubscriptionAPI.InvalidCalldata.selector); + linkToken.transferAndCall(address(s_subscriptionAPI), 1 ether, abi.encode(uint256(1), address(1))); + } + + function testOnTokenTransferInvalidSubscriptionId() public { + // create and set link token on subscription api + MockLinkToken linkToken = new MockLinkToken(); + s_subscriptionAPI.setLINKAndLINKETHFeed(address(linkToken), address(0)); + assertEq(address(s_subscriptionAPI.LINK()), address(linkToken)); + + // generate bogus sub id + uint256 subId = uint256(keccak256("idontexist")); + + // try to fund bogus sub id + vm.expectRevert(SubscriptionAPI.InvalidSubscription.selector); + linkToken.transferAndCall(address(s_subscriptionAPI), 1 ether, abi.encode(subId)); + } + + function testOnTokenTransferSuccess() public { + // happy path link funding test + // create and set link token on subscription api + MockLinkToken linkToken = new MockLinkToken(); + s_subscriptionAPI.setLINKAndLINKETHFeed(address(linkToken), address(0)); + assertEq(address(s_subscriptionAPI.LINK()), address(linkToken)); + + // create a subscription and fund it with 5 LINK + address subOwner = makeAddr("subOwner"); + changePrank(subOwner); + uint64 nonceBefore = s_subscriptionAPI.s_currentSubNonce(); + uint256 subId = s_subscriptionAPI.createSubscription(); + assertEq(s_subscriptionAPI.s_currentSubNonce(), nonceBefore + 1); + + // fund the subscription with link + changePrank(OWNER); + vm.expectEmit(true, false, false, true); + emit SubscriptionFunded(subId, 0, 5 ether); + bool success = linkToken.transferAndCall(address(s_subscriptionAPI), 5 ether, abi.encode(subId)); + assertTrue(success, "failed link transfer and call"); + + // assert that the subscription is funded + assertEq(s_subscriptionAPI.getSubscriptionStruct(subId).balance, 5 ether); + } + + function testFundSubscriptionWithEthInvalidSubscriptionId() public { + // CASE: invalid subscription id + // should revert with InvalidSubscription + + uint256 subId = uint256(keccak256("idontexist")); + + // try to fund the subscription with ether, should fail + address funder = makeAddr("funder"); + vm.deal(funder, 5 ether); + changePrank(funder); + vm.expectRevert(SubscriptionAPI.InvalidSubscription.selector); + s_subscriptionAPI.fundSubscriptionWithEth{value: 5 ether}(subId); + } + + function testFundSubscriptionWithEth() public { + // happy path test + // funding subscription with ether + + // create a subscription and fund it with ether + address subOwner = makeAddr("subOwner"); + changePrank(subOwner); + uint64 nonceBefore = s_subscriptionAPI.s_currentSubNonce(); + uint256 subId = s_subscriptionAPI.createSubscription(); + assertEq(s_subscriptionAPI.s_currentSubNonce(), nonceBefore + 1); + + // fund the subscription with ether + vm.deal(subOwner, 5 ether); + changePrank(subOwner); + vm.expectEmit(true, false, false, true); + emit SubscriptionFundedWithEth(subId, 0, 5 ether); + s_subscriptionAPI.fundSubscriptionWithEth{value: 5 ether}(subId); + + // assert that the subscription is funded + assertEq(s_subscriptionAPI.getSubscriptionStruct(subId).ethBalance, 5 ether); + } + + function testCreateSubscription() public { + // test that the subscription is created successfully + // and test the initial state of the subscription + address subOwner = makeAddr("subOwner"); + changePrank(subOwner); + uint64 nonceBefore = s_subscriptionAPI.s_currentSubNonce(); + uint256 subId = s_subscriptionAPI.createSubscription(); + assertEq(s_subscriptionAPI.s_currentSubNonce(), nonceBefore + 1); + assertEq(s_subscriptionAPI.getActiveSubscriptionIdsLength(), 1); + assertEq(s_subscriptionAPI.getSubscriptionConfig(subId).owner, subOwner); + assertEq(s_subscriptionAPI.getSubscriptionConfig(subId).consumers.length, 0); + assertEq(s_subscriptionAPI.getSubscriptionConfig(subId).requestedOwner, address(0)); + } + + function testCreateSubscriptionRecreate() public { + // create two subscriptions from the same eoa + // they should never be the same due to nonce incrementation + address subOwner = makeAddr("subOwner"); + changePrank(subOwner); + uint64 nonceBefore = s_subscriptionAPI.s_currentSubNonce(); + uint256 subId1 = s_subscriptionAPI.createSubscription(); + assertEq(s_subscriptionAPI.s_currentSubNonce(), nonceBefore + 1); + uint256 subId2 = s_subscriptionAPI.createSubscription(); + assertEq(s_subscriptionAPI.s_currentSubNonce(), nonceBefore + 2); + assertTrue(subId1 != subId2); + } + + function testSubscriptionOwnershipTransfer() public { + // create two eoa's, and create a subscription from one of them + // and transfer ownership to the other + // assert that the subscription is now owned by the other eoa + address oldOwner = makeAddr("oldOwner"); + address newOwner = makeAddr("newOwner"); + + // create sub + changePrank(oldOwner); + uint256 subId = s_subscriptionAPI.createSubscription(); + assertEq(s_subscriptionAPI.getSubscriptionConfig(subId).owner, oldOwner); + + // request ownership transfer + changePrank(oldOwner); + vm.expectEmit(true, false, false, true); + emit SubscriptionOwnerTransferRequested(subId, oldOwner, newOwner); + s_subscriptionAPI.requestSubscriptionOwnerTransfer(subId, newOwner); + + // accept ownership transfer from newOwner + changePrank(newOwner); + vm.expectEmit(true, false, false, true); + emit SubscriptionOwnerTransferred(subId, oldOwner, newOwner); + s_subscriptionAPI.acceptSubscriptionOwnerTransfer(subId); + assertEq(s_subscriptionAPI.getSubscriptionConfig(subId).requestedOwner, address(0)); + } + + function testAddConsumerTooManyConsumers() public { + // add 100 consumers to a sub and then + // try adding one more and see the revert + address subOwner = makeAddr("subOwner"); + changePrank(subOwner); + uint256 subId = s_subscriptionAPI.createSubscription(); + for (uint256 i = 0; i < 100; i++) { + address consumer = makeAddr(Strings.toString(i)); + vm.expectEmit(true, false, false, true); + emit SubscriptionConsumerAdded(subId, consumer); + s_subscriptionAPI.addConsumer(subId, consumer); + } + + // try adding one more consumer, should revert + address consumer = makeAddr("consumer"); + changePrank(subOwner); + vm.expectRevert(SubscriptionAPI.TooManyConsumers.selector); + s_subscriptionAPI.addConsumer(subId, consumer); + } + + function testAddConsumerReaddSameConsumer() public { + // try adding the same consumer twice + // should be a no-op + // assert state is unchanged after the 2nd add + address subOwner = makeAddr("subOwner"); + address consumer = makeAddr("consumer"); + changePrank(subOwner); + uint256 subId = s_subscriptionAPI.createSubscription(); + assertEq(s_subscriptionAPI.getSubscriptionConfig(subId).consumers.length, 0); + changePrank(subOwner); + vm.expectEmit(true, false, false, true); + emit SubscriptionConsumerAdded(subId, consumer); + s_subscriptionAPI.addConsumer(subId, consumer); + assertEq(s_subscriptionAPI.getSubscriptionConfig(subId).consumers.length, 1); + assertEq(s_subscriptionAPI.getSubscriptionConfig(subId).consumers[0], consumer); + + // add consumer again, should be no-op + changePrank(subOwner); + s_subscriptionAPI.addConsumer(subId, consumer); + assertEq(s_subscriptionAPI.getSubscriptionConfig(subId).consumers.length, 1); + assertEq(s_subscriptionAPI.getSubscriptionConfig(subId).consumers[0], consumer); + } + + function testAddConsumer() public { + // create a subscription and add a consumer + // assert subscription state afterwards + address subOwner = makeAddr("subOwner"); + address consumer = makeAddr("consumer"); + changePrank(subOwner); + uint256 subId = s_subscriptionAPI.createSubscription(); + assertEq(s_subscriptionAPI.getSubscriptionConfig(subId).consumers.length, 0); + changePrank(subOwner); + vm.expectEmit(true, false, false, true); + emit SubscriptionConsumerAdded(subId, consumer); + s_subscriptionAPI.addConsumer(subId, consumer); + assertEq(s_subscriptionAPI.getSubscriptionConfig(subId).consumers.length, 1); + assertEq(s_subscriptionAPI.getSubscriptionConfig(subId).consumers[0], consumer); + } +} diff --git a/contracts/test/v0.8/foundry/vrf/VRFV2Wrapper.t.sol b/contracts/test/v0.8/foundry/vrf/VRFV2Wrapper.t.sol index 4b506bb8c50..33bc72998f8 100644 --- a/contracts/test/v0.8/foundry/vrf/VRFV2Wrapper.t.sol +++ b/contracts/test/v0.8/foundry/vrf/VRFV2Wrapper.t.sol @@ -5,6 +5,7 @@ import {VRF} from "../../../../src/v0.8/vrf/VRF.sol"; import {MockLinkToken} from "../../../../src/v0.8/mocks/MockLinkToken.sol"; import {MockV3Aggregator} from "../../../../src/v0.8/tests/MockV3Aggregator.sol"; import {ExposedVRFCoordinatorV2Plus} from "../../../../src/v0.8/dev/vrf/testhelpers/ExposedVRFCoordinatorV2Plus.sol"; +import {VRFV2PlusWrapperConsumerBase} from "../../../../src/v0.8/dev/vrf/VRFV2PlusWrapperConsumerBase.sol"; import {VRFV2PlusWrapperConsumerExample} from "../../../../src/v0.8/dev/vrf/testhelpers/VRFV2PlusWrapperConsumerExample.sol"; import {VRFCoordinatorV2Plus} from "../../../../src/v0.8/dev/vrf/VRFCoordinatorV2Plus.sol"; import {VRFV2PlusWrapper} from "../../../../src/v0.8/dev/vrf/VRFV2PlusWrapper.sol"; @@ -70,6 +71,21 @@ contract VRFV2PlusWrapperTest is BaseTest { vrfKeyHash, // keyHash 10 // max number of words ); + ( + , + , + , + uint32 _wrapperGasOverhead, + uint32 _coordinatorGasOverhead, + uint8 _wrapperPremiumPercentage, + bytes32 _keyHash, + uint8 _maxNumWords + ) = s_wrapper.getConfig(); + assertEq(_wrapperGasOverhead, wrapperGasOverhead); + assertEq(_coordinatorGasOverhead, coordinatorGasOverhead); + assertEq(0, _wrapperPremiumPercentage); + assertEq(vrfKeyHash, _keyHash); + assertEq(10, _maxNumWords); } event RandomWordsRequested( @@ -84,11 +100,42 @@ contract VRFV2PlusWrapperTest is BaseTest { address indexed sender ); + function testSetLinkAndLinkEthFeed() public { + VRFV2PlusWrapper wrapper = new VRFV2PlusWrapper(address(0), address(0), address(s_testCoordinator)); + + // Set LINK and LINK/ETH feed on wrapper. + wrapper.setLINK(address(s_linkToken)); + wrapper.setLinkEthFeed(address(s_linkEthFeed)); + assertEq(address(wrapper.s_link()), address(s_linkToken)); + assertEq(address(wrapper.s_linkEthFeed()), address(s_linkEthFeed)); + + // Revert for subsequent assignment. + vm.expectRevert(VRFV2PlusWrapper.LinkAlreadySet.selector); + wrapper.setLINK(address(s_linkToken)); + + // Consumer can set LINK token. + VRFV2PlusWrapperConsumerExample consumer = new VRFV2PlusWrapperConsumerExample(address(0), address(wrapper)); + consumer.setLinkToken(address(s_linkToken)); + + // Revert for subsequent assignment. + vm.expectRevert(VRFV2PlusWrapperConsumerBase.LINKAlreadySet.selector); + consumer.setLinkToken(address(s_linkToken)); + } + function testRequestAndFulfillRandomWordsNativeWrapper() public { // Fund subscription. s_testCoordinator.fundSubscriptionWithEth{value: 10 ether}(s_wrapper.SUBSCRIPTION_ID()); vm.deal(address(s_consumer), 10 ether); + // Get type and version. + assertEq(s_wrapper.typeAndVersion(), "VRFV2Wrapper 1.0.0"); + + // Cannot make request while disabled. + s_wrapper.disable(); + vm.expectRevert("wrapper is disabled"); + s_consumer.makeRequestNative(500_000, 0, 1); + s_wrapper.enable(); + // Request randomness from wrapper. uint32 callbackGasLimit = 1_000_000; vm.expectEmit(true, true, true, true); @@ -114,7 +161,11 @@ contract VRFV2PlusWrapperTest is BaseTest { (uint256 paid, bool fulfilled, bool native) = s_consumer.s_requests(requestId); uint32 expectedPaid = callbackGasLimit + wrapperGasOverhead + coordinatorGasOverhead; + uint256 wrapperNativeCostEstimate = s_wrapper.estimateRequestPriceNative(callbackGasLimit, tx.gasprice); + uint256 wrapperCostCalculation = s_wrapper.calculateRequestPriceNative(callbackGasLimit); assertEq(paid, expectedPaid); + assertEq(uint256(paid), wrapperNativeCostEstimate); + assertEq(wrapperNativeCostEstimate, wrapperCostCalculation); assertEq(fulfilled, false); assertEq(native, true); assertEq(address(s_consumer).balance, 10 ether - expectedPaid); @@ -129,6 +180,13 @@ contract VRFV2PlusWrapperTest is BaseTest { (, bool nowFulfilled, uint256[] memory storedWords) = s_consumer.getRequestStatus(requestId); assertEq(nowFulfilled, true); assertEq(storedWords[0], 123); + + // Withdraw funds from wrapper. + changePrank(LINK_WHALE); + uint256 priorWhaleBalance = LINK_WHALE.balance; + s_wrapper.withdrawNative(LINK_WHALE, paid); + assertEq(LINK_WHALE.balance, priorWhaleBalance + paid); + assertEq(address(s_wrapper).balance, 0); } function testRequestAndFulfillRandomWordsLINKWrapper() public { @@ -162,7 +220,11 @@ contract VRFV2PlusWrapperTest is BaseTest { // Assert that the request was made correctly. (uint256 paid, bool fulfilled, bool native) = s_consumer.s_requests(requestId); uint32 expectedPaid = (callbackGasLimit + wrapperGasOverhead + coordinatorGasOverhead) * 2; + uint256 wrapperCostEstimate = s_wrapper.estimateRequestPrice(callbackGasLimit, tx.gasprice); + uint256 wrapperCostCalculation = s_wrapper.calculateRequestPrice(callbackGasLimit); assertEq(paid, expectedPaid); // 1_030_000 * 2 for link/eth ratio + assertEq(uint256(paid), wrapperCostEstimate); + assertEq(wrapperCostEstimate, wrapperCostCalculation); assertEq(fulfilled, false); assertEq(native, false); assertEq(s_linkToken.balanceOf(address(s_consumer)), 10 ether - expectedPaid); @@ -177,5 +239,12 @@ contract VRFV2PlusWrapperTest is BaseTest { (, bool nowFulfilled, uint256[] memory storedWords) = s_consumer.getRequestStatus(requestId); assertEq(nowFulfilled, true); assertEq(storedWords[0], 456); + + // Withdraw funds from wrapper. + changePrank(LINK_WHALE); + uint256 priorWhaleBalance = s_linkToken.balanceOf(LINK_WHALE); + s_wrapper.withdraw(LINK_WHALE, paid); + assertEq(s_linkToken.balanceOf(LINK_WHALE), priorWhaleBalance + paid); + assertEq(s_linkToken.balanceOf(address(s_wrapper)), 0); } } diff --git a/contracts/test/v0.8/functions/v0/FunctionsOracle.test.ts b/contracts/test/v0.8/functions/v0/FunctionsOracle.test.ts index ae44e1b037e..921c60bfc8f 100644 --- a/contracts/test/v0.8/functions/v0/FunctionsOracle.test.ts +++ b/contracts/test/v0.8/functions/v0/FunctionsOracle.test.ts @@ -351,9 +351,8 @@ describe('FunctionsOracle', () => { }) it('#estimateCost correctly estimates cost [ @skip-coverage ]', async () => { - const [subscriptionBalanceBefore] = await registry.getSubscription( - subscriptionId, - ) + const [subscriptionBalanceBefore] = + await registry.getSubscription(subscriptionId) const request = await client .connect(roles.oracleNode) @@ -376,9 +375,8 @@ describe('FunctionsOracle', () => { .withArgs(requestId, transmitter) .to.emit(registry, 'BillingEnd') - const [subscriptionBalanceAfter] = await registry.getSubscription( - subscriptionId, - ) + const [subscriptionBalanceAfter] = + await registry.getSubscription(subscriptionId) const feeData = await ethers.provider.getFeeData() const estimatedCost = await client.estimateJuelCost( diff --git a/contracts/test/v0.8/functions/v1/Functions.test.ts b/contracts/test/v0.8/functions/v1/Functions.test.ts index b0128b90204..981b3227073 100644 --- a/contracts/test/v0.8/functions/v1/Functions.test.ts +++ b/contracts/test/v0.8/functions/v1/Functions.test.ts @@ -41,7 +41,6 @@ describe('FunctionsTestHelper', () => { 'addSecretsReference', 'addTwoArgs', 'addEmptyArgs', - 'addSignature', ]), ).to.equal(true) }) @@ -170,29 +169,4 @@ describe('FunctionsTestHelper', () => { await expect(ctr.addEmptyArgs()).to.be.revertedWith('EmptyArgs()') }) }) - - describe('#addSignature', () => { - it('emits CBOR encoded request with js source and signature', async () => { - const signatureHex = 'aabbccddeeff' - const js = 'function run(args, responses) {}' - await ctr.initializeRequestForInlineJavaScript(js) - await ctr.addSignature('0x' + signatureHex) - const tx = await ctr.closeEvent() - const [payload] = await parseRequestDataEvent(tx) - const decoded = await decodeDietCBOR(payload) - assert.deepEqual( - { - ...decoded, - language: decoded.language.toNumber(), - codeLocation: decoded.codeLocation.toNumber(), - }, - { - language: 0, - codeLocation: 0, - source: js, - requestSignature: Buffer.from(signatureHex, 'hex'), - }, - ) - }) - }) }) diff --git a/contracts/test/v0.8/functions/v1/FunctionsSubscriptions.test.ts b/contracts/test/v0.8/functions/v1/FunctionsSubscriptions.test.ts index e2f0372be15..86cfb9dd5fc 100644 --- a/contracts/test/v0.8/functions/v1/FunctionsSubscriptions.test.ts +++ b/contracts/test/v0.8/functions/v1/FunctionsSubscriptions.test.ts @@ -370,6 +370,9 @@ describe('Functions Router - Subscriptions', () => { ).to.be.revertedWith(`MustBeSubscriptionOwner()`) }) it('can cancel', async function () { + const strangerBalanceBefore = await contracts.linkToken.balanceOf( + roles.strangerAddress, + ) await contracts.linkToken .connect(roles.subOwner) .transferAndCall( @@ -383,11 +386,13 @@ describe('Functions Router - Subscriptions', () => { .cancelSubscription(subId, roles.strangerAddress), ) .to.emit(contracts.router, 'SubscriptionCanceled') - .withArgs(subId, roles.strangerAddress, BigNumber.from('1000')) + .withArgs(subId, roles.strangerAddress, BigNumber.from('0')) const strangerBalance = await contracts.linkToken.balanceOf( roles.strangerAddress, ) - expect(strangerBalance.toString()).to.equal('1000000000000001000') + expect(strangerBalance.toString()).to.equal( + strangerBalanceBefore.toString(), + ) await expect( contracts.router.connect(roles.subOwner).getSubscription(subId), ).to.be.revertedWith('InvalidSubscription') @@ -493,7 +498,7 @@ describe('Functions Router - Subscriptions', () => { .connect(roles.subOwner) .cancelSubscription(subId, roles.strangerAddress) }, - BigNumber.from('-1000'), + BigNumber.from('0'), ], ] for (const [fn, expectedBalanceChange] of balanceChangingFns) { diff --git a/contracts/test/v0.8/functions/v1/utils.ts b/contracts/test/v0.8/functions/v1/utils.ts index a7a89871f32..0973a5cd845 100644 --- a/contracts/test/v0.8/functions/v1/utils.ts +++ b/contracts/test/v0.8/functions/v1/utils.ts @@ -77,6 +77,8 @@ export type FunctionsRouterConfig = { handleOracleFulfillmentSelector: string maxCallbackGasLimits: number[] gasForCallExactCheck: number + subscriptionDepositMinimumRequests: number + subscriptionDepositJuels: BigNumber } export const functionsRouterConfig: FunctionsRouterConfig = { maxConsumersPerSubscription: 100, @@ -84,9 +86,10 @@ export const functionsRouterConfig: FunctionsRouterConfig = { handleOracleFulfillmentSelector: '0x0ca76175', maxCallbackGasLimits: [300_000, 500_000, 1_000_000], gasForCallExactCheck: 5000, + subscriptionDepositMinimumRequests: 10, + subscriptionDepositJuels: BigNumber.from('1000000000000000000'), } export type CoordinatorConfig = { - maxCallbackGasLimit: number feedStalenessSeconds: number gasOverheadBeforeCallback: number gasOverheadAfterCallback: number @@ -98,7 +101,6 @@ export type CoordinatorConfig = { } const fallbackNativePerUnitLink = 5000000000000000 export const coordinatorConfig: CoordinatorConfig = { - maxCallbackGasLimit: 1_000_000, feedStalenessSeconds: 86_400, gasOverheadBeforeCallback: 44_615, gasOverheadAfterCallback: 44_615, diff --git a/core/chains/chain_kv.go b/core/chains/chain_kv.go index 6224be1c5c3..5094f2885e5 100644 --- a/core/chains/chain_kv.go +++ b/core/chains/chain_kv.go @@ -17,7 +17,6 @@ type ChainsKV[T types.ChainService] struct { var ErrNoSuchChainID = errors.New("chain id does not exist") func NewChainsKV[T types.ChainService](cs map[string]T) *ChainsKV[T] { - return &ChainsKV[T]{ chains: cs, } diff --git a/core/chains/chain_kv_test.go b/core/chains/chain_kv_test.go index e8b8f6c0ab4..a30de3090b8 100644 --- a/core/chains/chain_kv_test.go +++ b/core/chains/chain_kv_test.go @@ -89,19 +89,13 @@ func (s *testChainService) HealthReport() map[string]error { return map[string]error{} } -// Implement updated [loop.Relay] interface funcs in preparation for BCF-2441 -// TODO update this comment after BCF-2441 is done +// Implement [types.ChainService] interface func (s *testChainService) GetChainStatus(ctx context.Context) (stat types.ChainStatus, err error) { return } -func (s *testChainService) ListNodeStatuses(ctx context.Context, pageSize int32, pageToken string) (stats []types.NodeStatus, nextPageToken string, err error) { +func (s *testChainService) ListNodeStatuses(ctx context.Context, pageSize int32, pageToken string) (stats []types.NodeStatus, nextPageToken string, total int, err error) { return } - func (s *testChainService) Transact(ctx context.Context, from string, to string, amount *big.Int, balanceCheck bool) error { return nil } - -func (s *testChainService) SendTx(ctx context.Context, from string, to string, amount *big.Int, balanceCheck bool) error { - return nil -} diff --git a/core/chains/config.go b/core/chains/config.go index 8ce2a63fe0b..3556c33a785 100644 --- a/core/chains/config.go +++ b/core/chains/config.go @@ -1,11 +1,7 @@ package chains import ( - "context" "errors" - - "github.com/smartcontractkit/chainlink-relay/pkg/logger" - "github.com/smartcontractkit/chainlink-relay/pkg/types" ) var ( @@ -14,39 +10,7 @@ var ( ErrNotFound = errors.New("not found") ) -type ChainConfigs interface { - Chains(offset, limit int, ids ...string) ([]types.ChainStatus, int, error) -} - -type NodeConfigs[I ID, N Node] interface { - Node(name string) (N, error) - Nodes(chainID I) (nodes []N, err error) - - NodeStatus(name string) (types.NodeStatus, error) -} - -// Configs holds chain and node configurations. -// TODO: BCF-2605 audit the usage of this interface and potentially remove it -type Configs[I ID, N Node] interface { - ChainConfigs - NodeConfigs[I, N] -} - -// ChainStatuser is a generic interface for chain configuration. -type ChainStatuser interface { - // must return [ErrNotFound] if the id is not found - ChainStatus(ctx context.Context, id string) (types.ChainStatus, error) - ChainStatuses(ctx context.Context, offset, limit int) ([]types.ChainStatus, int, error) -} - -// NodesStatuser is an interface for node configuration and state. -// TODO BCF-2440, BCF-2511 may need Node(ctx,name) to get a node status by name -type NodesStatuser interface { - NodeStatuses(ctx context.Context, offset, limit int, chainIDs ...string) (nodes []types.NodeStatus, count int, err error) -} - // ChainOpts holds options for configuring a Chain -type ChainOpts[I ID, N Node] interface { +type ChainOpts interface { Validate() error - ConfigsAndLogger() (Configs[I, N], logger.Logger) } diff --git a/core/chains/config_v2.go b/core/chains/config_v2.go deleted file mode 100644 index 414179d8495..00000000000 --- a/core/chains/config_v2.go +++ /dev/null @@ -1,86 +0,0 @@ -package chains - -import "github.com/smartcontractkit/chainlink-relay/pkg/types" - -type configsV2AsV1[I ID, N Node] struct { - *configChains - *configNodes[I, N] -} - -type ConfigsV2[I ID, N Node] interface { - chainConfigsV2 - nodeConfigsV2[I, N] -} - -// NewConfigs returns a [Configs] backed by [ConfigsV2]. -func NewConfigs[I ID, N Node](cfgs ConfigsV2[I, N]) Configs[I, N] { - return configsV2AsV1[I, N]{ - newConfigChains[I](cfgs), - newConfigNodes[I, N](cfgs), - } -} - -// configChains is a generic, immutable Configs for chains. -type configChains struct { - v2 chainConfigsV2 -} - -type chainConfigsV2 interface { - Chains(ids ...string) ([]types.ChainStatus, error) -} - -// newConfigChains returns a chains backed by chains. -func newConfigChains[I ID](d chainConfigsV2) *configChains { - return &configChains{v2: d} -} - -func (o *configChains) Chains(offset, limit int, ids ...string) (chains []types.ChainStatus, count int, err error) { - chains, err = o.v2.Chains(ids...) - if err != nil { - return - } - count = len(chains) - if offset < len(chains) { - chains = chains[offset:] - } else { - chains = nil - } - if limit > 0 && len(chains) > limit { - chains = chains[:limit] - } - return -} - -type nodeConfigsV2[I ID, N Node] interface { - Node(name string) (N, error) - Nodes(chainID I) ([]N, error) - - NodeStatus(name string) (types.NodeStatus, error) - NodeStatuses(chainIDs ...string) (nodes []types.NodeStatus, err error) -} - -// configNodes is a generic Configs for nodes. -type configNodes[I ID, N Node] struct { - nodeConfigsV2[I, N] -} - -func newConfigNodes[I ID, N Node](d nodeConfigsV2[I, N]) *configNodes[I, N] { - return &configNodes[I, N]{d} -} - -func (o *configNodes[I, N]) NodeStatusesPaged(offset, limit int, chainIDs ...string) (nodes []types.NodeStatus, count int, err error) { - nodes, err = o.nodeConfigsV2.NodeStatuses(chainIDs...) - if err != nil { - return - } - count = len(nodes) - if offset < len(nodes) { - nodes = nodes[offset:] - } else { - nodes = nil - } - if limit > 0 && len(nodes) > limit { - nodes = nodes[:limit] - } - return -} diff --git a/core/chains/cosmos/chain.go b/core/chains/cosmos/chain.go index c73793c1c3a..c2c7f25f843 100644 --- a/core/chains/cosmos/chain.go +++ b/core/chains/cosmos/chain.go @@ -25,9 +25,9 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/chains" "github.com/smartcontractkit/chainlink/v2/core/chains/cosmos/cosmostxm" - "github.com/smartcontractkit/chainlink/v2/core/chains/cosmos/types" "github.com/smartcontractkit/chainlink/v2/core/chains/internal" "github.com/smartcontractkit/chainlink/v2/core/services/pg" + "github.com/smartcontractkit/chainlink/v2/core/services/relay" "github.com/smartcontractkit/chainlink/v2/core/utils" ) @@ -56,7 +56,6 @@ type ChainOpts struct { DB *sqlx.DB KeyStore loop.Keystore EventBroadcaster pg.EventBroadcaster - Configs types.Configs } func (o *ChainOpts) Validate() (err error) { @@ -78,21 +77,14 @@ func (o *ChainOpts) Validate() (err error) { if o.EventBroadcaster == nil { err = multierr.Append(err, required("EventBroadcaster")) } - if o.Configs == nil { - err = multierr.Append(err, required("Configs")) - } return } -func (o *ChainOpts) ConfigsAndLogger() (chains.Configs[string, db.Node], logger.Logger) { - return o.Configs, o.Logger -} - func NewChain(cfg *CosmosConfig, opts ChainOpts) (adapters.Chain, error) { if !cfg.IsEnabled() { return nil, fmt.Errorf("cannot create new chain with ID %s, the chain is disabled", *cfg.ChainID) } - c, err := newChain(*cfg.ChainID, cfg, opts.DB, opts.KeyStore, opts.QueryConfig, opts.EventBroadcaster, opts.Configs, opts.Logger) + c, err := newChain(*cfg.ChainID, cfg, opts.DB, opts.KeyStore, opts.QueryConfig, opts.EventBroadcaster, opts.Logger) if err != nil { return nil, err } @@ -103,21 +95,17 @@ var _ adapters.Chain = (*chain)(nil) type chain struct { utils.StartStopOnce - id string - cfg *CosmosConfig - txm *cosmostxm.Txm - // TODO remove this dep after BCF-2441 - // cfs implements the loop.Relayer interface that will be removed - cfgs types.Configs + id string + cfg *CosmosConfig + txm *cosmostxm.Txm lggr logger.Logger } -func newChain(id string, cfg *CosmosConfig, db *sqlx.DB, ks loop.Keystore, logCfg pg.QConfig, eb pg.EventBroadcaster, cfgs types.Configs, lggr logger.Logger) (*chain, error) { +func newChain(id string, cfg *CosmosConfig, db *sqlx.DB, ks loop.Keystore, logCfg pg.QConfig, eb pg.EventBroadcaster, lggr logger.Logger) (*chain, error) { lggr = logger.With(lggr, "cosmosChainID", id) var ch = chain{ id: id, cfg: cfg, - cfgs: cfgs, lggr: logger.Named(lggr, "Chain"), } tc := func() (cosmosclient.ReaderWriter, error) { @@ -143,6 +131,10 @@ func (c *chain) ID() string { return c.id } +func (c *chain) ChainID() relay.ChainID { + return relay.ChainID(c.id) +} + func (c *chain) Config() coscfg.Config { return c.cfg } @@ -159,23 +151,23 @@ func (c *chain) Reader(name string) (cosmosclient.Reader, error) { func (c *chain) getClient(name string) (cosmosclient.ReaderWriter, error) { var node db.Node if name == "" { // Any node - nodes, err := c.cfgs.Nodes(c.id) + nodes, err := c.cfg.ListNodes() if err != nil { - return nil, errors.Wrap(err, "failed to get nodes") + return nil, fmt.Errorf("failed to list nodes: %w", err) } if len(nodes) == 0 { return nil, errors.New("no nodes available") } nodeIndex, err := rand.Int(rand.Reader, big.NewInt(int64(len(nodes)))) if err != nil { - return nil, errors.Wrap(err, "could not generate a random node index") + return nil, fmt.Errorf("could not generate a random node index: %w", err) } node = nodes[nodeIndex.Int64()] } else { // Named node var err error - node, err = c.cfgs.Node(name) + node, err = c.cfg.GetNode(name) if err != nil { - return nil, errors.Wrapf(err, "failed to get node named %s", name) + return nil, fmt.Errorf("failed to get node named %s: %w", name, err) } if node.CosmosChainID != c.id { return nil, fmt.Errorf("failed to create client for chain %s with node %s: wrong chain id %s", c.id, name, node.CosmosChainID) @@ -183,7 +175,7 @@ func (c *chain) getClient(name string) (cosmosclient.ReaderWriter, error) { } client, err := cosmosclient.NewClient(c.id, node.TendermintURL, DefaultRequestTimeout, logger.Named(c.lggr, "Client."+name)) if err != nil { - return nil, errors.Wrap(err, "failed to create client") + return nil, fmt.Errorf("failed to create client: %w", err) } c.lggr.Debugw("Created client", "name", node.Name, "tendermint-url", node.TendermintURL) return client, nil @@ -239,10 +231,6 @@ func (c *chain) Transact(ctx context.Context, from, to string, amount *big.Int, return chains.ErrLOOPPUnsupported } -func (c *chain) SendTx(ctx context.Context, from, to string, amount *big.Int, balanceCheck bool) error { - return c.Transact(ctx, from, to, amount, balanceCheck) -} - // TODO BCF-2602 statuses are static for non-evm chain and should be dynamic func (c *chain) listNodeStatuses(start, end int) ([]relaytypes.NodeStatus, int, error) { stats := make([]relaytypes.NodeStatus, 0) @@ -255,7 +243,7 @@ func (c *chain) listNodeStatuses(start, end int) ([]relaytypes.NodeStatus, int, } nodes := c.cfg.Nodes[start:end] for _, node := range nodes { - stat, err := nodeStatus(node, c.id) + stat, err := nodeStatus(node, c.ChainID()) if err != nil { return stats, total, err } diff --git a/core/chains/cosmos/config.go b/core/chains/cosmos/config.go index 878de2130b6..21a46505255 100644 --- a/core/chains/cosmos/config.go +++ b/core/chains/cosmos/config.go @@ -16,7 +16,7 @@ import ( relaytypes "github.com/smartcontractkit/chainlink-relay/pkg/types" "github.com/smartcontractkit/chainlink/v2/core/chains" - "github.com/smartcontractkit/chainlink/v2/core/chains/cosmos/types" + "github.com/smartcontractkit/chainlink/v2/core/services/relay" "github.com/smartcontractkit/chainlink/v2/core/utils/config" ) @@ -77,119 +77,9 @@ func (cs *CosmosConfigs) SetFrom(fs *CosmosConfigs) (err error) { return } -func (cs CosmosConfigs) Chains(ids ...string) (r []relaytypes.ChainStatus, err error) { - for _, ch := range cs { - if ch == nil { - continue - } - if len(ids) > 0 { - var match bool - for _, id := range ids { - if id == *ch.ChainID { - match = true - break - } - } - if !match { - continue - } - } - ch2 := relaytypes.ChainStatus{ - ID: *ch.ChainID, - Enabled: ch.IsEnabled(), - } - ch2.Config, err = ch.TOMLString() - if err != nil { - return - } - r = append(r, ch2) - } - return -} - -func (cs CosmosConfigs) Node(name string) (n db.Node, err error) { - for i := range cs { - for _, n := range cs[i].Nodes { - if n.Name != nil && *n.Name == name { - return legacyNode(n, *cs[i].ChainID), nil - } - } - } - err = fmt.Errorf("node %s: %w", name, chains.ErrNotFound) - return -} - -func (cs CosmosConfigs) nodes(chainID string) (ns CosmosNodes) { - for _, c := range cs { - if *c.ChainID == chainID { - return c.Nodes - } - } - return nil -} - -func (cs CosmosConfigs) Nodes(chainID string) (ns []db.Node, err error) { - nodes := cs.nodes(chainID) - if nodes == nil { - err = fmt.Errorf("no nodes: chain %s: %w", chainID, chains.ErrNotFound) - return - } - for _, n := range nodes { - if n == nil { - continue - } - ns = append(ns, legacyNode(n, chainID)) - } - return - -} - -func (cs CosmosConfigs) NodeStatus(name string) (n relaytypes.NodeStatus, err error) { - for i := range cs { - for _, n := range cs[i].Nodes { - if n.Name != nil && *n.Name == name { - return nodeStatus(n, *cs[i].ChainID) - } - } - } - err = fmt.Errorf("node %s: %w", name, chains.ErrNotFound) - return -} - -func (cs CosmosConfigs) NodeStatuses(chainIDs ...string) (ns []relaytypes.NodeStatus, err error) { - if len(chainIDs) == 0 { - for i := range cs { - for _, n := range cs[i].Nodes { - if n == nil { - continue - } - n2, err := nodeStatus(n, *cs[i].ChainID) - if err != nil { - return nil, err - } - ns = append(ns, n2) - } - } - return - } - for _, id := range chainIDs { - for _, n := range cs.nodes(id) { - if n == nil { - continue - } - n2, err := nodeStatus(n, id) - if err != nil { - return nil, err - } - ns = append(ns, n2) - } - } - return -} - -func nodeStatus(n *coscfg.Node, chainID string) (relaytypes.NodeStatus, error) { +func nodeStatus(n *coscfg.Node, id relay.ChainID) (relaytypes.NodeStatus, error) { var s relaytypes.NodeStatus - s.ChainID = chainID + s.ChainID = id s.Name = *n.Name b, err := toml.Marshal(n) if err != nil { @@ -364,6 +254,19 @@ func sdkDecFromDecimal(d *decimal.Decimal) sdk.Dec { return sdk.NewDecFromBigIntWithPrec(i.BigInt(), sdk.Precision) } -func NewConfigs(cfgs chains.ConfigsV2[string, db.Node]) types.Configs { - return chains.NewConfigs(cfgs) +func (c *CosmosConfig) GetNode(name string) (db.Node, error) { + for _, n := range c.Nodes { + if *n.Name == name { + return legacyNode(n, *c.ChainID), nil + } + } + return db.Node{}, fmt.Errorf("%w: node %q", chains.ErrNotFound, name) +} + +func (c *CosmosConfig) ListNodes() ([]db.Node, error) { + var allNodes []db.Node + for _, n := range c.Nodes { + allNodes = append(allNodes, legacyNode(n, *c.ChainID)) + } + return allNodes, nil } diff --git a/core/chains/cosmos/config_test.go b/core/chains/cosmos/config_test.go index 3446e7bcb01..54f91a13620 100644 --- a/core/chains/cosmos/config_test.go +++ b/core/chains/cosmos/config_test.go @@ -1,11 +1,16 @@ package cosmos import ( + "reflect" "testing" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/shopspring/decimal" "github.com/stretchr/testify/assert" + + coscfg "github.com/smartcontractkit/chainlink-cosmos/pkg/cosmos/config" + "github.com/smartcontractkit/chainlink-cosmos/pkg/cosmos/db" + "github.com/smartcontractkit/chainlink-relay/pkg/utils" ) func Test_sdkDecFromDecimal(t *testing.T) { @@ -23,3 +28,69 @@ func Test_sdkDecFromDecimal(t *testing.T) { }) } } + +func TestCosmosConfig_GetNode(t *testing.T) { + type fields struct { + ChainID *string + Nodes CosmosNodes + } + type args struct { + name string + } + tests := []struct { + name string + fields fields + args args + want db.Node + wantErr bool + }{ + { + name: "not found", + args: args{ + name: "not a node", + }, + fields: fields{Nodes: CosmosNodes{}}, + want: db.Node{}, + wantErr: true, + }, + { + name: "success", + args: args{ + name: "node", + }, + fields: fields{ + ChainID: ptr("chainID"), + Nodes: []*coscfg.Node{ + &coscfg.Node{ + Name: ptr("node"), + TendermintURL: &utils.URL{}, + }, + }}, + want: db.Node{ + CosmosChainID: "chainID", + Name: "node", + TendermintURL: "", + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + c := &CosmosConfig{ + Nodes: tt.fields.Nodes, + ChainID: tt.fields.ChainID, + } + got, err := c.GetNode(tt.args.name) + if (err != nil) != tt.wantErr { + t.Errorf("CosmosConfig.GetNode() error = %v, wantErr %v", err, tt.wantErr) + return + } + if !reflect.DeepEqual(got, tt.want) { + t.Errorf("CosmosConfig.GetNode() = %v, want %v", got, tt.want) + } + }) + } +} + +func ptr[T any](t T) *T { + return &t +} diff --git a/core/chains/cosmos/relay_extender.go b/core/chains/cosmos/relay_extender.go deleted file mode 100644 index 3f9b9f5ad5b..00000000000 --- a/core/chains/cosmos/relay_extender.go +++ /dev/null @@ -1,85 +0,0 @@ -package cosmos - -import ( - "context" - "fmt" - "math/big" - - "github.com/smartcontractkit/chainlink-cosmos/pkg/cosmos/adapters" - - "github.com/smartcontractkit/chainlink-relay/pkg/loop" - relaytypes "github.com/smartcontractkit/chainlink-relay/pkg/types" - - pkgcosmos "github.com/smartcontractkit/chainlink-cosmos/pkg/cosmos" - "github.com/smartcontractkit/chainlink/v2/core/chains" - "github.com/smartcontractkit/chainlink/v2/core/services/relay" -) - -// LegacyChainContainer is container interface for Cosmos chains -type LegacyChainContainer interface { - Get(id string) (adapters.Chain, error) - Len() int - List(ids ...string) ([]adapters.Chain, error) - Slice() []adapters.Chain -} - -type LegacyChains = chains.ChainsKV[adapters.Chain] - -var _ LegacyChainContainer = &LegacyChains{} - -func NewLegacyChains(m map[string]adapters.Chain) *LegacyChains { - return chains.NewChainsKV[adapters.Chain](m) -} - -type LoopRelayerChainer interface { - loop.Relayer - Chain() adapters.Chain -} - -type LoopRelayerChain struct { - loop.Relayer - chain adapters.Chain -} - -func NewLoopRelayerChain(r *pkgcosmos.Relayer, s *RelayExtender) *LoopRelayerChain { - - ra := relay.NewRelayerAdapter(r, s) - return &LoopRelayerChain{ - Relayer: ra, - chain: s, - } -} -func (r *LoopRelayerChain) Chain() adapters.Chain { - return r.chain -} - -var _ LoopRelayerChainer = &LoopRelayerChain{} - -// TODO remove these wrappers after BCF-2441 -type RelayExtender struct { - adapters.Chain - chainImpl *chain -} - -var _ relay.RelayerExt = &RelayExtender{} - -func NewRelayExtender(cfg *CosmosConfig, opts ChainOpts) (*RelayExtender, error) { - c, err := NewChain(cfg, opts) - if err != nil { - return nil, err - } - chainImpl, ok := (c).(*chain) - if !ok { - return nil, fmt.Errorf("internal error: cosmos relay extender got wrong type %t", c) - } - return &RelayExtender{Chain: chainImpl, chainImpl: chainImpl}, nil -} -func (r *RelayExtender) GetChainStatus(ctx context.Context) (relaytypes.ChainStatus, error) { - return r.chainImpl.GetChainStatus(ctx) -} -func (r *RelayExtender) ListNodeStatuses(ctx context.Context, pageSize int32, pageToken string) (stats []relaytypes.NodeStatus, nextPageToken string, total int, err error) { - return r.chainImpl.ListNodeStatuses(ctx, pageSize, pageToken) -} -func (r *RelayExtender) Transact(ctx context.Context, from, to string, amount *big.Int, balanceCheck bool) error { - return chains.ErrLOOPPUnsupported -} diff --git a/core/chains/cosmos/relayer_adapter.go b/core/chains/cosmos/relayer_adapter.go new file mode 100644 index 00000000000..ffe4181ceb0 --- /dev/null +++ b/core/chains/cosmos/relayer_adapter.go @@ -0,0 +1,50 @@ +package cosmos + +import ( + "github.com/smartcontractkit/chainlink-cosmos/pkg/cosmos/adapters" + + "github.com/smartcontractkit/chainlink-relay/pkg/loop" + + pkgcosmos "github.com/smartcontractkit/chainlink-cosmos/pkg/cosmos" + "github.com/smartcontractkit/chainlink/v2/core/chains" + "github.com/smartcontractkit/chainlink/v2/core/services/relay" +) + +// LegacyChainContainer is container interface for Cosmos chains +type LegacyChainContainer interface { + Get(id string) (adapters.Chain, error) + Len() int + List(ids ...string) ([]adapters.Chain, error) + Slice() []adapters.Chain +} + +type LegacyChains = chains.ChainsKV[adapters.Chain] + +var _ LegacyChainContainer = &LegacyChains{} + +func NewLegacyChains(m map[string]adapters.Chain) *LegacyChains { + return chains.NewChainsKV[adapters.Chain](m) +} + +type LoopRelayerChainer interface { + loop.Relayer + Chain() adapters.Chain +} + +type LoopRelayerChain struct { + loop.Relayer + chain adapters.Chain +} + +func NewLoopRelayerChain(r *pkgcosmos.Relayer, s adapters.Chain) *LoopRelayerChain { + ra := relay.NewRelayerServerAdapter(r, s) + return &LoopRelayerChain{ + Relayer: ra, + chain: s, + } +} +func (r *LoopRelayerChain) Chain() adapters.Chain { + return r.chain +} + +var _ LoopRelayerChainer = &LoopRelayerChain{} diff --git a/core/chains/cosmos/types/types.go b/core/chains/cosmos/types/types.go index 082ffe1b4cc..69b086a9706 100644 --- a/core/chains/cosmos/types/types.go +++ b/core/chains/cosmos/types/types.go @@ -1,17 +1,5 @@ package types -import ( - "github.com/smartcontractkit/chainlink-cosmos/pkg/cosmos/db" - - "github.com/smartcontractkit/chainlink/v2/core/chains" -) - -// Configs manages cosmos chains and nodes. -type Configs interface { - chains.ChainConfigs - chains.NodeConfigs[string, db.Node] -} - // NewNode defines a new node to create. type NewNode struct { Name string `json:"name"` diff --git a/core/chains/evm/chain.go b/core/chains/evm/chain.go index 524e84fd51b..39c92252c7f 100644 --- a/core/chains/evm/chain.go +++ b/core/chains/evm/chain.go @@ -6,7 +6,6 @@ import ( "fmt" "math/big" "net/url" - "sync" "time" "go.uber.org/multierr" @@ -18,8 +17,6 @@ import ( "github.com/smartcontractkit/chainlink-relay/pkg/types" - relaytypes "github.com/smartcontractkit/chainlink-relay/pkg/types" - "github.com/smartcontractkit/chainlink/v2/core/chains" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" evmclient "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" @@ -57,13 +54,6 @@ type Chain interface { BalanceMonitor() monitor.BalanceMonitor LogPoller() logpoller.LogPoller GasEstimator() gas.EvmFeeEstimator - - // TODO remove after BCF-2441 - // This funcs are implemented now in preparation the interface change, which is expected - // to absorb these definitions into [types.ChainService] - GetChainStatus(ctx context.Context) (relaytypes.ChainStatus, error) - ListNodeStatuses(ctx context.Context, pageSize int32, pageToken string) (stats []relaytypes.NodeStatus, nextPageToken string, total int, err error) - Transact(ctx context.Context, from, to string, amount *big.Int, balanceCheck bool) error } var ( @@ -77,7 +67,7 @@ type LegacyChains struct { *chains.ChainsKV[Chain] dflt Chain - cfgs evmtypes.Configs + cfgs toml.EVMConfigs } // LegacyChainContainer is container for EVM chains. @@ -91,6 +81,9 @@ type LegacyChainContainer interface { List(ids ...string) ([]Chain, error) Slice() []Chain + // BCF-2516: this is only used for EVMORM. When we delete that + // we can promote/move the needed funcs from it to LegacyChainContainer + // so instead of EVMORM().XYZ() we'd have something like legacyChains.XYZ() ChainNodeConfigs() evmtypes.Configs } @@ -99,7 +92,7 @@ var _ LegacyChainContainer = &LegacyChains{} func NewLegacyChains(m map[string]Chain, evmCfgs toml.EVMConfigs) *LegacyChains { return &LegacyChains{ ChainsKV: chains.NewChainsKV[Chain](m), - cfgs: chains.NewConfigs[utils.Big, evmtypes.Node](evmCfgs), + cfgs: evmCfgs, } } @@ -180,9 +173,6 @@ type RelayerConfig struct { MailMon *utils.MailboxMonitor GasEstimator gas.EvmFeeEstimator - init sync.Once - operationalConfigs evmtypes.Configs - // TODO BCF-2513 remove test code from the API // Gen-functions are useful for dependency injection by tests GenEthClient func(*big.Int) client.Client @@ -193,14 +183,6 @@ type RelayerConfig struct { GenGasEstimator func(*big.Int) gas.EvmFeeEstimator } -func (r *RelayerConfig) EVMConfigs() evmtypes.Configs { - if r.operationalConfigs == nil { - r.init.Do(func() { - r.operationalConfigs = chains.NewConfigs[utils.Big, evmtypes.Node](r.AppConfig.EVMConfigs()) - }) - } - return r.operationalConfigs -} func NewTOMLChain(ctx context.Context, chain *toml.EVMConfig, opts ChainRelayExtenderConfig) (Chain, error) { chainID := chain.ChainID l := opts.Logger.With("evmChainID", chainID.String()) @@ -500,9 +482,5 @@ func (opts *ChainRelayExtenderConfig) Check() error { return errors.New("config must be non-nil") } - opts.init.Do(func() { - opts.operationalConfigs = chains.NewConfigs[utils.Big, evmtypes.Node](opts.AppConfig.EVMConfigs()) - }) - return nil } diff --git a/core/chains/evm/chain_test.go b/core/chains/evm/chain_test.go index 3ae8a74bfe2..41f498b3e76 100644 --- a/core/chains/evm/chain_test.go +++ b/core/chains/evm/chain_test.go @@ -5,13 +5,10 @@ import ( "testing" "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" "github.com/smartcontractkit/chainlink/v2/core/chains/evm" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/mocks" configtest "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest/v2" - "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" - "github.com/smartcontractkit/chainlink/v2/core/utils" ) func TestLegacyChains(t *testing.T) { @@ -27,29 +24,4 @@ func TestLegacyChains(t *testing.T) { assert.NoError(t, err) assert.Equal(t, c, got) - require.NotPanics(t, func() { - l = evm.NewLegacyChains(m, nil) - assert.NotNil(t, l.ChainNodeConfigs()) - }) -} - -func TestRelayConfigInit(t *testing.T) { - appCfg := configtest.NewGeneralConfig(t, nil) - rCfg := evm.RelayerConfig{ - AppConfig: appCfg, - } - - evmCfg := rCfg.EVMConfigs() - assert.NotNil(t, evmCfg) - - // test lazy init is done only once - // note this kind of swapping should never happen in prod - appCfg2 := configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { - c.EVM[0].ChainID = utils.NewBig(big.NewInt(27)) - }) - rCfg.AppConfig = appCfg2 - - newEvmCfg := rCfg.EVMConfigs() - assert.NotNil(t, newEvmCfg) - assert.Equal(t, evmCfg, newEvmCfg) } diff --git a/core/chains/evm/client/doc.go b/core/chains/evm/client/doc.go new file mode 100644 index 00000000000..f3cba4a0db2 --- /dev/null +++ b/core/chains/evm/client/doc.go @@ -0,0 +1,10 @@ +/* +The simulated backend cannot access old blocks and will return an error if +anything other than `latest`, `nil`, or the latest block are passed to +`CallContract`. + +The simulated client avoids the old block error from the simulated backend by +passing `nil` to `CallContract` when calling `CallContext` or `BatchCallContext` +and will not return an error when an old block is used. +*/ +package client diff --git a/core/chains/evm/client/simulated_backend_client.go b/core/chains/evm/client/simulated_backend_client.go index 74b7aa54ece..dd79c549bfe 100644 --- a/core/chains/evm/client/simulated_backend_client.go +++ b/core/chains/evm/client/simulated_backend_client.go @@ -3,6 +3,7 @@ package client import ( "bytes" "context" + "errors" "fmt" "math/big" "strings" @@ -16,7 +17,6 @@ import ( "github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/rpc" - "github.com/pkg/errors" clienttypes "github.com/smartcontractkit/chainlink/v2/common/chains/client" "github.com/smartcontractkit/chainlink/v2/core/assets" @@ -64,37 +64,85 @@ func (c *SimulatedBackendClient) checkEthCallArgs( "must be an eth.CallArgs, got %+#v", args[0]) } blockNumber, err := c.blockNumber(args[1]) - if err != nil || blockNumber.Cmp(c.currentBlockNumber()) != 0 { + if err != nil { return nil, nil, fmt.Errorf("fourth arg to SimulatedBackendClient.Call "+ - "must be the string \"latest\", or a *big.Int equal to current "+ - "blocknumber, got %#+v", args[1]) + "must be the string \"latest\", or a *big.Int, got %#+v", args[1]) } + + // to and from need to map to a common.Address but could come in as a string + var ( + toAddr common.Address + frmAddr common.Address + ) + + toAddr, err = interfaceToAddress(callArgs["to"]) + if err != nil { + return nil, nil, err + } + + // from is optional in the standard client; default to 0x when missing + if value, ok := callArgs["from"]; ok { + addr, err := interfaceToAddress(value) + if err != nil { + return nil, nil, err + } + + frmAddr = addr + } else { + frmAddr = common.HexToAddress("0x") + } + ca := CallArgs{ - From: callArgs["from"].(common.Address), - To: *callArgs["to"].(*common.Address), + To: toAddr, + From: frmAddr, Data: callArgs["data"].(hexutil.Bytes), } + return &ca, blockNumber, nil } +func interfaceToAddress(value interface{}) (common.Address, error) { + switch v := value.(type) { + case common.Address: + return v, nil + case string: + return common.HexToAddress(v), nil + case *big.Int: + return common.BigToAddress(v), nil + default: + return common.HexToAddress("0x"), fmt.Errorf("unrecognized value type for converting value to common.Address; try string, *big.Int, or common.Address") + } +} + // CallContext mocks the ethereum client RPC calls used by chainlink, copying the // return value into result. +// The simulated client avoids the old block error from the simulated backend by +// passing `nil` to `CallContract` when calling `CallContext` or `BatchCallContext` +// and will not return an error when an old block is used. func (c *SimulatedBackendClient) CallContext(ctx context.Context, result interface{}, method string, args ...interface{}) error { switch method { case "eth_call": - callArgs, _, err := c.checkEthCallArgs(args) - if err != nil { + var ( + callArgs *CallArgs + b []byte + err error + ) + + if callArgs, _, err = c.checkEthCallArgs(args); err != nil { return err } + callMsg := ethereum.CallMsg{From: callArgs.From, To: &callArgs.To, Data: callArgs.Data} - b, err := c.b.CallContract(ctx, callMsg, nil /* always latest block */) - if err != nil { - return errors.Wrapf(err, "while calling contract at address %x with "+ - "data %x", callArgs.To, callArgs.Data) + + if b, err = c.b.CallContract(ctx, callMsg, nil /* always latest block */); err != nil { + return fmt.Errorf("%w: while calling contract at address %x with "+ + "data %x", err, callArgs.To, callArgs.Data) } + switch r := result.(type) { case *hexutil.Bytes: *r = append(*r, b...) + if !bytes.Equal(*r, b) { return fmt.Errorf("was passed a non-empty array, or failed to copy "+ "answer. Expected %x = %x", *r, b) @@ -155,26 +203,26 @@ func init() { var err error balanceOfABI, err = abi.JSON(strings.NewReader(balanceOfABIString)) if err != nil { - panic(errors.Wrapf(err, "while parsing erc20ABI")) + panic(fmt.Errorf("%w: while parsing erc20ABI", err)) } } func (c *SimulatedBackendClient) TokenBalance(ctx context.Context, address common.Address, contractAddress common.Address) (balance *big.Int, err error) { callData, err := balanceOfABI.Pack("balanceOf", address) if err != nil { - return nil, errors.Wrapf(err, "while seeking the ERC20 balance of %s on %s", + return nil, fmt.Errorf("%w: while seeking the ERC20 balance of %s on %s", err, address, contractAddress) } b, err := c.b.CallContract(ctx, ethereum.CallMsg{ To: &contractAddress, Data: callData}, c.currentBlockNumber()) if err != nil { - return nil, errors.Wrapf(err, "while calling ERC20 balanceOf method on %s "+ - "for balance of %s", contractAddress, address) + return nil, fmt.Errorf("%w: while calling ERC20 balanceOf method on %s "+ + "for balance of %s", err, contractAddress, address) } err = balanceOfABI.UnpackIntoInterface(balance, "balanceOf", b) if err != nil { - return nil, errors.New("unable to unpack balance") + return nil, fmt.Errorf("unable to unpack balance") } return balance, nil } @@ -208,8 +256,8 @@ func (c *SimulatedBackendClient) blockNumber(number interface{}) (blockNumber *b default: blockNumber, err = utils.HexToUint256(n) if err != nil { - return nil, errors.Wrapf(err, "while parsing '%s' as hex-encoded"+ - "block number", n) + return nil, fmt.Errorf("%w: while parsing '%s' as hex-encoded"+ + "block number", err, n) } return blockNumber, nil } @@ -328,8 +376,8 @@ func (c *SimulatedBackendClient) SubscribeNewHead( var err error subscription.subscription, err = c.b.SubscribeNewHead(ctx, ch) if err != nil { - return nil, errors.Wrapf(err, "could not subscribe to new heads on "+ - "simulated backend") + return nil, fmt.Errorf("%w: could not subscribe to new heads on "+ + "simulated backend", err) } go func() { var lastHead *evmtypes.Head @@ -428,8 +476,7 @@ func (c *SimulatedBackendClient) CallContract(ctx context.Context, msg ethereum. res, err := c.b.CallContract(ctx, msg, blockNumber) if err != nil { dataErr := revertError{} - isCustomRevert := errors.As(err, &dataErr) - if isCustomRevert { + if errors.Is(err, &dataErr) { return nil, &JsonError{Data: dataErr.ErrorData(), Message: dataErr.Error(), Code: 3} } // Generic revert, no data @@ -459,6 +506,9 @@ func (c *SimulatedBackendClient) SuggestGasPrice(ctx context.Context) (*big.Int, } // BatchCallContext makes a batch rpc call. +// The simulated client avoids the old block error from the simulated backend by +// passing `nil` to `CallContract` when calling `CallContext` or `BatchCallContext` +// and will not return an error when an old block is used. func (c *SimulatedBackendClient) BatchCallContext(ctx context.Context, b []rpc.BatchElem) error { select { case <-ctx.Done(): @@ -471,14 +521,14 @@ func (c *SimulatedBackendClient) BatchCallContext(ctx context.Context, b []rpc.B switch elem.Method { case "eth_getTransactionReceipt": if _, ok := elem.Result.(*evmtypes.Receipt); !ok { - return errors.Errorf("SimulatedBackendClient expected return type of *evmtypes.Receipt for eth_getTransactionReceipt, got type %T", elem.Result) + return fmt.Errorf("SimulatedBackendClient expected return type of *evmtypes.Receipt for eth_getTransactionReceipt, got type %T", elem.Result) } if len(elem.Args) != 1 { - return errors.Errorf("SimulatedBackendClient expected 1 arg, got %d for eth_getTransactionReceipt", len(elem.Args)) + return fmt.Errorf("SimulatedBackendClient expected 1 arg, got %d for eth_getTransactionReceipt", len(elem.Args)) } hash, is := elem.Args[0].(common.Hash) if !is { - return errors.Errorf("SimulatedBackendClient expected arg to be a hash, got: %T", elem.Args[0]) + return fmt.Errorf("SimulatedBackendClient expected arg to be a hash, got: %T", elem.Args[0]) } receipt, err := c.b.TransactionReceipt(ctx, hash) if receipt != nil { @@ -490,22 +540,22 @@ func (c *SimulatedBackendClient) BatchCallContext(ctx context.Context, b []rpc.B case *evmtypes.Head: case *evmtypes.Block: default: - return errors.Errorf("SimulatedBackendClient expected return type of [*evmtypes.Head] or [*evmtypes.Block] for eth_getBlockByNumber, got type %T", v) + return fmt.Errorf("SimulatedBackendClient expected return type of [*evmtypes.Head] or [*evmtypes.Block] for eth_getBlockByNumber, got type %T", v) } if len(elem.Args) != 2 { - return errors.Errorf("SimulatedBackendClient expected 2 args, got %d for eth_getBlockByNumber", len(elem.Args)) + return fmt.Errorf("SimulatedBackendClient expected 2 args, got %d for eth_getBlockByNumber", len(elem.Args)) } blockNum, is := elem.Args[0].(string) if !is { - return errors.Errorf("SimulatedBackendClient expected first arg to be a string for eth_getBlockByNumber, got: %T", elem.Args[0]) + return fmt.Errorf("SimulatedBackendClient expected first arg to be a string for eth_getBlockByNumber, got: %T", elem.Args[0]) } _, is = elem.Args[1].(bool) if !is { - return errors.Errorf("SimulatedBackendClient expected second arg to be a boolean for eth_getBlockByNumber, got: %T", elem.Args[1]) + return fmt.Errorf("SimulatedBackendClient expected second arg to be a boolean for eth_getBlockByNumber, got: %T", elem.Args[1]) } n, ok := new(big.Int).SetString(blockNum, 0) if !ok { - return errors.Errorf("error while converting block number string: %s to big.Int ", blockNum) + return fmt.Errorf("error while converting block number string: %s to big.Int ", blockNum) } header, err := c.b.HeaderByNumber(ctx, n) if err != nil { @@ -525,33 +575,33 @@ func (c *SimulatedBackendClient) BatchCallContext(ctx context.Context, b []rpc.B Timestamp: time.Unix(int64(header.Time), 0), } default: - return errors.Errorf("SimulatedBackendClient Unexpected Type %T", v) + return fmt.Errorf("SimulatedBackendClient Unexpected Type %T", v) } b[i].Error = err case "eth_call": if len(elem.Args) != 2 { - return errors.Errorf("SimulatedBackendClient expected 2 args, got %d for eth_call", len(elem.Args)) + return fmt.Errorf("SimulatedBackendClient expected 2 args, got %d for eth_call", len(elem.Args)) } _, ok := elem.Result.(*string) if !ok { - return errors.Errorf("SimulatedBackendClient expected result to be *string for eth_call, got: %T", elem.Result) + return fmt.Errorf("SimulatedBackendClient expected result to be *string for eth_call, got: %T", elem.Result) } params, ok := elem.Args[0].(map[string]interface{}) if !ok { - return errors.Errorf("SimulatedBackendClient expected first arg to be map[string]interface{} for eth_call, got: %T", elem.Args[0]) + return fmt.Errorf("SimulatedBackendClient expected first arg to be map[string]interface{} for eth_call, got: %T", elem.Args[0]) } blockNum, ok := elem.Args[1].(string) if !ok { - return errors.Errorf("SimulatedBackendClient expected second arg to be a string for eth_call, got: %T", elem.Args[1]) + return fmt.Errorf("SimulatedBackendClient expected second arg to be a string for eth_call, got: %T", elem.Args[1]) } if blockNum != "" { if _, ok = new(big.Int).SetString(blockNum, 0); !ok { - return errors.Errorf("error while converting block number string: %s to big.Int ", blockNum) + return fmt.Errorf("error while converting block number string: %s to big.Int ", blockNum) } } @@ -561,15 +611,15 @@ func (c *SimulatedBackendClient) BatchCallContext(ctx context.Context, b []rpc.B b[i].Error = err case "eth_getHeaderByNumber": if len(elem.Args) != 1 { - return errors.Errorf("SimulatedBackendClient expected 2 args, got %d for eth_getHeaderByNumber", len(elem.Args)) + return fmt.Errorf("SimulatedBackendClient expected 2 args, got %d for eth_getHeaderByNumber", len(elem.Args)) } blockNum, is := elem.Args[0].(string) if !is { - return errors.Errorf("SimulatedBackendClient expected first arg to be a string for eth_getHeaderByNumber, got: %T", elem.Args[0]) + return fmt.Errorf("SimulatedBackendClient expected first arg to be a string for eth_getHeaderByNumber, got: %T", elem.Args[0]) } n, err := hexutil.DecodeBig(blockNum) if err != nil { - return errors.Errorf("error while converting hex block number %s to big.Int ", blockNum) + return fmt.Errorf("error while converting hex block number %s to big.Int ", blockNum) } header, err := c.b.HeaderByNumber(ctx, n) if err != nil { @@ -579,10 +629,10 @@ func (c *SimulatedBackendClient) BatchCallContext(ctx context.Context, b []rpc.B case *types.Header: b[i].Result = header default: - return errors.Errorf("SimulatedBackendClient Unexpected Type %T", v) + return fmt.Errorf("SimulatedBackendClient Unexpected Type %T", v) } default: - return errors.Errorf("SimulatedBackendClient got unsupported method %s", elem.Method) + return fmt.Errorf("SimulatedBackendClient got unsupported method %s", elem.Method) } } return nil diff --git a/core/chains/evm/config/toml/config.go b/core/chains/evm/config/toml/config.go index fdfce23a877..07183945194 100644 --- a/core/chains/evm/config/toml/config.go +++ b/core/chains/evm/config/toml/config.go @@ -3,6 +3,7 @@ package toml import ( "fmt" "net/url" + "strconv" "github.com/ethereum/go-ethereum/core/txpool" "github.com/pelletier/go-toml/v2" @@ -18,6 +19,7 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" "github.com/smartcontractkit/chainlink/v2/core/config" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/ethkey" + "github.com/smartcontractkit/chainlink/v2/core/services/relay" "github.com/smartcontractkit/chainlink/v2/core/store/models" "github.com/smartcontractkit/chainlink/v2/core/utils" configutils "github.com/smartcontractkit/chainlink/v2/core/utils/config" @@ -94,7 +96,18 @@ func (cs *EVMConfigs) SetFrom(fs *EVMConfigs) (err error) { return } -func (cs EVMConfigs) Chains(ids ...string) (r []relaytypes.ChainStatus, err error) { +func (cs EVMConfigs) totalChains() int { + total := 0 + for _, ch := range cs { + if ch == nil { + continue + } + total++ + } + return total +} +func (cs EVMConfigs) Chains(ids ...relay.ChainID) (r []relaytypes.ChainStatus, total int, err error) { + total = cs.totalChains() for _, ch := range cs { if ch == nil { continue @@ -140,7 +153,7 @@ func (cs EVMConfigs) NodeStatus(name string) (relaytypes.NodeStatus, error) { for i := range cs { for _, n := range cs[i].Nodes { if n.Name != nil && *n.Name == name { - return nodeStatus(n, cs[i].ChainID.String()) + return nodeStatus(n, relay.ChainID(cs[i].ChainID.String())) } } } @@ -165,7 +178,7 @@ func legacyNode(n *Node, chainID *utils.Big) (v2 types.Node) { return } -func nodeStatus(n *Node, chainID string) (relaytypes.NodeStatus, error) { +func nodeStatus(n *Node, chainID relay.ChainID) (relaytypes.NodeStatus, error) { var s relaytypes.NodeStatus s.ChainID = chainID s.Name = *n.Name @@ -177,18 +190,21 @@ func nodeStatus(n *Node, chainID string) (relaytypes.NodeStatus, error) { return s, nil } -func (cs EVMConfigs) nodes(chainID string) (ns EVMNodes) { +func (cs EVMConfigs) nodes(id relay.ChainID) (ns EVMNodes) { for _, c := range cs { - if c.ChainID.String() == chainID { + if c.ChainID.String() == id { return c.Nodes } } return nil } -func (cs EVMConfigs) Nodes(chainID utils.Big) (ns []types.Node, err error) { - id := chainID.String() - nodes := cs.nodes(id) +func (cs EVMConfigs) Nodes(chainID relay.ChainID) (ns []types.Node, err error) { + evmID, err := ChainIDInt64(chainID) + if err != nil { + return nil, fmt.Errorf("invalid evm chain id %q : %w", chainID, err) + } + nodes := cs.nodes(chainID) if nodes == nil { err = fmt.Errorf("no nodes: chain %s: %w", &chainID, chains.ErrNotFound) return @@ -197,19 +213,20 @@ func (cs EVMConfigs) Nodes(chainID utils.Big) (ns []types.Node, err error) { if n == nil { continue } - ns = append(ns, legacyNode(n, &chainID)) + + ns = append(ns, legacyNode(n, utils.NewBigI(evmID))) } return } -func (cs EVMConfigs) NodeStatuses(chainIDs ...string) (ns []relaytypes.NodeStatus, err error) { +func (cs EVMConfigs) NodeStatuses(chainIDs ...relay.ChainID) (ns []relaytypes.NodeStatus, err error) { if len(chainIDs) == 0 { for i := range cs { for _, n := range cs[i].Nodes { if n == nil { continue } - n2, err := nodeStatus(n, cs[i].ChainID.String()) + n2, err := nodeStatus(n, relay.ChainID(cs[i].ChainID.String())) if err != nil { return nil, err } @@ -785,3 +802,11 @@ func (n *Node) SetFrom(f *Node) { n.Order = f.Order } } + +func ChainIDInt64(cid relay.ChainID) (int64, error) { + i, err := strconv.Atoi(cid) + if err != nil { + return int64(0), err + } + return int64(i), nil +} diff --git a/core/chains/evm/logpoller/log_poller.go b/core/chains/evm/logpoller/log_poller.go index 69a3143859f..e4ad8dcdfaa 100644 --- a/core/chains/evm/logpoller/log_poller.go +++ b/core/chains/evm/logpoller/log_poller.go @@ -657,7 +657,7 @@ func (lp *logPoller) backfill(ctx context.Context, start, end int64) error { } } if batchSize == 1 { - lp.lggr.Criticalw("Too many log results in a single block, failed to retrieve logs! Node may run in a degraded state unless LogBackfillBatchSize is increased", "err", err, "from", from, "to", to, "LogBackfillBatchSize", lp.backfillBatchSize) + lp.lggr.Criticalw("Too many log results in a single block, failed to retrieve logs! Node may be running in a degraded state.", "err", err, "from", from, "to", to, "LogBackfillBatchSize", lp.backfillBatchSize) return err } batchSize /= 2 @@ -1043,7 +1043,7 @@ func (lp *logPoller) GetBlocksRange(ctx context.Context, numbers []uint64, qopts } // Fill any remaining blocks from the client. - blocksFoundFromRPC, err := lp.fillRemainingBlocksFromRPC(ctx, numbers, blocksFound) + blocksFoundFromRPC, err := lp.fillRemainingBlocksFromRPC(ctx, blocksRequested, blocksFound) if err != nil { return nil, err } @@ -1069,12 +1069,12 @@ func (lp *logPoller) GetBlocksRange(ctx context.Context, numbers []uint64, qopts func (lp *logPoller) fillRemainingBlocksFromRPC( ctx context.Context, - blocksRequested []uint64, + blocksRequested map[uint64]struct{}, blocksFound map[uint64]LogPollerBlock, ) (map[uint64]LogPollerBlock, error) { var reqs []rpc.BatchElem var remainingBlocks []uint64 - for _, num := range blocksRequested { + for num := range blocksRequested { if _, ok := blocksFound[num]; !ok { req := rpc.BatchElem{ Method: "eth_getBlockByNumber", diff --git a/core/chains/evm/logpoller/orm.go b/core/chains/evm/logpoller/orm.go index e8ced08a1e7..08a4d558fbf 100644 --- a/core/chains/evm/logpoller/orm.go +++ b/core/chains/evm/logpoller/orm.go @@ -1,6 +1,7 @@ package logpoller import ( + "context" "database/sql" "math/big" "time" @@ -189,6 +190,12 @@ func (o *ORM) InsertLogs(logs []Log, qopts ...pg.QOpt) error { (:evm_chain_id, :log_index, :block_hash, :block_number, :block_timestamp, :address, :event_sig, :topics, :tx_hash, :data, NOW()) ON CONFLICT DO NOTHING`, logs[start:end]) if err != nil { + if errors.Is(err, context.DeadlineExceeded) && batchInsertSize > 500 { + // In case of DB timeouts, try to insert again with a smaller batch upto a limit + batchInsertSize /= 2 + i -= batchInsertSize // counteract +=batchInsertSize on next loop iteration + continue + } return err } } diff --git a/core/chains/evm/mocks/chain.go b/core/chains/evm/mocks/chain.go index 92d39a95fb9..bf4d1581e22 100644 --- a/core/chains/evm/mocks/chain.go +++ b/core/chains/evm/mocks/chain.go @@ -320,20 +320,6 @@ func (_m *Chain) Ready() error { return r0 } -// SendTx provides a mock function with given fields: ctx, from, to, amount, balanceCheck -func (_m *Chain) SendTx(ctx context.Context, from string, to string, amount *big.Int, balanceCheck bool) error { - ret := _m.Called(ctx, from, to, amount, balanceCheck) - - var r0 error - if rf, ok := ret.Get(0).(func(context.Context, string, string, *big.Int, bool) error); ok { - r0 = rf(ctx, from, to, amount, balanceCheck) - } else { - r0 = ret.Error(0) - } - - return r0 -} - // Start provides a mock function with given fields: _a0 func (_m *Chain) Start(_a0 context.Context) error { ret := _m.Called(_a0) diff --git a/core/chains/evm/types/types.go b/core/chains/evm/types/types.go index dea4f9771fd..7d756485d00 100644 --- a/core/chains/evm/types/types.go +++ b/core/chains/evm/types/types.go @@ -12,13 +12,16 @@ import ( "github.com/pkg/errors" "gopkg.in/guregu/null.v4" - "github.com/smartcontractkit/chainlink/v2/core/chains" + "github.com/smartcontractkit/chainlink-relay/pkg/types" + "github.com/smartcontractkit/chainlink/v2/core/services/relay" "github.com/smartcontractkit/chainlink/v2/core/utils" ) type Configs interface { - chains.ChainConfigs - chains.NodeConfigs[utils.Big, Node] + Chains(ids ...relay.ChainID) ([]types.ChainStatus, int, error) + Node(name string) (Node, error) + Nodes(chainID relay.ChainID) (nodes []Node, err error) + NodeStatus(name string) (types.NodeStatus, error) } type Node struct { diff --git a/core/chains/solana/chain.go b/core/chains/solana/chain.go index 5678cc7f504..682fb23f9f2 100644 --- a/core/chains/solana/chain.go +++ b/core/chains/solana/chain.go @@ -30,6 +30,7 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/chains/internal" "github.com/smartcontractkit/chainlink/v2/core/chains/solana/monitor" "github.com/smartcontractkit/chainlink/v2/core/services" + "github.com/smartcontractkit/chainlink/v2/core/services/relay" "github.com/smartcontractkit/chainlink/v2/core/utils" ) @@ -40,7 +41,6 @@ const DefaultRequestTimeout = 30 * time.Second type ChainOpts struct { Logger logger.Logger KeyStore loop.Keystore - Configs Configs } func (o *ChainOpts) Validate() (err error) { @@ -53,21 +53,18 @@ func (o *ChainOpts) Validate() (err error) { if o.KeyStore == nil { err = multierr.Append(err, required("KeyStore")) } - if o.Configs == nil { - err = multierr.Append(err, required("Configs")) - } return } -func (o *ChainOpts) ConfigsAndLogger() (chains.Configs[string, db.Node], logger.Logger) { - return o.Configs, o.Logger +func (o *ChainOpts) GetLogger() logger.Logger { + return o.Logger } func NewChain(cfg *SolanaConfig, opts ChainOpts) (solana.Chain, error) { if !cfg.IsEnabled() { return nil, fmt.Errorf("cannot create new chain with ID %s: %w", *cfg.ChainID, chains.ErrChainDisabled) } - c, err := newChain(*cfg.ChainID, cfg, opts.KeyStore, opts.Configs, opts.Logger) + c, err := newChain(*cfg.ChainID, cfg, opts.KeyStore, opts.Logger) if err != nil { return nil, err } @@ -82,7 +79,6 @@ type chain struct { cfg *SolanaConfig txm *txm.Txm balanceMonitor services.ServiceCtx - nodes func(chainID string) (nodes []db.Node, err error) lggr logger.Logger // tracking node chain id for verification @@ -213,12 +209,11 @@ func (v *verifiedCachedClient) GetAccountInfoWithOpts(ctx context.Context, addr return v.ReaderWriter.GetAccountInfoWithOpts(ctx, addr, opts) } -func newChain(id string, cfg *SolanaConfig, ks loop.Keystore, cfgs Configs, lggr logger.Logger) (*chain, error) { +func newChain(id string, cfg *SolanaConfig, ks loop.Keystore, lggr logger.Logger) (*chain, error) { lggr = logger.With(lggr, "chainID", id, "chain", "solana") var ch = chain{ id: id, cfg: cfg, - nodes: cfgs.Nodes, lggr: logger.Named(lggr, "Chain"), clientCache: map[string]*verifiedCachedClient{}, } @@ -248,7 +243,7 @@ func (c *chain) ListNodeStatuses(ctx context.Context, pageSize int32, pageToken } func (c *chain) Transact(ctx context.Context, from, to string, amount *big.Int, balanceCheck bool) error { - panic("unimplmented") + return c.sendTx(ctx, from, to, amount, balanceCheck) } func (c *chain) listNodeStatuses(start, end int) ([]relaytypes.NodeStatus, int, error) { @@ -262,7 +257,7 @@ func (c *chain) listNodeStatuses(start, end int) ([]relaytypes.NodeStatus, int, } nodes := c.cfg.Nodes[start:end] for _, node := range nodes { - stat, err := nodeStatus(node, c.id) + stat, err := nodeStatus(node, c.ChainID()) if err != nil { return stats, total, err } @@ -291,11 +286,15 @@ func (c *chain) Reader() (client.Reader, error) { return c.getClient() } +func (c *chain) ChainID() relay.ChainID { + return relay.ChainID(c.id) +} + // getClient returns a client, randomly selecting one from available and valid nodes func (c *chain) getClient() (client.ReaderWriter, error) { var node db.Node var client client.ReaderWriter - nodes, err := c.nodes(c.id) // opt: pass static nodes set to constructor + nodes, err := c.cfg.ListNodes() if err != nil { return nil, errors.Wrap(err, "failed to get nodes") } @@ -392,7 +391,7 @@ func (c *chain) HealthReport() map[string]error { return report } -func (c *chain) SendTx(ctx context.Context, from, to string, amount *big.Int, balanceCheck bool) error { +func (c *chain) sendTx(ctx context.Context, from, to string, amount *big.Int, balanceCheck bool) error { reader, err := c.Reader() if err != nil { return fmt.Errorf("chain unreachable: %w", err) diff --git a/core/chains/solana/chain_test.go b/core/chains/solana/chain_test.go index 898b70213df..c8dfcf8501e 100644 --- a/core/chains/solana/chain_test.go +++ b/core/chains/solana/chain_test.go @@ -13,7 +13,7 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - "github.com/smartcontractkit/chainlink-relay/pkg/types" + "github.com/smartcontractkit/chainlink-relay/pkg/utils" "github.com/smartcontractkit/chainlink-solana/pkg/solana/client" solcfg "github.com/smartcontractkit/chainlink-solana/pkg/solana/config" "github.com/smartcontractkit/chainlink-solana/pkg/solana/db" @@ -44,8 +44,6 @@ func TestSolanaChain_GetClient(t *testing.T) { })) defer mockServer.Close() - solORM := &mockConfigs{} - ch := solcfg.Chain{} ch.SetDefaults() cfg := &SolanaConfig{ @@ -54,68 +52,66 @@ func TestSolanaChain_GetClient(t *testing.T) { } testChain := chain{ id: "devnet", - nodes: solORM.Nodes, cfg: cfg, lggr: logger.TestLogger(t), clientCache: map[string]*verifiedCachedClient{}, } - // random nodes (happy path, all valid) - solORM.nodesForChain = []db.Node{ - { - SolanaChainID: "devnet", - SolanaURL: mockServer.URL + "/1", + cfg.Nodes = SolanaNodes([]*solcfg.Node{ + &solcfg.Node{ + Name: ptr("devnet"), + URL: utils.MustParseURL(mockServer.URL + "/1"), }, - { - SolanaChainID: "devnet", - SolanaURL: mockServer.URL + "/2", + &solcfg.Node{ + Name: ptr("devnet"), + URL: utils.MustParseURL(mockServer.URL + "/2"), }, - } + }) _, err := testChain.getClient() assert.NoError(t, err) // random nodes (happy path, 1 valid + multiple invalid) - solORM.nodesForChain = []db.Node{ - { - SolanaChainID: "devnet", - SolanaURL: mockServer.URL + "/1", + cfg.Nodes = SolanaNodes([]*solcfg.Node{ + &solcfg.Node{ + Name: ptr("devnet"), + URL: utils.MustParseURL(mockServer.URL + "/1"), }, - { - SolanaChainID: "devnet", - SolanaURL: mockServer.URL + "/mismatch/1", + &solcfg.Node{ + Name: ptr("devnet"), + URL: utils.MustParseURL(mockServer.URL + "/mismatch/1"), }, - { - SolanaChainID: "devnet", - SolanaURL: mockServer.URL + "/mismatch/2", + &solcfg.Node{ + Name: ptr("devnet"), + URL: utils.MustParseURL(mockServer.URL + "/mismatch/2"), }, - { - SolanaChainID: "devnet", - SolanaURL: mockServer.URL + "/mismatch/3", + &solcfg.Node{ + Name: ptr("devnet"), + URL: utils.MustParseURL(mockServer.URL + "/mismatch/3"), }, - { - SolanaChainID: "devnet", - SolanaURL: mockServer.URL + "/mismatch/4", + &solcfg.Node{ + Name: ptr("devnet"), + URL: utils.MustParseURL(mockServer.URL + "/mismatch/4"), }, - } + }) _, err = testChain.getClient() assert.NoError(t, err) // empty nodes response - solORM.nodesForChain = nil + cfg.Nodes = nil _, err = testChain.getClient() assert.Error(t, err) // no valid nodes to select from - solORM.nodesForChain = []db.Node{ - { - SolanaChainID: "devnet", - SolanaURL: mockServer.URL + "/mismatch/1", + cfg.Nodes = SolanaNodes([]*solcfg.Node{ + &solcfg.Node{ + Name: ptr("devnet"), + URL: utils.MustParseURL(mockServer.URL + "/mismatch/1"), }, - { - SolanaChainID: "devnet", - SolanaURL: mockServer.URL + "/mismatch/2", + &solcfg.Node{ + Name: ptr("devnet"), + URL: utils.MustParseURL(mockServer.URL + "/mismatch/2"), }, - } + }) _, err = testChain.getClient() assert.NoError(t, err) } @@ -230,28 +226,6 @@ func TestSolanaChain_VerifiedClient_ParallelClients(t *testing.T) { assert.Equal(t, testChain.clientCache[mockServer.URL], client1) } -var _ Configs = &mockConfigs{} - -type mockConfigs struct { - nodesForChain []db.Node -} - -func (m *mockConfigs) Nodes(chainID string) (nodes []db.Node, err error) { - return m.nodesForChain, nil -} - -func (m *mockConfigs) Chains(offset, limit int, ids ...string) ([]types.ChainStatus, int, error) { - panic("unimplemented") -} - -func (m *mockConfigs) Node(s string) (db.Node, error) { panic("unimplemented") } - -func (m *mockConfigs) NodeStatus(s string) (types.NodeStatus, error) { panic("unimplemented") } - -func (m *mockConfigs) NodeStatusesPaged(offset, limit int, chainIDs ...string) (nodes []types.NodeStatus, count int, err error) { - panic("unimplemented") -} - func ptr[T any](t T) *T { return &t } diff --git a/core/chains/solana/config.go b/core/chains/solana/config.go index c9d2f19d61c..b6e4a077f9e 100644 --- a/core/chains/solana/config.go +++ b/core/chains/solana/config.go @@ -15,7 +15,7 @@ import ( solcfg "github.com/smartcontractkit/chainlink-solana/pkg/solana/config" soldb "github.com/smartcontractkit/chainlink-solana/pkg/solana/db" - "github.com/smartcontractkit/chainlink/v2/core/chains" + "github.com/smartcontractkit/chainlink/v2/core/services/relay" "github.com/smartcontractkit/chainlink/v2/core/utils/config" ) @@ -75,116 +75,9 @@ func (cs *SolanaConfigs) SetFrom(fs *SolanaConfigs) (err error) { return } -func (cs SolanaConfigs) Chains(ids ...string) (r []relaytypes.ChainStatus, err error) { - for _, ch := range cs { - if ch == nil { - continue - } - if len(ids) > 0 { - var match bool - for _, id := range ids { - if id == *ch.ChainID { - match = true - break - } - } - if !match { - continue - } - } - ch2 := relaytypes.ChainStatus{ - ID: *ch.ChainID, - Enabled: ch.IsEnabled(), - } - ch2.Config, err = ch.TOMLString() - if err != nil { - return - } - r = append(r, ch2) - } - return -} - -func (cs SolanaConfigs) Node(name string) (soldb.Node, error) { - for i := range cs { - for _, n := range cs[i].Nodes { - if n.Name != nil && *n.Name == name { - return legacySolNode(n, *cs[i].ChainID), nil - } - } - } - return soldb.Node{}, fmt.Errorf("node %s: %w", name, chains.ErrNotFound) -} - -func (cs SolanaConfigs) nodes(chainID string) (ns SolanaNodes) { - for _, c := range cs { - if *c.ChainID == chainID { - return c.Nodes - } - } - return nil -} - -func (cs SolanaConfigs) Nodes(chainID string) (ns []soldb.Node, err error) { - nodes := cs.nodes(chainID) - if nodes == nil { - err = fmt.Errorf("no nodes: chain %s: %w", chainID, chains.ErrNotFound) - return - } - for _, n := range nodes { - if n == nil { - continue - } - ns = append(ns, legacySolNode(n, chainID)) - } - return -} - -func (cs SolanaConfigs) NodeStatus(name string) (relaytypes.NodeStatus, error) { - for i := range cs { - for _, n := range cs[i].Nodes { - if n.Name != nil && *n.Name == name { - return nodeStatus(n, *cs[i].ChainID) - } - } - } - return relaytypes.NodeStatus{}, fmt.Errorf("node %s: %w", name, chains.ErrNotFound) -} - -func (cs SolanaConfigs) NodeStatuses(chainIDs ...string) (ns []relaytypes.NodeStatus, err error) { - if len(chainIDs) == 0 { - for i := range cs { - for _, n := range cs[i].Nodes { - if n == nil { - continue - } - n2, err := nodeStatus(n, *cs[i].ChainID) - if err != nil { - return nil, err - } - ns = append(ns, n2) - } - } - return - } - for _, id := range chainIDs { - for _, n := range cs.nodes(id) { - if n == nil { - continue - } - n2, err := nodeStatus(n, id) - if err != nil { - return nil, err - } - ns = append(ns, n2) - } - } - return -} - -func nodeStatus(n *solcfg.Node, chainID string) (relaytypes.NodeStatus, error) { +func nodeStatus(n *solcfg.Node, id relay.ChainID) (relaytypes.NodeStatus, error) { var s relaytypes.NodeStatus - s.ChainID = chainID + s.ChainID = id s.Name = *n.Name b, err := toml.Marshal(n) if err != nil { @@ -219,10 +112,10 @@ func setFromNode(n, f *solcfg.Node) { } } -func legacySolNode(n *solcfg.Node, chainID string) soldb.Node { +func legacySolNode(n *solcfg.Node, id relay.ChainID) soldb.Node { return soldb.Node{ Name: *n.Name, - SolanaChainID: chainID, + SolanaChainID: id, SolanaURL: (*url.URL)(n.URL).String(), } } @@ -370,14 +263,10 @@ func (c *SolanaConfig) FeeBumpPeriod() time.Duration { return c.Chain.FeeBumpPeriod.Duration() } -// Configs manages solana chains and nodes. -type Configs interface { - chains.ChainConfigs - chains.NodeConfigs[string, soldb.Node] -} - -var _ chains.Configs[string, soldb.Node] = (Configs)(nil) - -func NewConfigs(cfgs chains.ConfigsV2[string, soldb.Node]) Configs { - return chains.NewConfigs(cfgs) +func (c *SolanaConfig) ListNodes() ([]soldb.Node, error) { + var allNodes []soldb.Node + for _, n := range c.Nodes { + allNodes = append(allNodes, legacySolNode(n, *c.ChainID)) + } + return allNodes, nil } diff --git a/core/chains/solana/relay_extender.go b/core/chains/solana/relay_extender.go deleted file mode 100644 index e25cce0b697..00000000000 --- a/core/chains/solana/relay_extender.go +++ /dev/null @@ -1,40 +0,0 @@ -package solana - -import ( - "context" - "fmt" - "math/big" - - relaytypes "github.com/smartcontractkit/chainlink-relay/pkg/types" - "github.com/smartcontractkit/chainlink-solana/pkg/solana" - "github.com/smartcontractkit/chainlink/v2/core/services/relay" -) - -// TODO remove these wrappers after BCF-2441 -type RelayExtender struct { - solana.Chain - chainImpl *chain -} - -var _ relay.RelayerExt = &RelayExtender{} - -func NewRelayExtender(cfg *SolanaConfig, opts ChainOpts) (*RelayExtender, error) { - c, err := NewChain(cfg, opts) - if err != nil { - return nil, err - } - chainImpl, ok := (c).(*chain) - if !ok { - return nil, fmt.Errorf("internal error: cosmos relay extender got wrong type %t", c) - } - return &RelayExtender{Chain: chainImpl, chainImpl: chainImpl}, nil -} -func (r *RelayExtender) GetChainStatus(ctx context.Context) (relaytypes.ChainStatus, error) { - return r.chainImpl.GetChainStatus(ctx) -} -func (r *RelayExtender) ListNodeStatuses(ctx context.Context, pageSize int32, pageToken string) (stats []relaytypes.NodeStatus, nextPageToken string, total int, err error) { - return r.chainImpl.ListNodeStatuses(ctx, pageSize, pageToken) -} -func (r *RelayExtender) Transact(ctx context.Context, from, to string, amount *big.Int, balanceCheck bool) error { - return r.chainImpl.SendTx(ctx, from, to, amount, balanceCheck) -} diff --git a/core/chains/starknet/chain.go b/core/chains/starknet/chain.go index c6718c68065..fead94cda60 100644 --- a/core/chains/starknet/chain.go +++ b/core/chains/starknet/chain.go @@ -23,7 +23,7 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/chains" "github.com/smartcontractkit/chainlink/v2/core/chains/internal" - "github.com/smartcontractkit/chainlink/v2/core/chains/starknet/types" + "github.com/smartcontractkit/chainlink/v2/core/services/relay" "github.com/smartcontractkit/chainlink/v2/core/utils" ) @@ -31,7 +31,6 @@ type ChainOpts struct { Logger logger.Logger // the implementation used here needs to be co-ordinated with the starknet transaction manager keystore adapter KeyStore loop.Keystore - Configs types.Configs } func (o *ChainOpts) Name() string { @@ -48,23 +47,15 @@ func (o *ChainOpts) Validate() (err error) { if o.KeyStore == nil { err = multierr.Append(err, required("KeyStore")) } - if o.Configs == nil { - err = multierr.Append(err, required("Configs")) - } return } -func (o *ChainOpts) ConfigsAndLogger() (chains.Configs[string, db.Node], logger.Logger) { - return o.Configs, o.Logger -} - var _ starkChain.Chain = (*chain)(nil) type chain struct { utils.StartStopOnce id string cfg *StarknetConfig - cfgs types.Configs lggr logger.Logger txm txm.StarkTXM } @@ -73,19 +64,18 @@ func NewChain(cfg *StarknetConfig, opts ChainOpts) (starkchain.Chain, error) { if !cfg.IsEnabled() { return nil, fmt.Errorf("cannot create new chain with ID %s: %w", *cfg.ChainID, chains.ErrChainDisabled) } - c, err := newChain(*cfg.ChainID, cfg, opts.KeyStore, opts.Configs, opts.Logger) + c, err := newChain(*cfg.ChainID, cfg, opts.KeyStore, opts.Logger) if err != nil { return nil, err } return c, nil } -func newChain(id string, cfg *StarknetConfig, loopKs loop.Keystore, cfgs types.Configs, lggr logger.Logger) (*chain, error) { +func newChain(id string, cfg *StarknetConfig, loopKs loop.Keystore, lggr logger.Logger) (*chain, error) { lggr = logger.With(lggr, "starknetChainID", id) ch := &chain{ id: id, cfg: cfg, - cfgs: cfgs, lggr: logger.Named(lggr, "Chain"), } @@ -118,11 +108,15 @@ func (c *chain) Reader() (starknet.Reader, error) { return c.getClient() } +func (c *chain) ChainID() relay.ChainID { + return relay.ChainID(c.id) +} + // getClient returns a client, randomly selecting one from available and valid nodes func (c *chain) getClient() (*starknet.Client, error) { var node db.Node var client *starknet.Client - nodes, err := c.cfgs.Nodes(c.id) + nodes, err := c.cfg.ListNodes() if err != nil { return nil, errors.Wrap(err, "failed to get nodes") } @@ -215,7 +209,7 @@ func (c *chain) listNodeStatuses(start, end int) ([]relaytypes.NodeStatus, int, } nodes := c.cfg.Nodes[start:end] for _, node := range nodes { - stat, err := nodeStatus(node, c.id) + stat, err := nodeStatus(node, c.ChainID()) if err != nil { return stats, total, err } diff --git a/core/chains/starknet/config.go b/core/chains/starknet/config.go index b28d8e6a487..33b2a8d257a 100644 --- a/core/chains/starknet/config.go +++ b/core/chains/starknet/config.go @@ -14,7 +14,7 @@ import ( stkcfg "github.com/smartcontractkit/chainlink-starknet/relayer/pkg/chainlink/config" "github.com/smartcontractkit/chainlink-starknet/relayer/pkg/chainlink/db" - "github.com/smartcontractkit/chainlink/v2/core/chains" + "github.com/smartcontractkit/chainlink/v2/core/services/relay" "github.com/smartcontractkit/chainlink/v2/core/utils/config" ) @@ -74,118 +74,9 @@ func (cs *StarknetConfigs) SetFrom(fs *StarknetConfigs) (err error) { return } -func (cs StarknetConfigs) Chains(ids ...string) (r []types.ChainStatus, err error) { - for _, ch := range cs { - if ch == nil { - continue - } - if len(ids) > 0 { - var match bool - for _, id := range ids { - if id == *ch.ChainID { - match = true - break - } - } - if !match { - continue - } - } - ch2 := types.ChainStatus{ - ID: *ch.ChainID, - Enabled: ch.IsEnabled(), - } - ch2.Config, err = ch.TOMLString() - if err != nil { - return - } - r = append(r, ch2) - } - return -} - -func (cs StarknetConfigs) Node(name string) (n db.Node, err error) { - for i := range cs { - for _, n := range cs[i].Nodes { - if n.Name != nil && *n.Name == name { - return legacyNode(n, *cs[i].ChainID), nil - } - } - } - err = fmt.Errorf("node %s: %w", name, chains.ErrNotFound) - return -} - -func (cs StarknetConfigs) nodes(chainID string) (ns StarknetNodes) { - for _, c := range cs { - if *c.ChainID == chainID { - return c.Nodes - } - } - return nil -} - -func (cs StarknetConfigs) Nodes(chainID string) (ns []db.Node, err error) { - nodes := cs.nodes(chainID) - if nodes == nil { - err = fmt.Errorf("no nodes: chain %s: %w", chainID, chains.ErrNotFound) - return - } - for _, n := range nodes { - if n == nil { - continue - } - ns = append(ns, legacyNode(n, chainID)) - } - return -} - -func (cs StarknetConfigs) NodeStatus(name string) (n types.NodeStatus, err error) { - for i := range cs { - for _, n := range cs[i].Nodes { - if n.Name != nil && *n.Name == name { - return nodeStatus(n, *cs[i].ChainID) - } - } - } - err = fmt.Errorf("node %s: %w", name, chains.ErrNotFound) - return -} - -func (cs StarknetConfigs) NodeStatuses(chainIDs ...string) (ns []types.NodeStatus, err error) { - if len(chainIDs) == 0 { - for i := range cs { - for _, n := range cs[i].Nodes { - if n == nil { - continue - } - n2, err := nodeStatus(n, *cs[i].ChainID) - if err != nil { - return nil, err - } - ns = append(ns, n2) - } - } - return - } - for _, id := range chainIDs { - for _, n := range cs.nodes(id) { - if n == nil { - continue - } - n2, err := nodeStatus(n, id) - if err != nil { - return nil, err - } - ns = append(ns, n2) - } - } - return -} - -func nodeStatus(n *stkcfg.Node, chainID string) (types.NodeStatus, error) { +func nodeStatus(n *stkcfg.Node, id relay.ChainID) (types.NodeStatus, error) { var s types.NodeStatus - s.ChainID = chainID + s.ChainID = id s.Name = *n.Name b, err := toml.Marshal(n) if err != nil { @@ -283,7 +174,7 @@ func setFromNode(n, f *stkcfg.Node) { } } -func legacyNode(n *stkcfg.Node, id string) db.Node { +func legacyNode(n *stkcfg.Node, id relay.ChainID) db.Node { return db.Node{ Name: *n.Name, ChainID: id, @@ -312,3 +203,11 @@ func (c *StarknetConfig) OCR2CacheTTL() time.Duration { func (c *StarknetConfig) RequestTimeout() time.Duration { return c.Chain.RequestTimeout.Duration() } + +func (c *StarknetConfig) ListNodes() ([]db.Node, error) { + var allNodes []db.Node + for _, n := range c.Nodes { + allNodes = append(allNodes, legacyNode(n, *c.ChainID)) + } + return allNodes, nil +} diff --git a/core/chains/starknet/orm.go b/core/chains/starknet/orm.go deleted file mode 100644 index 9d7109d150e..00000000000 --- a/core/chains/starknet/orm.go +++ /dev/null @@ -1,12 +0,0 @@ -package starknet - -import ( - starknetdb "github.com/smartcontractkit/chainlink-starknet/relayer/pkg/chainlink/db" - - "github.com/smartcontractkit/chainlink/v2/core/chains" - "github.com/smartcontractkit/chainlink/v2/core/chains/starknet/types" -) - -func NewConfigs(cfgs chains.ConfigsV2[string, starknetdb.Node]) types.Configs { - return chains.NewConfigs(cfgs) -} diff --git a/core/chains/starknet/relay_extender.go b/core/chains/starknet/relay_extender.go deleted file mode 100644 index 54d5ab2ab03..00000000000 --- a/core/chains/starknet/relay_extender.go +++ /dev/null @@ -1,43 +0,0 @@ -package starknet - -import ( - "context" - "fmt" - "math/big" - - relaytypes "github.com/smartcontractkit/chainlink-relay/pkg/types" - starkchain "github.com/smartcontractkit/chainlink-starknet/relayer/pkg/chainlink/chain" - - "github.com/smartcontractkit/chainlink/v2/core/chains" - - "github.com/smartcontractkit/chainlink/v2/core/services/relay" -) - -// TODO remove these wrappers after BCF-2441 -type RelayExtender struct { - starkchain.Chain - chainImpl *chain -} - -var _ relay.RelayerExt = &RelayExtender{} - -func NewRelayExtender(cfg *StarknetConfig, opts ChainOpts) (*RelayExtender, error) { - c, err := NewChain(cfg, opts) - if err != nil { - return nil, err - } - chainImpl, ok := (c).(*chain) - if !ok { - return nil, fmt.Errorf("internal error: starkent relay extender got wrong type %t", c) - } - return &RelayExtender{Chain: chainImpl, chainImpl: chainImpl}, nil -} -func (r *RelayExtender) GetChainStatus(ctx context.Context) (relaytypes.ChainStatus, error) { - return r.chainImpl.GetChainStatus(ctx) -} -func (r *RelayExtender) ListNodeStatuses(ctx context.Context, pageSize int32, pageToken string) (stats []relaytypes.NodeStatus, nextPageToken string, total int, err error) { - return r.chainImpl.ListNodeStatuses(ctx, pageSize, pageToken) -} -func (r *RelayExtender) Transact(ctx context.Context, from, to string, amount *big.Int, balanceCheck bool) error { - return chains.ErrLOOPPUnsupported -} diff --git a/core/chains/starknet/types/types.go b/core/chains/starknet/types/types.go deleted file mode 100644 index 2158d80fbb9..00000000000 --- a/core/chains/starknet/types/types.go +++ /dev/null @@ -1,12 +0,0 @@ -package types - -import ( - "github.com/smartcontractkit/chainlink-starknet/relayer/pkg/chainlink/db" - - "github.com/smartcontractkit/chainlink/v2/core/chains" -) - -type Configs interface { - chains.ChainConfigs - chains.NodeConfigs[string, db.Node] -} diff --git a/core/config/docs/secrets.toml b/core/config/docs/secrets.toml index de097e50a0e..5ac02e5f55a 100644 --- a/core/config/docs/secrets.toml +++ b/core/config/docs/secrets.toml @@ -51,8 +51,10 @@ AuthToken = "prometheus-token" # Example Username = "A-Mercury-Username" # Example # Password is used for basic auth of the Mercury endpoint Password = "A-Mercury-Password" # Example -# URL is the Mercury endpoint URL which is used by OCR2 Automation to access Mercury price feed +# URL is the Mercury endpoint base URL used to access Mercury price feed URL = "https://example.com" # Example +# LegacyURL is the Mercury legacy endpoint base URL used to access Mercury v0.2 price feed +LegacyURL = "https://example.v1.com" # Example [Threshold] # ThresholdKeyShare used by the threshold decryption OCR plugin diff --git a/core/config/toml/types.go b/core/config/toml/types.go index 5aedcf4deb6..b5535781a42 100644 --- a/core/config/toml/types.go +++ b/core/config/toml/types.go @@ -1215,8 +1215,13 @@ func (ins *Insecure) setFrom(f *Insecure) { } type MercuryCredentials struct { - URL *models.SecretURL + // LegacyURL is the legacy base URL for mercury v0.2 API + LegacyURL *models.SecretURL + // URL is the base URL for mercury v0.3 API + URL *models.SecretURL + // Username is the user id for mercury credential Username *models.Secret + // Password is the user secret key for mercury credential Password *models.Secret } @@ -1263,6 +1268,10 @@ func (m *MercurySecrets) ValidateConfig() (err error) { err = multierr.Append(err, configutils.ErrMissing{Name: "URL", Msg: "must be provided and non-empty"}) continue } + if creds.LegacyURL != nil && creds.LegacyURL.URL() == nil { + err = multierr.Append(err, configutils.ErrMissing{Name: "Legacy URL", Msg: "must be a valid URL"}) + continue + } s := creds.URL.URL().String() if _, exists := urls[s]; exists { err = multierr.Append(err, configutils.NewErrDuplicate("URL", s)) diff --git a/core/config/toml/types_test.go b/core/config/toml/types_test.go index e2eb5eed815..2ab3f0fb86b 100644 --- a/core/config/toml/types_test.go +++ b/core/config/toml/types_test.go @@ -27,6 +27,12 @@ func TestMercurySecrets_valid(t *testing.T) { Username: models.NewSecret("new user1"), Password: models.NewSecret("new password2"), }, + "cred3": { + LegacyURL: models.MustSecretURL("https://abc.com"), + URL: models.MustSecretURL("HTTPS://GOOGLE1.COM"), + Username: models.NewSecret("new user1"), + Password: models.NewSecret("new password2"), + }, }, } diff --git a/core/gethwrappers/functions/generated/functions_client_example/functions_client_example.go b/core/gethwrappers/functions/generated/functions_client_example/functions_client_example.go index 6dc02520146..6ae90b45edb 100644 --- a/core/gethwrappers/functions/generated/functions_client_example/functions_client_example.go +++ b/core/gethwrappers/functions/generated/functions_client_example/functions_client_example.go @@ -32,7 +32,7 @@ var ( var FunctionsClientExampleMetaData = &bind.MetaData{ ABI: "[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"router\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"EmptyArgs\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"EmptySecrets\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"EmptySource\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"NoInlineSecrets\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyRouterCanFulfill\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"requestId\",\"type\":\"bytes32\"}],\"name\":\"UnexpectedRequestID\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"OwnershipTransferRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"id\",\"type\":\"bytes32\"}],\"name\":\"RequestFulfilled\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"id\",\"type\":\"bytes32\"}],\"name\":\"RequestSent\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"MAX_CALLBACK_GAS\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"acceptOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"requestId\",\"type\":\"bytes32\"},{\"internalType\":\"bytes\",\"name\":\"response\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"err\",\"type\":\"bytes\"}],\"name\":\"handleOracleFulfillment\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_lastError\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_lastErrorLength\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_lastRequestId\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_lastResponse\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_lastResponseLength\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"source\",\"type\":\"string\"},{\"internalType\":\"bytes\",\"name\":\"encryptedSecretsReferences\",\"type\":\"bytes\"},{\"internalType\":\"string[]\",\"name\":\"args\",\"type\":\"string[]\"},{\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"},{\"internalType\":\"bytes32\",\"name\":\"jobId\",\"type\":\"bytes32\"}],\"name\":\"sendRequest\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", - Bin: "0x60a06040523480156200001157600080fd5b5060405162001a7638038062001a76833981016040819052620000349162000180565b6001600160a01b0381166080523380600081620000985760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b0384811691909117909155811615620000cb57620000cb81620000d5565b50505050620001b2565b336001600160a01b038216036200012f5760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c6600000000000000000060448201526064016200008f565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b6000602082840312156200019357600080fd5b81516001600160a01b0381168114620001ab57600080fd5b9392505050565b6080516118a1620001d5600039600081816101c60152610a2a01526118a16000f3fe608060405234801561001057600080fd5b50600436106100c95760003560e01c80636d9809a011610081578063b1e217491161005b578063b1e2174914610182578063f2fde38b1461018b578063f7b4c06f1461019e57600080fd5b80636d9809a01461014857806379ba5097146101525780638da5cb5b1461015a57600080fd5b806342748b2a116100b257806342748b2a146100ff5780634b0795a81461012c5780635fa353e71461013557600080fd5b80630ca76175146100ce5780633944ea3a146100e3575b600080fd5b6100e16100dc3660046112ed565b6101ae565b005b6100ec60035481565b6040519081526020015b60405180910390f35b60055461011790640100000000900463ffffffff1681565b60405163ffffffff90911681526020016100f6565b6100ec60045481565b6100e16101433660046113c0565b61022d565b6101176201117081565b6100e1610347565b60005460405173ffffffffffffffffffffffffffffffffffffffff90911681526020016100f6565b6100ec60025481565b6100e16101993660046114a4565b610449565b6005546101179063ffffffff1681565b3373ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000161461021d576040517fc6829f8300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61022883838361045d565b505050565b61023561052b565b61027e6040805161010081019091528060008152602001600081526020016000815260200160608152602001606081526020016060815260200160608152602001606081525090565b6102c089898080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525085939250506105ae9050565b85156103085761030887878080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525085939250506105bf9050565b83156103225761032261031b85876114da565b8290610609565b61033961032e8261064c565b846201117085610a25565b600255505050505050505050565b60015473ffffffffffffffffffffffffffffffffffffffff1633146103cd576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e65720000000000000000000060448201526064015b60405180910390fd5b60008054337fffffffffffffffffffffffff00000000000000000000000000000000000000008083168217845560018054909116905560405173ffffffffffffffffffffffffffffffffffffffff90921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b61045161052b565b61045a81610b04565b50565b826002541461049b576040517fd068bf5b000000000000000000000000000000000000000000000000000000008152600481018490526024016103c4565b6104a482610bf9565b6003558151600580547fffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000001663ffffffff9092169190911790556104e681610bf9565b600455516005805463ffffffff909216640100000000027fffffffffffffffffffffffffffffffffffffffffffffffff00000000ffffffff9092169190911790555050565b60005473ffffffffffffffffffffffffffffffffffffffff1633146105ac576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e65720000000000000000000060448201526064016103c4565b565b6105bb8260008084610c7b565b5050565b80516000036105fa576040517fe889636f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60016020830152608090910152565b8051600003610644576040517ffe936cb700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60c090910152565b6060600061065b610100610d12565b90506106a56040518060400160405280600c81526020017f636f64654c6f636174696f6e000000000000000000000000000000000000000081525082610d3390919063ffffffff16565b82516106c39060028111156106bc576106bc611572565b8290610d4c565b60408051808201909152600881527f6c616e67756167650000000000000000000000000000000000000000000000006020820152610702908290610d33565b60408301516107199080156106bc576106bc611572565b60408051808201909152600681527f736f7572636500000000000000000000000000000000000000000000000000006020820152610758908290610d33565b6060830151610768908290610d33565b60a083015151156107c25760408051808201909152601081527f726571756573745369676e61747572650000000000000000000000000000000060208201526107b2908290610d33565b60a08301516107c2908290610d81565b60c0830151511561086f5760408051808201909152600481527f6172677300000000000000000000000000000000000000000000000000000000602082015261080c908290610d33565b61081581610d8e565b60005b8360c0015151811015610865576108558460c00151828151811061083e5761083e6115a1565b602002602001015183610d3390919063ffffffff16565b61085e816115ff565b9050610818565b5061086f81610db2565b608083015151156109705760008360200151600281111561089257610892611572565b036108c9576040517fa80d31f700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60408051808201909152600f81527f736563726574734c6f636174696f6e00000000000000000000000000000000006020820152610908908290610d33565b610921836020015160028111156106bc576106bc611572565b60408051808201909152600781527f73656372657473000000000000000000000000000000000000000000000000006020820152610960908290610d33565b6080830151610970908290610d81565b60e08301515115610a1d5760408051808201909152600981527f627974657341726773000000000000000000000000000000000000000000000060208201526109ba908290610d33565b6109c381610d8e565b60005b8360e0015151811015610a1357610a038460e0015182815181106109ec576109ec6115a1565b602002602001015183610d8190919063ffffffff16565b610a0c816115ff565b90506109c6565b50610a1d81610db2565b515192915050565b6000807f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663461d27628688600188886040518663ffffffff1660e01b8152600401610a8a959493929190611637565b6020604051808303816000875af1158015610aa9573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610acd91906116d7565b60405190915081907f1131472297a800fee664d1d89cfa8f7676ff07189ecc53f80bbb5f4969099db890600090a295945050505050565b3373ffffffffffffffffffffffffffffffffffffffff821603610b83576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c6600000000000000000060448201526064016103c4565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b60008060209050602083511015610c0e575081515b60005b81811015610c7457610c248160086116f0565b848281518110610c3657610c366115a1565b01602001517fff0000000000000000000000000000000000000000000000000000000000000016901c9290921791610c6d816115ff565b9050610c11565b5050919050565b8051600003610cb6576040517f22ce3edd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b83836002811115610cc957610cc9611572565b90816002811115610cdc57610cdc611572565b90525060408401828015610cf257610cf2611572565b90818015610d0257610d02611572565b9052506060909301929092525050565b610d1a6111a4565b8051610d269083610dd0565b5060006020820152919050565b610d408260038351610e4a565b81516102289082610f71565b8151610d599060c2610f99565b506105bb8282604051602001610d7191815260200190565b6040516020818303038152906040525b610d408260028351610e4a565b610d99816004611002565b600181602001818151610dac9190611707565b90525050565b610dbd816007611002565b600181602001818151610dac919061171a565b604080518082019091526060815260006020820152610df060208361172d565b15610e1857610e0060208361172d565b610e0b90602061171a565b610e159083611707565b91505b602080840183905260405180855260008152908184010181811015610e3c57600080fd5b604052508290505b92915050565b60178167ffffffffffffffff1611610e77578251610e719060e0600585901b168317610f99565b50505050565b60ff8167ffffffffffffffff1611610eb9578251610ea0906018611fe0600586901b1617610f99565b508251610e719067ffffffffffffffff83166001611019565b61ffff8167ffffffffffffffff1611610efc578251610ee3906019611fe0600586901b1617610f99565b508251610e719067ffffffffffffffff83166002611019565b63ffffffff8167ffffffffffffffff1611610f41578251610f2890601a611fe0600586901b1617610f99565b508251610e719067ffffffffffffffff83166004611019565b8251610f5890601b611fe0600586901b1617610f99565b508251610e719067ffffffffffffffff83166008611019565b604080518082019091526060815260006020820152610f928383845161109e565b9392505050565b6040805180820190915260608152600060208201528251516000610fbe826001611707565b905084602001518210610fdf57610fdf85610fda8360026116f0565b61118d565b8451602083820101858153508051821115610ff8578181525b5093949350505050565b815161022890601f611fe0600585901b1617610f99565b604080518082019091526060815260006020820152835151600061103d8285611707565b9050856020015181111561105a5761105a86610fda8360026116f0565b6000600161106a86610100611888565b611074919061171a565b90508651828101878319825116178152508051831115611092578281525b50959695505050505050565b60408051808201909152606081526000602082015282518211156110c157600080fd5b83515160006110d08483611707565b905085602001518111156110ed576110ed86610fda8360026116f0565b855180518382016020019160009180851115611107578482525b505050602086015b602086106111475780518252611126602083611707565b9150611133602082611707565b905061114060208761171a565b955061110f565b5181517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60208890036101000a0190811690199190911617905250849150509392505050565b81516111998383610dd0565b50610e718382610f71565b60405180604001604052806111cc604051806040016040528060608152602001600081525090565b8152602001600081525090565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff8111828210171561124f5761124f6111d9565b604052919050565b600067ffffffffffffffff831115611271576112716111d9565b6112a260207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f86011601611208565b90508281528383830111156112b657600080fd5b828260208301376000602084830101529392505050565b600082601f8301126112de57600080fd5b610f9283833560208501611257565b60008060006060848603121561130257600080fd5b83359250602084013567ffffffffffffffff8082111561132157600080fd5b61132d878388016112cd565b9350604086013591508082111561134357600080fd5b50611350868287016112cd565b9150509250925092565b60008083601f84011261136c57600080fd5b50813567ffffffffffffffff81111561138457600080fd5b60208301915083602082850101111561139c57600080fd5b9250929050565b803567ffffffffffffffff811681146113bb57600080fd5b919050565b60008060008060008060008060a0898b0312156113dc57600080fd5b883567ffffffffffffffff808211156113f457600080fd5b6114008c838d0161135a565b909a50985060208b013591508082111561141957600080fd5b6114258c838d0161135a565b909850965060408b013591508082111561143e57600080fd5b818b0191508b601f83011261145257600080fd5b81358181111561146157600080fd5b8c60208260051b850101111561147657600080fd5b60208301965080955050505061148e60608a016113a3565b9150608089013590509295985092959890939650565b6000602082840312156114b657600080fd5b813573ffffffffffffffffffffffffffffffffffffffff81168114610f9257600080fd5b600067ffffffffffffffff808411156114f5576114f56111d9565b8360051b6020611506818301611208565b86815291850191818101903684111561151e57600080fd5b865b84811015611566578035868111156115385760008081fd5b880136601f82011261154a5760008081fd5b611558368235878401611257565b845250918301918301611520565b50979650505050505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203611630576116306115d0565b5060010190565b67ffffffffffffffff861681526000602060a08184015286518060a085015260005b818110156116755788810183015185820160c001528201611659565b50600060c0828601015260c07fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f830116850101925050506116be604083018661ffff169052565b63ffffffff939093166060820152608001529392505050565b6000602082840312156116e957600080fd5b5051919050565b8082028115828204841417610e4457610e446115d0565b80820180821115610e4457610e446115d0565b81810381811115610e4457610e446115d0565b600082611763577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500690565b600181815b808511156117c157817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff048211156117a7576117a76115d0565b808516156117b457918102915b93841c939080029061176d565b509250929050565b6000826117d857506001610e44565b816117e557506000610e44565b81600181146117fb576002811461180557611821565b6001915050610e44565b60ff841115611816576118166115d0565b50506001821b610e44565b5060208310610133831016604e8410600b8410161715611844575081810a610e44565b61184e8383611768565b807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff04821115611880576118806115d0565b029392505050565b6000610f9283836117c956fea164736f6c6343000813000a", + Bin: "0x60a06040523480156200001157600080fd5b5060405162001a4838038062001a48833981016040819052620000349162000180565b6001600160a01b0381166080523380600081620000985760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b0384811691909117909155811615620000cb57620000cb81620000d5565b50505050620001b2565b336001600160a01b038216036200012f5760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c6600000000000000000060448201526064016200008f565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b6000602082840312156200019357600080fd5b81516001600160a01b0381168114620001ab57600080fd5b9392505050565b608051611873620001d5600039600081816101c601526109f301526118736000f3fe608060405234801561001057600080fd5b50600436106100c95760003560e01c80636d9809a011610081578063b1e217491161005b578063b1e2174914610182578063f2fde38b1461018b578063f7b4c06f1461019e57600080fd5b80636d9809a01461014857806379ba5097146101525780638da5cb5b1461015a57600080fd5b806342748b2a116100b257806342748b2a146100ff5780634b0795a81461012c5780635fa353e71461013557600080fd5b80630ca76175146100ce5780633944ea3a146100e3575b600080fd5b6100e16100dc3660046112bf565b6101ae565b005b6100ec60035481565b6040519081526020015b60405180910390f35b60055461011790640100000000900463ffffffff1681565b60405163ffffffff90911681526020016100f6565b6100ec60045481565b6100e1610143366004611392565b610258565b6101176201117081565b6100e161036a565b60005460405173ffffffffffffffffffffffffffffffffffffffff90911681526020016100f6565b6100ec60025481565b6100e1610199366004611476565b61046c565b6005546101179063ffffffff1681565b3373ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000161461021d576040517fc6829f8300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610228838383610480565b60405183907f85e1543bf2f84fe80c6badbce3648c8539ad1df4d2b3d822938ca0538be727e690600090a2505050565b61026061054e565b6102a16040805160e0810190915280600081526020016000815260200160008152602001606081526020016060815260200160608152602001606081525090565b6102e389898080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525085939250506105d19050565b851561032b5761032b87878080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525085939250506105e29050565b83156103455761034561033e85876114ac565b829061062c565b61035c6103518261066f565b8462011170856109ee565b600255505050505050505050565b60015473ffffffffffffffffffffffffffffffffffffffff1633146103f0576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e65720000000000000000000060448201526064015b60405180910390fd5b60008054337fffffffffffffffffffffffff00000000000000000000000000000000000000008083168217845560018054909116905560405173ffffffffffffffffffffffffffffffffffffffff90921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b61047461054e565b61047d81610acd565b50565b82600254146104be576040517fd068bf5b000000000000000000000000000000000000000000000000000000008152600481018490526024016103e7565b6104c782610bc2565b6003558151600580547fffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000001663ffffffff90921691909117905561050981610bc2565b600455516005805463ffffffff909216640100000000027fffffffffffffffffffffffffffffffffffffffffffffffff00000000ffffffff9092169190911790555050565b60005473ffffffffffffffffffffffffffffffffffffffff1633146105cf576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e65720000000000000000000060448201526064016103e7565b565b6105de8260008084610c44565b5050565b805160000361061d576040517fe889636f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60016020830152608090910152565b8051600003610667576040517ffe936cb700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60a090910152565b6060600061067e610100610cdb565b90506106c86040518060400160405280600c81526020017f636f64654c6f636174696f6e000000000000000000000000000000000000000081525082610cfc90919063ffffffff16565b82516106e69060028111156106df576106df611544565b8290610d1a565b60408051808201909152600881527f6c616e67756167650000000000000000000000000000000000000000000000006020820152610725908290610cfc565b604083015161073c9080156106df576106df611544565b60408051808201909152600681527f736f757263650000000000000000000000000000000000000000000000000000602082015261077b908290610cfc565b606083015161078b908290610cfc565b60a083015151156108385760408051808201909152600481527f617267730000000000000000000000000000000000000000000000000000000060208201526107d5908290610cfc565b6107de81610d53565b60005b8360a001515181101561082e5761081e8460a00151828151811061080757610807611573565b602002602001015183610cfc90919063ffffffff16565b610827816115d1565b90506107e1565b5061083881610d77565b608083015151156109395760008360200151600281111561085b5761085b611544565b03610892576040517fa80d31f700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60408051808201909152600f81527f736563726574734c6f636174696f6e000000000000000000000000000000000060208201526108d1908290610cfc565b6108ea836020015160028111156106df576106df611544565b60408051808201909152600781527f73656372657473000000000000000000000000000000000000000000000000006020820152610929908290610cfc565b6080830151610939908290610d95565b60c083015151156109e65760408051808201909152600981527f62797465734172677300000000000000000000000000000000000000000000006020820152610983908290610cfc565b61098c81610d53565b60005b8360c00151518110156109dc576109cc8460c0015182815181106109b5576109b5611573565b602002602001015183610d9590919063ffffffff16565b6109d5816115d1565b905061098f565b506109e681610d77565b515192915050565b6000807f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663461d27628688600188886040518663ffffffff1660e01b8152600401610a53959493929190611609565b6020604051808303816000875af1158015610a72573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a9691906116a9565b60405190915081907f1131472297a800fee664d1d89cfa8f7676ff07189ecc53f80bbb5f4969099db890600090a295945050505050565b3373ffffffffffffffffffffffffffffffffffffffff821603610b4c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c6600000000000000000060448201526064016103e7565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b60008060209050602083511015610bd7575081515b60005b81811015610c3d57610bed8160086116c2565b848281518110610bff57610bff611573565b01602001517fff0000000000000000000000000000000000000000000000000000000000000016901c9290921791610c36816115d1565b9050610bda565b5050919050565b8051600003610c7f576040517f22ce3edd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b83836002811115610c9257610c92611544565b90816002811115610ca557610ca5611544565b90525060408401828015610cbb57610cbb611544565b90818015610ccb57610ccb611544565b9052506060909301929092525050565b610ce3611176565b8051610cef9083610da2565b5060006020820152919050565b610d098260038351610e1c565b8151610d159082610f43565b505050565b8151610d279060c2610f6b565b506105de8282604051602001610d3f91815260200190565b604051602081830303815290604052610d95565b610d5e816004610fd4565b600181602001818151610d7191906116d9565b90525050565b610d82816007610fd4565b600181602001818151610d7191906116ec565b610d098260028351610e1c565b604080518082019091526060815260006020820152610dc26020836116ff565b15610dea57610dd26020836116ff565b610ddd9060206116ec565b610de790836116d9565b91505b602080840183905260405180855260008152908184010181811015610e0e57600080fd5b604052508290505b92915050565b60178167ffffffffffffffff1611610e49578251610e439060e0600585901b168317610f6b565b50505050565b60ff8167ffffffffffffffff1611610e8b578251610e72906018611fe0600586901b1617610f6b565b508251610e439067ffffffffffffffff83166001610feb565b61ffff8167ffffffffffffffff1611610ece578251610eb5906019611fe0600586901b1617610f6b565b508251610e439067ffffffffffffffff83166002610feb565b63ffffffff8167ffffffffffffffff1611610f13578251610efa90601a611fe0600586901b1617610f6b565b508251610e439067ffffffffffffffff83166004610feb565b8251610f2a90601b611fe0600586901b1617610f6b565b508251610e439067ffffffffffffffff83166008610feb565b604080518082019091526060815260006020820152610f6483838451611070565b9392505050565b6040805180820190915260608152600060208201528251516000610f908260016116d9565b905084602001518210610fb157610fb185610fac8360026116c2565b61115f565b8451602083820101858153508051821115610fca578181525b5093949350505050565b8151610d1590601f611fe0600585901b1617610f6b565b604080518082019091526060815260006020820152835151600061100f82856116d9565b9050856020015181111561102c5761102c86610fac8360026116c2565b6000600161103c8661010061185a565b61104691906116ec565b90508651828101878319825116178152508051831115611064578281525b50959695505050505050565b604080518082019091526060815260006020820152825182111561109357600080fd5b83515160006110a284836116d9565b905085602001518111156110bf576110bf86610fac8360026116c2565b8551805183820160200191600091808511156110d9578482525b505050602086015b6020861061111957805182526110f86020836116d9565b91506111056020826116d9565b90506111126020876116ec565b95506110e1565b5181517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60208890036101000a0190811690199190911617905250849150509392505050565b815161116b8383610da2565b50610e438382610f43565b604051806040016040528061119e604051806040016040528060608152602001600081525090565b8152602001600081525090565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715611221576112216111ab565b604052919050565b600067ffffffffffffffff831115611243576112436111ab565b61127460207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f860116016111da565b905082815283838301111561128857600080fd5b828260208301376000602084830101529392505050565b600082601f8301126112b057600080fd5b610f6483833560208501611229565b6000806000606084860312156112d457600080fd5b83359250602084013567ffffffffffffffff808211156112f357600080fd5b6112ff8783880161129f565b9350604086013591508082111561131557600080fd5b506113228682870161129f565b9150509250925092565b60008083601f84011261133e57600080fd5b50813567ffffffffffffffff81111561135657600080fd5b60208301915083602082850101111561136e57600080fd5b9250929050565b803567ffffffffffffffff8116811461138d57600080fd5b919050565b60008060008060008060008060a0898b0312156113ae57600080fd5b883567ffffffffffffffff808211156113c657600080fd5b6113d28c838d0161132c565b909a50985060208b01359150808211156113eb57600080fd5b6113f78c838d0161132c565b909850965060408b013591508082111561141057600080fd5b818b0191508b601f83011261142457600080fd5b81358181111561143357600080fd5b8c60208260051b850101111561144857600080fd5b60208301965080955050505061146060608a01611375565b9150608089013590509295985092959890939650565b60006020828403121561148857600080fd5b813573ffffffffffffffffffffffffffffffffffffffff81168114610f6457600080fd5b600067ffffffffffffffff808411156114c7576114c76111ab565b8360051b60206114d88183016111da565b8681529185019181810190368411156114f057600080fd5b865b848110156115385780358681111561150a5760008081fd5b880136601f82011261151c5760008081fd5b61152a368235878401611229565b8452509183019183016114f2565b50979650505050505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203611602576116026115a2565b5060010190565b67ffffffffffffffff861681526000602060a08184015286518060a085015260005b818110156116475788810183015185820160c00152820161162b565b50600060c0828601015260c07fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f83011685010192505050611690604083018661ffff169052565b63ffffffff939093166060820152608001529392505050565b6000602082840312156116bb57600080fd5b5051919050565b8082028115828204841417610e1657610e166115a2565b80820180821115610e1657610e166115a2565b81810381811115610e1657610e166115a2565b600082611735577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500690565b600181815b8085111561179357817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff04821115611779576117796115a2565b8085161561178657918102915b93841c939080029061173f565b509250929050565b6000826117aa57506001610e16565b816117b757506000610e16565b81600181146117cd57600281146117d7576117f3565b6001915050610e16565b60ff8411156117e8576117e86115a2565b50506001821b610e16565b5060208310610133831016604e8410600b8410161715611816575081810a610e16565b611820838361173a565b807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff04821115611852576118526115a2565b029392505050565b6000610f64838361179b56fea164736f6c6343000813000a", } var FunctionsClientExampleABI = FunctionsClientExampleMetaData.ABI diff --git a/core/gethwrappers/functions/generated/functions_coordinator/functions_coordinator.go b/core/gethwrappers/functions/generated/functions_coordinator/functions_coordinator.go index e1f6b2f7c15..94f1efd2d6a 100644 --- a/core/gethwrappers/functions/generated/functions_coordinator/functions_coordinator.go +++ b/core/gethwrappers/functions/generated/functions_coordinator/functions_coordinator.go @@ -31,14 +31,13 @@ var ( ) type FunctionsBillingConfig struct { - MaxCallbackGasLimit uint32 + FulfillmentGasPriceOverEstimationBP uint32 FeedStalenessSeconds uint32 GasOverheadBeforeCallback uint32 GasOverheadAfterCallback uint32 RequestTimeoutSeconds uint32 DonFee *big.Int MaxSupportedRequestDataVersion uint16 - FulfillmentGasPriceOverEstimationBP uint32 FallbackNativePerUnitLink *big.Int } @@ -71,8 +70,8 @@ type FunctionsResponseRequestMeta struct { } var FunctionsCoordinatorMetaData = &bind.MetaData{ - ABI: "[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"router\",\"type\":\"address\"},{\"components\":[{\"internalType\":\"uint32\",\"name\":\"maxCallbackGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"feedStalenessSeconds\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"gasOverheadBeforeCallback\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"gasOverheadAfterCallback\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"requestTimeoutSeconds\",\"type\":\"uint32\"},{\"internalType\":\"uint72\",\"name\":\"donFee\",\"type\":\"uint72\"},{\"internalType\":\"uint16\",\"name\":\"maxSupportedRequestDataVersion\",\"type\":\"uint16\"},{\"internalType\":\"uint32\",\"name\":\"fulfillmentGasPriceOverEstimationBP\",\"type\":\"uint32\"},{\"internalType\":\"uint224\",\"name\":\"fallbackNativePerUnitLink\",\"type\":\"uint224\"}],\"internalType\":\"structFunctionsBilling.Config\",\"name\":\"config\",\"type\":\"tuple\"},{\"internalType\":\"address\",\"name\":\"linkToNativeFeed\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"EmptyPublicKey\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InconsistentReportData\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InsufficientBalance\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidCalldata\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"message\",\"type\":\"string\"}],\"name\":\"InvalidConfig\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"int256\",\"name\":\"linkWei\",\"type\":\"int256\"}],\"name\":\"InvalidLinkWeiPrice\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidSubscription\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"}],\"name\":\"MustBeSubOwner\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"NoTransmittersSet\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByRouter\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByRouterOwner\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"PaymentTooLarge\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ReportInvalid\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"RouterMustBeSet\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"UnauthorizedPublicKeyChange\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"UnauthorizedSender\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"UnsupportedRequestDataVersion\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"requestId\",\"type\":\"bytes32\"}],\"name\":\"CommitmentDeleted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"previousConfigBlockNumber\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"configDigest\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"configCount\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"signers\",\"type\":\"address[]\"},{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"transmitters\",\"type\":\"address[]\"},{\"indexed\":false,\"internalType\":\"uint8\",\"name\":\"f\",\"type\":\"uint8\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"onchainConfig\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"offchainConfigVersion\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"offchainConfig\",\"type\":\"bytes\"}],\"name\":\"ConfigSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"maxCallbackGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"feedStalenessSeconds\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"gasOverheadBeforeCallback\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"gasOverheadAfterCallback\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"requestTimeoutSeconds\",\"type\":\"uint32\"},{\"internalType\":\"uint72\",\"name\":\"donFee\",\"type\":\"uint72\"},{\"internalType\":\"uint16\",\"name\":\"maxSupportedRequestDataVersion\",\"type\":\"uint16\"},{\"internalType\":\"uint32\",\"name\":\"fulfillmentGasPriceOverEstimationBP\",\"type\":\"uint32\"},{\"internalType\":\"uint224\",\"name\":\"fallbackNativePerUnitLink\",\"type\":\"uint224\"}],\"indexed\":false,\"internalType\":\"structFunctionsBilling.Config\",\"name\":\"config\",\"type\":\"tuple\"}],\"name\":\"ConfigUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"requestId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"requestingContract\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"requestInitiator\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"subscriptionOwner\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"uint16\",\"name\":\"dataVersion\",\"type\":\"uint16\"},{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"flags\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"callbackGasLimit\",\"type\":\"uint64\"},{\"components\":[{\"internalType\":\"bytes32\",\"name\":\"requestId\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"coordinator\",\"type\":\"address\"},{\"internalType\":\"uint96\",\"name\":\"estimatedTotalCostJuels\",\"type\":\"uint96\"},{\"internalType\":\"address\",\"name\":\"client\",\"type\":\"address\"},{\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"callbackGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint72\",\"name\":\"adminFee\",\"type\":\"uint72\"},{\"internalType\":\"uint72\",\"name\":\"donFee\",\"type\":\"uint72\"},{\"internalType\":\"uint40\",\"name\":\"gasOverheadBeforeCallback\",\"type\":\"uint40\"},{\"internalType\":\"uint40\",\"name\":\"gasOverheadAfterCallback\",\"type\":\"uint40\"},{\"internalType\":\"uint32\",\"name\":\"timeoutTimestamp\",\"type\":\"uint32\"}],\"indexed\":false,\"internalType\":\"structFunctionsResponse.Commitment\",\"name\":\"commitment\",\"type\":\"tuple\"}],\"name\":\"OracleRequest\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"requestId\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"transmitter\",\"type\":\"address\"}],\"name\":\"OracleResponse\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"OwnershipTransferRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"configDigest\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"epoch\",\"type\":\"uint32\"}],\"name\":\"Transmitted\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"acceptOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"requestId\",\"type\":\"bytes32\"}],\"name\":\"deleteCommitment\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"},{\"internalType\":\"uint32\",\"name\":\"callbackGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint256\",\"name\":\"gasPriceGwei\",\"type\":\"uint256\"}],\"name\":\"estimateCost\",\"outputs\":[{\"internalType\":\"uint96\",\"name\":\"\",\"type\":\"uint96\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getAdminFee\",\"outputs\":[{\"internalType\":\"uint72\",\"name\":\"\",\"type\":\"uint72\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getConfig\",\"outputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"maxCallbackGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"feedStalenessSeconds\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"gasOverheadBeforeCallback\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"gasOverheadAfterCallback\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"requestTimeoutSeconds\",\"type\":\"uint32\"},{\"internalType\":\"uint72\",\"name\":\"donFee\",\"type\":\"uint72\"},{\"internalType\":\"uint16\",\"name\":\"maxSupportedRequestDataVersion\",\"type\":\"uint16\"},{\"internalType\":\"uint32\",\"name\":\"fulfillmentGasPriceOverEstimationBP\",\"type\":\"uint32\"},{\"internalType\":\"uint224\",\"name\":\"fallbackNativePerUnitLink\",\"type\":\"uint224\"}],\"internalType\":\"structFunctionsBilling.Config\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"name\":\"getDONFee\",\"outputs\":[{\"internalType\":\"uint72\",\"name\":\"\",\"type\":\"uint72\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getDONPublicKey\",\"outputs\":[{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getThresholdPublicKey\",\"outputs\":[{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getWeiPerUnitLink\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"latestConfigDetails\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"configCount\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"blockNumber\",\"type\":\"uint32\"},{\"internalType\":\"bytes32\",\"name\":\"configDigest\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"latestConfigDigestAndEpoch\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"scanLogs\",\"type\":\"bool\"},{\"internalType\":\"bytes32\",\"name\":\"configDigest\",\"type\":\"bytes32\"},{\"internalType\":\"uint32\",\"name\":\"epoch\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"uint96\",\"name\":\"amount\",\"type\":\"uint96\"}],\"name\":\"oracleWithdraw\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"oracleWithdrawAll\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address[]\",\"name\":\"_signers\",\"type\":\"address[]\"},{\"internalType\":\"address[]\",\"name\":\"_transmitters\",\"type\":\"address[]\"},{\"internalType\":\"uint8\",\"name\":\"_f\",\"type\":\"uint8\"},{\"internalType\":\"bytes\",\"name\":\"_onchainConfig\",\"type\":\"bytes\"},{\"internalType\":\"uint64\",\"name\":\"_offchainConfigVersion\",\"type\":\"uint64\"},{\"internalType\":\"bytes\",\"name\":\"_offchainConfig\",\"type\":\"bytes\"}],\"name\":\"setConfig\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"donPublicKey\",\"type\":\"bytes\"}],\"name\":\"setDONPublicKey\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"thresholdPublicKey\",\"type\":\"bytes\"}],\"name\":\"setThresholdPublicKey\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"},{\"internalType\":\"bytes32\",\"name\":\"flags\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"requestingContract\",\"type\":\"address\"},{\"internalType\":\"uint96\",\"name\":\"availableBalance\",\"type\":\"uint96\"},{\"internalType\":\"uint72\",\"name\":\"adminFee\",\"type\":\"uint72\"},{\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"initiatedRequests\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"callbackGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint16\",\"name\":\"dataVersion\",\"type\":\"uint16\"},{\"internalType\":\"uint64\",\"name\":\"completedRequests\",\"type\":\"uint64\"},{\"internalType\":\"address\",\"name\":\"subscriptionOwner\",\"type\":\"address\"}],\"internalType\":\"structFunctionsResponse.RequestMeta\",\"name\":\"request\",\"type\":\"tuple\"}],\"name\":\"startRequest\",\"outputs\":[{\"components\":[{\"internalType\":\"bytes32\",\"name\":\"requestId\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"coordinator\",\"type\":\"address\"},{\"internalType\":\"uint96\",\"name\":\"estimatedTotalCostJuels\",\"type\":\"uint96\"},{\"internalType\":\"address\",\"name\":\"client\",\"type\":\"address\"},{\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"callbackGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint72\",\"name\":\"adminFee\",\"type\":\"uint72\"},{\"internalType\":\"uint72\",\"name\":\"donFee\",\"type\":\"uint72\"},{\"internalType\":\"uint40\",\"name\":\"gasOverheadBeforeCallback\",\"type\":\"uint40\"},{\"internalType\":\"uint40\",\"name\":\"gasOverheadAfterCallback\",\"type\":\"uint40\"},{\"internalType\":\"uint32\",\"name\":\"timeoutTimestamp\",\"type\":\"uint32\"}],\"internalType\":\"structFunctionsResponse.Commitment\",\"name\":\"commitment\",\"type\":\"tuple\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32[3]\",\"name\":\"reportContext\",\"type\":\"bytes32[3]\"},{\"internalType\":\"bytes\",\"name\":\"report\",\"type\":\"bytes\"},{\"internalType\":\"bytes32[]\",\"name\":\"rs\",\"type\":\"bytes32[]\"},{\"internalType\":\"bytes32[]\",\"name\":\"ss\",\"type\":\"bytes32[]\"},{\"internalType\":\"bytes32\",\"name\":\"rawVs\",\"type\":\"bytes32\"}],\"name\":\"transmit\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"transmitters\",\"outputs\":[{\"internalType\":\"address[]\",\"name\":\"\",\"type\":\"address[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"typeAndVersion\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"maxCallbackGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"feedStalenessSeconds\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"gasOverheadBeforeCallback\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"gasOverheadAfterCallback\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"requestTimeoutSeconds\",\"type\":\"uint32\"},{\"internalType\":\"uint72\",\"name\":\"donFee\",\"type\":\"uint72\"},{\"internalType\":\"uint16\",\"name\":\"maxSupportedRequestDataVersion\",\"type\":\"uint16\"},{\"internalType\":\"uint32\",\"name\":\"fulfillmentGasPriceOverEstimationBP\",\"type\":\"uint32\"},{\"internalType\":\"uint224\",\"name\":\"fallbackNativePerUnitLink\",\"type\":\"uint224\"}],\"internalType\":\"structFunctionsBilling.Config\",\"name\":\"config\",\"type\":\"tuple\"}],\"name\":\"updateConfig\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", - Bin: "0x60c06040523480156200001157600080fd5b50604051620051b4380380620051b483398101604081905262000034916200044f565b8282828260013380600081620000915760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b0384811691909117909155811615620000c457620000c48162000140565b50505015156080526001600160a01b038116620000f457604051632530e88560e11b815260040160405180910390fd5b6001600160a01b0390811660a052600b80549183166c01000000000000000000000000026001600160601b039092169190911790556200013482620001eb565b50505050505062000600565b336001600160a01b038216036200019a5760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c66000000000000000000604482015260640162000088565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b620001f56200033a565b80516008805460208401516040808601516060870151608088015160a089015160c08a015163ffffffff998a166001600160401b031990981697909717640100000000968a16870217600160401b600160801b03191668010000000000000000948a169490940263ffffffff60601b1916939093176c010000000000000000000000009289169290920291909117600160801b600160e81b031916600160801b91881691909102600160a01b600160e81b03191617600160a01b6001600160481b03909216919091021761ffff60e81b1916600160e81b61ffff909416939093029290921790925560e084015161010085015193166001600160e01b0390931690910291909117600955517f5b6e2e1a03ea742ce04ca36d0175411a0772f99ef4ee84aeb9868a1ef6ddc82c906200032f90839062000558565b60405180910390a150565b6200034462000346565b565b6000546001600160a01b03163314620003445760405162461bcd60e51b815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e657200000000000000000000604482015260640162000088565b80516001600160a01b0381168114620003ba57600080fd5b919050565b60405161012081016001600160401b0381118282101715620003f157634e487b7160e01b600052604160045260246000fd5b60405290565b805163ffffffff81168114620003ba57600080fd5b80516001600160481b0381168114620003ba57600080fd5b805161ffff81168114620003ba57600080fd5b80516001600160e01b0381168114620003ba57600080fd5b60008060008385036101608112156200046757600080fd5b6200047285620003a2565b935061012080601f19830112156200048957600080fd5b62000493620003bf565b9150620004a360208701620003f7565b8252620004b360408701620003f7565b6020830152620004c660608701620003f7565b6040830152620004d960808701620003f7565b6060830152620004ec60a08701620003f7565b6080830152620004ff60c087016200040c565b60a08301526200051260e0870162000424565b60c083015261010062000527818801620003f7565b60e08401526200053982880162000437565b908301525091506200054f6101408501620003a2565b90509250925092565b815163ffffffff9081168252602080840151821690830152604080840151821690830152606080840151821690830152608080840151918216908301526101208201905060a0830151620005b760a08401826001600160481b03169052565b5060c0830151620005ce60c084018261ffff169052565b5060e0830151620005e760e084018263ffffffff169052565b50610100928301516001600160e01b0316919092015290565b60805160a051614b6462000650600039600081816108060152818161099401528181610c7d01528181610f130152818161104a01528181611834015261329b015260006112720152614b646000f3fe608060405234801561001057600080fd5b506004361061018d5760003560e01c806381ff7048116100e3578063c3f909d41161008c578063e3d0e71211610066578063e3d0e7121461054e578063e4ddcea614610561578063f2fde38b1461057757600080fd5b8063c3f909d4146103c4578063d227d24514610516578063d328a91e1461054657600080fd5b8063a631571e116100bd578063a631571e14610371578063afcb95d714610391578063b1dc65a4146103b157600080fd5b806381ff7048146102b957806385b214cf146103265780638da5cb5b1461034957600080fd5b806366316d8d116101455780637f15e1661161011f5780637f15e16614610289578063814118341461029c57806381f1b938146102b157600080fd5b806366316d8d1461026657806379ba5097146102795780637d4807871461028157600080fd5b80631bdf7f1b116101765780631bdf7f1b146101f95780632a905ccc1461020c57806359b5b7ac1461022e57600080fd5b8063083a546614610192578063181f5a77146101a7575b600080fd5b6101a56101a036600461358e565b61058a565b005b6101e36040518060400160405280601c81526020017f46756e6374696f6e7320436f6f7264696e61746f722076312e302e300000000081525081565b6040516101f09190613634565b60405180910390f35b6101a5610207366004613797565b6105df565b610214610802565b60405168ffffffffffffffffff90911681526020016101f0565b61021461023c3660046138db565b5060085474010000000000000000000000000000000000000000900468ffffffffffffffffff1690565b6101a561027436600461396a565b610898565b6101a5610a51565b6101a5610b53565b6101a561029736600461358e565b610d69565b6102a4610db9565b6040516101f091906139f4565b6101e3610e28565b61030360015460025463ffffffff74010000000000000000000000000000000000000000830481169378010000000000000000000000000000000000000000000000009093041691565b6040805163ffffffff9485168152939092166020840152908201526060016101f0565b610339610334366004613a07565b610ef9565b60405190151581526020016101f0565b60005460405173ffffffffffffffffffffffffffffffffffffffff90911681526020016101f0565b61038461037f366004613a20565b610fd9565b6040516101f09190613b75565b6040805160018152600060208201819052918101919091526060016101f0565b6101a56103bf366004613bc9565b611179565b6105096040805161012081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e0810182905261010081019190915250604080516101208101825260085463ffffffff8082168352640100000000808304821660208501526801000000000000000083048216948401949094526c0100000000000000000000000082048116606084015270010000000000000000000000000000000082048116608084015274010000000000000000000000000000000000000000820468ffffffffffffffffff1660a08401527d01000000000000000000000000000000000000000000000000000000000090910461ffff1660c083015260095490811660e0830152919091047bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1661010082015290565b6040516101f09190613c80565b610529610524366004613d63565b611830565b6040516bffffffffffffffffffffffff90911681526020016101f0565b6101e361198f565b6101a561055c366004613e7c565b6119e6565b610569612412565b6040519081526020016101f0565b6101a5610585366004613f49565b612643565b610592612657565b60008190036105cd576040517f4f42be3d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600d6105da828483613fff565b505050565b6105e76126da565b80516008805460208401516040808601516060870151608088015160a089015160c08a015163ffffffff998a167fffffffffffffffffffffffffffffffffffffffffffffffff000000000000000090981697909717640100000000968a168702177fffffffffffffffffffffffffffffffff0000000000000000ffffffffffffffff1668010000000000000000948a16949094027fffffffffffffffffffffffffffffffff00000000ffffffffffffffffffffffff16939093176c0100000000000000000000000092891692909202919091177fffffff00000000000000000000000000ffffffffffffffffffffffffffffffff16700100000000000000000000000000000000918816919091027fffffff000000000000000000ffffffffffffffffffffffffffffffffffffffff16177401000000000000000000000000000000000000000068ffffffffffffffffff90921691909102177fff0000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff167d01000000000000000000000000000000000000000000000000000000000061ffff909416939093029290921790925560e084015161010085015193167bffffffffffffffffffffffffffffffffffffffffffffffffffffffff90931690910291909117600955517f5b6e2e1a03ea742ce04ca36d0175411a0772f99ef4ee84aeb9868a1ef6ddc82c906107f7908390613c80565b60405180910390a150565b60007f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16632a905ccc6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561086f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108939190614125565b905090565b6108a06126e2565b806bffffffffffffffffffffffff166000036108da5750336000908152600a60205260409020546bffffffffffffffffffffffff16610934565b336000908152600a60205260409020546bffffffffffffffffffffffff80831691161015610934576040517ff4d678b800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b336000908152600a6020526040812080548392906109619084906bffffffffffffffffffffffff16614171565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff1602179055506109b67f000000000000000000000000000000000000000000000000000000000000000090565b6040517f66316d8d00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff84811660048301526bffffffffffffffffffffffff8416602483015291909116906366316d8d90604401600060405180830381600087803b158015610a3557600080fd5b505af1158015610a49573d6000803e3d6000fd5b505050505050565b60015473ffffffffffffffffffffffffffffffffffffffff163314610ad7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e65720000000000000000000060448201526064015b60405180910390fd5b60008054337fffffffffffffffffffffffff00000000000000000000000000000000000000008083168217845560018054909116905560405173ffffffffffffffffffffffffffffffffffffffff90921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b610b5b6126da565b610b636126e2565b6000610b6d610db9565b905060005b8151811015610d65576000600a6000848481518110610b9357610b93614196565b602002602001015173ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a90046bffffffffffffffffffffffff1690506000600a6000858581518110610c0857610c08614196565b602002602001015173ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff160217905550610c9f7f000000000000000000000000000000000000000000000000000000000000000090565b73ffffffffffffffffffffffffffffffffffffffff166366316d8d848481518110610ccc57610ccc614196565b6020026020010151836040518363ffffffff1660e01b8152600401610d2192919073ffffffffffffffffffffffffffffffffffffffff9290921682526bffffffffffffffffffffffff16602082015260400190565b600060405180830381600087803b158015610d3b57600080fd5b505af1158015610d4f573d6000803e3d6000fd5b505050505080610d5e906141c5565b9050610b72565b5050565b610d71612657565b6000819003610dac576040517f4f42be3d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600c6105da828483613fff565b60606006805480602002602001604051908101604052809291908181526020018280548015610e1e57602002820191906000526020600020905b815473ffffffffffffffffffffffffffffffffffffffff168152600190910190602001808311610df3575b5050505050905090565b6060600d8054610e3790613f66565b9050600003610e72576040517f4f42be3d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600d8054610e7f90613f66565b80601f0160208091040260200160405190810160405280929190818152602001828054610eab90613f66565b8015610e1e5780601f10610ecd57610100808354040283529160200191610e1e565b820191906000526020600020905b815481529060010190602001808311610edb57509395945050505050565b60003373ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001614610f6a576040517fc41a5b0900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600082815260076020526040902054610f8557506000919050565b60008281526007602052604080822091909155517f8a4b97add3359bd6bcf5e82874363670eb5ad0f7615abddbd0ed0a3a98f0f41690610fc89084815260200190565b60405180910390a15060015b919050565b6040805161016081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e08101829052610100810182905261012081018290526101408101919091523373ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016146110a1576040517fc41a5b0900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6110b26110ad836141fd565b61288d565b90506110c46060830160408401613f49565b815173ffffffffffffffffffffffffffffffffffffffff91909116907fbf50768ccf13bd0110ca6d53a9c4f1f3271abdd4c24a56878863ed25b20598ff3261111260c0870160a088016142ea565b61112461016088016101408901613f49565b61112e8880614307565b6111406101208b016101008c0161436c565b60208b01356111566101008d0160e08e01614387565b8b60405161116c999897969594939291906143a4565b60405180910390a3919050565b60005a604080518b3580825262ffffff6020808f0135600881901c929092169084015293945092917fb04e63db38c49950639fa09d29872f21f5d49d614f3a969d8adf3d4b52e41a62910160405180910390a16040805160608101825260025480825260035460ff80821660208501526101009091041692820192909252908314611260576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f636f6e666967446967657374206d69736d6174636800000000000000000000006044820152606401610ace565b61126e8b8b8b8b8b8b612c9d565b60007f0000000000000000000000000000000000000000000000000000000000000000156112cb576002826020015183604001516112ac919061444c565b6112b69190614494565b6112c190600161444c565b60ff1690506112e1565b60208201516112db90600161444c565b60ff1690505b88811461134a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601a60248201527f77726f6e67206e756d626572206f66207369676e6174757265730000000000006044820152606401610ace565b8887146113b3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f7369676e617475726573206f7574206f6620726567697374726174696f6e00006044820152606401610ace565b3360009081526004602090815260408083208151808301909252805460ff808216845292939192918401916101009091041660028111156113f6576113f66144b6565b6002811115611407576114076144b6565b9052509050600281602001516002811115611424576114246144b6565b14801561146b57506006816000015160ff168154811061144657611446614196565b60009182526020909120015473ffffffffffffffffffffffffffffffffffffffff1633145b6114d1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f756e617574686f72697a6564207472616e736d697474657200000000000000006044820152606401610ace565b50505050506114de613526565b6000808a8a6040516114f19291906144e5565b604051908190038120611508918e906020016144f5565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181528282528051602091820120838301909252600080845290830152915060005b8981101561181257600060018489846020811061157157611571614196565b61157e91901a601b61444c565b8e8e8681811061159057611590614196565b905060200201358d8d878181106115a9576115a9614196565b90506020020135604051600081526020016040526040516115e6949392919093845260ff9290921660208401526040830152606082015260800190565b6020604051602081039080840390855afa158015611608573d6000803e3d6000fd5b5050604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081015173ffffffffffffffffffffffffffffffffffffffff811660009081526004602090815290849020838501909452835460ff80821685529296509294508401916101009004166002811115611688576116886144b6565b6002811115611699576116996144b6565b90525092506001836020015160028111156116b6576116b66144b6565b1461171d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f61646472657373206e6f7420617574686f72697a656420746f207369676e00006044820152606401610ace565b8251600090879060ff16601f811061173757611737614196565b602002015173ffffffffffffffffffffffffffffffffffffffff16146117b9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f6e6f6e2d756e69717565207369676e61747572650000000000000000000000006044820152606401610ace565b8086846000015160ff16601f81106117d3576117d3614196565b73ffffffffffffffffffffffffffffffffffffffff90921660209290920201526117fe60018661444c565b9450508061180b906141c5565b9050611552565b505050611823833383858e8e612d54565b5050505050505050505050565b60007f00000000000000000000000000000000000000000000000000000000000000006040517f10fc49c100000000000000000000000000000000000000000000000000000000815267ffffffffffffffff8816600482015263ffffffff8516602482015273ffffffffffffffffffffffffffffffffffffffff91909116906310fc49c19060440160006040518083038186803b1580156118d057600080fd5b505afa1580156118e4573d6000803e3d6000fd5b505050620f42408311159050611926576040517f8129bbcd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000611930610802565b9050600061197387878080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061023c92505050565b905061198185858385612f22565b925050505b95945050505050565b6060600c805461199e90613f66565b90506000036119d9576040517f4f42be3d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600c8054610e7f90613f66565b855185518560ff16601f831115611a59576040517f89a6198900000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f746f6f206d616e79207369676e657273000000000000000000000000000000006044820152606401610ace565b80600003611ac3576040517f89a6198900000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f66206d75737420626520706f73697469766500000000000000000000000000006044820152606401610ace565b818314611b51576040517f89a61989000000000000000000000000000000000000000000000000000000008152602060048201526024808201527f6f7261636c6520616464726573736573206f7574206f6620726567697374726160448201527f74696f6e000000000000000000000000000000000000000000000000000000006064820152608401610ace565b611b5c816003614509565b8311611bc4576040517f89a6198900000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f6661756c74792d6f7261636c65206620746f6f206869676800000000000000006044820152606401610ace565b611bcc612657565b6040805160c0810182528a8152602081018a905260ff89169181018290526060810188905267ffffffffffffffff8716608082015260a0810186905290611c13908861300c565b60055415611dc857600554600090611c2d90600190614520565b9050600060058281548110611c4457611c44614196565b60009182526020822001546006805473ffffffffffffffffffffffffffffffffffffffff90921693509084908110611c7e57611c7e614196565b600091825260208083209091015473ffffffffffffffffffffffffffffffffffffffff85811684526004909252604080842080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000090811690915592909116808452922080549091169055600580549192509080611cfe57611cfe614533565b60008281526020902081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff90810180547fffffffffffffffffffffffff00000000000000000000000000000000000000001690550190556006805480611d6757611d67614533565b60008281526020902081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff90810180547fffffffffffffffffffffffff000000000000000000000000000000000000000016905501905550611c13915050565b60005b81515181101561222f5760006004600084600001518481518110611df157611df1614196565b60209081029190910181015173ffffffffffffffffffffffffffffffffffffffff16825281019190915260400160002054610100900460ff166002811115611e3b57611e3b6144b6565b14611ea2576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f7265706561746564207369676e657220616464726573730000000000000000006044820152606401610ace565b6040805180820190915260ff82168152600160208201528251805160049160009185908110611ed357611ed3614196565b60209081029190910181015173ffffffffffffffffffffffffffffffffffffffff168252818101929092526040016000208251815460ff9091167fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0082168117835592840151919283917fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00001617610100836002811115611f7457611f746144b6565b021790555060009150611f849050565b6004600084602001518481518110611f9e57611f9e614196565b60209081029190910181015173ffffffffffffffffffffffffffffffffffffffff16825281019190915260400160002054610100900460ff166002811115611fe857611fe86144b6565b1461204f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601c60248201527f7265706561746564207472616e736d69747465722061646472657373000000006044820152606401610ace565b6040805180820190915260ff82168152602081016002815250600460008460200151848151811061208257612082614196565b60209081029190910181015173ffffffffffffffffffffffffffffffffffffffff168252818101929092526040016000208251815460ff9091167fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0082168117835592840151919283917fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00001617610100836002811115612123576121236144b6565b02179055505082518051600592508390811061214157612141614196565b602090810291909101810151825460018101845560009384529282902090920180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff90931692909217909155820151805160069190839081106121bd576121bd614196565b60209081029190910181015182546001810184556000938452919092200180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff90921691909117905580612227816141c5565b915050611dcb565b506040810151600380547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660ff909216919091179055600180547fffffffff00000000ffffffffffffffffffffffffffffffffffffffffffffffff8116780100000000000000000000000000000000000000000000000063ffffffff43811682029290921780855592048116929182916014916122e791849174010000000000000000000000000000000000000000900416614562565b92506101000a81548163ffffffff021916908363ffffffff1602179055506123464630600160149054906101000a900463ffffffff1663ffffffff16856000015186602001518760400151886060015189608001518a60a00151613025565b600281905582518051600380547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff1661010060ff9093169290920291909117905560015460208501516040808701516060880151608089015160a08a015193517f1591690b8638f5fb2dbec82ac741805ac5da8b45dc5263f4875b0496fdce4e05986123fd988b9891977401000000000000000000000000000000000000000090920463ffffffff1696909591949193919261457f565b60405180910390a15050505050505050505050565b604080516101208101825260085463ffffffff8082168352640100000000808304821660208501526801000000000000000083048216848601526c010000000000000000000000008084048316606086015270010000000000000000000000000000000084048316608086015274010000000000000000000000000000000000000000840468ffffffffffffffffff1660a0808701919091527d01000000000000000000000000000000000000000000000000000000000090940461ffff1660c086015260095492831660e086015291047bffffffffffffffffffffffffffffffffffffffffffffffffffffffff16610100840152600b5484517ffeaf968c00000000000000000000000000000000000000000000000000000000815294516000958694859490930473ffffffffffffffffffffffffffffffffffffffff169263feaf968c926004808401938290030181865afa158015612577573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061259b919061462f565b5093505092505080426125ae9190614520565b836020015163ffffffff161080156125d057506000836020015163ffffffff16115b156125ff57505061010001517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff16919050565b6000821361263c576040517f43d4cf6600000000000000000000000000000000000000000000000000000000815260048101839052602401610ace565b5092915050565b61264b612657565b612654816130d0565b50565b60005473ffffffffffffffffffffffffffffffffffffffff1633146126d8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e6572000000000000000000006044820152606401610ace565b565b6126d8612657565b600b546bffffffffffffffffffffffff166000036126fc57565b6000612706610db9565b90508051600003612743576040517f30274b3a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8051600b54600091612762916bffffffffffffffffffffffff1661467f565b905060005b825181101561282e5781600a600085848151811061278757612787614196565b602002602001015173ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008282829054906101000a90046bffffffffffffffffffffffff166127ef91906146aa565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff16021790555080612827906141c5565b9050612767565b50815161283b90826146cf565b600b805460009061285b9084906bffffffffffffffffffffffff16614171565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff1602179055505050565b6040805161016081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e0810182905261010081018290526101208101829052610140810191909152604080516101208101825260085463ffffffff8082168352640100000000808304821660208501526801000000000000000083048216948401949094526c0100000000000000000000000082048116606084015270010000000000000000000000000000000082048116608084015274010000000000000000000000000000000000000000820468ffffffffffffffffff1660a08401527d01000000000000000000000000000000000000000000000000000000000090910461ffff90811660c0840181905260095492831660e0850152939091047bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1661010080840191909152850151919291161115612a22576040517fdada758700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60085460009074010000000000000000000000000000000000000000900468ffffffffffffffffff1690506000612a638560e001513a848860800151612f22565b9050806bffffffffffffffffffffffff1685606001516bffffffffffffffffffffffff161015612abf576040517ff4d678b800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000612b423087604001518860a001518960c001516001612ae091906146f7565b6040805173ffffffffffffffffffffffffffffffffffffffff958616602080830191909152949095168582015267ffffffffffffffff928316606086015291166080808501919091528151808503909101815260a09093019052815191012090565b90506040518061016001604052808281526020013073ffffffffffffffffffffffffffffffffffffffff168152602001836bffffffffffffffffffffffff168152602001876040015173ffffffffffffffffffffffffffffffffffffffff1681526020018760a0015167ffffffffffffffff1681526020018760e0015163ffffffff168152602001876080015168ffffffffffffffffff1681526020018468ffffffffffffffffff168152602001856040015163ffffffff1664ffffffffff168152602001856060015163ffffffff1664ffffffffff168152602001856080015163ffffffff1642612c349190614718565b63ffffffff16815250945084604051602001612c509190613b75565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529181528151602092830120600093845260079092529091205550919392505050565b6000612caa826020614509565b612cb5856020614509565b612cc188610144614718565b612ccb9190614718565b612cd59190614718565b612ce0906000614718565b9050368114612d4b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f63616c6c64617461206c656e677468206d69736d6174636800000000000000006044820152606401610ace565b50505050505050565b606080808080612d6686880188614806565b8451949950929750909550935091501580612d8357508351855114155b80612d9057508251855114155b80612d9d57508151855114155b80612daa57508051855114155b15612de1576040517f0be3632800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60005b8551811015612f14576000612e79878381518110612e0457612e04614196565b6020026020010151878481518110612e1e57612e1e614196565b6020026020010151878581518110612e3857612e38614196565b6020026020010151878681518110612e5257612e52614196565b6020026020010151878781518110612e6c57612e6c614196565b60200260200101516131c5565b90506000816006811115612e8f57612e8f6144b6565b1480612eac57506001816006811115612eaa57612eaa6144b6565b145b15612f0357868281518110612ec357612ec3614196565b60209081029190910181015160405133815290917fc708e0440951fd63499c0f7a73819b469ee5dd3ecc356c0ab4eb7f18389009d9910160405180910390a25b50612f0d816141c5565b9050612de4565b505050505050505050505050565b60085460009081908690612f5a9063ffffffff6c01000000000000000000000000820481169168010000000000000000900416614562565b612f649190614562565b60095463ffffffff918216925060009161271091612f83911688614509565b612f8d91906148d8565b612f979087614718565b90506000612fa482613455565b90506000612fc0846bffffffffffffffffffffffff8416614509565b90506000612fdc68ffffffffffffffffff808916908a166146aa565b9050612ffe612ff96bffffffffffffffffffffffff831684614718565b613484565b9a9950505050505050505050565b6000613016610db9565b511115610d6557610d656126e2565b6000808a8a8a8a8a8a8a8a8a604051602001613049999897969594939291906148ec565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081840301815291905280516020909101207dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff167e01000000000000000000000000000000000000000000000000000000000000179150509998505050505050505050565b3373ffffffffffffffffffffffffffffffffffffffff82160361314f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c660000000000000000006044820152606401610ace565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b600080838060200190518101906131dc91906149c2565b9050806040516020016131ef9190613b75565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152918152815160209283012060008a8152600790935291205414613241576006915050611986565b60008781526007602052604090205461325e576002915050611986565b60006132693a613455565b905060008261012001518361010001516132839190614a8a565b6132949064ffffffffff16836146cf565b90506000807f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663330605298b8b878960e0015168ffffffffffffffffff16886132f391906146aa565b338b6040518763ffffffff1660e01b815260040161331696959493929190614aa8565b60408051808303816000875af1158015613334573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906133589190614b24565b90925090506000826006811115613371576133716144b6565b148061338e5750600182600681111561338c5761338c6144b6565b145b156134475760008b8152600760205260408120556133ac81846146aa565b336000908152600a6020526040812080547fffffffffffffffffffffffffffffffffffffffff000000000000000000000000166bffffffffffffffffffffffff93841617905560e0870151600b805468ffffffffffffffffff90921693909291613418918591166146aa565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff1602179055505b509998505050505050505050565b600061347e613462612412565b61347484670de0b6b3a7640000614509565b612ff991906148d8565b92915050565b60006bffffffffffffffffffffffff821115613522576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f53616665436173743a2076616c756520646f65736e27742066697420696e203960448201527f36206269747300000000000000000000000000000000000000000000000000006064820152608401610ace565b5090565b604051806103e00160405280601f906020820280368337509192915050565b60008083601f84011261355757600080fd5b50813567ffffffffffffffff81111561356f57600080fd5b60208301915083602082850101111561358757600080fd5b9250929050565b600080602083850312156135a157600080fd5b823567ffffffffffffffff8111156135b857600080fd5b6135c485828601613545565b90969095509350505050565b6000815180845260005b818110156135f6576020818501810151868301820152016135da565b5060006020828601015260207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f83011685010191505092915050565b60208152600061364760208301846135d0565b9392505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051610120810167ffffffffffffffff811182821017156136a1576136a161364e565b60405290565b604051610160810167ffffffffffffffff811182821017156136a1576136a161364e565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff811182821017156137125761371261364e565b604052919050565b63ffffffff8116811461265457600080fd5b8035610fd48161371a565b68ffffffffffffffffff8116811461265457600080fd5b8035610fd481613737565b803561ffff81168114610fd457600080fd5b80357bffffffffffffffffffffffffffffffffffffffffffffffffffffffff81168114610fd457600080fd5b600061012082840312156137aa57600080fd5b6137b261367d565b6137bb8361372c565b81526137c96020840161372c565b60208201526137da6040840161372c565b60408201526137eb6060840161372c565b60608201526137fc6080840161372c565b608082015261380d60a0840161374e565b60a082015261381e60c08401613759565b60c082015261382f60e0840161372c565b60e082015261010061384281850161376b565b908201529392505050565b600082601f83011261385e57600080fd5b813567ffffffffffffffff8111156138785761387861364e565b6138a960207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f840116016136cb565b8181528460208386010111156138be57600080fd5b816020850160208301376000918101602001919091529392505050565b6000602082840312156138ed57600080fd5b813567ffffffffffffffff81111561390457600080fd5b6139108482850161384d565b949350505050565b73ffffffffffffffffffffffffffffffffffffffff8116811461265457600080fd5b8035610fd481613918565b6bffffffffffffffffffffffff8116811461265457600080fd5b8035610fd481613945565b6000806040838503121561397d57600080fd5b823561398881613918565b9150602083013561399881613945565b809150509250929050565b600081518084526020808501945080840160005b838110156139e957815173ffffffffffffffffffffffffffffffffffffffff16875295820195908201906001016139b7565b509495945050505050565b60208152600061364760208301846139a3565b600060208284031215613a1957600080fd5b5035919050565b600060208284031215613a3257600080fd5b813567ffffffffffffffff811115613a4957600080fd5b8201610160818503121561364757600080fd5b805182526020810151613a87602084018273ffffffffffffffffffffffffffffffffffffffff169052565b506040810151613aa760408401826bffffffffffffffffffffffff169052565b506060810151613acf606084018273ffffffffffffffffffffffffffffffffffffffff169052565b506080810151613aeb608084018267ffffffffffffffff169052565b5060a0810151613b0360a084018263ffffffff169052565b5060c0810151613b2060c084018268ffffffffffffffffff169052565b5060e0810151613b3d60e084018268ffffffffffffffffff169052565b506101008181015164ffffffffff9081169184019190915261012080830151909116908301526101409081015163ffffffff16910152565b610160810161347e8284613a5c565b60008083601f840112613b9657600080fd5b50813567ffffffffffffffff811115613bae57600080fd5b6020830191508360208260051b850101111561358757600080fd5b60008060008060008060008060e0898b031215613be557600080fd5b606089018a811115613bf657600080fd5b8998503567ffffffffffffffff80821115613c1057600080fd5b613c1c8c838d01613545565b909950975060808b0135915080821115613c3557600080fd5b613c418c838d01613b84565b909750955060a08b0135915080821115613c5a57600080fd5b50613c678b828c01613b84565b999c989b50969995989497949560c00135949350505050565b815163ffffffff9081168252602080840151821690830152604080840151821690830152606080840151821690830152608080840151918216908301526101208201905060a0830151613ce060a084018268ffffffffffffffffff169052565b5060c0830151613cf660c084018261ffff169052565b5060e0830151613d0e60e084018263ffffffff169052565b50610100838101517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff8116848301525b505092915050565b67ffffffffffffffff8116811461265457600080fd5b8035610fd481613d42565b600080600080600060808688031215613d7b57600080fd5b8535613d8681613d42565b9450602086013567ffffffffffffffff811115613da257600080fd5b613dae88828901613545565b9095509350506040860135613dc28161371a565b949793965091946060013592915050565b600067ffffffffffffffff821115613ded57613ded61364e565b5060051b60200190565b600082601f830112613e0857600080fd5b81356020613e1d613e1883613dd3565b6136cb565b82815260059290921b84018101918181019086841115613e3c57600080fd5b8286015b84811015613e60578035613e5381613918565b8352918301918301613e40565b509695505050505050565b803560ff81168114610fd457600080fd5b60008060008060008060c08789031215613e9557600080fd5b863567ffffffffffffffff80821115613ead57600080fd5b613eb98a838b01613df7565b97506020890135915080821115613ecf57600080fd5b613edb8a838b01613df7565b9650613ee960408a01613e6b565b95506060890135915080821115613eff57600080fd5b613f0b8a838b0161384d565b9450613f1960808a01613d58565b935060a0890135915080821115613f2f57600080fd5b50613f3c89828a0161384d565b9150509295509295509295565b600060208284031215613f5b57600080fd5b813561364781613918565b600181811c90821680613f7a57607f821691505b602082108103613fb3577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b50919050565b601f8211156105da57600081815260208120601f850160051c81016020861015613fe05750805b601f850160051c820191505b81811015610a4957828155600101613fec565b67ffffffffffffffff8311156140175761401761364e565b61402b836140258354613f66565b83613fb9565b6000601f84116001811461407d57600085156140475750838201355b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600387901b1c1916600186901b178355614113565b6000838152602090207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0861690835b828110156140cc57868501358255602094850194600190920191016140ac565b5086821015614107577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60f88860031b161c19848701351681555b505060018560011b0183555b5050505050565b8051610fd481613737565b60006020828403121561413757600080fd5b815161364781613737565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b6bffffffffffffffffffffffff82811682821603908082111561263c5761263c614142565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82036141f6576141f6614142565b5060010190565b6000610160823603121561421057600080fd5b6142186136a7565b823567ffffffffffffffff81111561422f57600080fd5b61423b3682860161384d565b825250602083013560208201526142546040840161393a565b60408201526142656060840161395f565b60608201526142766080840161374e565b608082015261428760a08401613d58565b60a082015261429860c08401613d58565b60c08201526142a960e0840161372c565b60e08201526101006142bc818501613759565b908201526101206142ce848201613d58565b908201526101406142e084820161393a565b9082015292915050565b6000602082840312156142fc57600080fd5b813561364781613d42565b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe184360301811261433c57600080fd5b83018035915067ffffffffffffffff82111561435757600080fd5b60200191503681900382131561358757600080fd5b60006020828403121561437e57600080fd5b61364782613759565b60006020828403121561439957600080fd5b81356136478161371a565b73ffffffffffffffffffffffffffffffffffffffff8a8116825267ffffffffffffffff8a166020830152881660408201526102406060820181905281018690526000610260878982850137600083890182015261ffff8716608084015260a0830186905263ffffffff851660c0840152601f88017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168301019050612ffe60e0830184613a5c565b60ff818116838216019081111561347e5761347e614142565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b600060ff8316806144a7576144a7614465565b8060ff84160491505092915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b8183823760009101908152919050565b828152606082602083013760800192915050565b808202811582820484141761347e5761347e614142565b8181038181111561347e5761347e614142565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fd5b63ffffffff81811683821601908082111561263c5761263c614142565b600061012063ffffffff808d1684528b6020850152808b166040850152508060608401526145af8184018a6139a3565b905082810360808401526145c381896139a3565b905060ff871660a084015282810360c08401526145e081876135d0565b905067ffffffffffffffff851660e084015282810361010084015261460581856135d0565b9c9b505050505050505050505050565b805169ffffffffffffffffffff81168114610fd457600080fd5b600080600080600060a0868803121561464757600080fd5b61465086614615565b945060208601519350604086015192506060860151915061467360808701614615565b90509295509295909350565b60006bffffffffffffffffffffffff8084168061469e5761469e614465565b92169190910492915050565b6bffffffffffffffffffffffff81811683821601908082111561263c5761263c614142565b6bffffffffffffffffffffffff818116838216028082169190828114613d3a57613d3a614142565b67ffffffffffffffff81811683821601908082111561263c5761263c614142565b8082018082111561347e5761347e614142565b600082601f83011261473c57600080fd5b8135602061474c613e1883613dd3565b82815260059290921b8401810191818101908684111561476b57600080fd5b8286015b84811015613e60578035835291830191830161476f565b600082601f83011261479757600080fd5b813560206147a7613e1883613dd3565b82815260059290921b840181019181810190868411156147c657600080fd5b8286015b84811015613e6057803567ffffffffffffffff8111156147ea5760008081fd5b6147f88986838b010161384d565b8452509183019183016147ca565b600080600080600060a0868803121561481e57600080fd5b853567ffffffffffffffff8082111561483657600080fd5b61484289838a0161472b565b9650602088013591508082111561485857600080fd5b61486489838a01614786565b9550604088013591508082111561487a57600080fd5b61488689838a01614786565b9450606088013591508082111561489c57600080fd5b6148a889838a01614786565b935060808801359150808211156148be57600080fd5b506148cb88828901614786565b9150509295509295909350565b6000826148e7576148e7614465565b500490565b60006101208b835273ffffffffffffffffffffffffffffffffffffffff8b16602084015267ffffffffffffffff808b1660408501528160608501526149338285018b6139a3565b91508382036080850152614947828a6139a3565b915060ff881660a085015283820360c085015261496482886135d0565b90861660e0850152838103610100850152905061460581856135d0565b8051610fd481613918565b8051610fd481613945565b8051610fd481613d42565b8051610fd48161371a565b805164ffffffffff81168114610fd457600080fd5b600061016082840312156149d557600080fd5b6149dd6136a7565b825181526149ed60208401614981565b60208201526149fe6040840161498c565b6040820152614a0f60608401614981565b6060820152614a2060808401614997565b6080820152614a3160a084016149a2565b60a0820152614a4260c0840161411a565b60c0820152614a5360e0840161411a565b60e0820152610100614a668185016149ad565b90820152610120614a788482016149ad565b908201526101406138428482016149a2565b64ffffffffff81811683821601908082111561263c5761263c614142565b6000610200808352614abc8184018a6135d0565b90508281036020840152614ad081896135d0565b6bffffffffffffffffffffffff88811660408601528716606085015273ffffffffffffffffffffffffffffffffffffffff861660808501529150614b19905060a0830184613a5c565b979650505050505050565b60008060408385031215614b3757600080fd5b825160078110614b4657600080fd5b60208401519092506139988161394556fea164736f6c6343000813000a", + ABI: "[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"router\",\"type\":\"address\"},{\"components\":[{\"internalType\":\"uint32\",\"name\":\"fulfillmentGasPriceOverEstimationBP\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"feedStalenessSeconds\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"gasOverheadBeforeCallback\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"gasOverheadAfterCallback\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"requestTimeoutSeconds\",\"type\":\"uint32\"},{\"internalType\":\"uint72\",\"name\":\"donFee\",\"type\":\"uint72\"},{\"internalType\":\"uint16\",\"name\":\"maxSupportedRequestDataVersion\",\"type\":\"uint16\"},{\"internalType\":\"uint224\",\"name\":\"fallbackNativePerUnitLink\",\"type\":\"uint224\"}],\"internalType\":\"structFunctionsBilling.Config\",\"name\":\"config\",\"type\":\"tuple\"},{\"internalType\":\"address\",\"name\":\"linkToNativeFeed\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"EmptyPublicKey\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InconsistentReportData\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InsufficientBalance\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidCalldata\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"message\",\"type\":\"string\"}],\"name\":\"InvalidConfig\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"int256\",\"name\":\"linkWei\",\"type\":\"int256\"}],\"name\":\"InvalidLinkWeiPrice\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidSubscription\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"}],\"name\":\"MustBeSubOwner\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"NoTransmittersSet\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByRouter\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByRouterOwner\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"PaymentTooLarge\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ReportInvalid\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"RouterMustBeSet\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"UnauthorizedPublicKeyChange\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"UnauthorizedSender\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"UnsupportedRequestDataVersion\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"requestId\",\"type\":\"bytes32\"}],\"name\":\"CommitmentDeleted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"previousConfigBlockNumber\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"configDigest\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"configCount\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"signers\",\"type\":\"address[]\"},{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"transmitters\",\"type\":\"address[]\"},{\"indexed\":false,\"internalType\":\"uint8\",\"name\":\"f\",\"type\":\"uint8\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"onchainConfig\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"offchainConfigVersion\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"offchainConfig\",\"type\":\"bytes\"}],\"name\":\"ConfigSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"fulfillmentGasPriceOverEstimationBP\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"feedStalenessSeconds\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"gasOverheadBeforeCallback\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"gasOverheadAfterCallback\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"requestTimeoutSeconds\",\"type\":\"uint32\"},{\"internalType\":\"uint72\",\"name\":\"donFee\",\"type\":\"uint72\"},{\"internalType\":\"uint16\",\"name\":\"maxSupportedRequestDataVersion\",\"type\":\"uint16\"},{\"internalType\":\"uint224\",\"name\":\"fallbackNativePerUnitLink\",\"type\":\"uint224\"}],\"indexed\":false,\"internalType\":\"structFunctionsBilling.Config\",\"name\":\"config\",\"type\":\"tuple\"}],\"name\":\"ConfigUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"requestId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"requestingContract\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"requestInitiator\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"subscriptionOwner\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"uint16\",\"name\":\"dataVersion\",\"type\":\"uint16\"},{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"flags\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"callbackGasLimit\",\"type\":\"uint64\"},{\"components\":[{\"internalType\":\"bytes32\",\"name\":\"requestId\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"coordinator\",\"type\":\"address\"},{\"internalType\":\"uint96\",\"name\":\"estimatedTotalCostJuels\",\"type\":\"uint96\"},{\"internalType\":\"address\",\"name\":\"client\",\"type\":\"address\"},{\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"callbackGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint72\",\"name\":\"adminFee\",\"type\":\"uint72\"},{\"internalType\":\"uint72\",\"name\":\"donFee\",\"type\":\"uint72\"},{\"internalType\":\"uint40\",\"name\":\"gasOverheadBeforeCallback\",\"type\":\"uint40\"},{\"internalType\":\"uint40\",\"name\":\"gasOverheadAfterCallback\",\"type\":\"uint40\"},{\"internalType\":\"uint32\",\"name\":\"timeoutTimestamp\",\"type\":\"uint32\"}],\"indexed\":false,\"internalType\":\"structFunctionsResponse.Commitment\",\"name\":\"commitment\",\"type\":\"tuple\"}],\"name\":\"OracleRequest\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"requestId\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"transmitter\",\"type\":\"address\"}],\"name\":\"OracleResponse\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"OwnershipTransferRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"configDigest\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"epoch\",\"type\":\"uint32\"}],\"name\":\"Transmitted\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"acceptOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"requestId\",\"type\":\"bytes32\"}],\"name\":\"deleteCommitment\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"},{\"internalType\":\"uint32\",\"name\":\"callbackGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint256\",\"name\":\"gasPriceWei\",\"type\":\"uint256\"}],\"name\":\"estimateCost\",\"outputs\":[{\"internalType\":\"uint96\",\"name\":\"\",\"type\":\"uint96\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getAdminFee\",\"outputs\":[{\"internalType\":\"uint72\",\"name\":\"\",\"type\":\"uint72\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getConfig\",\"outputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"fulfillmentGasPriceOverEstimationBP\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"feedStalenessSeconds\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"gasOverheadBeforeCallback\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"gasOverheadAfterCallback\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"requestTimeoutSeconds\",\"type\":\"uint32\"},{\"internalType\":\"uint72\",\"name\":\"donFee\",\"type\":\"uint72\"},{\"internalType\":\"uint16\",\"name\":\"maxSupportedRequestDataVersion\",\"type\":\"uint16\"},{\"internalType\":\"uint224\",\"name\":\"fallbackNativePerUnitLink\",\"type\":\"uint224\"}],\"internalType\":\"structFunctionsBilling.Config\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"name\":\"getDONFee\",\"outputs\":[{\"internalType\":\"uint72\",\"name\":\"\",\"type\":\"uint72\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getDONPublicKey\",\"outputs\":[{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getThresholdPublicKey\",\"outputs\":[{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getWeiPerUnitLink\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"latestConfigDetails\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"configCount\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"blockNumber\",\"type\":\"uint32\"},{\"internalType\":\"bytes32\",\"name\":\"configDigest\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"latestConfigDigestAndEpoch\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"scanLogs\",\"type\":\"bool\"},{\"internalType\":\"bytes32\",\"name\":\"configDigest\",\"type\":\"bytes32\"},{\"internalType\":\"uint32\",\"name\":\"epoch\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"uint96\",\"name\":\"amount\",\"type\":\"uint96\"}],\"name\":\"oracleWithdraw\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"oracleWithdrawAll\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address[]\",\"name\":\"_signers\",\"type\":\"address[]\"},{\"internalType\":\"address[]\",\"name\":\"_transmitters\",\"type\":\"address[]\"},{\"internalType\":\"uint8\",\"name\":\"_f\",\"type\":\"uint8\"},{\"internalType\":\"bytes\",\"name\":\"_onchainConfig\",\"type\":\"bytes\"},{\"internalType\":\"uint64\",\"name\":\"_offchainConfigVersion\",\"type\":\"uint64\"},{\"internalType\":\"bytes\",\"name\":\"_offchainConfig\",\"type\":\"bytes\"}],\"name\":\"setConfig\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"donPublicKey\",\"type\":\"bytes\"}],\"name\":\"setDONPublicKey\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"thresholdPublicKey\",\"type\":\"bytes\"}],\"name\":\"setThresholdPublicKey\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"},{\"internalType\":\"bytes32\",\"name\":\"flags\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"requestingContract\",\"type\":\"address\"},{\"internalType\":\"uint96\",\"name\":\"availableBalance\",\"type\":\"uint96\"},{\"internalType\":\"uint72\",\"name\":\"adminFee\",\"type\":\"uint72\"},{\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"initiatedRequests\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"callbackGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint16\",\"name\":\"dataVersion\",\"type\":\"uint16\"},{\"internalType\":\"uint64\",\"name\":\"completedRequests\",\"type\":\"uint64\"},{\"internalType\":\"address\",\"name\":\"subscriptionOwner\",\"type\":\"address\"}],\"internalType\":\"structFunctionsResponse.RequestMeta\",\"name\":\"request\",\"type\":\"tuple\"}],\"name\":\"startRequest\",\"outputs\":[{\"components\":[{\"internalType\":\"bytes32\",\"name\":\"requestId\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"coordinator\",\"type\":\"address\"},{\"internalType\":\"uint96\",\"name\":\"estimatedTotalCostJuels\",\"type\":\"uint96\"},{\"internalType\":\"address\",\"name\":\"client\",\"type\":\"address\"},{\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"callbackGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint72\",\"name\":\"adminFee\",\"type\":\"uint72\"},{\"internalType\":\"uint72\",\"name\":\"donFee\",\"type\":\"uint72\"},{\"internalType\":\"uint40\",\"name\":\"gasOverheadBeforeCallback\",\"type\":\"uint40\"},{\"internalType\":\"uint40\",\"name\":\"gasOverheadAfterCallback\",\"type\":\"uint40\"},{\"internalType\":\"uint32\",\"name\":\"timeoutTimestamp\",\"type\":\"uint32\"}],\"internalType\":\"structFunctionsResponse.Commitment\",\"name\":\"commitment\",\"type\":\"tuple\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32[3]\",\"name\":\"reportContext\",\"type\":\"bytes32[3]\"},{\"internalType\":\"bytes\",\"name\":\"report\",\"type\":\"bytes\"},{\"internalType\":\"bytes32[]\",\"name\":\"rs\",\"type\":\"bytes32[]\"},{\"internalType\":\"bytes32[]\",\"name\":\"ss\",\"type\":\"bytes32[]\"},{\"internalType\":\"bytes32\",\"name\":\"rawVs\",\"type\":\"bytes32\"}],\"name\":\"transmit\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"transmitters\",\"outputs\":[{\"internalType\":\"address[]\",\"name\":\"\",\"type\":\"address[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"typeAndVersion\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"fulfillmentGasPriceOverEstimationBP\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"feedStalenessSeconds\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"gasOverheadBeforeCallback\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"gasOverheadAfterCallback\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"requestTimeoutSeconds\",\"type\":\"uint32\"},{\"internalType\":\"uint72\",\"name\":\"donFee\",\"type\":\"uint72\"},{\"internalType\":\"uint16\",\"name\":\"maxSupportedRequestDataVersion\",\"type\":\"uint16\"},{\"internalType\":\"uint224\",\"name\":\"fallbackNativePerUnitLink\",\"type\":\"uint224\"}],\"internalType\":\"structFunctionsBilling.Config\",\"name\":\"config\",\"type\":\"tuple\"}],\"name\":\"updateConfig\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", + Bin: "0x60c06040523480156200001157600080fd5b50604051620050f4380380620050f4833981016040819052620000349162000418565b8282828260013380600081620000915760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b0384811691909117909155811615620000c457620000c48162000140565b50505015156080526001600160a01b038116620000f457604051632530e88560e11b815260040160405180910390fd5b6001600160a01b0390811660a052600b80549183166c01000000000000000000000000026001600160601b039092169190911790556200013482620001eb565b505050505050620005c6565b336001600160a01b038216036200019a5760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c66000000000000000000604482015260640162000088565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b620001f56200033b565b80516008805460208401516040808601516060870151608088015160a089015160c08a015161ffff16600160e81b0261ffff60e81b196001600160481b03909216600160a01b02600160a01b600160e81b031963ffffffff948516600160801b0216600160801b600160e81b03199585166c010000000000000000000000000263ffffffff60601b19978616680100000000000000000297909716600160401b600160801b0319998616640100000000026001600160401b0319909b1695909c1694909417989098179690961698909817929092171617929092179390931692909217905560e0820151600980546001600160e01b039092166001600160e01b0319909216919091179055517f8efd15b0efe82b55a8dc915f88e835007cc65ad0b442997d3c10604961e3907a906200033090839062000536565b60405180910390a150565b6200034562000347565b565b6000546001600160a01b03163314620003455760405162461bcd60e51b815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e657200000000000000000000604482015260640162000088565b80516001600160a01b0381168114620003bb57600080fd5b919050565b805163ffffffff81168114620003bb57600080fd5b80516001600160481b0381168114620003bb57600080fd5b805161ffff81168114620003bb57600080fd5b80516001600160e01b0381168114620003bb57600080fd5b60008060008385036101408112156200043057600080fd5b6200043b85620003a3565b935061010080601f19830112156200045257600080fd5b60405191508082016001600160401b03811183821017156200048457634e487b7160e01b600052604160045260246000fd5b6040526200049560208701620003c0565b8252620004a560408701620003c0565b6020830152620004b860608701620003c0565b6040830152620004cb60808701620003c0565b6060830152620004de60a08701620003c0565b6080830152620004f160c08701620003d5565b60a08301526200050460e08701620003ed565b60c08301526200051681870162000400565b60e08301525091506200052d6101208501620003a3565b90509250925092565b60006101008201905063ffffffff8084511683528060208501511660208401528060408501511660408401528060608501511660608401528060808501511660808401525060018060481b0360a08401511660a083015260c0830151620005a360c084018261ffff169052565b5060e0830151620005bf60e08401826001600160e01b03169052565b5092915050565b60805160a051614ade62000616600039600081816105be0152818161074c01528181610a1f01528181610cb301528181610ffa015281816117e50152613235015260006112230152614ade6000f3fe608060405234801561001057600080fd5b506004361061018d5760003560e01c806385b214cf116100e3578063c3f909d41161008c578063e3d0e71211610066578063e3d0e71214610529578063e4ddcea61461053c578063f2fde38b1461055257600080fd5b8063c3f909d4146103b4578063d227d245146104f1578063d328a91e1461052157600080fd5b8063a631571e116100bd578063a631571e14610361578063afcb95d714610381578063b1dc65a4146103a157600080fd5b806385b214cf146103135780638da5cb5b146103265780639314176d1461034e57600080fd5b806379ba509711610145578063814118341161011f578063814118341461028957806381f1b9381461029e57806381ff7048146102a657600080fd5b806379ba5097146102665780637d4807871461026e5780637f15e1661461027657600080fd5b80632a905ccc116101765780632a905ccc146101f957806359b5b7ac1461021b57806366316d8d1461025357600080fd5b8063083a546614610192578063181f5a77146101a7575b600080fd5b6101a56101a0366004613528565b610565565b005b6101e36040518060400160405280601c81526020017f46756e6374696f6e7320436f6f7264696e61746f722076312e302e300000000081525081565b6040516101f091906135ce565b60405180910390f35b6102016105ba565b60405168ffffffffffffffffff90911681526020016101f0565b61020161022936600461371e565b5060085474010000000000000000000000000000000000000000900468ffffffffffffffffff1690565b6101a56102613660046137ad565b610650565b6101a5610809565b6101a561090b565b6101a5610284366004613528565b610b0b565b610291610b5b565b6040516101f09190613837565b6101e3610bca565b6102f060015460025463ffffffff74010000000000000000000000000000000000000000830481169378010000000000000000000000000000000000000000000000009093041691565b6040805163ffffffff9485168152939092166020840152908201526060016101f0565b6101a561032136600461384a565b610c9b565b60005460405173ffffffffffffffffffffffffffffffffffffffff90911681526020016101f0565b6101a561035c3660046138e0565b610d58565b61037461036f3660046139aa565b610f89565b6040516101f09190613aff565b6040805160018152600060208201819052918101919091526060016101f0565b6101a56103af366004613b53565b61112a565b6104e46040805161010081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e081019190915250604080516101008101825260085463ffffffff80821683526401000000008204811660208401526801000000000000000082048116938301939093526c010000000000000000000000008104831660608301527001000000000000000000000000000000008104909216608082015274010000000000000000000000000000000000000000820468ffffffffffffffffff1660a08201527d01000000000000000000000000000000000000000000000000000000000090910461ffff1660c08201526009547bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1660e082015290565b6040516101f09190613c0a565b6105046104ff366004613cca565b6117e1565b6040516bffffffffffffffffffffffff90911681526020016101f0565b6101e3611943565b6101a5610537366004613de3565b61199a565b6105446123c6565b6040519081526020016101f0565b6101a5610560366004613eb0565b6125eb565b61056d6125ff565b60008190036105a8576040517f4f42be3d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600d6105b5828483613f66565b505050565b60007f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16632a905ccc6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610627573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061064b919061408c565b905090565b610658612682565b806bffffffffffffffffffffffff166000036106925750336000908152600a60205260409020546bffffffffffffffffffffffff166106ec565b336000908152600a60205260409020546bffffffffffffffffffffffff808316911610156106ec576040517ff4d678b800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b336000908152600a6020526040812080548392906107199084906bffffffffffffffffffffffff166140d8565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff16021790555061076e7f000000000000000000000000000000000000000000000000000000000000000090565b6040517f66316d8d00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff84811660048301526bffffffffffffffffffffffff8416602483015291909116906366316d8d90604401600060405180830381600087803b1580156107ed57600080fd5b505af1158015610801573d6000803e3d6000fd5b505050505050565b60015473ffffffffffffffffffffffffffffffffffffffff16331461088f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e65720000000000000000000060448201526064015b60405180910390fd5b60008054337fffffffffffffffffffffffff00000000000000000000000000000000000000008083168217845560018054909116905560405173ffffffffffffffffffffffffffffffffffffffff90921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b61091361282d565b61091b612682565b6000610925610b5b565b905060005b8151811015610b07576000600a600084848151811061094b5761094b6140fd565b60209081029190910181015173ffffffffffffffffffffffffffffffffffffffff168252810191909152604001600020546bffffffffffffffffffffffff1690508015610af6576000600a60008585815181106109aa576109aa6140fd565b602002602001015173ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff160217905550610a417f000000000000000000000000000000000000000000000000000000000000000090565b73ffffffffffffffffffffffffffffffffffffffff166366316d8d848481518110610a6e57610a6e6140fd565b6020026020010151836040518363ffffffff1660e01b8152600401610ac392919073ffffffffffffffffffffffffffffffffffffffff9290921682526bffffffffffffffffffffffff16602082015260400190565b600060405180830381600087803b158015610add57600080fd5b505af1158015610af1573d6000803e3d6000fd5b505050505b50610b008161412c565b905061092a565b5050565b610b136125ff565b6000819003610b4e576040517f4f42be3d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600c6105b5828483613f66565b60606006805480602002602001604051908101604052809291908181526020018280548015610bc057602002820191906000526020600020905b815473ffffffffffffffffffffffffffffffffffffffff168152600190910190602001808311610b95575b5050505050905090565b6060600d8054610bd990613ecd565b9050600003610c14576040517f4f42be3d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600d8054610c2190613ecd565b80601f0160208091040260200160405190810160405280929190818152602001828054610c4d90613ecd565b8015610bc05780601f10610c6f57610100808354040283529160200191610bc0565b820191906000526020600020905b815481529060010190602001808311610c7d57509395945050505050565b3373ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001614610d0a576040517fc41a5b0900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008181526007602052604080822091909155517f8a4b97add3359bd6bcf5e82874363670eb5ad0f7615abddbd0ed0a3a98f0f41690610d4d9083815260200190565b60405180910390a150565b610d6061282d565b80516008805460208401516040808601516060870151608088015160a089015160c08a015161ffff167d010000000000000000000000000000000000000000000000000000000000027fff0000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff68ffffffffffffffffff90921674010000000000000000000000000000000000000000027fffffff000000000000000000ffffffffffffffffffffffffffffffffffffffff63ffffffff94851670010000000000000000000000000000000002167fffffff00000000000000000000000000ffffffffffffffffffffffffffffffff9585166c01000000000000000000000000027fffffffffffffffffffffffffffffffff00000000ffffffffffffffffffffffff9786166801000000000000000002979097167fffffffffffffffffffffffffffffffff0000000000000000ffffffffffffffff998616640100000000027fffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000909b1695909c1694909417989098179690961698909817929092171617929092179390931692909217905560e0820151600980547bffffffffffffffffffffffffffffffffffffffffffffffffffffffff9092167fffffffff00000000000000000000000000000000000000000000000000000000909216919091179055517f8efd15b0efe82b55a8dc915f88e835007cc65ad0b442997d3c10604961e3907a90610d4d908390613c0a565b6040805161016081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e08101829052610100810182905261012081018290526101408101919091523373ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001614611051576040517fc41a5b0900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61106261105d83614164565b612835565b90506110746060830160408401613eb0565b815173ffffffffffffffffffffffffffffffffffffffff91909116907fbf50768ccf13bd0110ca6d53a9c4f1f3271abdd4c24a56878863ed25b20598ff326110c260c0870160a08801614251565b6110d461016088016101408901613eb0565b6110de888061426e565b6110f06101208b016101008c016142d3565b60208b01356111066101008d0160e08e016142ee565b8b60405161111c9998979695949392919061430b565b60405180910390a35b919050565b60005a604080518b3580825262ffffff6020808f0135600881901c929092169084015293945092917fb04e63db38c49950639fa09d29872f21f5d49d614f3a969d8adf3d4b52e41a62910160405180910390a16040805160608101825260025480825260035460ff80821660208501526101009091041692820192909252908314611211576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f636f6e666967446967657374206d69736d6174636800000000000000000000006044820152606401610886565b61121f8b8b8b8b8b8b612c36565b60007f00000000000000000000000000000000000000000000000000000000000000001561127c5760028260200151836040015161125d91906143b3565b61126791906143fb565b6112729060016143b3565b60ff169050611292565b602082015161128c9060016143b3565b60ff1690505b8881146112fb576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601a60248201527f77726f6e67206e756d626572206f66207369676e6174757265730000000000006044820152606401610886565b888714611364576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f7369676e617475726573206f7574206f6620726567697374726174696f6e00006044820152606401610886565b3360009081526004602090815260408083208151808301909252805460ff808216845292939192918401916101009091041660028111156113a7576113a761441d565b60028111156113b8576113b861441d565b90525090506002816020015160028111156113d5576113d561441d565b14801561141c57506006816000015160ff16815481106113f7576113f76140fd565b60009182526020909120015473ffffffffffffffffffffffffffffffffffffffff1633145b611482576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f756e617574686f72697a6564207472616e736d697474657200000000000000006044820152606401610886565b505050505061148f6134c0565b6000808a8a6040516114a292919061444c565b6040519081900381206114b9918e9060200161445c565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181528282528051602091820120838301909252600080845290830152915060005b898110156117c3576000600184898460208110611522576115226140fd565b61152f91901a601b6143b3565b8e8e86818110611541576115416140fd565b905060200201358d8d8781811061155a5761155a6140fd565b9050602002013560405160008152602001604052604051611597949392919093845260ff9290921660208401526040830152606082015260800190565b6020604051602081039080840390855afa1580156115b9573d6000803e3d6000fd5b5050604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081015173ffffffffffffffffffffffffffffffffffffffff811660009081526004602090815290849020838501909452835460ff808216855292965092945084019161010090041660028111156116395761163961441d565b600281111561164a5761164a61441d565b90525092506001836020015160028111156116675761166761441d565b146116ce576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f61646472657373206e6f7420617574686f72697a656420746f207369676e00006044820152606401610886565b8251600090879060ff16601f81106116e8576116e86140fd565b602002015173ffffffffffffffffffffffffffffffffffffffff161461176a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f6e6f6e2d756e69717565207369676e61747572650000000000000000000000006044820152606401610886565b8086846000015160ff16601f8110611784576117846140fd565b73ffffffffffffffffffffffffffffffffffffffff90921660209290920201526117af6001866143b3565b945050806117bc9061412c565b9050611503565b5050506117d4833383858e8e612ced565b5050505050505050505050565b60007f00000000000000000000000000000000000000000000000000000000000000006040517f10fc49c100000000000000000000000000000000000000000000000000000000815267ffffffffffffffff8816600482015263ffffffff8516602482015273ffffffffffffffffffffffffffffffffffffffff91909116906310fc49c19060440160006040518083038186803b15801561188157600080fd5b505afa158015611895573d6000803e3d6000fd5b5050505066038d7ea4c680008211156118da576040517f8129bbcd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60006118e46105ba565b9050600061192787878080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061022992505050565b905061193585858385612ebb565b925050505b95945050505050565b6060600c805461195290613ecd565b905060000361198d576040517f4f42be3d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600c8054610c2190613ecd565b855185518560ff16601f831115611a0d576040517f89a6198900000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f746f6f206d616e79207369676e657273000000000000000000000000000000006044820152606401610886565b80600003611a77576040517f89a6198900000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f66206d75737420626520706f73697469766500000000000000000000000000006044820152606401610886565b818314611b05576040517f89a61989000000000000000000000000000000000000000000000000000000008152602060048201526024808201527f6f7261636c6520616464726573736573206f7574206f6620726567697374726160448201527f74696f6e000000000000000000000000000000000000000000000000000000006064820152608401610886565b611b10816003614470565b8311611b78576040517f89a6198900000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f6661756c74792d6f7261636c65206620746f6f206869676800000000000000006044820152606401610886565b611b806125ff565b6040805160c0810182528a8152602081018a905260ff89169181018290526060810188905267ffffffffffffffff8716608082015260a0810186905290611bc79088612fa5565b60055415611d7c57600554600090611be190600190614487565b9050600060058281548110611bf857611bf86140fd565b60009182526020822001546006805473ffffffffffffffffffffffffffffffffffffffff90921693509084908110611c3257611c326140fd565b600091825260208083209091015473ffffffffffffffffffffffffffffffffffffffff85811684526004909252604080842080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000090811690915592909116808452922080549091169055600580549192509080611cb257611cb261449a565b60008281526020902081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff90810180547fffffffffffffffffffffffff00000000000000000000000000000000000000001690550190556006805480611d1b57611d1b61449a565b60008281526020902081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff90810180547fffffffffffffffffffffffff000000000000000000000000000000000000000016905501905550611bc7915050565b60005b8151518110156121e35760006004600084600001518481518110611da557611da56140fd565b60209081029190910181015173ffffffffffffffffffffffffffffffffffffffff16825281019190915260400160002054610100900460ff166002811115611def57611def61441d565b14611e56576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f7265706561746564207369676e657220616464726573730000000000000000006044820152606401610886565b6040805180820190915260ff82168152600160208201528251805160049160009185908110611e8757611e876140fd565b60209081029190910181015173ffffffffffffffffffffffffffffffffffffffff168252818101929092526040016000208251815460ff9091167fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0082168117835592840151919283917fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00001617610100836002811115611f2857611f2861441d565b021790555060009150611f389050565b6004600084602001518481518110611f5257611f526140fd565b60209081029190910181015173ffffffffffffffffffffffffffffffffffffffff16825281019190915260400160002054610100900460ff166002811115611f9c57611f9c61441d565b14612003576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601c60248201527f7265706561746564207472616e736d69747465722061646472657373000000006044820152606401610886565b6040805180820190915260ff821681526020810160028152506004600084602001518481518110612036576120366140fd565b60209081029190910181015173ffffffffffffffffffffffffffffffffffffffff168252818101929092526040016000208251815460ff9091167fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0082168117835592840151919283917fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000016176101008360028111156120d7576120d761441d565b0217905550508251805160059250839081106120f5576120f56140fd565b602090810291909101810151825460018101845560009384529282902090920180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff9093169290921790915582015180516006919083908110612171576121716140fd565b60209081029190910181015182546001810184556000938452919092200180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff909216919091179055806121db8161412c565b915050611d7f565b506040810151600380547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660ff909216919091179055600180547fffffffff00000000ffffffffffffffffffffffffffffffffffffffffffffffff8116780100000000000000000000000000000000000000000000000063ffffffff438116820292909217808555920481169291829160149161229b918491740100000000000000000000000000000000000000009004166144c9565b92506101000a81548163ffffffff021916908363ffffffff1602179055506122fa4630600160149054906101000a900463ffffffff1663ffffffff16856000015186602001518760400151886060015189608001518a60a00151612fbe565b600281905582518051600380547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff1661010060ff9093169290920291909117905560015460208501516040808701516060880151608089015160a08a015193517f1591690b8638f5fb2dbec82ac741805ac5da8b45dc5263f4875b0496fdce4e05986123b1988b9891977401000000000000000000000000000000000000000090920463ffffffff169690959194919391926144e6565b60405180910390a15050505050505050505050565b604080516101008101825260085463ffffffff80821683526401000000008204811660208401526801000000000000000082048116838501526c01000000000000000000000000808304821660608501527001000000000000000000000000000000008304909116608084015274010000000000000000000000000000000000000000820468ffffffffffffffffff1660a0808501919091527d01000000000000000000000000000000000000000000000000000000000090920461ffff1660c08401526009547bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1660e0840152600b5484517ffeaf968c00000000000000000000000000000000000000000000000000000000815294516000958694859490930473ffffffffffffffffffffffffffffffffffffffff169263feaf968c926004808401938290030181865afa158015612520573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906125449190614596565b5093505092505080426125579190614487565b836020015163ffffffff1610801561257957506000836020015163ffffffff16115b156125a757505060e001517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff16919050565b600082136125e4576040517f43d4cf6600000000000000000000000000000000000000000000000000000000815260048101839052602401610886565b5092915050565b6125f36125ff565b6125fc81613069565b50565b60005473ffffffffffffffffffffffffffffffffffffffff163314612680576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e6572000000000000000000006044820152606401610886565b565b600b546bffffffffffffffffffffffff1660000361269c57565b60006126a6610b5b565b905080516000036126e3576040517f30274b3a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8051600b54600091612702916bffffffffffffffffffffffff166145e6565b905060005b82518110156127ce5781600a6000858481518110612727576127276140fd565b602002602001015173ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008282829054906101000a90046bffffffffffffffffffffffff1661278f9190614611565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff160217905550806127c79061412c565b9050612707565b5081516127db9082614636565b600b80546000906127fb9084906bffffffffffffffffffffffff166140d8565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff1602179055505050565b6126806125ff565b6040805161016081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e081018290526101008101829052610120810182905261014081019190915260408051610100808201835260085463ffffffff80821684526401000000008204811660208501526801000000000000000082048116948401949094526c010000000000000000000000008104841660608401527001000000000000000000000000000000008104909316608083015274010000000000000000000000000000000000000000830468ffffffffffffffffff1660a08301527d01000000000000000000000000000000000000000000000000000000000090920461ffff90811660c083018190526009547bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1660e0840152928501519192911611156129bb576040517fdada758700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60085460009074010000000000000000000000000000000000000000900468ffffffffffffffffff16905060006129fc8560e001513a848860800151612ebb565b9050806bffffffffffffffffffffffff1685606001516bffffffffffffffffffffffff161015612a58576040517ff4d678b800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000612adb3087604001518860a001518960c001516001612a799190614666565b6040805173ffffffffffffffffffffffffffffffffffffffff958616602080830191909152949095168582015267ffffffffffffffff928316606086015291166080808501919091528151808503909101815260a09093019052815191012090565b90506040518061016001604052808281526020013073ffffffffffffffffffffffffffffffffffffffff168152602001836bffffffffffffffffffffffff168152602001876040015173ffffffffffffffffffffffffffffffffffffffff1681526020018760a0015167ffffffffffffffff1681526020018760e0015163ffffffff168152602001876080015168ffffffffffffffffff1681526020018468ffffffffffffffffff168152602001856040015163ffffffff1664ffffffffff168152602001856060015163ffffffff1664ffffffffff168152602001856080015163ffffffff1642612bcd9190614687565b63ffffffff16815250945084604051602001612be99190613aff565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529181528151602092830120600093845260079092529091205550919392505050565b6000612c43826020614470565b612c4e856020614470565b612c5a88610144614687565b612c649190614687565b612c6e9190614687565b612c79906000614687565b9050368114612ce4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f63616c6c64617461206c656e677468206d69736d6174636800000000000000006044820152606401610886565b50505050505050565b606080808080612cff86880188614775565b8451949950929750909550935091501580612d1c57508351855114155b80612d2957508251855114155b80612d3657508151855114155b80612d4357508051855114155b15612d7a576040517f0be3632800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60005b8551811015612ead576000612e12878381518110612d9d57612d9d6140fd565b6020026020010151878481518110612db757612db76140fd565b6020026020010151878581518110612dd157612dd16140fd565b6020026020010151878681518110612deb57612deb6140fd565b6020026020010151878781518110612e0557612e056140fd565b602002602001015161315e565b90506000816006811115612e2857612e2861441d565b1480612e4557506001816006811115612e4357612e4361441d565b145b15612e9c57868281518110612e5c57612e5c6140fd565b60209081029190910181015160405133815290917fc708e0440951fd63499c0f7a73819b469ee5dd3ecc356c0ab4eb7f18389009d9910160405180910390a25b50612ea68161412c565b9050612d7d565b505050505050505050505050565b60085460009081908690612ef39063ffffffff6c010000000000000000000000008204811691680100000000000000009004166144c9565b612efd91906144c9565b60085463ffffffff918216925060009161271091612f1c911688614470565b612f269190614847565b612f309087614687565b90506000612f3d826133ef565b90506000612f59846bffffffffffffffffffffffff8416614470565b90506000612f7568ffffffffffffffffff808916908a16614611565b9050612f97612f926bffffffffffffffffffffffff831684614687565b61341e565b9a9950505050505050505050565b6000612faf610b5b565b511115610b0757610b07612682565b6000808a8a8a8a8a8a8a8a8a604051602001612fe29998979695949392919061485b565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081840301815291905280516020909101207dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff167e01000000000000000000000000000000000000000000000000000000000000179150509998505050505050505050565b3373ffffffffffffffffffffffffffffffffffffffff8216036130e8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c660000000000000000006044820152606401610886565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b600080838060200190518101906131759190614931565b60008881526007602052604090205490915061319557600291505061193a565b806040516020016131a69190613aff565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152918152815160209283012060008a81526007909352912054146131f857600691505061193a565b60006132033a6133ef565b9050600082610120015183610100015161321d9190614a04565b61322e9064ffffffffff1683614636565b90506000807f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663330605298b8b878960e0015168ffffffffffffffffff168861328d9190614611565b338b6040518763ffffffff1660e01b81526004016132b096959493929190614a22565b60408051808303816000875af11580156132ce573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906132f29190614a9e565b9092509050600082600681111561330b5761330b61441d565b1480613328575060018260068111156133265761332661441d565b145b156133e15760008b8152600760205260408120556133468184614611565b336000908152600a6020526040812080547fffffffffffffffffffffffffffffffffffffffff000000000000000000000000166bffffffffffffffffffffffff93841617905560e0870151600b805468ffffffffffffffffff909216939092916133b291859116614611565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff1602179055505b509998505050505050505050565b60006134186133fc6123c6565b61340e84670de0b6b3a7640000614470565b612f929190614847565b92915050565b60006bffffffffffffffffffffffff8211156134bc576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f53616665436173743a2076616c756520646f65736e27742066697420696e203960448201527f36206269747300000000000000000000000000000000000000000000000000006064820152608401610886565b5090565b604051806103e00160405280601f906020820280368337509192915050565b60008083601f8401126134f157600080fd5b50813567ffffffffffffffff81111561350957600080fd5b60208301915083602082850101111561352157600080fd5b9250929050565b6000806020838503121561353b57600080fd5b823567ffffffffffffffff81111561355257600080fd5b61355e858286016134df565b90969095509350505050565b6000815180845260005b8181101561359057602081850181015186830182015201613574565b5060006020828601015260207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f83011685010191505092915050565b6020815260006135e1602083018461356a565b9392505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051610160810167ffffffffffffffff8111828210171561363b5761363b6135e8565b60405290565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715613688576136886135e8565b604052919050565b600082601f8301126136a157600080fd5b813567ffffffffffffffff8111156136bb576136bb6135e8565b6136ec60207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f84011601613641565b81815284602083860101111561370157600080fd5b816020850160208301376000918101602001919091529392505050565b60006020828403121561373057600080fd5b813567ffffffffffffffff81111561374757600080fd5b61375384828501613690565b949350505050565b73ffffffffffffffffffffffffffffffffffffffff811681146125fc57600080fd5b80356111258161375b565b6bffffffffffffffffffffffff811681146125fc57600080fd5b803561112581613788565b600080604083850312156137c057600080fd5b82356137cb8161375b565b915060208301356137db81613788565b809150509250929050565b600081518084526020808501945080840160005b8381101561382c57815173ffffffffffffffffffffffffffffffffffffffff16875295820195908201906001016137fa565b509495945050505050565b6020815260006135e160208301846137e6565b60006020828403121561385c57600080fd5b5035919050565b63ffffffff811681146125fc57600080fd5b803561112581613863565b68ffffffffffffffffff811681146125fc57600080fd5b803561112581613880565b803561ffff8116811461112557600080fd5b80357bffffffffffffffffffffffffffffffffffffffffffffffffffffffff8116811461112557600080fd5b60006101008083850312156138f457600080fd5b6040519081019067ffffffffffffffff82118183101715613917576139176135e8565b816040528335915061392882613863565b81815261393760208501613875565b602082015261394860408501613875565b604082015261395960608501613875565b606082015261396a60808501613875565b608082015261397b60a08501613897565b60a082015261398c60c085016138a2565b60c082015261399d60e085016138b4565b60e0820152949350505050565b6000602082840312156139bc57600080fd5b813567ffffffffffffffff8111156139d357600080fd5b820161016081850312156135e157600080fd5b805182526020810151613a11602084018273ffffffffffffffffffffffffffffffffffffffff169052565b506040810151613a3160408401826bffffffffffffffffffffffff169052565b506060810151613a59606084018273ffffffffffffffffffffffffffffffffffffffff169052565b506080810151613a75608084018267ffffffffffffffff169052565b5060a0810151613a8d60a084018263ffffffff169052565b5060c0810151613aaa60c084018268ffffffffffffffffff169052565b5060e0810151613ac760e084018268ffffffffffffffffff169052565b506101008181015164ffffffffff9081169184019190915261012080830151909116908301526101409081015163ffffffff16910152565b610160810161341882846139e6565b60008083601f840112613b2057600080fd5b50813567ffffffffffffffff811115613b3857600080fd5b6020830191508360208260051b850101111561352157600080fd5b60008060008060008060008060e0898b031215613b6f57600080fd5b606089018a811115613b8057600080fd5b8998503567ffffffffffffffff80821115613b9a57600080fd5b613ba68c838d016134df565b909950975060808b0135915080821115613bbf57600080fd5b613bcb8c838d01613b0e565b909750955060a08b0135915080821115613be457600080fd5b50613bf18b828c01613b0e565b999c989b50969995989497949560c00135949350505050565b60006101008201905063ffffffff8084511683528060208501511660208401528060408501511660408401528060608501511660608401528060808501511660808401525068ffffffffffffffffff60a08401511660a083015260c0830151613c7960c084018261ffff169052565b5060e08301516125e460e08401827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff169052565b67ffffffffffffffff811681146125fc57600080fd5b803561112581613ca9565b600080600080600060808688031215613ce257600080fd5b8535613ced81613ca9565b9450602086013567ffffffffffffffff811115613d0957600080fd5b613d15888289016134df565b9095509350506040860135613d2981613863565b949793965091946060013592915050565b600067ffffffffffffffff821115613d5457613d546135e8565b5060051b60200190565b600082601f830112613d6f57600080fd5b81356020613d84613d7f83613d3a565b613641565b82815260059290921b84018101918181019086841115613da357600080fd5b8286015b84811015613dc7578035613dba8161375b565b8352918301918301613da7565b509695505050505050565b803560ff8116811461112557600080fd5b60008060008060008060c08789031215613dfc57600080fd5b863567ffffffffffffffff80821115613e1457600080fd5b613e208a838b01613d5e565b97506020890135915080821115613e3657600080fd5b613e428a838b01613d5e565b9650613e5060408a01613dd2565b95506060890135915080821115613e6657600080fd5b613e728a838b01613690565b9450613e8060808a01613cbf565b935060a0890135915080821115613e9657600080fd5b50613ea389828a01613690565b9150509295509295509295565b600060208284031215613ec257600080fd5b81356135e18161375b565b600181811c90821680613ee157607f821691505b602082108103613f1a577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b50919050565b601f8211156105b557600081815260208120601f850160051c81016020861015613f475750805b601f850160051c820191505b8181101561080157828155600101613f53565b67ffffffffffffffff831115613f7e57613f7e6135e8565b613f9283613f8c8354613ecd565b83613f20565b6000601f841160018114613fe45760008515613fae5750838201355b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600387901b1c1916600186901b17835561407a565b6000838152602090207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0861690835b828110156140335786850135825560209485019460019092019101614013565b508682101561406e577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60f88860031b161c19848701351681555b505060018560011b0183555b5050505050565b805161112581613880565b60006020828403121561409e57600080fd5b81516135e181613880565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b6bffffffffffffffffffffffff8281168282160390808211156125e4576125e46140a9565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff820361415d5761415d6140a9565b5060010190565b6000610160823603121561417757600080fd5b61417f613617565b823567ffffffffffffffff81111561419657600080fd5b6141a236828601613690565b825250602083013560208201526141bb6040840161377d565b60408201526141cc606084016137a2565b60608201526141dd60808401613897565b60808201526141ee60a08401613cbf565b60a08201526141ff60c08401613cbf565b60c082015261421060e08401613875565b60e08201526101006142238185016138a2565b90820152610120614235848201613cbf565b9082015261014061424784820161377d565b9082015292915050565b60006020828403121561426357600080fd5b81356135e181613ca9565b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe18436030181126142a357600080fd5b83018035915067ffffffffffffffff8211156142be57600080fd5b60200191503681900382131561352157600080fd5b6000602082840312156142e557600080fd5b6135e1826138a2565b60006020828403121561430057600080fd5b81356135e181613863565b73ffffffffffffffffffffffffffffffffffffffff8a8116825267ffffffffffffffff8a166020830152881660408201526102406060820181905281018690526000610260878982850137600083890182015261ffff8716608084015260a0830186905263ffffffff851660c0840152601f88017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168301019050612f9760e08301846139e6565b60ff8181168382160190811115613418576134186140a9565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b600060ff83168061440e5761440e6143cc565b8060ff84160491505092915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b8183823760009101908152919050565b828152606082602083013760800192915050565b8082028115828204841417613418576134186140a9565b81810381811115613418576134186140a9565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fd5b63ffffffff8181168382160190808211156125e4576125e46140a9565b600061012063ffffffff808d1684528b6020850152808b166040850152508060608401526145168184018a6137e6565b9050828103608084015261452a81896137e6565b905060ff871660a084015282810360c0840152614547818761356a565b905067ffffffffffffffff851660e084015282810361010084015261456c818561356a565b9c9b505050505050505050505050565b805169ffffffffffffffffffff8116811461112557600080fd5b600080600080600060a086880312156145ae57600080fd5b6145b78661457c565b94506020860151935060408601519250606086015191506145da6080870161457c565b90509295509295909350565b60006bffffffffffffffffffffffff80841680614605576146056143cc565b92169190910492915050565b6bffffffffffffffffffffffff8181168382160190808211156125e4576125e46140a9565b6bffffffffffffffffffffffff81811683821602808216919082811461465e5761465e6140a9565b505092915050565b67ffffffffffffffff8181168382160190808211156125e4576125e46140a9565b80820180821115613418576134186140a9565b600082601f8301126146ab57600080fd5b813560206146bb613d7f83613d3a565b82815260059290921b840181019181810190868411156146da57600080fd5b8286015b84811015613dc757803583529183019183016146de565b600082601f83011261470657600080fd5b81356020614716613d7f83613d3a565b82815260059290921b8401810191818101908684111561473557600080fd5b8286015b84811015613dc757803567ffffffffffffffff8111156147595760008081fd5b6147678986838b0101613690565b845250918301918301614739565b600080600080600060a0868803121561478d57600080fd5b853567ffffffffffffffff808211156147a557600080fd5b6147b189838a0161469a565b965060208801359150808211156147c757600080fd5b6147d389838a016146f5565b955060408801359150808211156147e957600080fd5b6147f589838a016146f5565b9450606088013591508082111561480b57600080fd5b61481789838a016146f5565b9350608088013591508082111561482d57600080fd5b5061483a888289016146f5565b9150509295509295909350565b600082614856576148566143cc565b500490565b60006101208b835273ffffffffffffffffffffffffffffffffffffffff8b16602084015267ffffffffffffffff808b1660408501528160608501526148a28285018b6137e6565b915083820360808501526148b6828a6137e6565b915060ff881660a085015283820360c08501526148d3828861356a565b90861660e0850152838103610100850152905061456c818561356a565b80516111258161375b565b805161112581613788565b805161112581613ca9565b805161112581613863565b805164ffffffffff8116811461112557600080fd5b6000610160828403121561494457600080fd5b61494c613617565b8251815261495c602084016148f0565b602082015261496d604084016148fb565b604082015261497e606084016148f0565b606082015261498f60808401614906565b60808201526149a060a08401614911565b60a08201526149b160c08401614081565b60c08201526149c260e08401614081565b60e08201526101006149d581850161491c565b908201526101206149e784820161491c565b908201526101406149f9848201614911565b908201529392505050565b64ffffffffff8181168382160190808211156125e4576125e46140a9565b6000610200808352614a368184018a61356a565b90508281036020840152614a4a818961356a565b6bffffffffffffffffffffffff88811660408601528716606085015273ffffffffffffffffffffffffffffffffffffffff861660808501529150614a93905060a08301846139e6565b979650505050505050565b60008060408385031215614ab157600080fd5b825160078110614ac057600080fd5b60208401519092506137db8161378856fea164736f6c6343000813000a", } var FunctionsCoordinatorABI = FunctionsCoordinatorMetaData.ABI @@ -211,9 +210,9 @@ func (_FunctionsCoordinator *FunctionsCoordinatorTransactorRaw) Transact(opts *b return _FunctionsCoordinator.Contract.contract.Transact(opts, method, params...) } -func (_FunctionsCoordinator *FunctionsCoordinatorCaller) EstimateCost(opts *bind.CallOpts, subscriptionId uint64, data []byte, callbackGasLimit uint32, gasPriceGwei *big.Int) (*big.Int, error) { +func (_FunctionsCoordinator *FunctionsCoordinatorCaller) EstimateCost(opts *bind.CallOpts, subscriptionId uint64, data []byte, callbackGasLimit uint32, gasPriceWei *big.Int) (*big.Int, error) { var out []interface{} - err := _FunctionsCoordinator.contract.Call(opts, &out, "estimateCost", subscriptionId, data, callbackGasLimit, gasPriceGwei) + err := _FunctionsCoordinator.contract.Call(opts, &out, "estimateCost", subscriptionId, data, callbackGasLimit, gasPriceWei) if err != nil { return *new(*big.Int), err @@ -225,12 +224,12 @@ func (_FunctionsCoordinator *FunctionsCoordinatorCaller) EstimateCost(opts *bind } -func (_FunctionsCoordinator *FunctionsCoordinatorSession) EstimateCost(subscriptionId uint64, data []byte, callbackGasLimit uint32, gasPriceGwei *big.Int) (*big.Int, error) { - return _FunctionsCoordinator.Contract.EstimateCost(&_FunctionsCoordinator.CallOpts, subscriptionId, data, callbackGasLimit, gasPriceGwei) +func (_FunctionsCoordinator *FunctionsCoordinatorSession) EstimateCost(subscriptionId uint64, data []byte, callbackGasLimit uint32, gasPriceWei *big.Int) (*big.Int, error) { + return _FunctionsCoordinator.Contract.EstimateCost(&_FunctionsCoordinator.CallOpts, subscriptionId, data, callbackGasLimit, gasPriceWei) } -func (_FunctionsCoordinator *FunctionsCoordinatorCallerSession) EstimateCost(subscriptionId uint64, data []byte, callbackGasLimit uint32, gasPriceGwei *big.Int) (*big.Int, error) { - return _FunctionsCoordinator.Contract.EstimateCost(&_FunctionsCoordinator.CallOpts, subscriptionId, data, callbackGasLimit, gasPriceGwei) +func (_FunctionsCoordinator *FunctionsCoordinatorCallerSession) EstimateCost(subscriptionId uint64, data []byte, callbackGasLimit uint32, gasPriceWei *big.Int) (*big.Int, error) { + return _FunctionsCoordinator.Contract.EstimateCost(&_FunctionsCoordinator.CallOpts, subscriptionId, data, callbackGasLimit, gasPriceWei) } func (_FunctionsCoordinator *FunctionsCoordinatorCaller) GetAdminFee(opts *bind.CallOpts) (*big.Int, error) { @@ -1690,7 +1689,7 @@ func (FunctionsCoordinatorConfigSet) Topic() common.Hash { } func (FunctionsCoordinatorConfigUpdated) Topic() common.Hash { - return common.HexToHash("0x5b6e2e1a03ea742ce04ca36d0175411a0772f99ef4ee84aeb9868a1ef6ddc82c") + return common.HexToHash("0x8efd15b0efe82b55a8dc915f88e835007cc65ad0b442997d3c10604961e3907a") } func (FunctionsCoordinatorOracleRequest) Topic() common.Hash { @@ -1718,7 +1717,7 @@ func (_FunctionsCoordinator *FunctionsCoordinator) Address() common.Address { } type FunctionsCoordinatorInterface interface { - EstimateCost(opts *bind.CallOpts, subscriptionId uint64, data []byte, callbackGasLimit uint32, gasPriceGwei *big.Int) (*big.Int, error) + EstimateCost(opts *bind.CallOpts, subscriptionId uint64, data []byte, callbackGasLimit uint32, gasPriceWei *big.Int) (*big.Int, error) GetAdminFee(opts *bind.CallOpts) (*big.Int, error) diff --git a/core/gethwrappers/functions/generated/functions_load_test_client/functions_load_test_client.go b/core/gethwrappers/functions/generated/functions_load_test_client/functions_load_test_client.go index d4f8d1fc7e6..37a895fe8cd 100644 --- a/core/gethwrappers/functions/generated/functions_load_test_client/functions_load_test_client.go +++ b/core/gethwrappers/functions/generated/functions_load_test_client/functions_load_test_client.go @@ -31,8 +31,8 @@ var ( ) var FunctionsLoadTestClientMetaData = &bind.MetaData{ - ABI: "[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"router\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"EmptyArgs\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"EmptySecrets\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"EmptySource\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"NoInlineSecrets\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyRouterCanFulfill\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"OwnershipTransferRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"id\",\"type\":\"bytes32\"}],\"name\":\"RequestFulfilled\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"id\",\"type\":\"bytes32\"}],\"name\":\"RequestSent\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"MAX_CALLBACK_GAS\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"acceptOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getStats\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"},{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"requestId\",\"type\":\"bytes32\"},{\"internalType\":\"bytes\",\"name\":\"response\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"err\",\"type\":\"bytes\"}],\"name\":\"handleOracleFulfillment\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"lastError\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"lastRequestID\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"lastResponse\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"resetStats\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"times\",\"type\":\"uint32\"},{\"internalType\":\"string\",\"name\":\"source\",\"type\":\"string\"},{\"internalType\":\"bytes\",\"name\":\"encryptedSecretsReferences\",\"type\":\"bytes\"},{\"internalType\":\"string[]\",\"name\":\"args\",\"type\":\"string[]\"},{\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"},{\"internalType\":\"bytes32\",\"name\":\"jobId\",\"type\":\"bytes32\"}],\"name\":\"sendRequest\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"totalEmptyResponses\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"totalFailedResponses\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"totalRequests\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"totalSucceededResponses\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", - Bin: "0x60a06040523480156200001157600080fd5b5060405162001cc238038062001cc2833981016040819052620000349162000180565b6001600160a01b0381166080523380600081620000985760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b0384811691909117909155811615620000cb57620000cb81620000d5565b50505050620001b2565b336001600160a01b038216036200012f5760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c6600000000000000000060448201526064016200008f565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b6000602082840312156200019357600080fd5b81516001600160a01b0381168114620001ab57600080fd5b9392505050565b608051611aed620001d56000396000818161027e0152610c220152611aed6000f3fe608060405234801561001057600080fd5b50600436106100f55760003560e01c8063724ec8a2116100975780638da5cb5b116100665780638da5cb5b146101c3578063c59d4847146101eb578063c9429e2a14610233578063f2fde38b1461025357600080fd5b8063724ec8a21461019057806379ba509714610198578063887efe94146101a05780638aea61dc146101b357600080fd5b806347c03186116100d357806347c031861461015c5780635c1d92e91461016557806362747e421461017d5780636d9809a01461018657600080fd5b80630ca76175146100fa57806329f0de3f1461010f5780632ab424da1461012b575b600080fd5b61010d6101083660046114e5565b610266565b005b61011860045481565b6040519081526020015b60405180910390f35b6005546101479068010000000000000000900463ffffffff1681565b60405163ffffffff9091168152602001610122565b61011860025481565b60055461014790640100000000900463ffffffff1681565b61011860035481565b6101476201117081565b61010d6102e5565b61010d610326565b61010d6101ae3660046115fd565b610428565b6005546101479063ffffffff1681565b60005460405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610122565b6101f36105a2565b6040805197885260208801969096529486019390935263ffffffff91821660608601528116608085015290811660a08401521660c082015260e001610122565b600554610147906c01000000000000000000000000900463ffffffff1681565b61010d6102613660046116cc565b610607565b3373ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016146102d5576040517fc6829f8300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6102e083838361061b565b505050565b6102ed610723565b600060028190556003819055600455600580547fffffffffffffffffffffffffffffffff00000000000000000000000000000000169055565b60015473ffffffffffffffffffffffffffffffffffffffff1633146103ac576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e65720000000000000000000060448201526064015b60405180910390fd5b60008054337fffffffffffffffffffffffff00000000000000000000000000000000000000008083168217845560018054909116905560405173ffffffffffffffffffffffffffffffffffffffff90921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b610430610723565b6104796040805161010081019091528060008152602001600081526020016000815260200160608152602001606081526020016060815260200160608152602001606081525090565b6104bb89898080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525085939250506107a69050565b85156105035761050387878080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525085939250506107b79050565b831561051d5761051d6105168587611702565b8290610801565b60005b8a63ffffffff168110156105955761054561053a83610844565b856201117086610c1d565b600255600580546001919060009061056490849063ffffffff166117c9565b92506101000a81548163ffffffff021916908363ffffffff160217905550808061058d906117ed565b915050610520565b5050505050505050505050565b60008060008060008060006105b5610723565b50506002546003546004546005549298919750955063ffffffff8083169550680100000000000000008304811694506c0100000000000000000000000083048116935064010000000090920490911690565b61060f610723565b61061881610cfc565b50565b600283905561062982610df1565b60035561063581610df1565b6004558151600003610682576001600560048282829054906101000a900463ffffffff1661066391906117c9565b92506101000a81548163ffffffff021916908363ffffffff1602179055505b8051156106ca5760016005600c8282829054906101000a900463ffffffff166106ab91906117c9565b92506101000a81548163ffffffff021916908363ffffffff1602179055505b8151158015906106d957508051155b156102e0576001600560088282829054906101000a900463ffffffff1661070091906117c9565b92506101000a81548163ffffffff021916908363ffffffff160217905550505050565b60005473ffffffffffffffffffffffffffffffffffffffff1633146107a4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e65720000000000000000000060448201526064016103a3565b565b6107b38260008084610e73565b5050565b80516000036107f2576040517fe889636f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60016020830152608090910152565b805160000361083c576040517ffe936cb700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60c090910152565b60606000610853610100610f0a565b905061089d6040518060400160405280600c81526020017f636f64654c6f636174696f6e000000000000000000000000000000000000000081525082610f2b90919063ffffffff16565b82516108bb9060028111156108b4576108b4611825565b8290610f44565b60408051808201909152600881527f6c616e677561676500000000000000000000000000000000000000000000000060208201526108fa908290610f2b565b60408301516109119080156108b4576108b4611825565b60408051808201909152600681527f736f7572636500000000000000000000000000000000000000000000000000006020820152610950908290610f2b565b6060830151610960908290610f2b565b60a083015151156109ba5760408051808201909152601081527f726571756573745369676e61747572650000000000000000000000000000000060208201526109aa908290610f2b565b60a08301516109ba908290610f79565b60c08301515115610a675760408051808201909152600481527f61726773000000000000000000000000000000000000000000000000000000006020820152610a04908290610f2b565b610a0d81610f86565b60005b8360c0015151811015610a5d57610a4d8460c001518281518110610a3657610a36611854565b602002602001015183610f2b90919063ffffffff16565b610a56816117ed565b9050610a10565b50610a6781610faa565b60808301515115610b6857600083602001516002811115610a8a57610a8a611825565b03610ac1576040517fa80d31f700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60408051808201909152600f81527f736563726574734c6f636174696f6e00000000000000000000000000000000006020820152610b00908290610f2b565b610b19836020015160028111156108b4576108b4611825565b60408051808201909152600781527f73656372657473000000000000000000000000000000000000000000000000006020820152610b58908290610f2b565b6080830151610b68908290610f79565b60e08301515115610c155760408051808201909152600981527f62797465734172677300000000000000000000000000000000000000000000006020820152610bb2908290610f2b565b610bbb81610f86565b60005b8360e0015151811015610c0b57610bfb8460e001518281518110610be457610be4611854565b602002602001015183610f7990919063ffffffff16565b610c04816117ed565b9050610bbe565b50610c1581610faa565b515192915050565b6000807f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663461d27628688600188886040518663ffffffff1660e01b8152600401610c82959493929190611883565b6020604051808303816000875af1158015610ca1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610cc59190611923565b60405190915081907f1131472297a800fee664d1d89cfa8f7676ff07189ecc53f80bbb5f4969099db890600090a295945050505050565b3373ffffffffffffffffffffffffffffffffffffffff821603610d7b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c6600000000000000000060448201526064016103a3565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b60008060209050602083511015610e06575081515b60005b81811015610e6c57610e1c81600861193c565b848281518110610e2e57610e2e611854565b01602001517fff0000000000000000000000000000000000000000000000000000000000000016901c9290921791610e65816117ed565b9050610e09565b5050919050565b8051600003610eae576040517f22ce3edd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b83836002811115610ec157610ec1611825565b90816002811115610ed457610ed4611825565b90525060408401828015610eea57610eea611825565b90818015610efa57610efa611825565b9052506060909301929092525050565b610f1261139c565b8051610f1e9083610fc8565b5060006020820152919050565b610f388260038351611042565b81516102e09082611169565b8151610f519060c2611191565b506107b38282604051602001610f6991815260200190565b6040516020818303038152906040525b610f388260028351611042565b610f918160046111fa565b600181602001818151610fa49190611953565b90525050565b610fb58160076111fa565b600181602001818151610fa49190611966565b604080518082019091526060815260006020820152610fe8602083611979565b1561101057610ff8602083611979565b611003906020611966565b61100d9083611953565b91505b60208084018390526040518085526000815290818401018181101561103457600080fd5b604052508290505b92915050565b60178167ffffffffffffffff161161106f5782516110699060e0600585901b168317611191565b50505050565b60ff8167ffffffffffffffff16116110b1578251611098906018611fe0600586901b1617611191565b5082516110699067ffffffffffffffff83166001611211565b61ffff8167ffffffffffffffff16116110f45782516110db906019611fe0600586901b1617611191565b5082516110699067ffffffffffffffff83166002611211565b63ffffffff8167ffffffffffffffff161161113957825161112090601a611fe0600586901b1617611191565b5082516110699067ffffffffffffffff83166004611211565b825161115090601b611fe0600586901b1617611191565b5082516110699067ffffffffffffffff83166008611211565b60408051808201909152606081526000602082015261118a83838451611296565b9392505050565b60408051808201909152606081526000602082015282515160006111b6826001611953565b9050846020015182106111d7576111d7856111d283600261193c565b611385565b84516020838201018581535080518211156111f0578181525b5093949350505050565b81516102e090601f611fe0600585901b1617611191565b60408051808201909152606081526000602082015283515160006112358285611953565b9050856020015181111561125257611252866111d283600261193c565b6000600161126286610100611ad4565b61126c9190611966565b9050865182810187831982511617815250805183111561128a578281525b50959695505050505050565b60408051808201909152606081526000602082015282518211156112b957600080fd5b83515160006112c88483611953565b905085602001518111156112e5576112e5866111d283600261193c565b8551805183820160200191600091808511156112ff578482525b505050602086015b6020861061133f578051825261131e602083611953565b915061132b602082611953565b9050611338602087611966565b9550611307565b5181517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60208890036101000a0190811690199190911617905250849150509392505050565b81516113918383610fc8565b506110698382611169565b60405180604001604052806113c4604051806040016040528060608152602001600081525090565b8152602001600081525090565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715611447576114476113d1565b604052919050565b600067ffffffffffffffff831115611469576114696113d1565b61149a60207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f86011601611400565b90508281528383830111156114ae57600080fd5b828260208301376000602084830101529392505050565b600082601f8301126114d657600080fd5b61118a8383356020850161144f565b6000806000606084860312156114fa57600080fd5b83359250602084013567ffffffffffffffff8082111561151957600080fd5b611525878388016114c5565b9350604086013591508082111561153b57600080fd5b50611548868287016114c5565b9150509250925092565b60008083601f84011261156457600080fd5b50813567ffffffffffffffff81111561157c57600080fd5b60208301915083602082850101111561159457600080fd5b9250929050565b60008083601f8401126115ad57600080fd5b50813567ffffffffffffffff8111156115c557600080fd5b6020830191508360208260051b850101111561159457600080fd5b803567ffffffffffffffff811681146115f857600080fd5b919050565b600080600080600080600080600060c08a8c03121561161b57600080fd5b893563ffffffff8116811461162f57600080fd5b985060208a013567ffffffffffffffff8082111561164c57600080fd5b6116588d838e01611552565b909a50985060408c013591508082111561167157600080fd5b61167d8d838e01611552565b909850965060608c013591508082111561169657600080fd5b506116a38c828d0161159b565b90955093506116b6905060808b016115e0565b915060a08a013590509295985092959850929598565b6000602082840312156116de57600080fd5b813573ffffffffffffffffffffffffffffffffffffffff8116811461118a57600080fd5b600067ffffffffffffffff8084111561171d5761171d6113d1565b8360051b602061172e818301611400565b86815291850191818101903684111561174657600080fd5b865b8481101561178e578035868111156117605760008081fd5b880136601f8201126117725760008081fd5b61178036823587840161144f565b845250918301918301611748565b50979650505050505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b63ffffffff8181168382160190808211156117e6576117e661179a565b5092915050565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff820361181e5761181e61179a565b5060010190565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b67ffffffffffffffff861681526000602060a08184015286518060a085015260005b818110156118c15788810183015185820160c0015282016118a5565b50600060c0828601015260c07fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8301168501019250505061190a604083018661ffff169052565b63ffffffff939093166060820152608001529392505050565b60006020828403121561193557600080fd5b5051919050565b808202811582820484141761103c5761103c61179a565b8082018082111561103c5761103c61179a565b8181038181111561103c5761103c61179a565b6000826119af577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500690565b600181815b80851115611a0d57817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff048211156119f3576119f361179a565b80851615611a0057918102915b93841c93908002906119b9565b509250929050565b600082611a245750600161103c565b81611a315750600061103c565b8160018114611a475760028114611a5157611a6d565b600191505061103c565b60ff841115611a6257611a6261179a565b50506001821b61103c565b5060208310610133831016604e8410600b8410161715611a90575081810a61103c565b611a9a83836119b4565b807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff04821115611acc57611acc61179a565b029392505050565b600061118a8383611a1556fea164736f6c6343000813000a", + ABI: "[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"router\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"EmptyArgs\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"EmptySecrets\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"EmptySource\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"NoInlineSecrets\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyRouterCanFulfill\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"OwnershipTransferRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"id\",\"type\":\"bytes32\"}],\"name\":\"RequestFulfilled\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"id\",\"type\":\"bytes32\"}],\"name\":\"RequestSent\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"MAX_CALLBACK_GAS\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"acceptOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getStats\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"},{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"},{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"requestId\",\"type\":\"bytes32\"},{\"internalType\":\"bytes\",\"name\":\"response\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"err\",\"type\":\"bytes\"}],\"name\":\"handleOracleFulfillment\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"lastError\",\"outputs\":[{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"lastRequestID\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"lastResponse\",\"outputs\":[{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"resetStats\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"times\",\"type\":\"uint32\"},{\"internalType\":\"bytes\",\"name\":\"cborEncodedRequest\",\"type\":\"bytes\"},{\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"},{\"internalType\":\"bytes32\",\"name\":\"donId\",\"type\":\"bytes32\"}],\"name\":\"sendEncodedRequest\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"times\",\"type\":\"uint32\"},{\"internalType\":\"string\",\"name\":\"source\",\"type\":\"string\"},{\"internalType\":\"bytes\",\"name\":\"encryptedSecretsReferences\",\"type\":\"bytes\"},{\"internalType\":\"string[]\",\"name\":\"args\",\"type\":\"string[]\"},{\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"},{\"internalType\":\"bytes32\",\"name\":\"donId\",\"type\":\"bytes32\"}],\"name\":\"sendRequest\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"times\",\"type\":\"uint32\"},{\"internalType\":\"string\",\"name\":\"source\",\"type\":\"string\"},{\"internalType\":\"uint8\",\"name\":\"slotId\",\"type\":\"uint8\"},{\"internalType\":\"uint64\",\"name\":\"slotVersion\",\"type\":\"uint64\"},{\"internalType\":\"string[]\",\"name\":\"args\",\"type\":\"string[]\"},{\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"},{\"internalType\":\"bytes32\",\"name\":\"donId\",\"type\":\"bytes32\"}],\"name\":\"sendRequestWithDONHostedSecrets\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"totalEmptyResponses\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"totalFailedResponses\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"totalRequests\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"totalSucceededResponses\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", + Bin: "0x60a06040523480156200001157600080fd5b50604051620023ff380380620023ff833981016040819052620000349162000180565b6001600160a01b0381166080523380600081620000985760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b0384811691909117909155811615620000cb57620000cb81620000d5565b50505050620001b2565b336001600160a01b038216036200012f5760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c6600000000000000000060448201526064016200008f565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b6000602082840312156200019357600080fd5b81516001600160a01b0381168114620001ab57600080fd5b9392505050565b60805161222a620001d5600039600081816102ac0152610fa0015261222a6000f3fe608060405234801561001057600080fd5b506004361061011b5760003560e01c806379ba5097116100b2578063954491c111610081578063c59d484711610066578063c59d484714610246578063c9429e2a14610261578063f2fde38b1461028157600080fd5b8063954491c114610220578063b2518e0e1461023357600080fd5b806379ba5097146101cd578063887efe94146101d55780638aea61dc146101e85780638da5cb5b146101f857600080fd5b80635c1d92e9116100ee5780635c1d92e91461019b57806362747e42146101b35780636d9809a0146101bb578063724ec8a2146101c557600080fd5b80630ca761751461012057806329f0de3f146101355780632ab424da1461015357806347c0318614610184575b600080fd5b61013361012e3660046118b4565b610294565b005b61013d61033e565b60405161014a9190611985565b60405180910390f35b60055461016f9068010000000000000000900463ffffffff1681565b60405163ffffffff909116815260200161014a565b61018d60025481565b60405190815260200161014a565b60055461016f90640100000000900463ffffffff1681565b61013d6103cc565b61016f6203d09081565b6101336103d9565b61013361044b565b6101336101e3366004611a57565b61054d565b60055461016f9063ffffffff1681565b60005460405173ffffffffffffffffffffffffffffffffffffffff909116815260200161014a565b61013361022e366004611b1b565b6106bf565b610133610241366004611be1565b6107d5565b61024e610854565b60405161014a9796959493929190611c47565b60055461016f906c01000000000000000000000000900463ffffffff1681565b61013361028f366004611ca4565b6109dc565b3373ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001614610303576040517fc6829f8300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61030e8383836109f0565b60405183907f85e1543bf2f84fe80c6badbce3648c8539ad1df4d2b3d822938ca0538be727e690600090a2505050565b6004805461034b90611cda565b80601f016020809104026020016040519081016040528092919081815260200182805461037790611cda565b80156103c45780601f10610399576101008083540402835291602001916103c4565b820191906000526020600020905b8154815290600101906020018083116103a757829003601f168201915b505050505081565b6003805461034b90611cda565b6103e1610afb565b6000600281905560408051602081019091529081526003906104039082611d7b565b506040805160208101909152600081526004906104209082611d7b565b50600580547fffffffffffffffffffffffffffffffff00000000000000000000000000000000169055565b60015473ffffffffffffffffffffffffffffffffffffffff1633146104d1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e65720000000000000000000060448201526064015b60405180910390fd5b60008054337fffffffffffffffffffffffff00000000000000000000000000000000000000008083168217845560018054909116905560405173ffffffffffffffffffffffffffffffffffffffff90921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b610555610afb565b6105966040805160e0810190915280600081526020016000815260200160008152602001606081526020016060815260200160608152602001606081525090565b6105d889898080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152508593925050610b7e9050565b85156106205761062087878080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152508593925050610b8f9050565b831561063a5761063a6106338587611e95565b8290610bd9565b60005b8a63ffffffff168110156106b25761066261065783610c1c565b856203d09086610f9b565b600255600580546001919060009061068190849063ffffffff16611f5c565b92506101000a81548163ffffffff021916908363ffffffff16021790555080806106aa90611f80565b91505061063d565b5050505050505050505050565b6106c7610afb565b6107086040805160e0810190915280600081526020016000815260200160008152602001606081526020016060815260200160608152602001606081525090565b61074a89898080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152508593925050610b7e9050565b61075581888861107a565b8315610768576107686106338587611e95565b60005b8a63ffffffff168110156106b25761078561065783610c1c565b60025560058054600191906000906107a490849063ffffffff16611f5c565b92506101000a81548163ffffffff021916908363ffffffff16021790555080806107cd90611f80565b91505061076b565b6107dd610afb565b60005b8463ffffffff1681101561084d576107fd84846203d09085610f9b565b600255600580546001919060009061081c90849063ffffffff16611f5c565b92506101000a81548163ffffffff021916908363ffffffff160217905550808061084590611f80565b9150506107e0565b5050505050565b6000606080600080600080610867610afb565b60025460055460038054909160049163ffffffff808316926801000000000000000081048216926c0100000000000000000000000082048316926401000000009092049091169086906108b990611cda565b80601f01602080910402602001604051908101604052809291908181526020018280546108e590611cda565b80156109325780601f1061090757610100808354040283529160200191610932565b820191906000526020600020905b81548152906001019060200180831161091557829003601f168201915b5050505050955084805461094590611cda565b80601f016020809104026020016040519081016040528092919081815260200182805461097190611cda565b80156109be5780601f10610993576101008083540402835291602001916109be565b820191906000526020600020905b8154815290600101906020018083116109a157829003601f168201915b50505050509450965096509650965096509650965090919293949596565b6109e4610afb565b6109ed8161113d565b50565b60028390556003610a018382611d7b565b506004610a0e8282611d7b565b508151600003610a59576001600560048282829054906101000a900463ffffffff16610a3a9190611f5c565b92506101000a81548163ffffffff021916908363ffffffff1602179055505b805115610aa15760016005600c8282829054906101000a900463ffffffff16610a829190611f5c565b92506101000a81548163ffffffff021916908363ffffffff1602179055505b815115801590610ab057508051155b15610af6576001600560088282829054906101000a900463ffffffff16610ad79190611f5c565b92506101000a81548163ffffffff021916908363ffffffff1602179055505b505050565b60005473ffffffffffffffffffffffffffffffffffffffff163314610b7c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e65720000000000000000000060448201526064016104c8565b565b610b8b8260008084611232565b5050565b8051600003610bca576040517fe889636f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60016020830152608090910152565b8051600003610c14576040517ffe936cb700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60a090910152565b60606000610c2b6101006112c9565b9050610c756040518060400160405280600c81526020017f636f64654c6f636174696f6e0000000000000000000000000000000000000000815250826112ea90919063ffffffff16565b8251610c93906002811115610c8c57610c8c611fb8565b8290611303565b60408051808201909152600881527f6c616e67756167650000000000000000000000000000000000000000000000006020820152610cd29082906112ea565b6040830151610ce9908015610c8c57610c8c611fb8565b60408051808201909152600681527f736f7572636500000000000000000000000000000000000000000000000000006020820152610d289082906112ea565b6060830151610d389082906112ea565b60a08301515115610de55760408051808201909152600481527f61726773000000000000000000000000000000000000000000000000000000006020820152610d829082906112ea565b610d8b8161133c565b60005b8360a0015151811015610ddb57610dcb8460a001518281518110610db457610db4611fe7565b6020026020010151836112ea90919063ffffffff16565b610dd481611f80565b9050610d8e565b50610de581611360565b60808301515115610ee657600083602001516002811115610e0857610e08611fb8565b03610e3f576040517fa80d31f700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60408051808201909152600f81527f736563726574734c6f636174696f6e00000000000000000000000000000000006020820152610e7e9082906112ea565b610e9783602001516002811115610c8c57610c8c611fb8565b60408051808201909152600781527f73656372657473000000000000000000000000000000000000000000000000006020820152610ed69082906112ea565b6080830151610ee690829061137e565b60c08301515115610f935760408051808201909152600981527f62797465734172677300000000000000000000000000000000000000000000006020820152610f309082906112ea565b610f398161133c565b60005b8360c0015151811015610f8957610f798460c001518281518110610f6257610f62611fe7565b60200260200101518361137e90919063ffffffff16565b610f8281611f80565b9050610f3c565b50610f9381611360565b515192915050565b6000807f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663461d27628688600188886040518663ffffffff1660e01b8152600401611000959493929190612016565b6020604051808303816000875af115801561101f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110439190612060565b60405190915081907f1131472297a800fee664d1d89cfa8f7676ff07189ecc53f80bbb5f4969099db890600090a295945050505050565b60006110876101006112c9565b90506110d16040518060400160405280600681526020017f736c6f7449440000000000000000000000000000000000000000000000000000815250826112ea90919063ffffffff16565b6110de8160ff851661138b565b60408051808201909152600781527f76657273696f6e00000000000000000000000000000000000000000000000000602082015261111d9082906112ea565b611127818361138b565b6002602085015251516080909301929092525050565b3373ffffffffffffffffffffffffffffffffffffffff8216036111bc576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c6600000000000000000060448201526064016104c8565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b805160000361126d576040517f22ce3edd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8383600281111561128057611280611fb8565b9081600281111561129357611293611fb8565b905250604084018280156112a9576112a9611fb8565b908180156112b9576112b9611fb8565b9052506060909301929092525050565b6112d161176b565b80516112dd9083611397565b5060006020820152919050565b6112f78260038351611411565b8151610af69082611538565b81516113109060c2611560565b50610b8b828260405160200161132891815260200190565b60405160208183030381529060405261137e565b6113478160046115c9565b60018160200181815161135a9190612079565b90525050565b61136b8160076115c9565b60018160200181815161135a919061208c565b6112f78260028351611411565b610b8b82600083611411565b6040805180820190915260608152600060208201526113b760208361209f565b156113df576113c760208361209f565b6113d290602061208c565b6113dc9083612079565b91505b60208084018390526040518085526000815290818401018181101561140357600080fd5b604052508290505b92915050565b60178167ffffffffffffffff161161143e5782516114389060e0600585901b168317611560565b50505050565b60ff8167ffffffffffffffff1611611480578251611467906018611fe0600586901b1617611560565b5082516114389067ffffffffffffffff831660016115e0565b61ffff8167ffffffffffffffff16116114c35782516114aa906019611fe0600586901b1617611560565b5082516114389067ffffffffffffffff831660026115e0565b63ffffffff8167ffffffffffffffff16116115085782516114ef90601a611fe0600586901b1617611560565b5082516114389067ffffffffffffffff831660046115e0565b825161151f90601b611fe0600586901b1617611560565b5082516114389067ffffffffffffffff831660086115e0565b60408051808201909152606081526000602082015261155983838451611665565b9392505050565b6040805180820190915260608152600060208201528251516000611585826001612079565b9050846020015182106115a6576115a6856115a18360026120da565b611754565b84516020838201018581535080518211156115bf578181525b5093949350505050565b8151610af690601f611fe0600585901b1617611560565b60408051808201909152606081526000602082015283515160006116048285612079565b9050856020015181111561162157611621866115a18360026120da565b6000600161163186610100612211565b61163b919061208c565b90508651828101878319825116178152508051831115611659578281525b50959695505050505050565b604080518082019091526060815260006020820152825182111561168857600080fd5b83515160006116978483612079565b905085602001518111156116b4576116b4866115a18360026120da565b8551805183820160200191600091808511156116ce578482525b505050602086015b6020861061170e57805182526116ed602083612079565b91506116fa602082612079565b905061170760208761208c565b95506116d6565b5181517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60208890036101000a0190811690199190911617905250849150509392505050565b81516117608383611397565b506114388382611538565b6040518060400160405280611793604051806040016040528060608152602001600081525090565b8152602001600081525090565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715611816576118166117a0565b604052919050565b600067ffffffffffffffff831115611838576118386117a0565b61186960207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f860116016117cf565b905082815283838301111561187d57600080fd5b828260208301376000602084830101529392505050565b600082601f8301126118a557600080fd5b6115598383356020850161181e565b6000806000606084860312156118c957600080fd5b83359250602084013567ffffffffffffffff808211156118e857600080fd5b6118f487838801611894565b9350604086013591508082111561190a57600080fd5b5061191786828701611894565b9150509250925092565b6000815180845260005b818110156119475760208185018101518683018201520161192b565b5060006020828601015260207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f83011685010191505092915050565b6020815260006115596020830184611921565b803563ffffffff811681146119ac57600080fd5b919050565b60008083601f8401126119c357600080fd5b50813567ffffffffffffffff8111156119db57600080fd5b6020830191508360208285010111156119f357600080fd5b9250929050565b60008083601f840112611a0c57600080fd5b50813567ffffffffffffffff811115611a2457600080fd5b6020830191508360208260051b85010111156119f357600080fd5b803567ffffffffffffffff811681146119ac57600080fd5b600080600080600080600080600060c08a8c031215611a7557600080fd5b611a7e8a611998565b985060208a013567ffffffffffffffff80821115611a9b57600080fd5b611aa78d838e016119b1565b909a50985060408c0135915080821115611ac057600080fd5b611acc8d838e016119b1565b909850965060608c0135915080821115611ae557600080fd5b50611af28c828d016119fa565b9095509350611b05905060808b01611a3f565b915060a08a013590509295985092959850929598565b600080600080600080600080600060e08a8c031215611b3957600080fd5b611b428a611998565b985060208a013567ffffffffffffffff80821115611b5f57600080fd5b611b6b8d838e016119b1565b909a50985060408c0135915060ff82168214611b8657600080fd5b819750611b9560608d01611a3f565b965060808c0135915080821115611bab57600080fd5b50611bb88c828d016119fa565b9095509350611bcb905060a08b01611a3f565b915060c08a013590509295985092959850929598565b60008060008060808587031215611bf757600080fd5b611c0085611998565b9350602085013567ffffffffffffffff811115611c1c57600080fd5b611c2887828801611894565b935050611c3760408601611a3f565b9396929550929360600135925050565b87815260e060208201526000611c6060e0830189611921565b8281036040840152611c728189611921565b63ffffffff97881660608501529587166080840152505091841660a083015290921660c0909201919091529392505050565b600060208284031215611cb657600080fd5b813573ffffffffffffffffffffffffffffffffffffffff8116811461155957600080fd5b600181811c90821680611cee57607f821691505b602082108103611d27577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b50919050565b601f821115610af657600081815260208120601f850160051c81016020861015611d545750805b601f850160051c820191505b81811015611d7357828155600101611d60565b505050505050565b815167ffffffffffffffff811115611d9557611d956117a0565b611da981611da38454611cda565b84611d2d565b602080601f831160018114611dfc5760008415611dc65750858301515b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600386901b1c1916600185901b178555611d73565b6000858152602081207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08616915b82811015611e4957888601518255948401946001909101908401611e2a565b5085821015611e8557878501517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600388901b60f8161c191681555b5050505050600190811b01905550565b600067ffffffffffffffff80841115611eb057611eb06117a0565b8360051b6020611ec18183016117cf565b868152918501918181019036841115611ed957600080fd5b865b84811015611f2157803586811115611ef35760008081fd5b880136601f820112611f055760008081fd5b611f1336823587840161181e565b845250918301918301611edb565b50979650505050505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b63ffffffff818116838216019080821115611f7957611f79611f2d565b5092915050565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203611fb157611fb1611f2d565b5060010190565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b67ffffffffffffffff8616815260a06020820152600061203960a0830187611921565b61ffff9590951660408301525063ffffffff92909216606083015260809091015292915050565b60006020828403121561207257600080fd5b5051919050565b8082018082111561140b5761140b611f2d565b8181038181111561140b5761140b611f2d565b6000826120d5577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500690565b808202811582820484141761140b5761140b611f2d565b600181815b8085111561214a57817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0482111561213057612130611f2d565b8085161561213d57918102915b93841c93908002906120f6565b509250929050565b6000826121615750600161140b565b8161216e5750600061140b565b8160018114612184576002811461218e576121aa565b600191505061140b565b60ff84111561219f5761219f611f2d565b50506001821b61140b565b5060208310610133831016604e8410600b84101617156121cd575081810a61140b565b6121d783836120f1565b807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0482111561220957612209611f2d565b029392505050565b6000611559838361215256fea164736f6c6343000813000a", } var FunctionsLoadTestClientABI = FunctionsLoadTestClientMetaData.ABI @@ -193,17 +193,17 @@ func (_FunctionsLoadTestClient *FunctionsLoadTestClientCallerSession) MAXCALLBAC return _FunctionsLoadTestClient.Contract.MAXCALLBACKGAS(&_FunctionsLoadTestClient.CallOpts) } -func (_FunctionsLoadTestClient *FunctionsLoadTestClientCaller) GetStats(opts *bind.CallOpts) ([32]byte, [32]byte, [32]byte, uint32, uint32, uint32, uint32, error) { +func (_FunctionsLoadTestClient *FunctionsLoadTestClientCaller) GetStats(opts *bind.CallOpts) ([32]byte, []byte, []byte, uint32, uint32, uint32, uint32, error) { var out []interface{} err := _FunctionsLoadTestClient.contract.Call(opts, &out, "getStats") if err != nil { - return *new([32]byte), *new([32]byte), *new([32]byte), *new(uint32), *new(uint32), *new(uint32), *new(uint32), err + return *new([32]byte), *new([]byte), *new([]byte), *new(uint32), *new(uint32), *new(uint32), *new(uint32), err } out0 := *abi.ConvertType(out[0], new([32]byte)).(*[32]byte) - out1 := *abi.ConvertType(out[1], new([32]byte)).(*[32]byte) - out2 := *abi.ConvertType(out[2], new([32]byte)).(*[32]byte) + out1 := *abi.ConvertType(out[1], new([]byte)).(*[]byte) + out2 := *abi.ConvertType(out[2], new([]byte)).(*[]byte) out3 := *abi.ConvertType(out[3], new(uint32)).(*uint32) out4 := *abi.ConvertType(out[4], new(uint32)).(*uint32) out5 := *abi.ConvertType(out[5], new(uint32)).(*uint32) @@ -213,33 +213,33 @@ func (_FunctionsLoadTestClient *FunctionsLoadTestClientCaller) GetStats(opts *bi } -func (_FunctionsLoadTestClient *FunctionsLoadTestClientSession) GetStats() ([32]byte, [32]byte, [32]byte, uint32, uint32, uint32, uint32, error) { +func (_FunctionsLoadTestClient *FunctionsLoadTestClientSession) GetStats() ([32]byte, []byte, []byte, uint32, uint32, uint32, uint32, error) { return _FunctionsLoadTestClient.Contract.GetStats(&_FunctionsLoadTestClient.CallOpts) } -func (_FunctionsLoadTestClient *FunctionsLoadTestClientCallerSession) GetStats() ([32]byte, [32]byte, [32]byte, uint32, uint32, uint32, uint32, error) { +func (_FunctionsLoadTestClient *FunctionsLoadTestClientCallerSession) GetStats() ([32]byte, []byte, []byte, uint32, uint32, uint32, uint32, error) { return _FunctionsLoadTestClient.Contract.GetStats(&_FunctionsLoadTestClient.CallOpts) } -func (_FunctionsLoadTestClient *FunctionsLoadTestClientCaller) LastError(opts *bind.CallOpts) ([32]byte, error) { +func (_FunctionsLoadTestClient *FunctionsLoadTestClientCaller) LastError(opts *bind.CallOpts) ([]byte, error) { var out []interface{} err := _FunctionsLoadTestClient.contract.Call(opts, &out, "lastError") if err != nil { - return *new([32]byte), err + return *new([]byte), err } - out0 := *abi.ConvertType(out[0], new([32]byte)).(*[32]byte) + out0 := *abi.ConvertType(out[0], new([]byte)).(*[]byte) return out0, err } -func (_FunctionsLoadTestClient *FunctionsLoadTestClientSession) LastError() ([32]byte, error) { +func (_FunctionsLoadTestClient *FunctionsLoadTestClientSession) LastError() ([]byte, error) { return _FunctionsLoadTestClient.Contract.LastError(&_FunctionsLoadTestClient.CallOpts) } -func (_FunctionsLoadTestClient *FunctionsLoadTestClientCallerSession) LastError() ([32]byte, error) { +func (_FunctionsLoadTestClient *FunctionsLoadTestClientCallerSession) LastError() ([]byte, error) { return _FunctionsLoadTestClient.Contract.LastError(&_FunctionsLoadTestClient.CallOpts) } @@ -265,25 +265,25 @@ func (_FunctionsLoadTestClient *FunctionsLoadTestClientCallerSession) LastReques return _FunctionsLoadTestClient.Contract.LastRequestID(&_FunctionsLoadTestClient.CallOpts) } -func (_FunctionsLoadTestClient *FunctionsLoadTestClientCaller) LastResponse(opts *bind.CallOpts) ([32]byte, error) { +func (_FunctionsLoadTestClient *FunctionsLoadTestClientCaller) LastResponse(opts *bind.CallOpts) ([]byte, error) { var out []interface{} err := _FunctionsLoadTestClient.contract.Call(opts, &out, "lastResponse") if err != nil { - return *new([32]byte), err + return *new([]byte), err } - out0 := *abi.ConvertType(out[0], new([32]byte)).(*[32]byte) + out0 := *abi.ConvertType(out[0], new([]byte)).(*[]byte) return out0, err } -func (_FunctionsLoadTestClient *FunctionsLoadTestClientSession) LastResponse() ([32]byte, error) { +func (_FunctionsLoadTestClient *FunctionsLoadTestClientSession) LastResponse() ([]byte, error) { return _FunctionsLoadTestClient.Contract.LastResponse(&_FunctionsLoadTestClient.CallOpts) } -func (_FunctionsLoadTestClient *FunctionsLoadTestClientCallerSession) LastResponse() ([32]byte, error) { +func (_FunctionsLoadTestClient *FunctionsLoadTestClientCallerSession) LastResponse() ([]byte, error) { return _FunctionsLoadTestClient.Contract.LastResponse(&_FunctionsLoadTestClient.CallOpts) } @@ -433,16 +433,40 @@ func (_FunctionsLoadTestClient *FunctionsLoadTestClientTransactorSession) ResetS return _FunctionsLoadTestClient.Contract.ResetStats(&_FunctionsLoadTestClient.TransactOpts) } -func (_FunctionsLoadTestClient *FunctionsLoadTestClientTransactor) SendRequest(opts *bind.TransactOpts, times uint32, source string, encryptedSecretsReferences []byte, args []string, subscriptionId uint64, jobId [32]byte) (*types.Transaction, error) { - return _FunctionsLoadTestClient.contract.Transact(opts, "sendRequest", times, source, encryptedSecretsReferences, args, subscriptionId, jobId) +func (_FunctionsLoadTestClient *FunctionsLoadTestClientTransactor) SendEncodedRequest(opts *bind.TransactOpts, times uint32, cborEncodedRequest []byte, subscriptionId uint64, donId [32]byte) (*types.Transaction, error) { + return _FunctionsLoadTestClient.contract.Transact(opts, "sendEncodedRequest", times, cborEncodedRequest, subscriptionId, donId) +} + +func (_FunctionsLoadTestClient *FunctionsLoadTestClientSession) SendEncodedRequest(times uint32, cborEncodedRequest []byte, subscriptionId uint64, donId [32]byte) (*types.Transaction, error) { + return _FunctionsLoadTestClient.Contract.SendEncodedRequest(&_FunctionsLoadTestClient.TransactOpts, times, cborEncodedRequest, subscriptionId, donId) +} + +func (_FunctionsLoadTestClient *FunctionsLoadTestClientTransactorSession) SendEncodedRequest(times uint32, cborEncodedRequest []byte, subscriptionId uint64, donId [32]byte) (*types.Transaction, error) { + return _FunctionsLoadTestClient.Contract.SendEncodedRequest(&_FunctionsLoadTestClient.TransactOpts, times, cborEncodedRequest, subscriptionId, donId) +} + +func (_FunctionsLoadTestClient *FunctionsLoadTestClientTransactor) SendRequest(opts *bind.TransactOpts, times uint32, source string, encryptedSecretsReferences []byte, args []string, subscriptionId uint64, donId [32]byte) (*types.Transaction, error) { + return _FunctionsLoadTestClient.contract.Transact(opts, "sendRequest", times, source, encryptedSecretsReferences, args, subscriptionId, donId) +} + +func (_FunctionsLoadTestClient *FunctionsLoadTestClientSession) SendRequest(times uint32, source string, encryptedSecretsReferences []byte, args []string, subscriptionId uint64, donId [32]byte) (*types.Transaction, error) { + return _FunctionsLoadTestClient.Contract.SendRequest(&_FunctionsLoadTestClient.TransactOpts, times, source, encryptedSecretsReferences, args, subscriptionId, donId) +} + +func (_FunctionsLoadTestClient *FunctionsLoadTestClientTransactorSession) SendRequest(times uint32, source string, encryptedSecretsReferences []byte, args []string, subscriptionId uint64, donId [32]byte) (*types.Transaction, error) { + return _FunctionsLoadTestClient.Contract.SendRequest(&_FunctionsLoadTestClient.TransactOpts, times, source, encryptedSecretsReferences, args, subscriptionId, donId) } -func (_FunctionsLoadTestClient *FunctionsLoadTestClientSession) SendRequest(times uint32, source string, encryptedSecretsReferences []byte, args []string, subscriptionId uint64, jobId [32]byte) (*types.Transaction, error) { - return _FunctionsLoadTestClient.Contract.SendRequest(&_FunctionsLoadTestClient.TransactOpts, times, source, encryptedSecretsReferences, args, subscriptionId, jobId) +func (_FunctionsLoadTestClient *FunctionsLoadTestClientTransactor) SendRequestWithDONHostedSecrets(opts *bind.TransactOpts, times uint32, source string, slotId uint8, slotVersion uint64, args []string, subscriptionId uint64, donId [32]byte) (*types.Transaction, error) { + return _FunctionsLoadTestClient.contract.Transact(opts, "sendRequestWithDONHostedSecrets", times, source, slotId, slotVersion, args, subscriptionId, donId) } -func (_FunctionsLoadTestClient *FunctionsLoadTestClientTransactorSession) SendRequest(times uint32, source string, encryptedSecretsReferences []byte, args []string, subscriptionId uint64, jobId [32]byte) (*types.Transaction, error) { - return _FunctionsLoadTestClient.Contract.SendRequest(&_FunctionsLoadTestClient.TransactOpts, times, source, encryptedSecretsReferences, args, subscriptionId, jobId) +func (_FunctionsLoadTestClient *FunctionsLoadTestClientSession) SendRequestWithDONHostedSecrets(times uint32, source string, slotId uint8, slotVersion uint64, args []string, subscriptionId uint64, donId [32]byte) (*types.Transaction, error) { + return _FunctionsLoadTestClient.Contract.SendRequestWithDONHostedSecrets(&_FunctionsLoadTestClient.TransactOpts, times, source, slotId, slotVersion, args, subscriptionId, donId) +} + +func (_FunctionsLoadTestClient *FunctionsLoadTestClientTransactorSession) SendRequestWithDONHostedSecrets(times uint32, source string, slotId uint8, slotVersion uint64, args []string, subscriptionId uint64, donId [32]byte) (*types.Transaction, error) { + return _FunctionsLoadTestClient.Contract.SendRequestWithDONHostedSecrets(&_FunctionsLoadTestClient.TransactOpts, times, source, slotId, slotVersion, args, subscriptionId, donId) } func (_FunctionsLoadTestClient *FunctionsLoadTestClientTransactor) TransferOwnership(opts *bind.TransactOpts, to common.Address) (*types.Transaction, error) { @@ -1022,13 +1046,13 @@ func (_FunctionsLoadTestClient *FunctionsLoadTestClient) Address() common.Addres type FunctionsLoadTestClientInterface interface { MAXCALLBACKGAS(opts *bind.CallOpts) (uint32, error) - GetStats(opts *bind.CallOpts) ([32]byte, [32]byte, [32]byte, uint32, uint32, uint32, uint32, error) + GetStats(opts *bind.CallOpts) ([32]byte, []byte, []byte, uint32, uint32, uint32, uint32, error) - LastError(opts *bind.CallOpts) ([32]byte, error) + LastError(opts *bind.CallOpts) ([]byte, error) LastRequestID(opts *bind.CallOpts) ([32]byte, error) - LastResponse(opts *bind.CallOpts) ([32]byte, error) + LastResponse(opts *bind.CallOpts) ([]byte, error) Owner(opts *bind.CallOpts) (common.Address, error) @@ -1046,7 +1070,11 @@ type FunctionsLoadTestClientInterface interface { ResetStats(opts *bind.TransactOpts) (*types.Transaction, error) - SendRequest(opts *bind.TransactOpts, times uint32, source string, encryptedSecretsReferences []byte, args []string, subscriptionId uint64, jobId [32]byte) (*types.Transaction, error) + SendEncodedRequest(opts *bind.TransactOpts, times uint32, cborEncodedRequest []byte, subscriptionId uint64, donId [32]byte) (*types.Transaction, error) + + SendRequest(opts *bind.TransactOpts, times uint32, source string, encryptedSecretsReferences []byte, args []string, subscriptionId uint64, donId [32]byte) (*types.Transaction, error) + + SendRequestWithDONHostedSecrets(opts *bind.TransactOpts, times uint32, source string, slotId uint8, slotVersion uint64, args []string, subscriptionId uint64, donId [32]byte) (*types.Transaction, error) TransferOwnership(opts *bind.TransactOpts, to common.Address) (*types.Transaction, error) diff --git a/core/gethwrappers/functions/generated/functions_router/functions_router.go b/core/gethwrappers/functions/generated/functions_router/functions_router.go index 83c3f9b6132..2c482048c49 100644 --- a/core/gethwrappers/functions/generated/functions_router/functions_router.go +++ b/core/gethwrappers/functions/generated/functions_router/functions_router.go @@ -45,11 +45,13 @@ type FunctionsResponseCommitment struct { } type FunctionsRouterConfig struct { - MaxConsumersPerSubscription uint16 - AdminFee *big.Int - HandleOracleFulfillmentSelector [4]byte - GasForCallExactCheck uint16 - MaxCallbackGasLimits []uint32 + MaxConsumersPerSubscription uint16 + AdminFee *big.Int + HandleOracleFulfillmentSelector [4]byte + GasForCallExactCheck uint16 + MaxCallbackGasLimits []uint32 + SubscriptionDepositMinimumRequests uint16 + SubscriptionDepositJuels *big.Int } type IFunctionsSubscriptionsConsumer struct { @@ -68,8 +70,8 @@ type IFunctionsSubscriptionsSubscription struct { } var FunctionsRouterMetaData = &bind.MetaData{ - ABI: "[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"linkToken\",\"type\":\"address\"},{\"components\":[{\"internalType\":\"uint16\",\"name\":\"maxConsumersPerSubscription\",\"type\":\"uint16\"},{\"internalType\":\"uint72\",\"name\":\"adminFee\",\"type\":\"uint72\"},{\"internalType\":\"bytes4\",\"name\":\"handleOracleFulfillmentSelector\",\"type\":\"bytes4\"},{\"internalType\":\"uint16\",\"name\":\"gasForCallExactCheck\",\"type\":\"uint16\"},{\"internalType\":\"uint32[]\",\"name\":\"maxCallbackGasLimits\",\"type\":\"uint32[]\"}],\"internalType\":\"structFunctionsRouter.Config\",\"name\":\"config\",\"type\":\"tuple\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"CannotRemoveWithPendingRequests\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"EmptyRequestData\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"limit\",\"type\":\"uint32\"}],\"name\":\"GasLimitTooBig\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"id\",\"type\":\"bytes32\"}],\"name\":\"IdentifierIsReserved\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint96\",\"name\":\"currentBalanceJuels\",\"type\":\"uint96\"}],\"name\":\"InsufficientBalance\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidCalldata\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidConsumer\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint8\",\"name\":\"value\",\"type\":\"uint8\"}],\"name\":\"InvalidGasFlagValue\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidProposal\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidSubscription\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"proposedOwner\",\"type\":\"address\"}],\"name\":\"MustBeProposedOwner\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"MustBeSubscriptionOwner\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableFromCoordinator\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableFromLink\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"id\",\"type\":\"bytes32\"}],\"name\":\"RouteNotFound\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"SenderMustAcceptTermsOfService\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"TimeoutNotExceeded\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint16\",\"name\":\"maximumConsumers\",\"type\":\"uint16\"}],\"name\":\"TooManyConsumers\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"totalBalance\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"deductionAttempt\",\"type\":\"uint256\"}],\"name\":\"TotalBalanceInvariantViolated\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"components\":[{\"internalType\":\"uint16\",\"name\":\"maxConsumersPerSubscription\",\"type\":\"uint16\"},{\"internalType\":\"uint72\",\"name\":\"adminFee\",\"type\":\"uint72\"},{\"internalType\":\"bytes4\",\"name\":\"handleOracleFulfillmentSelector\",\"type\":\"bytes4\"},{\"internalType\":\"uint16\",\"name\":\"gasForCallExactCheck\",\"type\":\"uint16\"},{\"internalType\":\"uint32[]\",\"name\":\"maxCallbackGasLimits\",\"type\":\"uint32[]\"}],\"indexed\":false,\"internalType\":\"structFunctionsRouter.Config\",\"name\":\"\",\"type\":\"tuple\"}],\"name\":\"ConfigUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"proposedContractSetId\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"proposedContractSetFromAddress\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"proposedContractSetToAddress\",\"type\":\"address\"}],\"name\":\"ContractProposed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"id\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"ContractUpdated\",\"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\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"Paused\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"requestId\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"coordinator\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"transmitter\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"enumFunctionsResponse.FulfillResult\",\"name\":\"resultCode\",\"type\":\"uint8\"}],\"name\":\"RequestNotProcessed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"requestId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"uint96\",\"name\":\"totalCostJuels\",\"type\":\"uint96\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"transmitter\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"enumFunctionsResponse.FulfillResult\",\"name\":\"resultCode\",\"type\":\"uint8\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"response\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"err\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"callbackReturnData\",\"type\":\"bytes\"}],\"name\":\"RequestProcessed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"requestId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"donId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"subscriptionOwner\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"requestingContract\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"requestInitiator\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"uint16\",\"name\":\"dataVersion\",\"type\":\"uint16\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"callbackGasLimit\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"uint96\",\"name\":\"estimatedTotalCostJuels\",\"type\":\"uint96\"}],\"name\":\"RequestStart\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"requestId\",\"type\":\"bytes32\"}],\"name\":\"RequestTimedOut\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"fundsRecipient\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"fundsAmount\",\"type\":\"uint256\"}],\"name\":\"SubscriptionCanceled\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"consumer\",\"type\":\"address\"}],\"name\":\"SubscriptionConsumerAdded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"consumer\",\"type\":\"address\"}],\"name\":\"SubscriptionConsumerRemoved\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"}],\"name\":\"SubscriptionCreated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"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\":\"subscriptionId\",\"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\":\"subscriptionId\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"SubscriptionOwnerTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"Unpaused\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"MAX_CALLBACK_RETURN_BYTES\",\"outputs\":[{\"internalType\":\"uint16\",\"name\":\"\",\"type\":\"uint16\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"acceptOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"}],\"name\":\"acceptSubscriptionOwnerTransfer\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"},{\"internalType\":\"address\",\"name\":\"consumer\",\"type\":\"address\"}],\"name\":\"addConsumer\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"cancelSubscription\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"createSubscription\",\"outputs\":[{\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"consumer\",\"type\":\"address\"}],\"name\":\"createSubscriptionWithConsumer\",\"outputs\":[{\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"response\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"err\",\"type\":\"bytes\"},{\"internalType\":\"uint96\",\"name\":\"juelsPerGas\",\"type\":\"uint96\"},{\"internalType\":\"uint96\",\"name\":\"costWithoutCallback\",\"type\":\"uint96\"},{\"internalType\":\"address\",\"name\":\"transmitter\",\"type\":\"address\"},{\"components\":[{\"internalType\":\"bytes32\",\"name\":\"requestId\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"coordinator\",\"type\":\"address\"},{\"internalType\":\"uint96\",\"name\":\"estimatedTotalCostJuels\",\"type\":\"uint96\"},{\"internalType\":\"address\",\"name\":\"client\",\"type\":\"address\"},{\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"callbackGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint72\",\"name\":\"adminFee\",\"type\":\"uint72\"},{\"internalType\":\"uint72\",\"name\":\"donFee\",\"type\":\"uint72\"},{\"internalType\":\"uint40\",\"name\":\"gasOverheadBeforeCallback\",\"type\":\"uint40\"},{\"internalType\":\"uint40\",\"name\":\"gasOverheadAfterCallback\",\"type\":\"uint40\"},{\"internalType\":\"uint32\",\"name\":\"timeoutTimestamp\",\"type\":\"uint32\"}],\"internalType\":\"structFunctionsResponse.Commitment\",\"name\":\"commitment\",\"type\":\"tuple\"}],\"name\":\"fulfill\",\"outputs\":[{\"internalType\":\"enumFunctionsResponse.FulfillResult\",\"name\":\"resultCode\",\"type\":\"uint8\"},{\"internalType\":\"uint96\",\"name\":\"\",\"type\":\"uint96\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getAdminFee\",\"outputs\":[{\"internalType\":\"uint72\",\"name\":\"\",\"type\":\"uint72\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getAllowListId\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getConfig\",\"outputs\":[{\"components\":[{\"internalType\":\"uint16\",\"name\":\"maxConsumersPerSubscription\",\"type\":\"uint16\"},{\"internalType\":\"uint72\",\"name\":\"adminFee\",\"type\":\"uint72\"},{\"internalType\":\"bytes4\",\"name\":\"handleOracleFulfillmentSelector\",\"type\":\"bytes4\"},{\"internalType\":\"uint16\",\"name\":\"gasForCallExactCheck\",\"type\":\"uint16\"},{\"internalType\":\"uint32[]\",\"name\":\"maxCallbackGasLimits\",\"type\":\"uint32[]\"}],\"internalType\":\"structFunctionsRouter.Config\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"client\",\"type\":\"address\"},{\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"}],\"name\":\"getConsumer\",\"outputs\":[{\"components\":[{\"internalType\":\"bool\",\"name\":\"allowed\",\"type\":\"bool\"},{\"internalType\":\"uint64\",\"name\":\"initiatedRequests\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"completedRequests\",\"type\":\"uint64\"}],\"internalType\":\"structIFunctionsSubscriptions.Consumer\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"id\",\"type\":\"bytes32\"}],\"name\":\"getContractById\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"}],\"name\":\"getFlags\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"id\",\"type\":\"bytes32\"}],\"name\":\"getProposedContractById\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getProposedContractSet\",\"outputs\":[{\"internalType\":\"bytes32[]\",\"name\":\"\",\"type\":\"bytes32[]\"},{\"internalType\":\"address[]\",\"name\":\"\",\"type\":\"address[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"}],\"name\":\"getSubscription\",\"outputs\":[{\"components\":[{\"internalType\":\"uint96\",\"name\":\"balance\",\"type\":\"uint96\"},{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"internalType\":\"uint96\",\"name\":\"blockedBalance\",\"type\":\"uint96\"},{\"internalType\":\"address\",\"name\":\"proposedOwner\",\"type\":\"address\"},{\"internalType\":\"address[]\",\"name\":\"consumers\",\"type\":\"address[]\"},{\"internalType\":\"bytes32\",\"name\":\"flags\",\"type\":\"bytes32\"}],\"internalType\":\"structIFunctionsSubscriptions.Subscription\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getSubscriptionCount\",\"outputs\":[{\"internalType\":\"uint64\",\"name\":\"\",\"type\":\"uint64\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getTotalBalance\",\"outputs\":[{\"internalType\":\"uint96\",\"name\":\"\",\"type\":\"uint96\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"callbackGasLimit\",\"type\":\"uint32\"}],\"name\":\"isValidCallbackGasLimit\",\"outputs\":[],\"stateMutability\":\"view\",\"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\":\"subscriptionId\",\"type\":\"uint64\"}],\"name\":\"ownerCancelSubscription\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"uint96\",\"name\":\"amount\",\"type\":\"uint96\"}],\"name\":\"ownerWithdraw\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"pause\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"paused\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"}],\"name\":\"pendingRequestExists\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32[]\",\"name\":\"proposedContractSetIds\",\"type\":\"bytes32[]\"},{\"internalType\":\"address[]\",\"name\":\"proposedContractSetAddresses\",\"type\":\"address[]\"}],\"name\":\"proposeContractsUpdate\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"},{\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"proposeSubscriptionOwnerTransfer\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"recoverFunds\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"},{\"internalType\":\"address\",\"name\":\"consumer\",\"type\":\"address\"}],\"name\":\"removeConsumer\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"},{\"internalType\":\"uint16\",\"name\":\"dataVersion\",\"type\":\"uint16\"},{\"internalType\":\"uint32\",\"name\":\"callbackGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"bytes32\",\"name\":\"donId\",\"type\":\"bytes32\"}],\"name\":\"sendRequest\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"},{\"internalType\":\"uint16\",\"name\":\"dataVersion\",\"type\":\"uint16\"},{\"internalType\":\"uint32\",\"name\":\"callbackGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"bytes32\",\"name\":\"donId\",\"type\":\"bytes32\"}],\"name\":\"sendRequestToProposed\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"allowListId\",\"type\":\"bytes32\"}],\"name\":\"setAllowListId\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"},{\"internalType\":\"bytes32\",\"name\":\"flags\",\"type\":\"bytes32\"}],\"name\":\"setFlags\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"bytes32\",\"name\":\"requestId\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"coordinator\",\"type\":\"address\"},{\"internalType\":\"uint96\",\"name\":\"estimatedTotalCostJuels\",\"type\":\"uint96\"},{\"internalType\":\"address\",\"name\":\"client\",\"type\":\"address\"},{\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"callbackGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint72\",\"name\":\"adminFee\",\"type\":\"uint72\"},{\"internalType\":\"uint72\",\"name\":\"donFee\",\"type\":\"uint72\"},{\"internalType\":\"uint40\",\"name\":\"gasOverheadBeforeCallback\",\"type\":\"uint40\"},{\"internalType\":\"uint40\",\"name\":\"gasOverheadAfterCallback\",\"type\":\"uint40\"},{\"internalType\":\"uint32\",\"name\":\"timeoutTimestamp\",\"type\":\"uint32\"}],\"internalType\":\"structFunctionsResponse.Commitment[]\",\"name\":\"requestsToTimeoutByCommitment\",\"type\":\"tuple[]\"}],\"name\":\"timeoutRequests\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"typeAndVersion\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"unpause\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint16\",\"name\":\"maxConsumersPerSubscription\",\"type\":\"uint16\"},{\"internalType\":\"uint72\",\"name\":\"adminFee\",\"type\":\"uint72\"},{\"internalType\":\"bytes4\",\"name\":\"handleOracleFulfillmentSelector\",\"type\":\"bytes4\"},{\"internalType\":\"uint16\",\"name\":\"gasForCallExactCheck\",\"type\":\"uint16\"},{\"internalType\":\"uint32[]\",\"name\":\"maxCallbackGasLimits\",\"type\":\"uint32[]\"}],\"internalType\":\"structFunctionsRouter.Config\",\"name\":\"config\",\"type\":\"tuple\"}],\"name\":\"updateConfig\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"updateContracts\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", - Bin: "0x60a06040523480156200001157600080fd5b5060405162006254380380620062548339810160408190526200003491620004df565b6001600160a01b0382166080526006805460ff191690553380600081620000a25760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600680546001600160a01b0380851661010002610100600160a81b031990921691909117909155811615620000dc57620000dc81620000f8565b505050620000f081620001aa60201b60201c565b50506200067b565b336001600160a01b03821603620001525760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c66000000000000000000604482015260640162000099565b600780546001600160a01b0319166001600160a01b03838116918217909255600654604051919261010090910416907fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae127890600090a350565b620001b462000287565b8051600a80546020808501516040860151606087015161ffff908116600160781b0261ffff60781b1960e09390931c6b010000000000000000000000029290921665ffffffffffff60581b196001600160481b0390941662010000026001600160581b031990961691909716179390931716939093171781556080830151805184936200024792600b92910190620002ea565b509050507f049ce2e6e1420eb4b07b425e90129186833eb346bda40b37d5d921aad482f71c816040516200027c9190620005dd565b60405180910390a150565b60065461010090046001600160a01b03163314620002e85760405162461bcd60e51b815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e657200000000000000000000604482015260640162000099565b565b828054828255906000526020600020906007016008900481019282156200038e5791602002820160005b838211156200035a57835183826101000a81548163ffffffff021916908363ffffffff160217905550926020019260040160208160030104928301926001030262000314565b80156200038c5782816101000a81549063ffffffff02191690556004016020816003010492830192600103026200035a565b505b506200039c929150620003a0565b5090565b5b808211156200039c5760008155600101620003a1565b634e487b7160e01b600052604160045260246000fd5b60405160a081016001600160401b0381118282101715620003f257620003f2620003b7565b60405290565b604051601f8201601f191681016001600160401b0381118282101715620004235762000423620003b7565b604052919050565b805161ffff811681146200043e57600080fd5b919050565b600082601f8301126200045557600080fd5b815160206001600160401b03821115620004735762000473620003b7565b8160051b62000484828201620003f8565b92835284810182019282810190878511156200049f57600080fd5b83870192505b84831015620004d457825163ffffffff81168114620004c45760008081fd5b82529183019190830190620004a5565b979650505050505050565b60008060408385031215620004f357600080fd5b82516001600160a01b03811681146200050b57600080fd5b60208401519092506001600160401b03808211156200052957600080fd5b9084019060a082870312156200053e57600080fd5b62000548620003cd565b62000553836200042b565b815260208301516001600160481b03811681146200057057600080fd5b602082015260408301516001600160e01b0319811681146200059157600080fd5b6040820152620005a4606084016200042b565b6060820152608083015182811115620005bc57600080fd5b620005ca8882860162000443565b6080830152508093505050509250929050565b6020808252825161ffff90811683830152838201516001600160481b03166040808501919091528401516001600160e01b0319166060808501919091528401511660808084019190915283015160a080840152805160c0840181905260009291820190839060e08601905b808310156200067057835163ffffffff16825292840192600192909201919084019062000648565b509695505050505050565b608051615ba1620006b3600039600081816113b40152818161218701528181612a7f01528181612b4301526132be0152615ba16000f3fe608060405234801561001057600080fd5b50600436106102de5760003560e01c80637341c10c11610186578063aab396bd116100e3578063d7ae1d3011610097578063e82ad7d411610071578063e82ad7d4146106bf578063ea320e0b146106d2578063f2fde38b146106e557600080fd5b8063d7ae1d3014610686578063e72f6e3014610699578063e82622aa146106ac57600080fd5b8063badc3eb6116100c8578063badc3eb614610648578063c3f909d41461065e578063cc77470a1461067357600080fd5b8063aab396bd14610638578063b734c0f41461064057600080fd5b80639f87fad71161013a578063a47c76961161011f578063a47c7696146105f2578063a4c0ed3614610612578063a9c9a9181461062557600080fd5b80639f87fad7146105d7578063a21a23e4146105ea57600080fd5b8063823597401161016b57806382359740146105995780638456cb59146105ac5780638da5cb5b146105b457600080fd5b80637341c10c1461057e57806379ba50971461059157600080fd5b80633f4ba83a1161023f5780635c975abb116101f357806366419970116101cd57806366419970146104d6578063674603d0146104fd5780636a2215de1461054657600080fd5b80635c975abb146104995780635ed6dfba146104b057806366316d8d146104c357600080fd5b8063461d276211610224578063461d2762146104455780634b8832d31461045857806355fedefa1461046b57600080fd5b80633f4ba83a1461041c57806341db4ca31461042457600080fd5b80631ded3b36116102965780632a905ccc1161027b5780632a905ccc146103ba57806333060529146103e85780633e871e4d1461040957600080fd5b80631ded3b361461039457806321b60e7f146103a757600080fd5b806310fc49c1116102c757806310fc49c11461031857806312b583491461032b578063181f5a771461034b57600080fd5b806302bcc5b6146102e35780630c5d49cb146102f8575b600080fd5b6102f66102f136600461487a565b6106f8565b005b610300608481565b60405161ffff90911681526020015b60405180910390f35b6102f66103263660046148bb565b610757565b6000546040516bffffffffffffffffffffffff909116815260200161030f565b6103876040518060400160405280601781526020017f46756e6374696f6e7320526f757465722076312e302e3000000000000000000081525081565b60405161030f9190614962565b6102f66103a2366004614975565b610853565b6102f66103b5366004614b38565b610885565b600a5462010000900468ffffffffffffffffff1660405168ffffffffffffffffff909116815260200161030f565b6103fb6103f6366004614de4565b6109b2565b60405161030f929190614ecc565b6102f6610417366004614f59565b610d8a565b6102f661100f565b61043761043236600461505b565b611021565b60405190815260200161030f565b61043761045336600461505b565b611081565b6102f66104663660046150df565b61108d565b61043761047936600461487a565b67ffffffffffffffff166000908152600360208190526040909120015490565b60065460ff165b604051901515815260200161030f565b6102f66104be36600461510d565b6111db565b6102f66104d136600461510d565b6113fd565b60025467ffffffffffffffff165b60405167ffffffffffffffff909116815260200161030f565b61051061050b36600461513b565b61154f565b6040805182511515815260208084015167ffffffffffffffff90811691830191909152928201519092169082015260600161030f565b610559610554366004615169565b6115df565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200161030f565b6102f661058c3660046150df565b61169e565b6102f6611852565b6102f66105a736600461487a565b611979565b6102f6611ac0565b600654610100900473ffffffffffffffffffffffffffffffffffffffff16610559565b6102f66105e53660046150df565b611ad0565b6104e4611ea5565b61060561060036600461487a565b612032565b60405161030f91906151d3565b6102f661062036600461525b565b612167565b610559610633366004615169565b6123b3565b600954610437565b6102f6612412565b61065061255e565b60405161030f9291906152b7565b61066661262e565b60405161030f919061530e565b6104e46106813660046153b8565b612763565b6102f66106943660046150df565b6129e3565b6102f66106a73660046153b8565b612a46565b6102f66106ba3660046153d5565b612bbf565b6104a06106cd36600461487a565b612e90565b6102f66106e0366004615169565b612fdf565b6102f66106f33660046153b8565b612fec565b610700612ffd565b61070981613005565b67ffffffffffffffff81166000908152600360205260409020546107549082906c01000000000000000000000000900473ffffffffffffffffffffffffffffffffffffffff1661307b565b50565b67ffffffffffffffff8216600090815260036020819052604082200154600b54911a9081106107bc576040517f45c108ce00000000000000000000000000000000000000000000000000000000815260ff821660048201526024015b60405180910390fd5b6000600a6001018260ff16815481106107d7576107d761544b565b90600052602060002090600891828204019190066004029054906101000a900463ffffffff1690508063ffffffff168363ffffffff16111561084d576040517f1d70f87a00000000000000000000000000000000000000000000000000000000815263ffffffff821660048201526024016107b3565b50505050565b61085b612ffd565b61086482613005565b67ffffffffffffffff90911660009081526003602081905260409091200155565b61088d613367565b8051600a80546020808501516040860151606087015161ffff9081166f01000000000000000000000000000000027fffffffffffffffffffffffffffffff0000ffffffffffffffffffffffffffffff60e09390931c6b01000000000000000000000002929092167fffffffffffffffffffffffffffffff000000000000ffffffffffffffffffffff68ffffffffffffffffff90941662010000027fffffffffffffffffffffffffffffffffffffffffff0000000000000000000000909616919097161793909317169390931717815560808301518051849361097492600b929101906146c5565b509050507f049ce2e6e1420eb4b07b425e90129186833eb346bda40b37d5d921aad482f71c816040516109a7919061530e565b60405180910390a150565b6000806109bd6133ed565b826020015173ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614610a26576040517f8bec23e700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8251600090815260056020526040902054610a885782516020840151604051600294507f1a90e9a50793db2e394cf581e7c522e10c358a81e70acf6b5a0edd620c08dee191610a78918890879061547a565b60405180910390a2506000610d7f565b8251600090815260056020908152604091829020549151610aab918691016154ac565b6040516020818303038152906040528051906020012014610b035782516020840151604051600694507f1a90e9a50793db2e394cf581e7c522e10c358a81e70acf6b5a0edd620c08dee191610a78918890879061547a565b8261012001518360a0015163ffffffff16610b1e9190615608565b64ffffffffff165a1015610b695782516020840151604051600494507f1a90e9a50793db2e394cf581e7c522e10c358a81e70acf6b5a0edd620c08dee191610a78918890879061547a565b6000610b7e8460a0015163ffffffff166133f5565b610b88908861562d565b9050600081878660c0015168ffffffffffffffffff16610ba89190615655565b610bb29190615655565b9050610bc18560800151612032565b600001516bffffffffffffffffffffffff16816bffffffffffffffffffffffff161115610c395784516020860151604051600596507f1a90e9a50793db2e394cf581e7c522e10c358a81e70acf6b5a0edd620c08dee191610c25918a90899061547a565b60405180910390a25060009150610d7f9050565b84604001516bffffffffffffffffffffffff16816bffffffffffffffffffffffff161115610c9e5784516020860151604051600396507f1a90e9a50793db2e394cf581e7c522e10c358a81e70acf6b5a0edd620c08dee191610c25918a90899061547a565b505082516000908152600560205260408120819055835160a08501516060860151610cce92918c918c9190613497565b8051909150610cde576001610ce1565b60005b92506000610d1b8560800151866040015187606001518860c0015168ffffffffffffffffff168c610d1588602001516133f5565b8d613626565b9050846080015167ffffffffffffffff1685600001517f64778f26c70b60a8d7e29e2451b3844302d959448401c0535b768ed88c6b505e836020015189888f8f8960400151604051610d729695949392919061567a565b60405180910390a3519150505b965096945050505050565b610d92613367565b8151815181141580610da45750600881115b15610ddb576040517fee03280800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60005b81811015610ecd576000848281518110610dfa57610dfa61544b565b602002602001015190506000848381518110610e1857610e1861544b565b60200260200101519050600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff161480610e83575060008281526008602052604090205473ffffffffffffffffffffffffffffffffffffffff8281169116145b15610eba576040517fee03280800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b505080610ec6906156fd565b9050610dde565b506040805180820190915283815260208082018490528451600c91610ef6918391880190614770565b506020828101518051610f0f92600185019201906147ab565b5090505060005b835181101561084d577f8b052f0f4bf82fede7daffea71592b29d5ef86af1f3c7daaa0345dbb2f52f481848281518110610f5257610f5261544b565b602002602001015160086000878581518110610f7057610f7061544b565b6020026020010151815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16858481518110610fb957610fb961544b565b6020026020010151604051610ff79392919092835273ffffffffffffffffffffffffffffffffffffffff918216602084015216604082015260600190565b60405180910390a1611008816156fd565b9050610f16565b611017613367565b61101f6139a8565b565b60008061102d836115df565b905061107583828a8a8a8080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152508c92508b9150613a259050565b98975050505050505050565b60008061102d836123b3565b6110956133ed565b61109e82613dce565b6110a6613e94565b73ffffffffffffffffffffffffffffffffffffffff8116158061110d575067ffffffffffffffff821660009081526003602052604090206001015473ffffffffffffffffffffffffffffffffffffffff8281166c0100000000000000000000000090920416145b15611144576040517f8129bbcd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b67ffffffffffffffff821660008181526003602090815260409182902060010180546bffffffffffffffffffffffff166c0100000000000000000000000073ffffffffffffffffffffffffffffffffffffffff8716908102919091179091558251338152918201527f69436ea6df009049404f564eff6622cd00522b0bd6a89efd9e52a355c4a879be910160405180910390a25050565b6111e3612ffd565b806bffffffffffffffffffffffff166000036112195750306000908152600160205260409020546bffffffffffffffffffffffff165b306000908152600160205260409020546bffffffffffffffffffffffff908116908216811015611285576040517f6b0fe56f0000000000000000000000000000000000000000000000000000000081526bffffffffffffffffffffffff821660048201526024016107b3565b6000546bffffffffffffffffffffffff808416911610156112ee576000546040517fdda2b2160000000000000000000000000000000000000000000000000000000081526bffffffffffffffffffffffff918216600482015290831660248201526044016107b3565b306000908152600160205260408120805484929061131b9084906bffffffffffffffffffffffff16615735565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff160217905550816000808282829054906101000a90046bffffffffffffffffffffffff166113719190615735565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff1602179055506113f883836bffffffffffffffffffffffff167f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16613f9e9092919063ffffffff16565b505050565b6114056133ed565b806bffffffffffffffffffffffff1660000361144d576040517f8129bbcd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b336000908152600160205260409020546bffffffffffffffffffffffff9081169082168110156114b9576040517f6b0fe56f0000000000000000000000000000000000000000000000000000000081526bffffffffffffffffffffffff821660048201526024016107b3565b6000546bffffffffffffffffffffffff80841691161015611522576000546040517fdda2b2160000000000000000000000000000000000000000000000000000000081526bffffffffffffffffffffffff918216600482015290831660248201526044016107b3565b336000908152600160205260408120805484929061131b9084906bffffffffffffffffffffffff16615735565b60408051606080820183526000808352602080840182905292840181905273ffffffffffffffffffffffffffffffffffffffff861681526004835283812067ffffffffffffffff868116835290845290849020845192830185525460ff81161515835261010081048216938301939093526901000000000000000000909204909116918101919091525b92915050565b6000805b600c5460ff8216101561166857600c805460ff83169081106116075761160761544b565b9060005260206000200154830361165857600d805460ff831690811061162f5761162f61544b565b60009182526020909120015473ffffffffffffffffffffffffffffffffffffffff169392505050565b6116618161575a565b90506115e3565b506040517f80833e33000000000000000000000000000000000000000000000000000000008152600481018390526024016107b3565b6116a66133ed565b6116af82613dce565b6116b7613e94565b60006116c6600a5461ffff1690565b67ffffffffffffffff841660009081526003602052604090206002015490915061ffff82169003611729576040517fb72bc70300000000000000000000000000000000000000000000000000000000815261ffff821660048201526024016107b3565b73ffffffffffffffffffffffffffffffffffffffff8216600090815260046020908152604080832067ffffffffffffffff8716845290915290205460ff161561177157505050565b73ffffffffffffffffffffffffffffffffffffffff8216600081815260046020908152604080832067ffffffffffffffff881680855290835281842080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001908117909155600384528285206002018054918201815585529383902090930180547fffffffffffffffffffffffff000000000000000000000000000000000000000016851790555192835290917f43dc749a04ac8fb825cbd514f7c0e13f13bc6f2ee66043b76629d51776cff8e091015b60405180910390a2505050565b60075473ffffffffffffffffffffffffffffffffffffffff1633146118d3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e65720000000000000000000060448201526064016107b3565b600680547fffffffffffffffffffffff0000000000000000000000000000000000000000ff81166101003381810292909217909355600780547fffffffffffffffffffffffff00000000000000000000000000000000000000001690556040519290910473ffffffffffffffffffffffffffffffffffffffff169182907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a350565b6119816133ed565b611989613e94565b67ffffffffffffffff81166000908152600360205260409020805460019091015473ffffffffffffffffffffffffffffffffffffffff6c010000000000000000000000009283900481169290910416338114611a29576040517f4e1d9f1800000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff821660048201526024016107b3565b67ffffffffffffffff831660008181526003602090815260409182902080546c01000000000000000000000000339081026bffffffffffffffffffffffff928316178355600190920180549091169055825173ffffffffffffffffffffffffffffffffffffffff87168152918201527f6f1dc65165ffffedfd8e507b4a0f1fcfdada045ed11f6c26ba27cedfe87802f09101611845565b611ac8613367565b61101f61402b565b611ad86133ed565b611ae182613dce565b611ae9613e94565b73ffffffffffffffffffffffffffffffffffffffff8116600090815260046020908152604080832067ffffffffffffffff8087168552908352928190208151606081018352905460ff8116151580835261010082048616948301949094526901000000000000000000900490931690830152611b91576040517f71e8313700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b806040015167ffffffffffffffff16816020015167ffffffffffffffff1614611be6576040517f06eb10c800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b67ffffffffffffffff8316600090815260036020908152604080832060020180548251818502810185019093528083529192909190830182828015611c6157602002820191906000526020600020905b815473ffffffffffffffffffffffffffffffffffffffff168152600190910190602001808311611c36575b5050505050905060005b8151811015611e09578373ffffffffffffffffffffffffffffffffffffffff16828281518110611c9d57611c9d61544b565b602002602001015173ffffffffffffffffffffffffffffffffffffffff1603611df9578160018351611ccf9190615779565b81518110611cdf57611cdf61544b565b6020026020010151600360008767ffffffffffffffff1667ffffffffffffffff1681526020019081526020016000206002018281548110611d2257611d2261544b565b600091825260208083209190910180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff949094169390931790925567ffffffffffffffff87168152600390915260409020600201805480611d9c57611d9c61578c565b60008281526020902081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff90810180547fffffffffffffffffffffffff0000000000000000000000000000000000000000169055019055611e09565b611e02816156fd565b9050611c6b565b5073ffffffffffffffffffffffffffffffffffffffff8316600081815260046020908152604080832067ffffffffffffffff89168085529083529281902080547fffffffffffffffffffffffffffffff00000000000000000000000000000000001690555192835290917f182bff9831466789164ca77075fffd84916d35a8180ba73c27e45634549b445b91015b60405180910390a250505050565b6000611eaf6133ed565b611eb7613e94565b60028054600090611ed19067ffffffffffffffff166157bb565b825467ffffffffffffffff8083166101009490940a93840293021916919091179091556040805160c0810182526000808252336020830152918101829052606081018290529192506080820190604051908082528060200260200182016040528015611f47578160200160208202803683370190505b5081526000602091820181905267ffffffffffffffff841681526003825260409081902083518484015173ffffffffffffffffffffffffffffffffffffffff9081166c010000000000000000000000009081026bffffffffffffffffffffffff9384161784559386015160608701519091169093029216919091176001820155608083015180519192611fe2926002850192909101906147ab565b5060a0919091015160039091015560405133815267ffffffffffffffff8216907f464722b4166576d3dcbba877b999bc35cf911f4eaf434b7eba68fa113951d0bf9060200160405180910390a290565b6040805160c0810182526000808252602082018190529181018290526060808201839052608082015260a081019190915261206c82613005565b67ffffffffffffffff8216600090815260036020908152604091829020825160c08101845281546bffffffffffffffffffffffff808216835273ffffffffffffffffffffffffffffffffffffffff6c0100000000000000000000000092839004811684870152600185015491821684880152919004166060820152600282018054855181860281018601909652808652919492936080860193929083018282801561214d57602002820191906000526020600020905b815473ffffffffffffffffffffffffffffffffffffffff168152600190910190602001808311612122575b505050505081526020016003820154815250509050919050565b61216f6133ed565b3373ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016146121de576040517f44b0e3c300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60208114612218576040517f8129bbcd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60006122268284018461487a565b67ffffffffffffffff81166000908152600360205260409020549091506c01000000000000000000000000900473ffffffffffffffffffffffffffffffffffffffff1661229f576040517f1f6a65b600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b67ffffffffffffffff8116600090815260036020526040812080546bffffffffffffffffffffffff16918691906122d68385615655565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff160217905550846000808282829054906101000a90046bffffffffffffffffffffffff1661232c9190615655565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff1602179055508167ffffffffffffffff167fd39ec07f4e209f627a4c427971473820dc129761ba28de8906bd56f57101d4f882878461239391906157e2565b6040805192835260208301919091520160405180910390a2505050505050565b60008181526008602052604081205473ffffffffffffffffffffffffffffffffffffffff16806115d9576040517f80833e33000000000000000000000000000000000000000000000000000000008152600481018490526024016107b3565b61241a613367565b60005b600c5481101561253d576000600c600001828154811061243f5761243f61544b565b906000526020600020015490506000600c60010183815481106124645761246461544b565b6000918252602080832091909101548483526008825260409283902054835186815273ffffffffffffffffffffffffffffffffffffffff91821693810193909352169181018290529091507ff8a6175bca1ba37d682089187edc5e20a859989727f10ca6bd9a5bc0de8caf949060600160405180910390a160009182526008602052604090912080547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff909216919091179055612536816156fd565b905061241d565b50600c600061254c8282614825565b61255a600183016000614825565b5050565b606080600c600001600c600101818054806020026020016040519081016040528092919081815260200182805480156125b657602002820191906000526020600020905b8154815260200190600101908083116125a2575b505050505091508080548060200260200160405190810160405280929190818152602001828054801561261f57602002820191906000526020600020905b815473ffffffffffffffffffffffffffffffffffffffff1681526001909101906020018083116125f4575b50505050509050915091509091565b6040805160a08101825260008082526020820181905291810182905260608082019290925260808101919091526040805160a081018252600a805461ffff808216845268ffffffffffffffffff620100008304166020808601919091527fffffffff000000000000000000000000000000000000000000000000000000006b010000000000000000000000840460e01b16858701526f01000000000000000000000000000000909204166060840152600b80548551818402810184019096528086529394929360808601939283018282801561275557602002820191906000526020600020906000905b82829054906101000a900463ffffffff1663ffffffff16815260200190600401906020826003010492830192600103820291508084116127185790505b505050505081525050905090565b600061276d6133ed565b612775613e94565b6002805460009061278f9067ffffffffffffffff166157bb565b825467ffffffffffffffff8083166101009490940a93840293021916919091179091556040805160c0810182526000808252336020830152918101829052606081018290529192506080820190604051908082528060200260200182016040528015612805578160200160208202803683370190505b5081526000602091820181905267ffffffffffffffff841681526003825260409081902083518484015173ffffffffffffffffffffffffffffffffffffffff9081166c010000000000000000000000009081026bffffffffffffffffffffffff93841617845593860151606087015190911690930292169190911760018201556080830151805191926128a0926002850192909101906147ab565b5060a0919091015160039182015567ffffffffffffffff82166000818152602092835260408082206002018054600180820183559184528584200180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff891690811790915583526004855281832084845285529181902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169092179091555133815290917f464722b4166576d3dcbba877b999bc35cf911f4eaf434b7eba68fa113951d0bf910160405180910390a260405173ffffffffffffffffffffffffffffffffffffffff8316815267ffffffffffffffff8216907f43dc749a04ac8fb825cbd514f7c0e13f13bc6f2ee66043b76629d51776cff8e09060200160405180910390a2919050565b6129eb6133ed565b6129f482613dce565b6129fc613e94565b612a0582612e90565b15612a3c576040517f06eb10c800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61255a828261307b565b612a4e612ffd565b6040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201526000907f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16906370a0823190602401602060405180830381865afa158015612adb573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612aff91906157f5565b6000549091506bffffffffffffffffffffffff16818110156113f8576000612b278284615779565b9050612b6a73ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168583613f9e565b6040805173ffffffffffffffffffffffffffffffffffffffff86168152602081018390527f59bfc682b673f8cbf945f1e454df9334834abf7dfe7f92237ca29ecb9b436600910160405180910390a150505050565b612bc76133ed565b60005b818110156113f8576000838383818110612be657612be661544b565b90506101600201803603810190612bfd919061580e565b80516080820151600082815260056020908152604091829020549151949550929391929091612c2e918691016154ac565b6040516020818303038152906040528051906020012014612c7b576040517f8129bbcd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b82610140015163ffffffff16421015612cc0576040517fa2376fe800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60208301516040517f85b214cf0000000000000000000000000000000000000000000000000000000081526004810184905273ffffffffffffffffffffffffffffffffffffffff909116906385b214cf906024016020604051808303816000875af1158015612d33573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612d57919061582b565b5060408084015167ffffffffffffffff831660009081526003602052918220600101805491929091612d989084906bffffffffffffffffffffffff16615735565b82546bffffffffffffffffffffffff9182166101009390930a928302919092021990911617905550606083015173ffffffffffffffffffffffffffffffffffffffff16600090815260046020908152604080832067ffffffffffffffff808616855292529091208054600192600991612e20918591690100000000000000000090041661584d565b825467ffffffffffffffff9182166101009390930a9283029190920219909116179055506000828152600560205260408082208290555183917ff1ca1e9147be737b04a2b018a79405f687a97de8dd8a2559bbe62357343af41491a250505080612e89906156fd565b9050612bca565b67ffffffffffffffff8116600090815260036020908152604080832060020180548251818502810185019093528083528493830182828015612f0857602002820191906000526020600020905b815473ffffffffffffffffffffffffffffffffffffffff168152600190910190602001808311612edd575b5050505050905060005b8151811015612fd557600060046000848481518110612f3357612f3361544b565b60209081029190910181015173ffffffffffffffffffffffffffffffffffffffff168252818101929092526040908101600090812067ffffffffffffffff808a168352908452908290208251606081018452905460ff8116151582526101008104831694820185905269010000000000000000009004909116918101829052925014612fc457506001949350505050565b50612fce816156fd565b9050612f12565b5060009392505050565b612fe7613367565b600955565b612ff4613367565b61075481614086565b61101f613367565b67ffffffffffffffff81166000908152600360205260409020546c01000000000000000000000000900473ffffffffffffffffffffffffffffffffffffffff16610754576040517f1f6a65b600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b67ffffffffffffffff82166000908152600360209081526040808320815160c08101835281546bffffffffffffffffffffffff808216835273ffffffffffffffffffffffffffffffffffffffff6c010000000000000000000000009283900481168488015260018501549182168487015291900416606082015260028201805484518187028101870190955280855291949293608086019390929083018282801561315c57602002820191906000526020600020905b815473ffffffffffffffffffffffffffffffffffffffff168152600190910190602001808311613131575b505050918352505060039190910154602090910152805190915060005b82608001515181101561321d5760046000846080015183815181106131a0576131a061544b565b60209081029190910181015173ffffffffffffffffffffffffffffffffffffffff168252818101929092526040908101600090812067ffffffffffffffff89168252909252902080547fffffffffffffffffffffffffffffff0000000000000000000000000000000000169055613216816156fd565b9050613179565b5067ffffffffffffffff84166000908152600360205260408120818155600181018290559061324f6002830182614825565b5060006003919091018190558054829190819061327b9084906bffffffffffffffffffffffff16615735565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff16021790555061330283826bffffffffffffffffffffffff167f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16613f9e9092919063ffffffff16565b6040805173ffffffffffffffffffffffffffffffffffffffff851681526bffffffffffffffffffffffff8316602082015267ffffffffffffffff8616917fe8ed5b475a5b5987aa9165e8731bb78043f39eee32ec5a1169a89e27fcd498159101611e97565b600654610100900473ffffffffffffffffffffffffffffffffffffffff16331461101f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e65720000000000000000000060448201526064016107b3565b61101f614182565b60006bffffffffffffffffffffffff821115613493576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f53616665436173743a2076616c756520646f65736e27742066697420696e203960448201527f362062697473000000000000000000000000000000000000000000000000000060648201526084016107b3565b5090565b60408051606080820183526000808352602083015291810191909152600a546040516000916b010000000000000000000000900460e01b906134e19089908990899060240161586e565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152918152602080830180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff000000000000000000000000000000000000000000000000000000009590951694909417909352600a548151608480825260c0820190935292945061ffff6f0100000000000000000000000000000090910416926000928392839282018180368337019050509050863b6135ac57600080fd5b5a848110156135ba57600080fd5b84900360408104810389106135ce57600080fd5b505a60008087516020890160008c8ef193505a900391503d60848111156135f3575060845b808252806000602084013e5060408051606081018252931515845260208401929092529082015298975050505050505050565b60408051808201909152600080825260208201526000613646848661562d565b90506000816136558886615655565b61365f9190615655565b67ffffffffffffffff8b166000908152600360205260409020549091506bffffffffffffffffffffffff808316911610156136f25767ffffffffffffffff8a16600090815260036020526040908190205490517f6b0fe56f0000000000000000000000000000000000000000000000000000000081526bffffffffffffffffffffffff90911660048201526024016107b3565b67ffffffffffffffff8a16600090815260036020526040812080548392906137299084906bffffffffffffffffffffffff16615735565b82546101009290920a6bffffffffffffffffffffffff81810219909316918316021790915567ffffffffffffffff8c166000908152600360205260409020600101548b82169116101590506137d65767ffffffffffffffff8a16600090815260036020526040908190205490517f6b0fe56f0000000000000000000000000000000000000000000000000000000081526bffffffffffffffffffffffff90911660048201526024016107b3565b67ffffffffffffffff8a16600090815260036020526040812060010180548b92906138109084906bffffffffffffffffffffffff16615735565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff160217905550818461384a9190615655565b33600090815260016020526040812080549091906138779084906bffffffffffffffffffffffff16615655565b82546101009290920a6bffffffffffffffffffffffff81810219909316918316021790915530600090815260016020526040812080548b945090926138be91859116615655565b82546bffffffffffffffffffffffff9182166101009390930a92830291909202199091161790555073ffffffffffffffffffffffffffffffffffffffff8816600090815260046020908152604080832067ffffffffffffffff808f16855292529091208054600192600991613942918591690100000000000000000090041661584d565b92506101000a81548167ffffffffffffffff021916908367ffffffffffffffff1602179055506040518060400160405280836bffffffffffffffffffffffff168152602001826bffffffffffffffffffffffff1681525092505050979650505050505050565b6139b06141ef565b600680547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200160405180910390a1565b6000613a2f6133ed565b613a3885613005565b613a42338661425b565b613a4c8583610757565b8351600003613a86576040517ec1cfc000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000613a9186612032565b90506000613a9f338861154f565b905060008873ffffffffffffffffffffffffffffffffffffffff1663a631571e6040518061016001604052808a8152602001613af58c67ffffffffffffffff166000908152600360208190526040909120015490565b815233602082015260408781015188519190920191613b1391615735565b6bffffffffffffffffffffffff168152602001600a60000160029054906101000a900468ffffffffffffffffff1668ffffffffffffffffff1681526020018b67ffffffffffffffff168152602001856020015167ffffffffffffffff1681526020018863ffffffff1681526020018961ffff168152602001856040015167ffffffffffffffff168152602001866020015173ffffffffffffffffffffffffffffffffffffffff168152506040518263ffffffff1660e01b8152600401613bd99190615899565b610160604051808303816000875af1158015613bf9573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613c1d91906159fe565b9050604051806101600160405280826000015181526020018a73ffffffffffffffffffffffffffffffffffffffff16815260200182604001516bffffffffffffffffffffffff1681526020013373ffffffffffffffffffffffffffffffffffffffff1681526020018967ffffffffffffffff1681526020018663ffffffff168152602001600a60000160029054906101000a900468ffffffffffffffffff1668ffffffffffffffffff1681526020018260e0015168ffffffffffffffffff16815260200182610100015164ffffffffff16815260200182610120015164ffffffffff16815260200182610140015163ffffffff16815250604051602001613d2491906154ac565b60405160208183030381529060405280519060200120600560008360000151815260200190815260200160002081905550613d64338983604001516142cf565b8767ffffffffffffffff168a82600001517ff67aec45c9a7ede407974a3e0c3a743dffeab99ee3f2d4c9a8144c2ebf2c7ec9866020015133328d8d8d8a60400151604051613db89796959493929190615ad1565b60405180910390a4519998505050505050505050565b67ffffffffffffffff81166000908152600360205260409020546c01000000000000000000000000900473ffffffffffffffffffffffffffffffffffffffff1680613e45576040517f1f6a65b600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b3373ffffffffffffffffffffffffffffffffffffffff82161461255a576040517f5a68151d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60095460009081526008602052604090205473ffffffffffffffffffffffffffffffffffffffff1680613ec45750565b604080516000815260208101918290527f6b14daf80000000000000000000000000000000000000000000000000000000090915273ffffffffffffffffffffffffffffffffffffffff821690636b14daf890613f2590339060248101615b49565b602060405180830381865afa158015613f42573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613f66919061582b565b610754576040517f229062630000000000000000000000000000000000000000000000000000000081523360048201526024016107b3565b6040805173ffffffffffffffffffffffffffffffffffffffff8416602482015260448082018490528251808303909101815260649091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fa9059cbb000000000000000000000000000000000000000000000000000000001790526113f89084906143aa565b614033614182565b600680547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2586139fb3390565b3373ffffffffffffffffffffffffffffffffffffffff821603614105576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c6600000000000000000060448201526064016107b3565b600780547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff838116918217909255600654604051919261010090910416907fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae127890600090a350565b60065460ff161561101f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f5061757361626c653a207061757365640000000000000000000000000000000060448201526064016107b3565b60065460ff1661101f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f5061757361626c653a206e6f742070617573656400000000000000000000000060448201526064016107b3565b73ffffffffffffffffffffffffffffffffffffffff8216600090815260046020908152604080832067ffffffffffffffff8516845290915290205460ff1661255a576040517f71e8313700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b67ffffffffffffffff8216600090815260036020526040812060010180548392906143099084906bffffffffffffffffffffffff16615655565b82546bffffffffffffffffffffffff91821661010093840a908102920219161790915573ffffffffffffffffffffffffffffffffffffffff8516600090815260046020908152604080832067ffffffffffffffff808916855292529091208054600194509092849261437f92849290041661584d565b92506101000a81548167ffffffffffffffff021916908367ffffffffffffffff160217905550505050565b600061440c826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff166144b69092919063ffffffff16565b8051909150156113f8578080602001905181019061442a919061582b565b6113f8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f7420737563636565640000000000000000000000000000000000000000000060648201526084016107b3565b60606144c584846000856144cd565b949350505050565b60608247101561455f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f60448201527f722063616c6c000000000000000000000000000000000000000000000000000060648201526084016107b3565b6000808673ffffffffffffffffffffffffffffffffffffffff1685876040516145889190615b78565b60006040518083038185875af1925050503d80600081146145c5576040519150601f19603f3d011682016040523d82523d6000602084013e6145ca565b606091505b50915091506145db878383876145e6565b979650505050505050565b6060831561467c5782516000036146755773ffffffffffffffffffffffffffffffffffffffff85163b614675576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064016107b3565b50816144c5565b6144c583838151156146915781518083602001fd5b806040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016107b39190614962565b828054828255906000526020600020906007016008900481019282156147645791602002820160005b8382111561473257835183826101000a81548163ffffffff021916908363ffffffff16021790555092602001926004016020816003010492830192600103026146ee565b80156147625782816101000a81549063ffffffff0219169055600401602081600301049283019260010302614732565b505b5061349392915061483f565b828054828255906000526020600020908101928215614764579160200282015b82811115614764578251825591602001919060010190614790565b828054828255906000526020600020908101928215614764579160200282015b8281111561476457825182547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff9091161782556020909201916001909101906147cb565b508054600082559060005260206000209081019061075491905b5b808211156134935760008155600101614840565b67ffffffffffffffff8116811461075457600080fd5b803561487581614854565b919050565b60006020828403121561488c57600080fd5b813561489781614854565b9392505050565b63ffffffff8116811461075457600080fd5b80356148758161489e565b600080604083850312156148ce57600080fd5b82356148d981614854565b915060208301356148e98161489e565b809150509250929050565b60005b8381101561490f5781810151838201526020016148f7565b50506000910152565b600081518084526149308160208601602086016148f4565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b6020815260006148976020830184614918565b6000806040838503121561498857600080fd5b823561499381614854565b946020939093013593505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b60405160a0810167ffffffffffffffff811182821017156149f3576149f36149a1565b60405290565b604051610160810167ffffffffffffffff811182821017156149f3576149f36149a1565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715614a6457614a646149a1565b604052919050565b803561ffff8116811461487557600080fd5b68ffffffffffffffffff8116811461075457600080fd5b803561487581614a7e565b600067ffffffffffffffff821115614aba57614aba6149a1565b5060051b60200190565b600082601f830112614ad557600080fd5b81356020614aea614ae583614aa0565b614a1d565b82815260059290921b84018101918181019086841115614b0957600080fd5b8286015b84811015614b2d578035614b208161489e565b8352918301918301614b0d565b509695505050505050565b600060208284031215614b4a57600080fd5b813567ffffffffffffffff80821115614b6257600080fd5b9083019060a08286031215614b7657600080fd5b614b7e6149d0565b614b8783614a6c565b81526020830135614b9781614a7e565b602082015260408301357fffffffff0000000000000000000000000000000000000000000000000000000081168114614bcf57600080fd5b6040820152614be060608401614a6c565b6060820152608083013582811115614bf757600080fd5b614c0387828601614ac4565b60808301525095945050505050565b600082601f830112614c2357600080fd5b813567ffffffffffffffff811115614c3d57614c3d6149a1565b614c6e60207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f84011601614a1d565b818152846020838601011115614c8357600080fd5b816020850160208301376000918101602001919091529392505050565b6bffffffffffffffffffffffff8116811461075457600080fd5b803561487581614ca0565b73ffffffffffffffffffffffffffffffffffffffff8116811461075457600080fd5b803561487581614cc5565b64ffffffffff8116811461075457600080fd5b803561487581614cf2565b60006101608284031215614d2357600080fd5b614d2b6149f9565b905081358152614d3d60208301614ce7565b6020820152614d4e60408301614cba565b6040820152614d5f60608301614ce7565b6060820152614d706080830161486a565b6080820152614d8160a083016148b0565b60a0820152614d9260c08301614a95565b60c0820152614da360e08301614a95565b60e0820152610100614db6818401614d05565b90820152610120614dc8838201614d05565b90820152610140614dda8382016148b0565b9082015292915050565b6000806000806000806102008789031215614dfe57600080fd5b863567ffffffffffffffff80821115614e1657600080fd5b614e228a838b01614c12565b97506020890135915080821115614e3857600080fd5b50614e4589828a01614c12565b9550506040870135614e5681614ca0565b93506060870135614e6681614ca0565b92506080870135614e7681614cc5565b9150614e858860a08901614d10565b90509295509295509295565b60078110614ec8577f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b9052565b60408101614eda8285614e91565b6bffffffffffffffffffffffff831660208301529392505050565b600082601f830112614f0657600080fd5b81356020614f16614ae583614aa0565b82815260059290921b84018101918181019086841115614f3557600080fd5b8286015b84811015614b2d578035614f4c81614cc5565b8352918301918301614f39565b60008060408385031215614f6c57600080fd5b823567ffffffffffffffff80821115614f8457600080fd5b818501915085601f830112614f9857600080fd5b81356020614fa8614ae583614aa0565b82815260059290921b84018101918181019089841115614fc757600080fd5b948201945b83861015614fe557853582529482019490820190614fcc565b96505086013592505080821115614ffb57600080fd5b5061500885828601614ef5565b9150509250929050565b60008083601f84011261502457600080fd5b50813567ffffffffffffffff81111561503c57600080fd5b60208301915083602082850101111561505457600080fd5b9250929050565b60008060008060008060a0878903121561507457600080fd5b863561507f81614854565b9550602087013567ffffffffffffffff81111561509b57600080fd5b6150a789828a01615012565b90965094506150ba905060408801614a6c565b925060608701356150ca8161489e565b80925050608087013590509295509295509295565b600080604083850312156150f257600080fd5b82356150fd81614854565b915060208301356148e981614cc5565b6000806040838503121561512057600080fd5b823561512b81614cc5565b915060208301356148e981614ca0565b6000806040838503121561514e57600080fd5b823561515981614cc5565b915060208301356148e981614854565b60006020828403121561517b57600080fd5b5035919050565b600081518084526020808501945080840160005b838110156151c857815173ffffffffffffffffffffffffffffffffffffffff1687529582019590820190600101615196565b509495945050505050565b6020815260006bffffffffffffffffffffffff808451166020840152602084015173ffffffffffffffffffffffffffffffffffffffff8082166040860152826040870151166060860152806060870151166080860152505050608083015160c060a084015261524560e0840182615182565b905060a084015160c08401528091505092915050565b6000806000806060858703121561527157600080fd5b843561527c81614cc5565b935060208501359250604085013567ffffffffffffffff81111561529f57600080fd5b6152ab87828801615012565b95989497509550505050565b604080825283519082018190526000906020906060840190828701845b828110156152f0578151845292840192908401906001016152d4565b505050838103828501526153048186615182565b9695505050505050565b6000602080835260c0830161ffff808651168386015268ffffffffffffffffff838701511660408601527fffffffff00000000000000000000000000000000000000000000000000000000604087015116606086015280606087015116608086015250608085015160a08086015281815180845260e0870191508483019350600092505b80831015614b2d57835163ffffffff168252928401926001929092019190840190615392565b6000602082840312156153ca57600080fd5b813561489781614cc5565b600080602083850312156153e857600080fd5b823567ffffffffffffffff8082111561540057600080fd5b818501915085601f83011261541457600080fd5b81358181111561542357600080fd5b8660206101608302850101111561543957600080fd5b60209290920196919550909350505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b73ffffffffffffffffffffffffffffffffffffffff848116825283166020820152606081016144c56040830184614e91565b815181526020808301516101608301916154dd9084018273ffffffffffffffffffffffffffffffffffffffff169052565b5060408301516154fd60408401826bffffffffffffffffffffffff169052565b506060830151615525606084018273ffffffffffffffffffffffffffffffffffffffff169052565b506080830151615541608084018267ffffffffffffffff169052565b5060a083015161555960a084018263ffffffff169052565b5060c083015161557660c084018268ffffffffffffffffff169052565b5060e083015161559360e084018268ffffffffffffffffff169052565b506101008381015164ffffffffff81168483015250506101208381015164ffffffffff81168483015250506101408381015163ffffffff8116848301525b505092915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b64ffffffffff818116838216019080821115615626576156266155d9565b5092915050565b6bffffffffffffffffffffffff8181168382160280821691908281146155d1576155d16155d9565b6bffffffffffffffffffffffff818116838216019080821115615626576156266155d9565b6bffffffffffffffffffffffff8716815273ffffffffffffffffffffffffffffffffffffffff861660208201526156b46040820186614e91565b60c0606082015260006156ca60c0830186614918565b82810360808401526156dc8186614918565b905082810360a08401526156f08185614918565b9998505050505050505050565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff820361572e5761572e6155d9565b5060010190565b6bffffffffffffffffffffffff828116828216039080821115615626576156266155d9565b600060ff821660ff8103615770576157706155d9565b60010192915050565b818103818111156115d9576115d96155d9565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fd5b600067ffffffffffffffff8083168181036157d8576157d86155d9565b6001019392505050565b808201808211156115d9576115d96155d9565b60006020828403121561580757600080fd5b5051919050565b6000610160828403121561582157600080fd5b6148978383614d10565b60006020828403121561583d57600080fd5b8151801515811461489757600080fd5b67ffffffffffffffff818116838216019080821115615626576156266155d9565b8381526060602082015260006158876060830185614918565b82810360408401526153048185614918565b60208152600082516101608060208501526158b8610180850183614918565b91506020850151604085015260408501516158eb606086018273ffffffffffffffffffffffffffffffffffffffff169052565b5060608501516bffffffffffffffffffffffff8116608086015250608085015168ffffffffffffffffff811660a08601525060a085015167ffffffffffffffff811660c08601525060c085015167ffffffffffffffff811660e08601525060e08501516101006159628187018363ffffffff169052565b86015190506101206159798682018361ffff169052565b86015190506101406159968682018367ffffffffffffffff169052565b9095015173ffffffffffffffffffffffffffffffffffffffff1693019290925250919050565b805161487581614cc5565b805161487581614ca0565b805161487581614854565b80516148758161489e565b805161487581614a7e565b805161487581614cf2565b60006101608284031215615a1157600080fd5b615a196149f9565b82518152615a29602084016159bc565b6020820152615a3a604084016159c7565b6040820152615a4b606084016159bc565b6060820152615a5c608084016159d2565b6080820152615a6d60a084016159dd565b60a0820152615a7e60c084016159e8565b60c0820152615a8f60e084016159e8565b60e0820152610100615aa28185016159f3565b90820152610120615ab48482016159f3565b90820152610140615ac68482016159dd565b908201529392505050565b600073ffffffffffffffffffffffffffffffffffffffff808a168352808916602084015280881660408401525060e06060830152615b1260e0830187614918565b61ffff9590951660808301525063ffffffff9290921660a08301526bffffffffffffffffffffffff1660c090910152949350505050565b73ffffffffffffffffffffffffffffffffffffffff831681526040602082015260006144c56040830184614918565b60008251615b8a8184602087016148f4565b919091019291505056fea164736f6c6343000813000a", + ABI: "[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"linkToken\",\"type\":\"address\"},{\"components\":[{\"internalType\":\"uint16\",\"name\":\"maxConsumersPerSubscription\",\"type\":\"uint16\"},{\"internalType\":\"uint72\",\"name\":\"adminFee\",\"type\":\"uint72\"},{\"internalType\":\"bytes4\",\"name\":\"handleOracleFulfillmentSelector\",\"type\":\"bytes4\"},{\"internalType\":\"uint16\",\"name\":\"gasForCallExactCheck\",\"type\":\"uint16\"},{\"internalType\":\"uint32[]\",\"name\":\"maxCallbackGasLimits\",\"type\":\"uint32[]\"},{\"internalType\":\"uint16\",\"name\":\"subscriptionDepositMinimumRequests\",\"type\":\"uint16\"},{\"internalType\":\"uint72\",\"name\":\"subscriptionDepositJuels\",\"type\":\"uint72\"}],\"internalType\":\"structFunctionsRouter.Config\",\"name\":\"config\",\"type\":\"tuple\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"CannotRemoveWithPendingRequests\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"requestId\",\"type\":\"bytes32\"}],\"name\":\"DuplicateRequestId\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"EmptyRequestData\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"limit\",\"type\":\"uint32\"}],\"name\":\"GasLimitTooBig\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"id\",\"type\":\"bytes32\"}],\"name\":\"IdentifierIsReserved\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint96\",\"name\":\"currentBalanceJuels\",\"type\":\"uint96\"}],\"name\":\"InsufficientBalance\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidCalldata\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidConsumer\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint8\",\"name\":\"value\",\"type\":\"uint8\"}],\"name\":\"InvalidGasFlagValue\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidProposal\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidSubscription\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"proposedOwner\",\"type\":\"address\"}],\"name\":\"MustBeProposedOwner\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"MustBeSubscriptionOwner\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableFromCoordinator\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableFromLink\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"id\",\"type\":\"bytes32\"}],\"name\":\"RouteNotFound\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"SenderMustAcceptTermsOfService\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"TimeoutNotExceeded\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint16\",\"name\":\"maximumConsumers\",\"type\":\"uint16\"}],\"name\":\"TooManyConsumers\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"components\":[{\"internalType\":\"uint16\",\"name\":\"maxConsumersPerSubscription\",\"type\":\"uint16\"},{\"internalType\":\"uint72\",\"name\":\"adminFee\",\"type\":\"uint72\"},{\"internalType\":\"bytes4\",\"name\":\"handleOracleFulfillmentSelector\",\"type\":\"bytes4\"},{\"internalType\":\"uint16\",\"name\":\"gasForCallExactCheck\",\"type\":\"uint16\"},{\"internalType\":\"uint32[]\",\"name\":\"maxCallbackGasLimits\",\"type\":\"uint32[]\"},{\"internalType\":\"uint16\",\"name\":\"subscriptionDepositMinimumRequests\",\"type\":\"uint16\"},{\"internalType\":\"uint72\",\"name\":\"subscriptionDepositJuels\",\"type\":\"uint72\"}],\"indexed\":false,\"internalType\":\"structFunctionsRouter.Config\",\"name\":\"\",\"type\":\"tuple\"}],\"name\":\"ConfigUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"proposedContractSetId\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"proposedContractSetFromAddress\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"proposedContractSetToAddress\",\"type\":\"address\"}],\"name\":\"ContractProposed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"id\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"ContractUpdated\",\"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\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"Paused\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"requestId\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"coordinator\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"transmitter\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"enumFunctionsResponse.FulfillResult\",\"name\":\"resultCode\",\"type\":\"uint8\"}],\"name\":\"RequestNotProcessed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"requestId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"uint96\",\"name\":\"totalCostJuels\",\"type\":\"uint96\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"transmitter\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"enumFunctionsResponse.FulfillResult\",\"name\":\"resultCode\",\"type\":\"uint8\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"response\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"err\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"callbackReturnData\",\"type\":\"bytes\"}],\"name\":\"RequestProcessed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"requestId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"donId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"subscriptionOwner\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"requestingContract\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"requestInitiator\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"uint16\",\"name\":\"dataVersion\",\"type\":\"uint16\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"callbackGasLimit\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"uint96\",\"name\":\"estimatedTotalCostJuels\",\"type\":\"uint96\"}],\"name\":\"RequestStart\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"requestId\",\"type\":\"bytes32\"}],\"name\":\"RequestTimedOut\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"fundsRecipient\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"fundsAmount\",\"type\":\"uint256\"}],\"name\":\"SubscriptionCanceled\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"consumer\",\"type\":\"address\"}],\"name\":\"SubscriptionConsumerAdded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"consumer\",\"type\":\"address\"}],\"name\":\"SubscriptionConsumerRemoved\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"}],\"name\":\"SubscriptionCreated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"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\":\"subscriptionId\",\"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\":\"subscriptionId\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"SubscriptionOwnerTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"Unpaused\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"MAX_CALLBACK_RETURN_BYTES\",\"outputs\":[{\"internalType\":\"uint16\",\"name\":\"\",\"type\":\"uint16\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"acceptOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"}],\"name\":\"acceptSubscriptionOwnerTransfer\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"},{\"internalType\":\"address\",\"name\":\"consumer\",\"type\":\"address\"}],\"name\":\"addConsumer\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"cancelSubscription\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"createSubscription\",\"outputs\":[{\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"consumer\",\"type\":\"address\"}],\"name\":\"createSubscriptionWithConsumer\",\"outputs\":[{\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"response\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"err\",\"type\":\"bytes\"},{\"internalType\":\"uint96\",\"name\":\"juelsPerGas\",\"type\":\"uint96\"},{\"internalType\":\"uint96\",\"name\":\"costWithoutCallback\",\"type\":\"uint96\"},{\"internalType\":\"address\",\"name\":\"transmitter\",\"type\":\"address\"},{\"components\":[{\"internalType\":\"bytes32\",\"name\":\"requestId\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"coordinator\",\"type\":\"address\"},{\"internalType\":\"uint96\",\"name\":\"estimatedTotalCostJuels\",\"type\":\"uint96\"},{\"internalType\":\"address\",\"name\":\"client\",\"type\":\"address\"},{\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"callbackGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint72\",\"name\":\"adminFee\",\"type\":\"uint72\"},{\"internalType\":\"uint72\",\"name\":\"donFee\",\"type\":\"uint72\"},{\"internalType\":\"uint40\",\"name\":\"gasOverheadBeforeCallback\",\"type\":\"uint40\"},{\"internalType\":\"uint40\",\"name\":\"gasOverheadAfterCallback\",\"type\":\"uint40\"},{\"internalType\":\"uint32\",\"name\":\"timeoutTimestamp\",\"type\":\"uint32\"}],\"internalType\":\"structFunctionsResponse.Commitment\",\"name\":\"commitment\",\"type\":\"tuple\"}],\"name\":\"fulfill\",\"outputs\":[{\"internalType\":\"enumFunctionsResponse.FulfillResult\",\"name\":\"resultCode\",\"type\":\"uint8\"},{\"internalType\":\"uint96\",\"name\":\"\",\"type\":\"uint96\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getAdminFee\",\"outputs\":[{\"internalType\":\"uint72\",\"name\":\"\",\"type\":\"uint72\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getAllowListId\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getConfig\",\"outputs\":[{\"components\":[{\"internalType\":\"uint16\",\"name\":\"maxConsumersPerSubscription\",\"type\":\"uint16\"},{\"internalType\":\"uint72\",\"name\":\"adminFee\",\"type\":\"uint72\"},{\"internalType\":\"bytes4\",\"name\":\"handleOracleFulfillmentSelector\",\"type\":\"bytes4\"},{\"internalType\":\"uint16\",\"name\":\"gasForCallExactCheck\",\"type\":\"uint16\"},{\"internalType\":\"uint32[]\",\"name\":\"maxCallbackGasLimits\",\"type\":\"uint32[]\"},{\"internalType\":\"uint16\",\"name\":\"subscriptionDepositMinimumRequests\",\"type\":\"uint16\"},{\"internalType\":\"uint72\",\"name\":\"subscriptionDepositJuels\",\"type\":\"uint72\"}],\"internalType\":\"structFunctionsRouter.Config\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"client\",\"type\":\"address\"},{\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"}],\"name\":\"getConsumer\",\"outputs\":[{\"components\":[{\"internalType\":\"bool\",\"name\":\"allowed\",\"type\":\"bool\"},{\"internalType\":\"uint64\",\"name\":\"initiatedRequests\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"completedRequests\",\"type\":\"uint64\"}],\"internalType\":\"structIFunctionsSubscriptions.Consumer\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"id\",\"type\":\"bytes32\"}],\"name\":\"getContractById\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"}],\"name\":\"getFlags\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"id\",\"type\":\"bytes32\"}],\"name\":\"getProposedContractById\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getProposedContractSet\",\"outputs\":[{\"internalType\":\"bytes32[]\",\"name\":\"\",\"type\":\"bytes32[]\"},{\"internalType\":\"address[]\",\"name\":\"\",\"type\":\"address[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"}],\"name\":\"getSubscription\",\"outputs\":[{\"components\":[{\"internalType\":\"uint96\",\"name\":\"balance\",\"type\":\"uint96\"},{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"internalType\":\"uint96\",\"name\":\"blockedBalance\",\"type\":\"uint96\"},{\"internalType\":\"address\",\"name\":\"proposedOwner\",\"type\":\"address\"},{\"internalType\":\"address[]\",\"name\":\"consumers\",\"type\":\"address[]\"},{\"internalType\":\"bytes32\",\"name\":\"flags\",\"type\":\"bytes32\"}],\"internalType\":\"structIFunctionsSubscriptions.Subscription\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getSubscriptionCount\",\"outputs\":[{\"internalType\":\"uint64\",\"name\":\"\",\"type\":\"uint64\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"subscriptionIdStart\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"subscriptionIdEnd\",\"type\":\"uint64\"}],\"name\":\"getSubscriptionsInRange\",\"outputs\":[{\"components\":[{\"internalType\":\"uint96\",\"name\":\"balance\",\"type\":\"uint96\"},{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"internalType\":\"uint96\",\"name\":\"blockedBalance\",\"type\":\"uint96\"},{\"internalType\":\"address\",\"name\":\"proposedOwner\",\"type\":\"address\"},{\"internalType\":\"address[]\",\"name\":\"consumers\",\"type\":\"address[]\"},{\"internalType\":\"bytes32\",\"name\":\"flags\",\"type\":\"bytes32\"}],\"internalType\":\"structIFunctionsSubscriptions.Subscription[]\",\"name\":\"subscriptions\",\"type\":\"tuple[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getTotalBalance\",\"outputs\":[{\"internalType\":\"uint96\",\"name\":\"\",\"type\":\"uint96\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"callbackGasLimit\",\"type\":\"uint32\"}],\"name\":\"isValidCallbackGasLimit\",\"outputs\":[],\"stateMutability\":\"view\",\"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\":\"subscriptionId\",\"type\":\"uint64\"}],\"name\":\"ownerCancelSubscription\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"uint96\",\"name\":\"amount\",\"type\":\"uint96\"}],\"name\":\"ownerWithdraw\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"pause\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"paused\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"}],\"name\":\"pendingRequestExists\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32[]\",\"name\":\"proposedContractSetIds\",\"type\":\"bytes32[]\"},{\"internalType\":\"address[]\",\"name\":\"proposedContractSetAddresses\",\"type\":\"address[]\"}],\"name\":\"proposeContractsUpdate\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"},{\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"proposeSubscriptionOwnerTransfer\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"recoverFunds\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"},{\"internalType\":\"address\",\"name\":\"consumer\",\"type\":\"address\"}],\"name\":\"removeConsumer\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"},{\"internalType\":\"uint16\",\"name\":\"dataVersion\",\"type\":\"uint16\"},{\"internalType\":\"uint32\",\"name\":\"callbackGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"bytes32\",\"name\":\"donId\",\"type\":\"bytes32\"}],\"name\":\"sendRequest\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"},{\"internalType\":\"uint16\",\"name\":\"dataVersion\",\"type\":\"uint16\"},{\"internalType\":\"uint32\",\"name\":\"callbackGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"bytes32\",\"name\":\"donId\",\"type\":\"bytes32\"}],\"name\":\"sendRequestToProposed\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"allowListId\",\"type\":\"bytes32\"}],\"name\":\"setAllowListId\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"},{\"internalType\":\"bytes32\",\"name\":\"flags\",\"type\":\"bytes32\"}],\"name\":\"setFlags\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"bytes32\",\"name\":\"requestId\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"coordinator\",\"type\":\"address\"},{\"internalType\":\"uint96\",\"name\":\"estimatedTotalCostJuels\",\"type\":\"uint96\"},{\"internalType\":\"address\",\"name\":\"client\",\"type\":\"address\"},{\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"callbackGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint72\",\"name\":\"adminFee\",\"type\":\"uint72\"},{\"internalType\":\"uint72\",\"name\":\"donFee\",\"type\":\"uint72\"},{\"internalType\":\"uint40\",\"name\":\"gasOverheadBeforeCallback\",\"type\":\"uint40\"},{\"internalType\":\"uint40\",\"name\":\"gasOverheadAfterCallback\",\"type\":\"uint40\"},{\"internalType\":\"uint32\",\"name\":\"timeoutTimestamp\",\"type\":\"uint32\"}],\"internalType\":\"structFunctionsResponse.Commitment[]\",\"name\":\"requestsToTimeoutByCommitment\",\"type\":\"tuple[]\"}],\"name\":\"timeoutRequests\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"typeAndVersion\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"unpause\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint16\",\"name\":\"maxConsumersPerSubscription\",\"type\":\"uint16\"},{\"internalType\":\"uint72\",\"name\":\"adminFee\",\"type\":\"uint72\"},{\"internalType\":\"bytes4\",\"name\":\"handleOracleFulfillmentSelector\",\"type\":\"bytes4\"},{\"internalType\":\"uint16\",\"name\":\"gasForCallExactCheck\",\"type\":\"uint16\"},{\"internalType\":\"uint32[]\",\"name\":\"maxCallbackGasLimits\",\"type\":\"uint32[]\"},{\"internalType\":\"uint16\",\"name\":\"subscriptionDepositMinimumRequests\",\"type\":\"uint16\"},{\"internalType\":\"uint72\",\"name\":\"subscriptionDepositJuels\",\"type\":\"uint72\"}],\"internalType\":\"structFunctionsRouter.Config\",\"name\":\"config\",\"type\":\"tuple\"}],\"name\":\"updateConfig\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"updateContracts\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", + Bin: "0x60a06040523480156200001157600080fd5b506040516200673c3803806200673c833981016040819052620000349162000549565b6001600160a01b0382166080526006805460ff191690553380600081620000a25760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600680546001600160a01b0380851661010002610100600160a81b031990921691909117909155811615620000dc57620000dc81620000f8565b505050620000f081620001aa60201b60201c565b50506200071a565b336001600160a01b03821603620001525760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c66000000000000000000604482015260640162000099565b600780546001600160a01b0319166001600160a01b03838116918217909255600654604051919261010090910416907fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae127890600090a350565b620001b4620002c0565b8051600a80546020808501516040860151606087015161ffff908116600160781b0261ffff60781b1960e09390931c6b010000000000000000000000029290921665ffffffffffff60581b196001600160481b0390941662010000026001600160581b031990961691909716179390931716939093171781556080830151805184936200024792600b9291019062000323565b5060a08201516002909101805460c0909301516001600160481b031662010000026001600160581b031990931661ffff909216919091179190911790556040517ea5832bf95f66c7814294cc4db681f20ee79608bfb8912a5321d66cfed5e98590620002b590839062000652565b60405180910390a150565b60065461010090046001600160a01b03163314620003215760405162461bcd60e51b815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e657200000000000000000000604482015260640162000099565b565b82805482825590600052602060002090600701600890048101928215620003c75791602002820160005b838211156200039357835183826101000a81548163ffffffff021916908363ffffffff16021790555092602001926004016020816003010492830192600103026200034d565b8015620003c55782816101000a81549063ffffffff021916905560040160208160030104928301926001030262000393565b505b50620003d5929150620003d9565b5090565b5b80821115620003d55760008155600101620003da565b634e487b7160e01b600052604160045260246000fd5b60405160e081016001600160401b03811182821017156200042b576200042b620003f0565b60405290565b604051601f8201601f191681016001600160401b03811182821017156200045c576200045c620003f0565b604052919050565b805161ffff811681146200047757600080fd5b919050565b80516001600160481b03811681146200047757600080fd5b80516001600160e01b0319811681146200047757600080fd5b600082601f830112620004bf57600080fd5b815160206001600160401b03821115620004dd57620004dd620003f0565b8160051b620004ee82820162000431565b92835284810182019282810190878511156200050957600080fd5b83870192505b848310156200053e57825163ffffffff811681146200052e5760008081fd5b825291830191908301906200050f565b979650505050505050565b600080604083850312156200055d57600080fd5b82516001600160a01b03811681146200057557600080fd5b60208401519092506001600160401b03808211156200059357600080fd5b9084019060e08287031215620005a857600080fd5b620005b262000406565b620005bd8362000464565b8152620005cd602084016200047c565b6020820152620005e06040840162000494565b6040820152620005f36060840162000464565b60608201526080830151828111156200060b57600080fd5b6200061988828601620004ad565b6080830152506200062d60a0840162000464565b60a08201526200064060c084016200047c565b60c08201528093505050509250929050565b6020808252825161ffff90811683830152838201516001600160481b03166040808501919091528401516001600160e01b0319166060808501919091528401511660808084019190915283015160e060a0840152805161010084018190526000929182019083906101208601905b80831015620006e857835163ffffffff168252928401926001929092019190840190620006c0565b5060a087015161ffff811660c0880152935060c08701516001600160481b03811660e088015293509695505050505050565b608051615fea62000752600039600081816111cd0152818161208c015281816129b801528181612a7c01526135d30152615fea6000f3fe608060405234801561001057600080fd5b50600436106102e95760003560e01c80637341c10c11610191578063b734c0f4116100e3578063e72f6e3011610097578063ea320e0b11610071578063ea320e0b146106dd578063ec2454e5146106f0578063f2fde38b1461071057600080fd5b8063e72f6e30146106a4578063e82622aa146106b7578063e82ad7d4146106ca57600080fd5b8063c3f909d4116100c8578063c3f909d414610669578063cc77470a1461067e578063d7ae1d301461069157600080fd5b8063b734c0f41461064b578063badc3eb61461065357600080fd5b80639f87fad711610145578063a4c0ed361161011f578063a4c0ed361461061d578063a9c9a91814610630578063aab396bd1461064357600080fd5b80639f87fad7146105e2578063a21a23e4146105f5578063a47c7696146105fd57600080fd5b8063823597401161017657806382359740146105a45780638456cb59146105b75780638da5cb5b146105bf57600080fd5b80637341c10c1461058957806379ba50971461059c57600080fd5b806341db4ca31161024a5780635ed6dfba116101fe57806366419970116101d857806366419970146104e1578063674603d0146105085780636a2215de1461055157600080fd5b80635ed6dfba146104a85780636162a323146104bb57806366316d8d146104ce57600080fd5b80634b8832d31161022f5780634b8832d31461045057806355fedefa146104635780635c975abb1461049157600080fd5b806341db4ca31461041c578063461d27621461043d57600080fd5b80631ded3b36116102a1578063330605291161028657806333060529146103e05780633e871e4d146104015780633f4ba83a1461041457600080fd5b80631ded3b361461039f5780632a905ccc146103b257600080fd5b806310fc49c1116102d257806310fc49c11461032357806312b5834914610336578063181f5a771461035657600080fd5b806302bcc5b6146102ee5780630c5d49cb14610303575b600080fd5b6103016102fc366004614ba6565b610723565b005b61030b608481565b60405161ffff90911681526020015b60405180910390f35b610301610331366004614be7565b610783565b6000546040516bffffffffffffffffffffffff909116815260200161031a565b6103926040518060400160405280601781526020017f46756e6374696f6e7320526f757465722076312e302e3000000000000000000081525081565b60405161031a9190614c8e565b6103016103ad366004614ca1565b61087f565b600a5462010000900468ffffffffffffffffff1660405168ffffffffffffffffff909116815260200161031a565b6103f36103ee366004614f8c565b6108b1565b60405161031a929190615074565b61030161040f366004615135565b610c7c565b610301610e91565b61042f61042a366004615249565b610ea3565b60405190815260200161031a565b61042f61044b366004615249565b610f03565b61030161045e3660046152cd565b610f0f565b61042f610471366004614ba6565b67ffffffffffffffff166000908152600360208190526040909120015490565b60065460ff165b604051901515815260200161031a565b6103016104b63660046152fb565b61105d565b6103016104c93660046153bd565b611216565b6103016104dc3660046152fb565b611396565b60025467ffffffffffffffff165b60405167ffffffffffffffff909116815260200161031a565b61051b610516366004615490565b61147f565b6040805182511515815260208084015167ffffffffffffffff90811691830191909152928201519092169082015260600161031a565b61056461055f3660046154be565b61150f565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200161031a565b6103016105973660046152cd565b6115ce565b610301611781565b6103016105b2366004614ba6565b6118a8565b6103016119ef565b600654610100900473ffffffffffffffffffffffffffffffffffffffff16610564565b6103016105f03660046152cd565b6119ff565b6104ef611daa565b61061061060b366004614ba6565b611f37565b60405161031a91906155a7565b61030161062b3660046155ba565b61206c565b61056461063e3660046154be565b6122b8565b60095461042f565b610301612317565b61065b612463565b60405161031a929190615616565b610671612533565b60405161031a919061566d565b6104ef61068c366004615749565b61269a565b61030161069f3660046152cd565b61291a565b6103016106b2366004615749565b61297f565b6103016106c5366004615766565b612af8565b6104986106d8366004614ba6565b612db7565b6103016106eb3660046154be565b612f06565b6107036106fe3660046157dc565b612f13565b60405161031a91906157fa565b61030161071e366004615749565b6131a8565b61072b6131b9565b610734816131c1565b67ffffffffffffffff81166000908152600360205260408120546107809183916c01000000000000000000000000900473ffffffffffffffffffffffffffffffffffffffff1690613237565b50565b67ffffffffffffffff8216600090815260036020819052604082200154600b54911a9081106107e8576040517f45c108ce00000000000000000000000000000000000000000000000000000000815260ff821660048201526024015b60405180910390fd5b6000600a6001018260ff16815481106108035761080361587a565b90600052602060002090600891828204019190066004029054906101000a900463ffffffff1690508063ffffffff168363ffffffff161115610879576040517f1d70f87a00000000000000000000000000000000000000000000000000000000815263ffffffff821660048201526024016107df565b50505050565b6108876131b9565b610890826131c1565b67ffffffffffffffff90911660009081526003602081905260409091200155565b6000806108bc613689565b826020015173ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614610925576040517f8bec23e700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b82516000908152600560205260409020548061098a5783516020850151604051600295507f1a90e9a50793db2e394cf581e7c522e10c358a81e70acf6b5a0edd620c08dee19161097891899088906158a9565b60405180910390a25060009050610c71565b808460405160200161099c91906158db565b60405160208183030381529060405280519060200120146109f45783516020850151604051600695507f1a90e9a50793db2e394cf581e7c522e10c358a81e70acf6b5a0edd620c08dee19161097891899088906158a9565b8361012001518460a0015163ffffffff16610a0f9190615a37565b64ffffffffff165a1015610a5a5783516020850151604051600495507f1a90e9a50793db2e394cf581e7c522e10c358a81e70acf6b5a0edd620c08dee19161097891899088906158a9565b506000610a708460a0015163ffffffff16613691565b610a7a9088615a55565b9050600081878660c0015168ffffffffffffffffff16610a9a9190615a7d565b610aa49190615a7d565b9050610ab38560800151611f37565b600001516bffffffffffffffffffffffff16816bffffffffffffffffffffffff161115610b2b5784516020860151604051600596507f1a90e9a50793db2e394cf581e7c522e10c358a81e70acf6b5a0edd620c08dee191610b17918a9089906158a9565b60405180910390a25060009150610c719050565b84604001516bffffffffffffffffffffffff16816bffffffffffffffffffffffff161115610b905784516020860151604051600396507f1a90e9a50793db2e394cf581e7c522e10c358a81e70acf6b5a0edd620c08dee191610b17918a9089906158a9565b505082516000908152600560205260408120819055835160a08501516060860151610bc092918c918c9190613733565b8051909150610bd0576001610bd3565b60005b92506000610c0d8560800151866040015187606001518860c0015168ffffffffffffffffff168c610c078860200151613691565b8d6138f1565b9050846080015167ffffffffffffffff1685600001517f64778f26c70b60a8d7e29e2451b3844302d959448401c0535b768ed88c6b505e836020015189888f8f8960400151604051610c6496959493929190615aa2565b60405180910390a3519150505b965096945050505050565b610c84613c17565b8151815181141580610c965750600881115b15610ccd576040517fee03280800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60005b81811015610e47576000848281518110610cec57610cec61587a565b602002602001015190506000848381518110610d0a57610d0a61587a565b60200260200101519050600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff161480610d75575060008281526008602052604090205473ffffffffffffffffffffffffffffffffffffffff8281169116145b15610dac576040517fee03280800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600082815260086020526040908190205490517f8b052f0f4bf82fede7daffea71592b29d5ef86af1f3c7daaa0345dbb2f52f48191610e2c91859173ffffffffffffffffffffffffffffffffffffffff1690859092835273ffffffffffffffffffffffffffffffffffffffff918216602084015216604082015260600190565b60405180910390a1505080610e4090615b25565b9050610cd0565b506040805180820190915283815260208082018490528451600d91610e709183918801906149e6565b506020828101518051610e899260018501920190614a2d565b505050505050565b610e99613c17565b610ea1613c9d565b565b600080610eaf8361150f565b9050610ef783828a8a8a8080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152508c92508b9150613d1a9050565b98975050505050505050565b600080610eaf836122b8565b610f17613689565b610f20826140ef565b610f286141b5565b73ffffffffffffffffffffffffffffffffffffffff81161580610f8f575067ffffffffffffffff821660009081526003602052604090206001015473ffffffffffffffffffffffffffffffffffffffff8281166c0100000000000000000000000090920416145b15610fc6576040517f8129bbcd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b67ffffffffffffffff821660008181526003602090815260409182902060010180546bffffffffffffffffffffffff166c0100000000000000000000000073ffffffffffffffffffffffffffffffffffffffff8716908102919091179091558251338152918201527f69436ea6df009049404f564eff6622cd00522b0bd6a89efd9e52a355c4a879be910160405180910390a25050565b6110656131b9565b806bffffffffffffffffffffffff1660000361109b5750306000908152600160205260409020546bffffffffffffffffffffffff165b306000908152600160205260409020546bffffffffffffffffffffffff908116908216811015611107576040517f6b0fe56f0000000000000000000000000000000000000000000000000000000081526bffffffffffffffffffffffff821660048201526024016107df565b30600090815260016020526040812080548492906111349084906bffffffffffffffffffffffff16615b5d565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff160217905550816000808282829054906101000a90046bffffffffffffffffffffffff1661118a9190615b5d565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff16021790555061121183836bffffffffffffffffffffffff167f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff166142bf9092919063ffffffff16565b505050565b61121e613c17565b8051600a80546020808501516040860151606087015161ffff9081166f01000000000000000000000000000000027fffffffffffffffffffffffffffffff0000ffffffffffffffffffffffffffffff60e09390931c6b01000000000000000000000002929092167fffffffffffffffffffffffffffffff000000000000ffffffffffffffffffffff68ffffffffffffffffff90941662010000027fffffffffffffffffffffffffffffffffffffffffff0000000000000000000000909616919097161793909317169390931717815560808301518051849361130592600b92910190614aa7565b5060a08201516002909101805460c09093015168ffffffffffffffffff1662010000027fffffffffffffffffffffffffffffffffffffffffff000000000000000000000090931661ffff909216919091179190911790556040517ea5832bf95f66c7814294cc4db681f20ee79608bfb8912a5321d66cfed5e9859061138b90839061566d565b60405180910390a150565b61139e613689565b806bffffffffffffffffffffffff166000036113e6576040517f8129bbcd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b336000908152600160205260409020546bffffffffffffffffffffffff908116908216811015611452576040517f6b0fe56f0000000000000000000000000000000000000000000000000000000081526bffffffffffffffffffffffff821660048201526024016107df565b33600090815260016020526040812080548492906111349084906bffffffffffffffffffffffff16615b5d565b60408051606080820183526000808352602080840182905292840181905273ffffffffffffffffffffffffffffffffffffffff861681526004835283812067ffffffffffffffff868116835290845290849020845192830185525460ff81161515835261010081048216938301939093526901000000000000000000909204909116918101919091525b92915050565b6000805b600d5460ff8216101561159857600d805460ff83169081106115375761153761587a565b9060005260206000200154830361158857600e805460ff831690811061155f5761155f61587a565b60009182526020909120015473ffffffffffffffffffffffffffffffffffffffff169392505050565b61159181615b82565b9050611513565b506040517f80833e33000000000000000000000000000000000000000000000000000000008152600481018390526024016107df565b6115d6613689565b6115df826140ef565b6115e76141b5565b60006115f6600a5461ffff1690565b67ffffffffffffffff841660009081526003602052604090206002015490915061ffff821611611658576040517fb72bc70300000000000000000000000000000000000000000000000000000000815261ffff821660048201526024016107df565b73ffffffffffffffffffffffffffffffffffffffff8216600090815260046020908152604080832067ffffffffffffffff8716845290915290205460ff16156116a057505050565b73ffffffffffffffffffffffffffffffffffffffff8216600081815260046020908152604080832067ffffffffffffffff881680855290835281842080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001908117909155600384528285206002018054918201815585529383902090930180547fffffffffffffffffffffffff000000000000000000000000000000000000000016851790555192835290917f43dc749a04ac8fb825cbd514f7c0e13f13bc6f2ee66043b76629d51776cff8e091015b60405180910390a2505050565b60075473ffffffffffffffffffffffffffffffffffffffff163314611802576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e65720000000000000000000060448201526064016107df565b600680547fffffffffffffffffffffff0000000000000000000000000000000000000000ff81166101003381810292909217909355600780547fffffffffffffffffffffffff00000000000000000000000000000000000000001690556040519290910473ffffffffffffffffffffffffffffffffffffffff169182907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a350565b6118b0613689565b6118b86141b5565b67ffffffffffffffff81166000908152600360205260409020805460019091015473ffffffffffffffffffffffffffffffffffffffff6c010000000000000000000000009283900481169290910416338114611958576040517f4e1d9f1800000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff821660048201526024016107df565b67ffffffffffffffff831660008181526003602090815260409182902080546c01000000000000000000000000339081026bffffffffffffffffffffffff928316178355600190920180549091169055825173ffffffffffffffffffffffffffffffffffffffff87168152918201527f6f1dc65165ffffedfd8e507b4a0f1fcfdada045ed11f6c26ba27cedfe87802f09101611774565b6119f7613c17565b610ea161434c565b611a07613689565b611a10826140ef565b611a186141b5565b73ffffffffffffffffffffffffffffffffffffffff8116600090815260046020908152604080832067ffffffffffffffff8087168552908352928190208151606081018352905460ff8116151582526101008104851693820193909352690100000000000000000090920490921691810191909152611a9782846143a7565b806040015167ffffffffffffffff16816020015167ffffffffffffffff1614611aec576040517f06eb10c800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b67ffffffffffffffff8316600090815260036020908152604080832060020180548251818502810185019093528083529192909190830182828015611b6757602002820191906000526020600020905b815473ffffffffffffffffffffffffffffffffffffffff168152600190910190602001808311611b3c575b5050505050905060005b8151811015611d0f578373ffffffffffffffffffffffffffffffffffffffff16828281518110611ba357611ba361587a565b602002602001015173ffffffffffffffffffffffffffffffffffffffff1603611cff578160018351611bd59190615ba1565b81518110611be557611be561587a565b6020026020010151600360008767ffffffffffffffff1667ffffffffffffffff1681526020019081526020016000206002018281548110611c2857611c2861587a565b600091825260208083209190910180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff949094169390931790925567ffffffffffffffff87168152600390915260409020600201805480611ca257611ca2615bb4565b60008281526020902081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff90810180547fffffffffffffffffffffffff0000000000000000000000000000000000000000169055019055611d0f565b611d0881615b25565b9050611b71565b5073ffffffffffffffffffffffffffffffffffffffff8316600081815260046020908152604080832067ffffffffffffffff89168085529083529281902080547fffffffffffffffffffffffffffffff00000000000000000000000000000000001690555192835290917f182bff9831466789164ca77075fffd84916d35a8180ba73c27e45634549b445b910160405180910390a250505050565b6000611db4613689565b611dbc6141b5565b60028054600090611dd69067ffffffffffffffff16615be3565b825467ffffffffffffffff8083166101009490940a93840293021916919091179091556040805160c0810182526000808252336020830152918101829052606081018290529192506080820190604051908082528060200260200182016040528015611e4c578160200160208202803683370190505b5081526000602091820181905267ffffffffffffffff841681526003825260409081902083518484015173ffffffffffffffffffffffffffffffffffffffff9081166c010000000000000000000000009081026bffffffffffffffffffffffff9384161784559386015160608701519091169093029216919091176001820155608083015180519192611ee792600285019290910190614a2d565b5060a0919091015160039091015560405133815267ffffffffffffffff8216907f464722b4166576d3dcbba877b999bc35cf911f4eaf434b7eba68fa113951d0bf9060200160405180910390a290565b6040805160c0810182526000808252602082018190529181018290526060808201839052608082015260a0810191909152611f71826131c1565b67ffffffffffffffff8216600090815260036020908152604091829020825160c08101845281546bffffffffffffffffffffffff808216835273ffffffffffffffffffffffffffffffffffffffff6c0100000000000000000000000092839004811684870152600185015491821684880152919004166060820152600282018054855181860281018601909652808652919492936080860193929083018282801561205257602002820191906000526020600020905b815473ffffffffffffffffffffffffffffffffffffffff168152600190910190602001808311612027575b505050505081526020016003820154815250509050919050565b612074613689565b3373ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016146120e3576040517f44b0e3c300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6020811461211d576040517f8129bbcd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600061212b82840184614ba6565b67ffffffffffffffff81166000908152600360205260409020549091506c01000000000000000000000000900473ffffffffffffffffffffffffffffffffffffffff166121a4576040517f1f6a65b600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b67ffffffffffffffff8116600090815260036020526040812080546bffffffffffffffffffffffff16918691906121db8385615a7d565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff160217905550846000808282829054906101000a90046bffffffffffffffffffffffff166122319190615a7d565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff1602179055508167ffffffffffffffff167fd39ec07f4e209f627a4c427971473820dc129761ba28de8906bd56f57101d4f88287846122989190615c0a565b6040805192835260208301919091520160405180910390a2505050505050565b60008181526008602052604081205473ffffffffffffffffffffffffffffffffffffffff1680611509576040517f80833e33000000000000000000000000000000000000000000000000000000008152600481018490526024016107df565b61231f613c17565b60005b600d54811015612442576000600d60000182815481106123445761234461587a565b906000526020600020015490506000600d60010183815481106123695761236961587a565b6000918252602080832091909101548483526008825260409283902054835186815273ffffffffffffffffffffffffffffffffffffffff91821693810193909352169181018290529091507ff8a6175bca1ba37d682089187edc5e20a859989727f10ca6bd9a5bc0de8caf949060600160405180910390a160009182526008602052604090912080547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff90921691909117905561243b81615b25565b9050612322565b50600d60006124518282614b51565b61245f600183016000614b51565b5050565b606080600d600001600d600101818054806020026020016040519081016040528092919081815260200182805480156124bb57602002820191906000526020600020905b8154815260200190600101908083116124a7575b505050505091508080548060200260200160405190810160405280929190818152602001828054801561252457602002820191906000526020600020905b815473ffffffffffffffffffffffffffffffffffffffff1681526001909101906020018083116124f9575b50505050509050915091509091565b6040805160e0810182526000808252602082018190529181018290526060808201839052608082015260a0810182905260c08101919091526040805160e08082018352600a805461ffff808216855262010000820468ffffffffffffffffff166020808701919091526b010000000000000000000000830490941b7fffffffff0000000000000000000000000000000000000000000000000000000016858701526f01000000000000000000000000000000909104166060840152600b805485518185028101850190965280865293949193608086019383018282801561266557602002820191906000526020600020906000905b82829054906101000a900463ffffffff1663ffffffff16815260200190600401906020826003010492830192600103820291508084116126285790505b50505091835250506002919091015461ffff8116602083015262010000900468ffffffffffffffffff16604090910152919050565b60006126a4613689565b6126ac6141b5565b600280546000906126c69067ffffffffffffffff16615be3565b825467ffffffffffffffff8083166101009490940a93840293021916919091179091556040805160c081018252600080825233602083015291810182905260608101829052919250608082019060405190808252806020026020018201604052801561273c578160200160208202803683370190505b5081526000602091820181905267ffffffffffffffff841681526003825260409081902083518484015173ffffffffffffffffffffffffffffffffffffffff9081166c010000000000000000000000009081026bffffffffffffffffffffffff93841617845593860151606087015190911690930292169190911760018201556080830151805191926127d792600285019290910190614a2d565b5060a0919091015160039182015567ffffffffffffffff82166000818152602092835260408082206002018054600180820183559184528584200180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff891690811790915583526004855281832084845285529181902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169092179091555133815290917f464722b4166576d3dcbba877b999bc35cf911f4eaf434b7eba68fa113951d0bf910160405180910390a260405173ffffffffffffffffffffffffffffffffffffffff8316815267ffffffffffffffff8216907f43dc749a04ac8fb825cbd514f7c0e13f13bc6f2ee66043b76629d51776cff8e09060200160405180910390a2919050565b612922613689565b61292b826140ef565b6129336141b5565b61293c82612db7565b15612973576040517f06eb10c800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61245f82826001613237565b6129876131b9565b6040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201526000907f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16906370a0823190602401602060405180830381865afa158015612a14573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612a389190615c1d565b6000549091506bffffffffffffffffffffffff1681811015611211576000612a608284615ba1565b9050612aa373ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001685836142bf565b6040805173ffffffffffffffffffffffffffffffffffffffff86168152602081018390527f59bfc682b673f8cbf945f1e454df9334834abf7dfe7f92237ca29ecb9b436600910160405180910390a150505050565b612b00613689565b60005b81811015611211576000838383818110612b1f57612b1f61587a565b90506101600201803603810190612b369190615c36565b80516080820151600082815260056020908152604091829020549151949550929391929091612b67918691016158db565b6040516020818303038152906040528051906020012014612bb4576040517f8129bbcd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b82610140015163ffffffff16421015612bf9576040517fa2376fe800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60208301516040517f85b214cf0000000000000000000000000000000000000000000000000000000081526004810184905273ffffffffffffffffffffffffffffffffffffffff909116906385b214cf90602401600060405180830381600087803b158015612c6757600080fd5b505af1158015612c7b573d6000803e3d6000fd5b50505060408085015167ffffffffffffffff84166000908152600360205291822060010180549193509190612cbf9084906bffffffffffffffffffffffff16615b5d565b82546bffffffffffffffffffffffff9182166101009390930a928302919092021990911617905550606083015173ffffffffffffffffffffffffffffffffffffffff16600090815260046020908152604080832067ffffffffffffffff808616855292529091208054600192600991612d479185916901000000000000000000900416615c53565b825467ffffffffffffffff9182166101009390930a9283029190920219909116179055506000828152600560205260408082208290555183917ff1ca1e9147be737b04a2b018a79405f687a97de8dd8a2559bbe62357343af41491a250505080612db090615b25565b9050612b03565b67ffffffffffffffff8116600090815260036020908152604080832060020180548251818502810185019093528083528493830182828015612e2f57602002820191906000526020600020905b815473ffffffffffffffffffffffffffffffffffffffff168152600190910190602001808311612e04575b5050505050905060005b8151811015612efc57600060046000848481518110612e5a57612e5a61587a565b60209081029190910181015173ffffffffffffffffffffffffffffffffffffffff168252818101929092526040908101600090812067ffffffffffffffff808a168352908452908290208251606081018452905460ff8116151582526101008104831694820185905269010000000000000000009004909116918101829052925014612eeb57506001949350505050565b50612ef581615b25565b9050612e39565b5060009392505050565b612f0e613c17565b600955565b60608167ffffffffffffffff168367ffffffffffffffff161180612f46575060025467ffffffffffffffff908116908316115b80612f5b575060025467ffffffffffffffff16155b15612f92576040517f8129bbcd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b612f9c8383615c74565b612fa7906001615c53565b67ffffffffffffffff1667ffffffffffffffff811115612fc957612fc9614ccd565b60405190808252806020026020018201604052801561304657816020015b6040805160c081018252600080825260208083018290529282018190526060808301829052608083015260a082015282527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff909201910181612fe75790505b50905060005b6130568484615c74565b67ffffffffffffffff1681116131a1576003600061307e8367ffffffffffffffff8816615c0a565b67ffffffffffffffff1681526020808201929092526040908101600020815160c08101835281546bffffffffffffffffffffffff808216835273ffffffffffffffffffffffffffffffffffffffff6c010000000000000000000000009283900481168488015260018501549182168487015291900416606082015260028201805484518187028101870190955280855291949293608086019390929083018282801561316057602002820191906000526020600020905b815473ffffffffffffffffffffffffffffffffffffffff168152600190910190602001808311613135575b505050505081526020016003820154815250508282815181106131855761318561587a565b60200260200101819052508061319a90615b25565b905061304c565b5092915050565b6131b0613c17565b6107808161441b565b610ea1613c17565b67ffffffffffffffff81166000908152600360205260409020546c01000000000000000000000000900473ffffffffffffffffffffffffffffffffffffffff16610780576040517f1f6a65b600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b67ffffffffffffffff83166000908152600360209081526040808320815160c08101835281546bffffffffffffffffffffffff808216835273ffffffffffffffffffffffffffffffffffffffff6c010000000000000000000000009283900481168488015260018501549182168487015291900416606082015260028201805484518187028101870190955280855291949293608086019390929083018282801561331857602002820191906000526020600020905b815473ffffffffffffffffffffffffffffffffffffffff1681526001909101906020018083116132ed575b50505091835250506003919091015460209091015280519091506000805b83608001515181101561342e5760008460800151828151811061335b5761335b61587a565b60209081029190910181015173ffffffffffffffffffffffffffffffffffffffff8116600090815260048352604080822067ffffffffffffffff808e16845294529020549092506133bb9169010000000000000000009091041684615c53565b73ffffffffffffffffffffffffffffffffffffffff909116600090815260046020908152604080832067ffffffffffffffff8c168452909152902080547fffffffffffffffffffffffffffffff0000000000000000000000000000000000169055915061342781615b25565b9050613336565b5067ffffffffffffffff8616600090815260036020526040812081815560018101829055906134606002830182614b51565b50600060039190910155600c5461ffff81169062010000900468ffffffffffffffffff1685801561349e57508161ffff168367ffffffffffffffff16105b1561355a576000846bffffffffffffffffffffffff168268ffffffffffffffffff16116134d6578168ffffffffffffffffff166134d8565b845b90506bffffffffffffffffffffffff81161561355857306000908152600160205260408120805483929061351b9084906bffffffffffffffffffffffff16615a7d565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff16021790555080856135559190615b5d565b94505b505b6bffffffffffffffffffffffff841615613617576000805485919081906135909084906bffffffffffffffffffffffff16615b5d565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff16021790555061361787856bffffffffffffffffffffffff167f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff166142bf9092919063ffffffff16565b6040805173ffffffffffffffffffffffffffffffffffffffff891681526bffffffffffffffffffffffff8616602082015267ffffffffffffffff8a16917fe8ed5b475a5b5987aa9165e8731bb78043f39eee32ec5a1169a89e27fcd49815910160405180910390a25050505050505050565b610ea1614517565b60006bffffffffffffffffffffffff82111561372f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f53616665436173743a2076616c756520646f65736e27742066697420696e203960448201527f362062697473000000000000000000000000000000000000000000000000000060648201526084016107df565b5090565b60408051606080820183526000808352602083015291810191909152813b1580156137865750506040805160608101825260008082526020808301829052835191825281018352918101919091526138e8565b600a546040516000916b010000000000000000000000900460e01b906137b4908a908a908a90602401615c95565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152918152602080830180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff000000000000000000000000000000000000000000000000000000009590951694909417909352600a548151608480825260c0820190935292945061ffff6f01000000000000000000000000000000909104169260009283928392820181803683370190505090505a8481101561388257600080fd5b8490036040810481038a1061389657600080fd5b505a60008087516020890160008d8ff193505a900391503d60848111156138bb575060845b808252806000602084013e5060408051606081018252931515845260208401929092529082015293505050505b95945050505050565b604080518082019091526000808252602082015260006139118486615a55565b90506000816139208886615a7d565b61392a9190615a7d565b67ffffffffffffffff8b166000908152600360205260409020549091506bffffffffffffffffffffffff80831691161080613991575067ffffffffffffffff8a166000908152600360205260409020600101546bffffffffffffffffffffffff808b169116105b156139f45767ffffffffffffffff8a16600090815260036020526040908190205490517f6b0fe56f0000000000000000000000000000000000000000000000000000000081526bffffffffffffffffffffffff90911660048201526024016107df565b67ffffffffffffffff8a1660009081526003602052604081208054839290613a2b9084906bffffffffffffffffffffffff16615b5d565b82546101009290920a6bffffffffffffffffffffffff81810219909316918316021790915567ffffffffffffffff8c16600090815260036020526040812060010180548d94509092613a7f91859116615b5d565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff1602179055508184613ab99190615a7d565b3360009081526001602052604081208054909190613ae69084906bffffffffffffffffffffffff16615a7d565b82546101009290920a6bffffffffffffffffffffffff81810219909316918316021790915530600090815260016020526040812080548b94509092613b2d91859116615a7d565b82546bffffffffffffffffffffffff9182166101009390930a92830291909202199091161790555073ffffffffffffffffffffffffffffffffffffffff8816600090815260046020908152604080832067ffffffffffffffff808f16855292529091208054600192600991613bb19185916901000000000000000000900416615c53565b92506101000a81548167ffffffffffffffff021916908367ffffffffffffffff1602179055506040518060400160405280836bffffffffffffffffffffffff168152602001826bffffffffffffffffffffffff1681525092505050979650505050505050565b600654610100900473ffffffffffffffffffffffffffffffffffffffff163314610ea1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e65720000000000000000000060448201526064016107df565b613ca5614584565b600680547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200160405180910390a1565b6000613d24613689565b613d2d856131c1565b613d3733866143a7565b613d418583610783565b8351600003613d7b576040517ec1cfc000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000613d8686611f37565b90506000613d94338861147f565b600a54604080516101608101825289815267ffffffffffffffff8b1660009081526003602081815293822001549495506201000090930468ffffffffffffffffff169373ffffffffffffffffffffffffffffffffffffffff8d169263a631571e929190820190815233602082015260408881015189519190920191613e1891615b5d565b6bffffffffffffffffffffffff1681526020018568ffffffffffffffffff1681526020018c67ffffffffffffffff168152602001866020015167ffffffffffffffff1681526020018963ffffffff1681526020018a61ffff168152602001866040015167ffffffffffffffff168152602001876020015173ffffffffffffffffffffffffffffffffffffffff168152506040518263ffffffff1660e01b8152600401613ec49190615cc0565b610160604051808303816000875af1158015613ee4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613f089190615e25565b805160009081526005602052604090205490915015613f595780516040517f304f32e800000000000000000000000000000000000000000000000000000000815260048101919091526024016107df565b604051806101600160405280826000015181526020018b73ffffffffffffffffffffffffffffffffffffffff16815260200182604001516bffffffffffffffffffffffff1681526020013373ffffffffffffffffffffffffffffffffffffffff1681526020018a67ffffffffffffffff1681526020018763ffffffff1681526020018368ffffffffffffffffff1681526020018260e0015168ffffffffffffffffff16815260200182610100015164ffffffffff16815260200182610120015164ffffffffff16815260200182610140015163ffffffff1681525060405160200161404491906158db565b60405160208183030381529060405280519060200120600560008360000151815260200190815260200160002081905550614084338a83604001516145f0565b8867ffffffffffffffff168b82600001517ff67aec45c9a7ede407974a3e0c3a743dffeab99ee3f2d4c9a8144c2ebf2c7ec9876020015133328e8e8e8a604001516040516140d89796959493929190615ef8565b60405180910390a4519a9950505050505050505050565b67ffffffffffffffff81166000908152600360205260409020546c01000000000000000000000000900473ffffffffffffffffffffffffffffffffffffffff1680614166576040517f1f6a65b600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b3373ffffffffffffffffffffffffffffffffffffffff82161461245f576040517f5a68151d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60095460009081526008602052604090205473ffffffffffffffffffffffffffffffffffffffff16806141e55750565b604080516000815260208101918290527f6b14daf80000000000000000000000000000000000000000000000000000000090915273ffffffffffffffffffffffffffffffffffffffff821690636b14daf89061424690339060248101615f70565b602060405180830381865afa158015614263573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906142879190615f9f565b610780576040517f229062630000000000000000000000000000000000000000000000000000000081523360048201526024016107df565b6040805173ffffffffffffffffffffffffffffffffffffffff8416602482015260448082018490528251808303909101815260649091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fa9059cbb000000000000000000000000000000000000000000000000000000001790526112119084906146cb565b614354614517565b600680547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a258613cf03390565b73ffffffffffffffffffffffffffffffffffffffff8216600090815260046020908152604080832067ffffffffffffffff8516845290915290205460ff1661245f576040517f71e8313700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b3373ffffffffffffffffffffffffffffffffffffffff82160361449a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c6600000000000000000060448201526064016107df565b600780547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff838116918217909255600654604051919261010090910416907fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae127890600090a350565b60065460ff1615610ea1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f5061757361626c653a207061757365640000000000000000000000000000000060448201526064016107df565b60065460ff16610ea1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f5061757361626c653a206e6f742070617573656400000000000000000000000060448201526064016107df565b67ffffffffffffffff82166000908152600360205260408120600101805483929061462a9084906bffffffffffffffffffffffff16615a7d565b82546bffffffffffffffffffffffff91821661010093840a908102920219161790915573ffffffffffffffffffffffffffffffffffffffff8516600090815260046020908152604080832067ffffffffffffffff80891685529252909120805460019450909284926146a0928492900416615c53565b92506101000a81548167ffffffffffffffff021916908367ffffffffffffffff160217905550505050565b600061472d826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff166147d79092919063ffffffff16565b805190915015611211578080602001905181019061474b9190615f9f565b611211576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f7420737563636565640000000000000000000000000000000000000000000060648201526084016107df565b60606147e684846000856147ee565b949350505050565b606082471015614880576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f60448201527f722063616c6c000000000000000000000000000000000000000000000000000060648201526084016107df565b6000808673ffffffffffffffffffffffffffffffffffffffff1685876040516148a99190615fc1565b60006040518083038185875af1925050503d80600081146148e6576040519150601f19603f3d011682016040523d82523d6000602084013e6148eb565b606091505b50915091506148fc87838387614907565b979650505050505050565b6060831561499d5782516000036149965773ffffffffffffffffffffffffffffffffffffffff85163b614996576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064016107df565b50816147e6565b6147e683838151156149b25781518083602001fd5b806040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016107df9190614c8e565b828054828255906000526020600020908101928215614a21579160200282015b82811115614a21578251825591602001919060010190614a06565b5061372f929150614b6b565b828054828255906000526020600020908101928215614a21579160200282015b82811115614a2157825182547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff909116178255602090920191600190910190614a4d565b82805482825590600052602060002090600701600890048101928215614a215791602002820160005b83821115614b1457835183826101000a81548163ffffffff021916908363ffffffff1602179055509260200192600401602081600301049283019260010302614ad0565b8015614b445782816101000a81549063ffffffff0219169055600401602081600301049283019260010302614b14565b505061372f929150614b6b565b508054600082559060005260206000209081019061078091905b5b8082111561372f5760008155600101614b6c565b67ffffffffffffffff8116811461078057600080fd5b8035614ba181614b80565b919050565b600060208284031215614bb857600080fd5b8135614bc381614b80565b9392505050565b63ffffffff8116811461078057600080fd5b8035614ba181614bca565b60008060408385031215614bfa57600080fd5b8235614c0581614b80565b91506020830135614c1581614bca565b809150509250929050565b60005b83811015614c3b578181015183820152602001614c23565b50506000910152565b60008151808452614c5c816020860160208601614c20565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b602081526000614bc36020830184614c44565b60008060408385031215614cb457600080fd5b8235614cbf81614b80565b946020939093013593505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051610160810167ffffffffffffffff81118282101715614d2057614d20614ccd565b60405290565b60405160e0810167ffffffffffffffff81118282101715614d2057614d20614ccd565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715614d9057614d90614ccd565b604052919050565b600082601f830112614da957600080fd5b813567ffffffffffffffff811115614dc357614dc3614ccd565b614df460207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f84011601614d49565b818152846020838601011115614e0957600080fd5b816020850160208301376000918101602001919091529392505050565b6bffffffffffffffffffffffff8116811461078057600080fd5b8035614ba181614e26565b73ffffffffffffffffffffffffffffffffffffffff8116811461078057600080fd5b8035614ba181614e4b565b68ffffffffffffffffff8116811461078057600080fd5b8035614ba181614e78565b64ffffffffff8116811461078057600080fd5b8035614ba181614e9a565b60006101608284031215614ecb57600080fd5b614ed3614cfc565b905081358152614ee560208301614e6d565b6020820152614ef660408301614e40565b6040820152614f0760608301614e6d565b6060820152614f1860808301614b96565b6080820152614f2960a08301614bdc565b60a0820152614f3a60c08301614e8f565b60c0820152614f4b60e08301614e8f565b60e0820152610100614f5e818401614ead565b90820152610120614f70838201614ead565b90820152610140614f82838201614bdc565b9082015292915050565b6000806000806000806102008789031215614fa657600080fd5b863567ffffffffffffffff80821115614fbe57600080fd5b614fca8a838b01614d98565b97506020890135915080821115614fe057600080fd5b50614fed89828a01614d98565b9550506040870135614ffe81614e26565b9350606087013561500e81614e26565b9250608087013561501e81614e4b565b915061502d8860a08901614eb8565b90509295509295509295565b60078110615070577f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b9052565b604081016150828285615039565b6bffffffffffffffffffffffff831660208301529392505050565b600067ffffffffffffffff8211156150b7576150b7614ccd565b5060051b60200190565b600082601f8301126150d257600080fd5b813560206150e76150e28361509d565b614d49565b82815260059290921b8401810191818101908684111561510657600080fd5b8286015b8481101561512a57803561511d81614e4b565b835291830191830161510a565b509695505050505050565b6000806040838503121561514857600080fd5b823567ffffffffffffffff8082111561516057600080fd5b818501915085601f83011261517457600080fd5b813560206151846150e28361509d565b82815260059290921b840181019181810190898411156151a357600080fd5b948201945b838610156151c1578535825294820194908201906151a8565b965050860135925050808211156151d757600080fd5b506151e4858286016150c1565b9150509250929050565b60008083601f84011261520057600080fd5b50813567ffffffffffffffff81111561521857600080fd5b60208301915083602082850101111561523057600080fd5b9250929050565b803561ffff81168114614ba157600080fd5b60008060008060008060a0878903121561526257600080fd5b863561526d81614b80565b9550602087013567ffffffffffffffff81111561528957600080fd5b61529589828a016151ee565b90965094506152a8905060408801615237565b925060608701356152b881614bca565b80925050608087013590509295509295509295565b600080604083850312156152e057600080fd5b82356152eb81614b80565b91506020830135614c1581614e4b565b6000806040838503121561530e57600080fd5b823561531981614e4b565b91506020830135614c1581614e26565b80357fffffffff0000000000000000000000000000000000000000000000000000000081168114614ba157600080fd5b600082601f83011261536a57600080fd5b8135602061537a6150e28361509d565b82815260059290921b8401810191818101908684111561539957600080fd5b8286015b8481101561512a5780356153b081614bca565b835291830191830161539d565b6000602082840312156153cf57600080fd5b813567ffffffffffffffff808211156153e757600080fd5b9083019060e082860312156153fb57600080fd5b615403614d26565b61540c83615237565b815261541a60208401614e8f565b602082015261542b60408401615329565b604082015261543c60608401615237565b606082015260808301358281111561545357600080fd5b61545f87828601615359565b60808301525061547160a08401615237565b60a082015261548260c08401614e8f565b60c082015295945050505050565b600080604083850312156154a357600080fd5b82356154ae81614e4b565b91506020830135614c1581614b80565b6000602082840312156154d057600080fd5b5035919050565b600081518084526020808501945080840160005b8381101561551d57815173ffffffffffffffffffffffffffffffffffffffff16875295820195908201906001016154eb565b509495945050505050565b60006bffffffffffffffffffffffff808351168452602083015173ffffffffffffffffffffffffffffffffffffffff8082166020870152826040860151166040870152806060860151166060870152505050608082015160c0608085015261559360c08501826154d7565b60a093840151949093019390935250919050565b602081526000614bc36020830184615528565b600080600080606085870312156155d057600080fd5b84356155db81614e4b565b935060208501359250604085013567ffffffffffffffff8111156155fe57600080fd5b61560a878288016151ee565b95989497509550505050565b604080825283519082018190526000906020906060840190828701845b8281101561564f57815184529284019290840190600101615633565b5050508381038285015261566381866154d7565b9695505050505050565b60006020808352610100830161ffff808651168386015268ffffffffffffffffff838701511660408601527fffffffff00000000000000000000000000000000000000000000000000000000604087015116606086015280606087015116608086015250608085015160e060a0860152818151808452610120870191508483019350600092505b8083101561571a57835163ffffffff1682529284019260019290920191908401906156f4565b5060a087015161ffff811660c0880152935060c087015168ffffffffffffffffff811660e08801529350615663565b60006020828403121561575b57600080fd5b8135614bc381614e4b565b6000806020838503121561577957600080fd5b823567ffffffffffffffff8082111561579157600080fd5b818501915085601f8301126157a557600080fd5b8135818111156157b457600080fd5b866020610160830285010111156157ca57600080fd5b60209290920196919550909350505050565b600080604083850312156157ef57600080fd5b82356154ae81614b80565b6000602080830181845280855180835260408601915060408160051b870101925083870160005b8281101561586d577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc088860301845261585b858351615528565b94509285019290850190600101615821565b5092979650505050505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b73ffffffffffffffffffffffffffffffffffffffff848116825283166020820152606081016147e66040830184615039565b8151815260208083015161016083019161590c9084018273ffffffffffffffffffffffffffffffffffffffff169052565b50604083015161592c60408401826bffffffffffffffffffffffff169052565b506060830151615954606084018273ffffffffffffffffffffffffffffffffffffffff169052565b506080830151615970608084018267ffffffffffffffff169052565b5060a083015161598860a084018263ffffffff169052565b5060c08301516159a560c084018268ffffffffffffffffff169052565b5060e08301516159c260e084018268ffffffffffffffffff169052565b506101008381015164ffffffffff81168483015250506101208381015164ffffffffff81168483015250506101408381015163ffffffff8116848301525b505092915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b64ffffffffff8181168382160190808211156131a1576131a1615a08565b6bffffffffffffffffffffffff818116838216028082169190828114615a0057615a00615a08565b6bffffffffffffffffffffffff8181168382160190808211156131a1576131a1615a08565b6bffffffffffffffffffffffff8716815273ffffffffffffffffffffffffffffffffffffffff86166020820152615adc6040820186615039565b60c060608201526000615af260c0830186614c44565b8281036080840152615b048186614c44565b905082810360a0840152615b188185614c44565b9998505050505050505050565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203615b5657615b56615a08565b5060010190565b6bffffffffffffffffffffffff8281168282160390808211156131a1576131a1615a08565b600060ff821660ff8103615b9857615b98615a08565b60010192915050565b8181038181111561150957611509615a08565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fd5b600067ffffffffffffffff808316818103615c0057615c00615a08565b6001019392505050565b8082018082111561150957611509615a08565b600060208284031215615c2f57600080fd5b5051919050565b60006101608284031215615c4957600080fd5b614bc38383614eb8565b67ffffffffffffffff8181168382160190808211156131a1576131a1615a08565b67ffffffffffffffff8281168282160390808211156131a1576131a1615a08565b838152606060208201526000615cae6060830185614c44565b82810360408401526156638185614c44565b6020815260008251610160806020850152615cdf610180850183614c44565b9150602085015160408501526040850151615d12606086018273ffffffffffffffffffffffffffffffffffffffff169052565b5060608501516bffffffffffffffffffffffff8116608086015250608085015168ffffffffffffffffff811660a08601525060a085015167ffffffffffffffff811660c08601525060c085015167ffffffffffffffff811660e08601525060e0850151610100615d898187018363ffffffff169052565b8601519050610120615da08682018361ffff169052565b8601519050610140615dbd8682018367ffffffffffffffff169052565b9095015173ffffffffffffffffffffffffffffffffffffffff1693019290925250919050565b8051614ba181614e4b565b8051614ba181614e26565b8051614ba181614b80565b8051614ba181614bca565b8051614ba181614e78565b8051614ba181614e9a565b60006101608284031215615e3857600080fd5b615e40614cfc565b82518152615e5060208401615de3565b6020820152615e6160408401615dee565b6040820152615e7260608401615de3565b6060820152615e8360808401615df9565b6080820152615e9460a08401615e04565b60a0820152615ea560c08401615e0f565b60c0820152615eb660e08401615e0f565b60e0820152610100615ec9818501615e1a565b90820152610120615edb848201615e1a565b90820152610140615eed848201615e04565b908201529392505050565b600073ffffffffffffffffffffffffffffffffffffffff808a168352808916602084015280881660408401525060e06060830152615f3960e0830187614c44565b61ffff9590951660808301525063ffffffff9290921660a08301526bffffffffffffffffffffffff1660c090910152949350505050565b73ffffffffffffffffffffffffffffffffffffffff831681526040602082015260006147e66040830184614c44565b600060208284031215615fb157600080fd5b81518015158114614bc357600080fd5b60008251615fd3818460208701614c20565b919091019291505056fea164736f6c6343000813000a", } var FunctionsRouterABI = FunctionsRouterMetaData.ABI @@ -451,6 +453,28 @@ func (_FunctionsRouter *FunctionsRouterCallerSession) GetSubscriptionCount() (ui return _FunctionsRouter.Contract.GetSubscriptionCount(&_FunctionsRouter.CallOpts) } +func (_FunctionsRouter *FunctionsRouterCaller) GetSubscriptionsInRange(opts *bind.CallOpts, subscriptionIdStart uint64, subscriptionIdEnd uint64) ([]IFunctionsSubscriptionsSubscription, error) { + var out []interface{} + err := _FunctionsRouter.contract.Call(opts, &out, "getSubscriptionsInRange", subscriptionIdStart, subscriptionIdEnd) + + if err != nil { + return *new([]IFunctionsSubscriptionsSubscription), err + } + + out0 := *abi.ConvertType(out[0], new([]IFunctionsSubscriptionsSubscription)).(*[]IFunctionsSubscriptionsSubscription) + + return out0, err + +} + +func (_FunctionsRouter *FunctionsRouterSession) GetSubscriptionsInRange(subscriptionIdStart uint64, subscriptionIdEnd uint64) ([]IFunctionsSubscriptionsSubscription, error) { + return _FunctionsRouter.Contract.GetSubscriptionsInRange(&_FunctionsRouter.CallOpts, subscriptionIdStart, subscriptionIdEnd) +} + +func (_FunctionsRouter *FunctionsRouterCallerSession) GetSubscriptionsInRange(subscriptionIdStart uint64, subscriptionIdEnd uint64) ([]IFunctionsSubscriptionsSubscription, error) { + return _FunctionsRouter.Contract.GetSubscriptionsInRange(&_FunctionsRouter.CallOpts, subscriptionIdStart, subscriptionIdEnd) +} + func (_FunctionsRouter *FunctionsRouterCaller) GetTotalBalance(opts *bind.CallOpts) (*big.Int, error) { var out []interface{} err := _FunctionsRouter.contract.Call(opts, &out, "getTotalBalance") @@ -3358,7 +3382,7 @@ func (_FunctionsRouter *FunctionsRouter) ParseLog(log types.Log) (generated.Abig } func (FunctionsRouterConfigUpdated) Topic() common.Hash { - return common.HexToHash("0x049ce2e6e1420eb4b07b425e90129186833eb346bda40b37d5d921aad482f71c") + return common.HexToHash("0x00a5832bf95f66c7814294cc4db681f20ee79608bfb8912a5321d66cfed5e985") } func (FunctionsRouterContractProposed) Topic() common.Hash { @@ -3460,6 +3484,8 @@ type FunctionsRouterInterface interface { GetSubscriptionCount(opts *bind.CallOpts) (uint64, error) + GetSubscriptionsInRange(opts *bind.CallOpts, subscriptionIdStart uint64, subscriptionIdEnd uint64) ([]IFunctionsSubscriptionsSubscription, error) + GetTotalBalance(opts *bind.CallOpts) (*big.Int, error) IsValidCallbackGasLimit(opts *bind.CallOpts, subscriptionId uint64, callbackGasLimit uint32) 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 46f10db9d5d..07a431d993a 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 @@ -3,11 +3,11 @@ functions: ../../../contracts/solc/v0.8.19/functions/1_0_0/FunctionsRequest.abi functions_allow_list: ../../../contracts/solc/v0.8.19/functions/1_0_0/TermsOfServiceAllowList.abi ../../../contracts/solc/v0.8.19/functions/1_0_0/TermsOfServiceAllowList.bin b2697ad4dfece903a1d34028826a017fa445eb3cd984006f1734fa9d47836ca0 functions_billing_registry_events_mock: ../../../contracts/solc/v0.8.6/functions/0_0_0/FunctionsBillingRegistryEventsMock.abi ../../../contracts/solc/v0.8.6/functions/0_0_0/FunctionsBillingRegistryEventsMock.bin 50deeb883bd9c3729702be335c0388f9d8553bab4be5e26ecacac496a89e2b77 functions_client: ../../../contracts/solc/v0.8.19/functions/1_0_0/FunctionsClient.abi ../../../contracts/solc/v0.8.19/functions/1_0_0/FunctionsClient.bin 2368f537a04489c720a46733f8596c4fc88a31062ecfa966d05f25dd98608aca -functions_client_example: ../../../contracts/solc/v0.8.19/functions/1_0_0/FunctionsClientExample.abi ../../../contracts/solc/v0.8.19/functions/1_0_0/FunctionsClientExample.bin 25036bdb94a50a81df4222418bf9aa1e0c8540d5834b7e6e639aa63a2a2c8206 -functions_coordinator: ../../../contracts/solc/v0.8.19/functions/1_0_0/FunctionsCoordinator.abi ../../../contracts/solc/v0.8.19/functions/1_0_0/FunctionsCoordinator.bin e453fd45029ff99658d029bfbb8711b748c432323f12585c039a30977e801a79 -functions_load_test_client: ../../../contracts/solc/v0.8.19/functions/1_0_0/FunctionsLoadTestClient.abi ../../../contracts/solc/v0.8.19/functions/1_0_0/FunctionsLoadTestClient.bin 08b0ba467a0d2913ad146c293cc92ed1e0e5f25398bc8185addf9c4c1a41df2c +functions_client_example: ../../../contracts/solc/v0.8.19/functions/1_0_0/FunctionsClientExample.abi ../../../contracts/solc/v0.8.19/functions/1_0_0/FunctionsClientExample.bin abf32e69f268f40e8530eb8d8e96bf310b798a4c0049a58022d9d2fb527b601b +functions_coordinator: ../../../contracts/solc/v0.8.19/functions/1_0_0/FunctionsCoordinator.abi ../../../contracts/solc/v0.8.19/functions/1_0_0/FunctionsCoordinator.bin 21bd322caf977c4802d2c17419b57487cca438c7c5fafc52a9a9e1c9f4a72289 +functions_load_test_client: ../../../contracts/solc/v0.8.19/functions/1_0_0/FunctionsLoadTestClient.abi ../../../contracts/solc/v0.8.19/functions/1_0_0/FunctionsLoadTestClient.bin c8dbbd5ebb34435800d6674700068837c3a252db60046a14b0e61e829db517de functions_oracle_events_mock: ../../../contracts/solc/v0.8.6/functions/0_0_0/FunctionsOracleEventsMock.abi ../../../contracts/solc/v0.8.6/functions/0_0_0/FunctionsOracleEventsMock.bin 3ca70f966f8fe751987f0ccb50bebb6aa5be77e4a9f835d1ae99e0e9bfb7d52c -functions_router: ../../../contracts/solc/v0.8.19/functions/1_0_0/FunctionsRouter.abi ../../../contracts/solc/v0.8.19/functions/1_0_0/FunctionsRouter.bin dd1d3527e19d65efe029c4a131ded44dc0ca961e5c4f459743992435431ec478 +functions_router: ../../../contracts/solc/v0.8.19/functions/1_0_0/FunctionsRouter.abi ../../../contracts/solc/v0.8.19/functions/1_0_0/FunctionsRouter.bin 9dedd3a36043605fd9bedf821e7ec5b4281a5c7ae2e4a1955f37aff8ba13519f functions_v1_events_mock: ../../../contracts/solc/v0.8.19/functions/1_0_0/FunctionsV1EventsMock.abi ../../../contracts/solc/v0.8.19/functions/1_0_0/FunctionsV1EventsMock.bin 0f0ba42e0cc33c7abc8b8fd4fdfce903748a169886dd5f16cfdd56e75bcf708d ocr2dr: ../../../contracts/solc/v0.8.6/functions/0_0_0/Functions.abi ../../../contracts/solc/v0.8.6/functions/0_0_0/Functions.bin d9a794b33f47cc57563d216f7cf3a612309fc3062356a27e30005cf1d59e449d ocr2dr_client: ../../../contracts/solc/v0.8.6/functions/0_0_0/FunctionsClient.abi ../../../contracts/solc/v0.8.6/functions/0_0_0/FunctionsClient.bin 84aa63f9dbc5c7eac240db699b09e613ca4c6cd56dab10bdc25b02461b717e21 diff --git a/core/gethwrappers/generated/automation_utils_2_1/automation_utils_2_1.go b/core/gethwrappers/generated/automation_utils_2_1/automation_utils_2_1.go index 6d6991546f0..6e22e4423f5 100644 --- a/core/gethwrappers/generated/automation_utils_2_1/automation_utils_2_1.go +++ b/core/gethwrappers/generated/automation_utils_2_1/automation_utils_2_1.go @@ -34,10 +34,11 @@ type KeeperRegistryBase21ConditionalTrigger struct { } type KeeperRegistryBase21LogTrigger struct { - TxHash [32]byte - LogIndex uint32 - BlockNum uint32 - BlockHash [32]byte + LogBlockHash [32]byte + TxHash [32]byte + LogIndex uint32 + BlockNum uint32 + BlockHash [32]byte } type KeeperRegistryBase21OnchainConfig struct { @@ -88,8 +89,8 @@ type LogTriggerConfig struct { } var AutomationUtilsMetaData = &bind.MetaData{ - ABI: "[{\"inputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"blockNum\",\"type\":\"uint32\"},{\"internalType\":\"bytes32\",\"name\":\"blockHash\",\"type\":\"bytes32\"}],\"internalType\":\"structKeeperRegistryBase2_1.ConditionalTrigger\",\"name\":\"\",\"type\":\"tuple\"}],\"name\":\"_conditionalTrigger\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint256\",\"name\":\"index\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"txIndex\",\"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\":\"txHash\",\"type\":\"bytes32\"},{\"internalType\":\"uint32\",\"name\":\"logIndex\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"blockNum\",\"type\":\"uint32\"},{\"internalType\":\"bytes32\",\"name\":\"blockHash\",\"type\":\"bytes32\"}],\"internalType\":\"structKeeperRegistryBase2_1.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\":\"structKeeperRegistryBase2_1.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\":\"structKeeperRegistryBase2_1.Report\",\"name\":\"\",\"type\":\"tuple\"}],\"name\":\"_report\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", - Bin: "0x608060405234801561001057600080fd5b506108be806100206000396000f3fe608060405234801561001057600080fd5b50600436106100725760003560e01c80634b6df294116100505780634b6df294146100a6578063e65d6546146100b4578063e9720a49146100c257600080fd5b80631c8d82601461007757806321f373d71461008a5780632ff92a8114610098575b600080fd5b6100886100853660046101d8565b50565b005b61008861008536600461026e565b6100886100853660046103d5565b61008861008536600461052f565b6100886100853660046106ef565b6100886100853660046107dc565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6040516101e0810167ffffffffffffffff81118282101715610123576101236100d0565b60405290565b60405160c0810167ffffffffffffffff81118282101715610123576101236100d0565b604051610100810167ffffffffffffffff81118282101715610123576101236100d0565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff811182821017156101b7576101b76100d0565b604052919050565b803563ffffffff811681146101d357600080fd5b919050565b6000608082840312156101ea57600080fd5b6040516080810181811067ffffffffffffffff8211171561020d5761020d6100d0565b60405282358152610220602084016101bf565b6020820152610231604084016101bf565b6040820152606083013560608201528091505092915050565b803573ffffffffffffffffffffffffffffffffffffffff811681146101d357600080fd5b600060c0828403121561028057600080fd5b60405160c0810181811067ffffffffffffffff821117156102a3576102a36100d0565b6040526102af8361024a565b8152602083013560ff811681146102c557600080fd5b8060208301525060408301356040820152606083013560608201526080830135608082015260a083013560a08201528091505092915050565b803562ffffff811681146101d357600080fd5b803561ffff811681146101d357600080fd5b80356bffffffffffffffffffffffff811681146101d357600080fd5b600067ffffffffffffffff821115610359576103596100d0565b5060051b60200190565b600082601f83011261037457600080fd5b813560206103896103848361033f565b610170565b82815260059290921b840181019181810190868411156103a857600080fd5b8286015b848110156103ca576103bd8161024a565b83529183019183016103ac565b509695505050505050565b6000602082840312156103e757600080fd5b813567ffffffffffffffff808211156103ff57600080fd5b908301906101e0828603121561041457600080fd5b61041c6100ff565b610425836101bf565b8152610433602084016101bf565b6020820152610444604084016101bf565b6040820152610455606084016102fe565b606082015261046660808401610311565b608082015261047760a08401610323565b60a082015261048860c084016101bf565b60c082015261049960e084016101bf565b60e08201526101006104ac8185016101bf565b908201526101206104be8482016101bf565b90820152610140838101359082015261016080840135908201526101806104e681850161024a565b908201526101a083810135838111156104fe57600080fd5b61050a88828701610363565b8284015250506101c0915061052082840161024a565b91810191909152949350505050565b60006040828403121561054157600080fd5b6040516040810181811067ffffffffffffffff82111715610564576105646100d0565b604052610570836101bf565b8152602083013560208201528091505092915050565b600082601f83011261059757600080fd5b813560206105a76103848361033f565b82815260059290921b840181019181810190868411156105c657600080fd5b8286015b848110156103ca57803583529183019183016105ca565b600082601f8301126105f257600080fd5b813567ffffffffffffffff81111561060c5761060c6100d0565b61063d60207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f84011601610170565b81815284602083860101111561065257600080fd5b816020850160208301376000918101602001919091529392505050565b600082601f83011261068057600080fd5b813560206106906103848361033f565b82815260059290921b840181019181810190868411156106af57600080fd5b8286015b848110156103ca57803567ffffffffffffffff8111156106d35760008081fd5b6106e18986838b01016105e1565b8452509183019183016106b3565b60006020828403121561070157600080fd5b813567ffffffffffffffff8082111561071957600080fd5b9083019060c0828603121561072d57600080fd5b610735610129565b823581526020830135602082015260408301358281111561075557600080fd5b61076187828601610586565b60408301525060608301358281111561077957600080fd5b61078587828601610586565b60608301525060808301358281111561079d57600080fd5b6107a98782860161066f565b60808301525060a0830135828111156107c157600080fd5b6107cd8782860161066f565b60a08301525095945050505050565b6000602082840312156107ee57600080fd5b813567ffffffffffffffff8082111561080657600080fd5b90830190610100828603121561081b57600080fd5b61082361014c565b823581526020830135602082015260408301356040820152606083013560608201526080830135608082015261085b60a0840161024a565b60a082015260c08301358281111561087257600080fd5b61087e87828601610586565b60c08301525060e08301358281111561089657600080fd5b6108a2878286016105e1565b60e0830152509594505050505056fea164736f6c6343000810000a", + ABI: "[{\"inputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"blockNum\",\"type\":\"uint32\"},{\"internalType\":\"bytes32\",\"name\":\"blockHash\",\"type\":\"bytes32\"}],\"internalType\":\"structKeeperRegistryBase2_1.ConditionalTrigger\",\"name\":\"\",\"type\":\"tuple\"}],\"name\":\"_conditionalTrigger\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint256\",\"name\":\"index\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"txIndex\",\"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\":\"structKeeperRegistryBase2_1.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\":\"structKeeperRegistryBase2_1.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\":\"structKeeperRegistryBase2_1.Report\",\"name\":\"\",\"type\":\"tuple\"}],\"name\":\"_report\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", + Bin: "0x608060405234801561001057600080fd5b506108ca806100206000396000f3fe608060405234801561001057600080fd5b50600436106100725760003560e01c8063776f306111610050578063776f3061146100a6578063e65d6546146100b4578063e9720a49146100c257600080fd5b806321f373d7146100775780632ff92a811461008a5780634b6df29414610098575b600080fd5b6100886100853660046101e8565b50565b005b610088610085366004610363565b6100886100853660046104bd565b610088610085366004610514565b6100886100853660046106fb565b6100886100853660046107e8565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6040516101e0810167ffffffffffffffff81118282101715610123576101236100d0565b60405290565b60405160c0810167ffffffffffffffff81118282101715610123576101236100d0565b604051610100810167ffffffffffffffff81118282101715610123576101236100d0565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff811182821017156101b7576101b76100d0565b604052919050565b803573ffffffffffffffffffffffffffffffffffffffff811681146101e357600080fd5b919050565b600060c082840312156101fa57600080fd5b60405160c0810181811067ffffffffffffffff8211171561021d5761021d6100d0565b604052610229836101bf565b8152602083013560ff8116811461023f57600080fd5b8060208301525060408301356040820152606083013560608201526080830135608082015260a083013560a08201528091505092915050565b803563ffffffff811681146101e357600080fd5b803562ffffff811681146101e357600080fd5b803561ffff811681146101e357600080fd5b80356bffffffffffffffffffffffff811681146101e357600080fd5b600067ffffffffffffffff8211156102e7576102e76100d0565b5060051b60200190565b600082601f83011261030257600080fd5b81356020610317610312836102cd565b610170565b82815260059290921b8401810191818101908684111561033657600080fd5b8286015b848110156103585761034b816101bf565b835291830191830161033a565b509695505050505050565b60006020828403121561037557600080fd5b813567ffffffffffffffff8082111561038d57600080fd5b908301906101e082860312156103a257600080fd5b6103aa6100ff565b6103b383610278565b81526103c160208401610278565b60208201526103d260408401610278565b60408201526103e36060840161028c565b60608201526103f46080840161029f565b608082015261040560a084016102b1565b60a082015261041660c08401610278565b60c082015261042760e08401610278565b60e082015261010061043a818501610278565b9082015261012061044c848201610278565b90820152610140838101359082015261016080840135908201526101806104748185016101bf565b908201526101a0838101358381111561048c57600080fd5b610498888287016102f1565b8284015250506101c091506104ae8284016101bf565b91810191909152949350505050565b6000604082840312156104cf57600080fd5b6040516040810181811067ffffffffffffffff821117156104f2576104f26100d0565b6040526104fe83610278565b8152602083013560208201528091505092915050565b600060a0828403121561052657600080fd5b60405160a0810181811067ffffffffffffffff82111715610549576105496100d0565b8060405250823581526020830135602082015261056860408401610278565b604082015261057960608401610278565b6060820152608083013560808201528091505092915050565b600082601f8301126105a357600080fd5b813560206105b3610312836102cd565b82815260059290921b840181019181810190868411156105d257600080fd5b8286015b8481101561035857803583529183019183016105d6565b600082601f8301126105fe57600080fd5b813567ffffffffffffffff811115610618576106186100d0565b61064960207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f84011601610170565b81815284602083860101111561065e57600080fd5b816020850160208301376000918101602001919091529392505050565b600082601f83011261068c57600080fd5b8135602061069c610312836102cd565b82815260059290921b840181019181810190868411156106bb57600080fd5b8286015b8481101561035857803567ffffffffffffffff8111156106df5760008081fd5b6106ed8986838b01016105ed565b8452509183019183016106bf565b60006020828403121561070d57600080fd5b813567ffffffffffffffff8082111561072557600080fd5b9083019060c0828603121561073957600080fd5b610741610129565b823581526020830135602082015260408301358281111561076157600080fd5b61076d87828601610592565b60408301525060608301358281111561078557600080fd5b61079187828601610592565b6060830152506080830135828111156107a957600080fd5b6107b58782860161067b565b60808301525060a0830135828111156107cd57600080fd5b6107d98782860161067b565b60a08301525095945050505050565b6000602082840312156107fa57600080fd5b813567ffffffffffffffff8082111561081257600080fd5b90830190610100828603121561082757600080fd5b61082f61014c565b823581526020830135602082015260408301356040820152606083013560608201526080830135608082015261086760a084016101bf565b60a082015260c08301358281111561087e57600080fd5b61088a87828601610592565b60c08301525060e0830135828111156108a257600080fd5b6108ae878286016105ed565b60e0830152509594505050505056fea164736f6c6343000810000a", } var AutomationUtilsABI = AutomationUtilsMetaData.ABI diff --git a/core/gethwrappers/generated/keeper_registry_wrapper_2_1/keeper_registry_wrapper_2_1.go b/core/gethwrappers/generated/keeper_registry_wrapper_2_1/keeper_registry_wrapper_2_1.go index 4bbd827dc52..1db34ca3953 100644 --- a/core/gethwrappers/generated/keeper_registry_wrapper_2_1/keeper_registry_wrapper_2_1.go +++ b/core/gethwrappers/generated/keeper_registry_wrapper_2_1/keeper_registry_wrapper_2_1.go @@ -50,7 +50,7 @@ type KeeperRegistryBase21OnchainConfig struct { var KeeperRegistryMetaData = &bind.MetaData{ ABI: "[{\"inputs\":[{\"internalType\":\"contractKeeperRegistryLogicB2_1\",\"name\":\"logicA\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"ArrayHasNoEntries\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"CannotCancel\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"CheckDataExceedsLimit\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ConfigDigestMismatch\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DuplicateEntry\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DuplicateSigners\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"GasLimitCanOnlyIncrease\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"GasLimitOutsideRange\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"IncorrectNumberOfFaultyOracles\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"IncorrectNumberOfSignatures\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"IncorrectNumberOfSigners\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"IndexOutOfRange\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InsufficientFunds\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidDataLength\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidPayee\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidRecipient\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidReport\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidSigner\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidTransmitter\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidTrigger\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidTriggerType\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"MaxCheckDataSizeCanOnlyIncrease\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"MaxPerformDataSizeCanOnlyIncrease\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"MigrationNotPermitted\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"NotAContract\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyActiveSigners\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyActiveTransmitters\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByAdmin\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByLINKToken\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByOwnerOrAdmin\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByOwnerOrRegistrar\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByPayee\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByProposedAdmin\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByProposedPayee\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByUpkeepPrivilegeManager\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyPausedUpkeep\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlySimulatedBackend\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyUnpausedUpkeep\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ParameterLengthError\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"PaymentGreaterThanAllLINK\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ReentrantCall\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"RegistryPaused\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"RepeatedSigner\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"RepeatedTransmitter\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"reason\",\"type\":\"bytes\"}],\"name\":\"TargetCheckReverted\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"TooManyOracles\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"TranscoderNotSet\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"UpkeepAlreadyExists\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"UpkeepCancelled\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"UpkeepNotCanceled\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"UpkeepNotNeeded\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ValueNotChanged\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"admin\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"privilegeConfig\",\"type\":\"bytes\"}],\"name\":\"AdminPrivilegeConfigSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"trigger\",\"type\":\"bytes\"}],\"name\":\"CancelledUpkeepReport\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"previousConfigBlockNumber\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"configDigest\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"configCount\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"signers\",\"type\":\"address[]\"},{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"transmitters\",\"type\":\"address[]\"},{\"indexed\":false,\"internalType\":\"uint8\",\"name\":\"f\",\"type\":\"uint8\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"onchainConfig\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"offchainConfigVersion\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"offchainConfig\",\"type\":\"bytes\"}],\"name\":\"ConfigSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"dedupKey\",\"type\":\"bytes32\"}],\"name\":\"DedupKeyAdded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint96\",\"name\":\"amount\",\"type\":\"uint96\"}],\"name\":\"FundsAdded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"FundsWithdrawn\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"trigger\",\"type\":\"bytes\"}],\"name\":\"InsufficientFundsUpkeepReport\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint96\",\"name\":\"amount\",\"type\":\"uint96\"}],\"name\":\"OwnerFundsWithdrawn\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"OwnershipTransferRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"Paused\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"transmitters\",\"type\":\"address[]\"},{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"payees\",\"type\":\"address[]\"}],\"name\":\"PayeesUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"transmitter\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"PayeeshipTransferRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"transmitter\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"PayeeshipTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"transmitter\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"payee\",\"type\":\"address\"}],\"name\":\"PaymentWithdrawn\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"trigger\",\"type\":\"bytes\"}],\"name\":\"ReorgedUpkeepReport\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"trigger\",\"type\":\"bytes\"}],\"name\":\"StaleUpkeepReport\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"configDigest\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"epoch\",\"type\":\"uint32\"}],\"name\":\"Transmitted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"Unpaused\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"UpkeepAdminTransferRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"UpkeepAdminTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint64\",\"name\":\"atBlockHeight\",\"type\":\"uint64\"}],\"name\":\"UpkeepCanceled\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"newCheckData\",\"type\":\"bytes\"}],\"name\":\"UpkeepCheckDataSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint96\",\"name\":\"gasLimit\",\"type\":\"uint96\"}],\"name\":\"UpkeepGasLimitSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"remainingBalance\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"destination\",\"type\":\"address\"}],\"name\":\"UpkeepMigrated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"offchainConfig\",\"type\":\"bytes\"}],\"name\":\"UpkeepOffchainConfigSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"name\":\"UpkeepPaused\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"bool\",\"name\":\"success\",\"type\":\"bool\"},{\"indexed\":false,\"internalType\":\"uint96\",\"name\":\"totalPayment\",\"type\":\"uint96\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"gasUsed\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"gasOverhead\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"trigger\",\"type\":\"bytes\"}],\"name\":\"UpkeepPerformed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"privilegeConfig\",\"type\":\"bytes\"}],\"name\":\"UpkeepPrivilegeConfigSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"startingBalance\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"importedFrom\",\"type\":\"address\"}],\"name\":\"UpkeepReceived\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"performGas\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"admin\",\"type\":\"address\"}],\"name\":\"UpkeepRegistered\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"triggerConfig\",\"type\":\"bytes\"}],\"name\":\"UpkeepTriggerConfigSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"name\":\"UpkeepUnpaused\",\"type\":\"event\"},{\"stateMutability\":\"nonpayable\",\"type\":\"fallback\"},{\"inputs\":[],\"name\":\"acceptOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"fallbackTo\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"latestConfigDetails\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"configCount\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"blockNumber\",\"type\":\"uint32\"},{\"internalType\":\"bytes32\",\"name\":\"configDigest\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"latestConfigDigestAndEpoch\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"scanLogs\",\"type\":\"bool\"},{\"internalType\":\"bytes32\",\"name\":\"configDigest\",\"type\":\"bytes32\"},{\"internalType\":\"uint32\",\"name\":\"epoch\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"onTokenTransfer\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address[]\",\"name\":\"signers\",\"type\":\"address[]\"},{\"internalType\":\"address[]\",\"name\":\"transmitters\",\"type\":\"address[]\"},{\"internalType\":\"uint8\",\"name\":\"f\",\"type\":\"uint8\"},{\"internalType\":\"bytes\",\"name\":\"onchainConfigBytes\",\"type\":\"bytes\"},{\"internalType\":\"uint64\",\"name\":\"offchainConfigVersion\",\"type\":\"uint64\"},{\"internalType\":\"bytes\",\"name\":\"offchainConfig\",\"type\":\"bytes\"}],\"name\":\"setConfig\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address[]\",\"name\":\"signers\",\"type\":\"address[]\"},{\"internalType\":\"address[]\",\"name\":\"transmitters\",\"type\":\"address[]\"},{\"internalType\":\"uint8\",\"name\":\"f\",\"type\":\"uint8\"},{\"components\":[{\"internalType\":\"uint32\",\"name\":\"paymentPremiumPPB\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"flatFeeMicroLink\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"checkGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint24\",\"name\":\"stalenessSeconds\",\"type\":\"uint24\"},{\"internalType\":\"uint16\",\"name\":\"gasCeilingMultiplier\",\"type\":\"uint16\"},{\"internalType\":\"uint96\",\"name\":\"minUpkeepSpend\",\"type\":\"uint96\"},{\"internalType\":\"uint32\",\"name\":\"maxPerformGas\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"maxCheckDataSize\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"maxPerformDataSize\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"maxRevertDataSize\",\"type\":\"uint32\"},{\"internalType\":\"uint256\",\"name\":\"fallbackGasPrice\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"fallbackLinkPrice\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"transcoder\",\"type\":\"address\"},{\"internalType\":\"address[]\",\"name\":\"registrars\",\"type\":\"address[]\"},{\"internalType\":\"address\",\"name\":\"upkeepPrivilegeManager\",\"type\":\"address\"}],\"internalType\":\"structKeeperRegistryBase2_1.OnchainConfig\",\"name\":\"onchainConfig\",\"type\":\"tuple\"},{\"internalType\":\"uint64\",\"name\":\"offchainConfigVersion\",\"type\":\"uint64\"},{\"internalType\":\"bytes\",\"name\":\"offchainConfig\",\"type\":\"bytes\"}],\"name\":\"setConfigTypeSafe\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"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: "0x6101406040523480156200001257600080fd5b50604051620054b9380380620054b98339810160408190526200003591620003df565b80816001600160a01b0316634b4fd03b6040518163ffffffff1660e01b8152600401602060405180830381865afa15801562000075573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200009b919062000406565b826001600160a01b031663ca30e6036040518163ffffffff1660e01b8152600401602060405180830381865afa158015620000da573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620001009190620003df565b836001600160a01b031663b10b673c6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156200013f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620001659190620003df565b846001600160a01b0316636709d0e56040518163ffffffff1660e01b8152600401602060405180830381865afa158015620001a4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620001ca9190620003df565b856001600160a01b0316635425d8ac6040518163ffffffff1660e01b8152600401602060405180830381865afa15801562000209573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200022f9190620003df565b3380600081620002865760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b0384811691909117909155811615620002b957620002b9816200031b565b505050846002811115620002d157620002d162000429565b60e0816002811115620002e857620002e862000429565b9052506001600160a01b0393841660805291831660a052821660c0528116610100529190911661012052506200043f9050565b336001600160a01b03821603620003755760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c6600000000000000000060448201526064016200027d565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b6001600160a01b0381168114620003dc57600080fd5b50565b600060208284031215620003f257600080fd5b8151620003ff81620003c6565b9392505050565b6000602082840312156200041957600080fd5b815160038110620003ff57600080fd5b634e487b7160e01b600052602160045260246000fd5b60805160a05160c05160e0516101005161012051615018620004a16000396000818160d6015261016f01526000505060008181612eb701528181613220015281816133b30152613a3e01526000505060005050600061043b01526150186000f3fe608060405234801561001057600080fd5b50600436106100d45760003560e01c8063aed2e92911610081578063e29b753c1161005b578063e29b753c146102e8578063e3d0e712146102fb578063f2fde38b1461030e576100d4565b8063aed2e92914610262578063afcb95d71461028c578063b1dc65a4146102d5576100d4565b806381ff7048116100b257806381ff7048146101bc5780638da5cb5b14610231578063a4c0ed361461024f576100d4565b8063181f5a771461011b578063349e8cca1461016d57806379ba5097146101b4575b7f00000000000000000000000000000000000000000000000000000000000000003660008037600080366000845af43d6000803e808015610114573d6000f35b3d6000fd5b005b6101576040518060400160405280601481526020017f4b6565706572526567697374727920322e312e3000000000000000000000000081525081565b6040516101649190613cbd565b60405180910390f35b7f00000000000000000000000000000000000000000000000000000000000000005b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610164565b610119610321565b61020e60145460115463ffffffff780100000000000000000000000000000000000000000000000083048116937c01000000000000000000000000000000000000000000000000000000009093041691565b6040805163ffffffff948516815293909216602084015290820152606001610164565b60005473ffffffffffffffffffffffffffffffffffffffff1661018f565b61011961025d366004613d46565b610423565b610275610270366004613da2565b61063f565b604080519215158352602083019190915201610164565b601154601254604080516000815260208101939093527c010000000000000000000000000000000000000000000000000000000090910463ffffffff1690820152606001610164565b6101196102e3366004613e33565b6107a7565b6101196102f63660046142ae565b6112ea565b61011961030936600461437b565b6121e6565b61011961031c36600461440a565b61220f565b60015473ffffffffffffffffffffffffffffffffffffffff1633146103a7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e65720000000000000000000060448201526064015b60405180910390fd5b60008054337fffffffffffffffffffffffff00000000000000000000000000000000000000008083168217845560018054909116905560405173ffffffffffffffffffffffffffffffffffffffff90921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b3373ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001614610492576040517fc8bad78d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b602081146104cc576040517fdfe9309000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60006104da82840184614427565b60008181526004602052604090205490915065010000000000900463ffffffff90811614610534576040517f9c0083a200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008181526004602052604090206001015461056f9085906c0100000000000000000000000090046bffffffffffffffffffffffff1661446f565b600082815260046020526040902060010180546bffffffffffffffffffffffff929092166c01000000000000000000000000027fffffffffffffffff000000000000000000000000ffffffffffffffffffffffff9092169190911790556018546105da908590614494565b6018556040516bffffffffffffffffffffffff8516815273ffffffffffffffffffffffffffffffffffffffff86169082907fafd24114486da8ebfc32f3626dada8863652e187461aa74d4bfa7348915062039060200160405180910390a35050505050565b60008061064a612223565b6012546e010000000000000000000000000000900460ff1615610699576040517f24522f3400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600085815260046020908152604091829020825160e081018452815460ff811615158252610100810463ffffffff908116838601819052650100000000008304821684880152690100000000000000000090920473ffffffffffffffffffffffffffffffffffffffff16606084018190526001909401546bffffffffffffffffffffffff80821660808601526c0100000000000000000000000082041660a0850152780100000000000000000000000000000000000000000000000090041660c08301528451601f8901859004850281018501909552878552909361079893899089908190840183828082843760009201919091525061225d92505050565b9093509150505b935093915050565b60005a604080516101208101825260125460ff808216835261010080830463ffffffff90811660208601526501000000000084048116958501959095526901000000000000000000830462ffffff1660608501526c01000000000000000000000000830461ffff1660808501526e0100000000000000000000000000008304821615801560a08601526f010000000000000000000000000000008404909216151560c085015270010000000000000000000000000000000083046bffffffffffffffffffffffff1660e08501527c0100000000000000000000000000000000000000000000000000000000909204909316908201529192506108d5576040517f24522f3400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b336000908152600b602052604090205460ff1661091e576040517f1099ed7500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6011548a351461095a576040517fdfdcf8e700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b80516109679060016144d6565b60ff16861415806109785750858414155b156109af576040517f0244f71a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6109bf8a8a8a8a8a8a8a8a612468565b60006109cb8a8a6126d1565b9050600081604001515167ffffffffffffffff8111156109ed576109ed613eea565b604051908082528060200260200182016040528015610ab157816020015b604080516101e0810182526000610100820181815261012083018290526101408301829052610160830182905261018083018290526101a083018290526101c0830182905282526020808301829052928201819052606082018190526080820181905260a0820181905260c0820181905260e082015282527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff909201910181610a0b5790505b5090506000805b836040015151811015610efa576004600085604001518381518110610adf57610adf6144a7565b6020908102919091018101518252818101929092526040908101600020815160e081018352815460ff811615158252610100810463ffffffff90811695830195909552650100000000008104851693820193909352690100000000000000000090920473ffffffffffffffffffffffffffffffffffffffff166060830152600101546bffffffffffffffffffffffff80821660808401526c0100000000000000000000000082041660a08301527801000000000000000000000000000000000000000000000000900490911660c08201528351849083908110610bc457610bc46144a7565b602002602001015160000181905250610bf984604001518281518110610bec57610bec6144a7565b602002602001015161278c565b838281518110610c0b57610c0b6144a7565b6020026020010151608001906001811115610c2857610c286144ef565b90816001811115610c3b57610c3b6144ef565b81525050610caf85848381518110610c5557610c556144a7565b60200260200101516080015186606001518481518110610c7757610c776144a7565b60200260200101518760a001518581518110610c9557610c956144a7565b602002602001015151886000015189602001516001612837565b838281518110610cc157610cc16144a7565b6020026020010151604001906bffffffffffffffffffffffff1690816bffffffffffffffffffffffff1681525050610d4d84604001518281518110610d0857610d086144a7565b602002602001015185608001518381518110610d2657610d266144a7565b6020026020010151858481518110610d4057610d406144a7565b6020026020010151612882565b848381518110610d5f57610d5f6144a7565b6020026020010151602001858481518110610d7c57610d7c6144a7565b602002602001015160e0018281525082151515158152505050828181518110610da757610da76144a7565b60200260200101516020015115610dca57610dc360018361451e565b9150610dcf565b610ee8565b610e35838281518110610de457610de46144a7565b6020026020010151600001516060015185606001518381518110610e0a57610e0a6144a7565b60200260200101518660a001518481518110610e2857610e286144a7565b602002602001015161225d565b848381518110610e4757610e476144a7565b6020026020010151606001858481518110610e6457610e646144a7565b602002602001015160a0018281525082151515158152505050828181518110610e8f57610e8f6144a7565b602002602001015160a0015186610ea69190614539565b9550610ee884604001518281518110610ec157610ec16144a7565b6020026020010151848381518110610edb57610edb6144a7565b6020026020010151612a01565b80610ef28161454c565b915050610ab8565b508061ffff16600003610f115750505050506112e0565b8351610f1e9060016144d6565b610f2d9060ff1661044c614584565b616b6c610f3b8d6010614584565b5a610f469089614539565b610f509190614494565b610f5a9190614494565b610f649190614494565b9450611b58610f7761ffff8316876145f0565b610f819190614494565b945060008060008060005b87604001515181101561118257868181518110610fab57610fab6144a7565b60200260200101516020015115611170576110078a888381518110610fd257610fd26144a7565b6020026020010151608001518a60a001518481518110610ff457610ff46144a7565b6020026020010151518c60000151612b13565b878281518110611019576110196144a7565b602002602001015160c00181815250506110758989604001518381518110611043576110436144a7565b602002602001015189848151811061105d5761105d6144a7565b60200260200101518b600001518c602001518b612b33565b9093509150611084828561446f565b9350611090838661446f565b94508681815181106110a4576110a46144a7565b6020026020010151606001511515886040015182815181106110c8576110c86144a7565b60200260200101517fad8cc9579b21dfe2c2f6ea35ba15b656e46b4f5b0cb424f52739b8ce5cac9c5b84866110fd919061446f565b8a858151811061110f5761110f6144a7565b602002602001015160a001518b868151811061112d5761112d6144a7565b602002602001015160c001518d60800151878151811061114f5761114f6144a7565b60200260200101516040516111679493929190614604565b60405180910390a35b8061117a8161454c565b915050610f8c565b5050336000908152600b6020526040902080548492506002906111ba9084906201000090046bffffffffffffffffffffffff1661446f565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff16021790555080601260000160108282829054906101000a90046bffffffffffffffffffffffff16611214919061446f565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff16021790555060008f600160038110611257576112576144a7565b602002013560001c9050600060088264ffffffffff16901c905087610100015163ffffffff168163ffffffff1611156112d657601280547bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167c010000000000000000000000000000000000000000000000000000000063ffffffff8416021790555b5050505050505050505b5050505050505050565b6112f2612c26565b601f8651111561132e576040517f25d0209c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8360ff1660000361136b576040517fe77dba5600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8451865114158061138a5750611382846003614641565b60ff16865111155b156113c1576040517f1d2d1c5800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b601254600e547001000000000000000000000000000000009091046bffffffffffffffffffffffff169060005b816bffffffffffffffffffffffff1681101561145657611443600e828154811061141a5761141a6144a7565b60009182526020909120015473ffffffffffffffffffffffffffffffffffffffff168484612ca7565b508061144e8161454c565b9150506113ee565b5060008060005b836bffffffffffffffffffffffff1681101561155f57600d8181548110611486576114866144a7565b600091825260209091200154600e805473ffffffffffffffffffffffffffffffffffffffff909216945090829081106114c1576114c16144a7565b600091825260208083209091015473ffffffffffffffffffffffffffffffffffffffff8681168452600c8352604080852080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00001690559116808452600b90925290912080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001690559150806115578161454c565b91505061145d565b5061156c600d6000613b92565b611578600e6000613b92565b604080516080810182526000808252602082018190529181018290526060810182905290805b8c518110156119e157600c60008e83815181106115bd576115bd6144a7565b60209081029190910181015173ffffffffffffffffffffffffffffffffffffffff1682528101919091526040016000205460ff1615611628576040517f77cea0fa00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168d8281518110611652576116526144a7565b602002602001015173ffffffffffffffffffffffffffffffffffffffff16036116a7576040517f815e1d6400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60405180604001604052806001151581526020018260ff16815250600c60008f84815181106116d8576116d86144a7565b60209081029190910181015173ffffffffffffffffffffffffffffffffffffffff1682528181019290925260400160002082518154939092015160ff16610100027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff921515929092167fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000909316929092171790558b518c9082908110611780576117806144a7565b60200260200101519150600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16036117f0576040517f58a70a0a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff82166000908152600b60209081526040918290208251608081018452905460ff80821615801584526101008304909116938301939093526bffffffffffffffffffffffff6201000082048116948301949094526e010000000000000000000000000000900490921660608301529093506118ab576040517f6a7281ad00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001835260ff80821660208086019182526bffffffffffffffffffffffff808b166060880190815273ffffffffffffffffffffffffffffffffffffffff87166000908152600b909352604092839020885181549551948a0151925184166e010000000000000000000000000000027fffffffffffff000000000000000000000000ffffffffffffffffffffffffffff939094166201000002929092167fffffffffffff000000000000000000000000000000000000000000000000ffff94909616610100027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff921515929092167fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000090951694909417179190911692909217919091179055806119d98161454c565b91505061159e565b50508a516119f79150600d9060208d0190613bb0565b508851611a0b90600e9060208c0190613bb0565b506040518061012001604052808960ff168152602001886000015163ffffffff168152602001886020015163ffffffff168152602001886060015162ffffff168152602001886080015161ffff1681526020016012600001600e9054906101000a900460ff16151581526020016012600001600f9054906101000a900460ff1615158152602001856bffffffffffffffffffffffff168152602001600063ffffffff16815250601260008201518160000160006101000a81548160ff021916908360ff16021790555060208201518160000160016101000a81548163ffffffff021916908363ffffffff16021790555060408201518160000160056101000a81548163ffffffff021916908363ffffffff16021790555060608201518160000160096101000a81548162ffffff021916908362ffffff160217905550608082015181600001600c6101000a81548161ffff021916908361ffff16021790555060a082015181600001600e6101000a81548160ff02191690831515021790555060c082015181600001600f6101000a81548160ff02191690831515021790555060e08201518160000160106101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff16021790555061010082015181600001601c6101000a81548163ffffffff021916908363ffffffff1602179055509050506040518061018001604052808860a001516bffffffffffffffffffffffff16815260200188610180015173ffffffffffffffffffffffffffffffffffffffff168152602001601360010160009054906101000a90046bffffffffffffffffffffffff166bffffffffffffffffffffffff168152602001886040015163ffffffff1681526020018860c0015163ffffffff168152602001601360010160149054906101000a900463ffffffff1663ffffffff168152602001601360010160189054906101000a900463ffffffff1663ffffffff1681526020016013600101601c9054906101000a900463ffffffff1663ffffffff1681526020018860e0015163ffffffff16815260200188610100015163ffffffff16815260200188610120015163ffffffff168152602001886101c0015173ffffffffffffffffffffffffffffffffffffffff16815250601360008201518160000160006101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff160217905550602082015181600001600c6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060408201518160010160006101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff160217905550606082015181600101600c6101000a81548163ffffffff021916908363ffffffff16021790555060808201518160010160106101000a81548163ffffffff021916908363ffffffff16021790555060a08201518160010160146101000a81548163ffffffff021916908363ffffffff16021790555060c08201518160010160186101000a81548163ffffffff021916908363ffffffff16021790555060e082015181600101601c6101000a81548163ffffffff021916908363ffffffff1602179055506101008201518160020160006101000a81548163ffffffff021916908363ffffffff1602179055506101208201518160020160046101000a81548163ffffffff021916908363ffffffff1602179055506101408201518160020160086101000a81548163ffffffff021916908363ffffffff16021790555061016082015181600201600c6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555090505086610140015160168190555086610160015160178190555060006013600101601c9054906101000a900463ffffffff169050611fcd612eb1565b601480547bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167c010000000000000000000000000000000000000000000000000000000063ffffffff9384160217808255600192601891612048918591780100000000000000000000000000000000000000000000000090041661466a565b92506101000a81548163ffffffff021916908363ffffffff16021790555060008860405160200161207991906146d8565b604080518083037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe00181529190526014549091506120e290469030907801000000000000000000000000000000000000000000000000900463ffffffff168f8f8f878f8f612f66565b60115560005b6120f26009613010565b8110156121225761210f61210760098361301a565b600990613026565b508061211a8161454c565b9150506120e8565b5060005b896101a0015151811015612179576121668a6101a00151828151811061214e5761214e6144a7565b6020026020010151600961304890919063ffffffff16565b50806121718161454c565b915050612126565b507f1591690b8638f5fb2dbec82ac741805ac5da8b45dc5263f4875b0496fdce4e0582601154601360010160189054906101000a900463ffffffff168f8f8f878f8f6040516121d09998979695949392919061483c565b60405180910390a1505050505050505050505050565b61220786868686806020019051810190612200919061496d565b86866112ea565b505050505050565b612217612c26565b6122208161306a565b50565b321561225b576040517fb60ac5db00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b565b60125460009081906f01000000000000000000000000000000900460ff16156122b2576040517f37ed32e800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b601280547fffffffffffffffffffffffffffffffff00ffffffffffffffffffffffffffffff166f010000000000000000000000000000001790556040517f4585e33b000000000000000000000000000000000000000000000000000000009061231f908590602401613cbd565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff000000000000000000000000000000000000000000000000000000009094169390931790925290517f79188d1600000000000000000000000000000000000000000000000000000000815290935073ffffffffffffffffffffffffffffffffffffffff8616906379188d16906123f29087908790600401614ac7565b60408051808303816000875af1158015612410573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906124349190614ae0565b601280547fffffffffffffffffffffffffffffffff00ffffffffffffffffffffffffffffff16905590969095509350505050565b6000878760405161247a929190614b13565b604051908190038120612491918b90602001614b23565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081840301815282825280516020918201208383019092526000808452908301819052909250906000805b88811015612668576001858783602081106124fd576124fd6144a7565b61250a91901a601b6144d6565b8c8c8581811061251c5761251c6144a7565b905060200201358b8b86818110612535576125356144a7565b9050602002013560405160008152602001604052604051612572949392919093845260ff9290921660208401526040830152606082015260800190565b6020604051602081039080840390855afa158015612594573d6000803e3d6000fd5b5050604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081015173ffffffffffffffffffffffffffffffffffffffff81166000908152600c602090815290849020838501909452925460ff8082161515808552610100909204169383019390935290955093509050612642576040517f0f4c073700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b826020015160080260ff166001901b8401935080806126609061454c565b9150506124e0565b50827e010101010101010101010101010101010101010101010101010101010101018416146126c3576040517fc103be2e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b505050505050505050505050565b61270a6040518060c001604052806000815260200160008152602001606081526020016060815260200160608152602001606081525090565b600061271883850185614c14565b604081015151606082015151919250908114158061273b57508082608001515114155b8061274b5750808260a001515114155b15612782576040517fb55ac75400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5090505b92915050565b6000818160045b600f811015612819577fff0000000000000000000000000000000000000000000000000000000000000082168382602081106127d1576127d16144a7565b1a60f81b7effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff19161461280757506000949350505050565b806128118161454c565b915050612793565b5081600f1a600181111561282f5761282f6144ef565b949350505050565b60008061284988878b6000015161315f565b90506000806128648b8a63ffffffff16858a8a60018b6131eb565b9092509050612873818361446f565b9b9a5050505050505050505050565b60008080808460800151600181111561289d5761289d6144ef565b036128c1576128ad868686613644565b6128bc5760009250905061079f565b612938565b6001846080015160018111156128d9576128d96144ef565b036129065760006128eb878787613738565b9250905080612900575060009250905061079f565b50612938565b6040517ff2b2d41200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b612940612eb1565b84516040015163ffffffff161161299457857fc3237c8807c467c1b39b8d0395eff077313e691bf0a7388106792564ebfd5636866040516129819190613cbd565b60405180910390a260009250905061079f565b83604001516bffffffffffffffffffffffff16846000015160a001516bffffffffffffffffffffffff1610156129f457857f377c8b0c126ae5248d27aca1c76fac4608aff85673ee3caf09747e1044549e02866040516129819190613cbd565b6001969095509350505050565b600081608001516001811115612a1957612a196144ef565b03612a8b57612a26612eb1565b6000838152600460205260409020600101805463ffffffff929092167801000000000000000000000000000000000000000000000000027fffffffff00000000ffffffffffffffffffffffffffffffffffffffffffffffff9092169190911790555050565b600181608001516001811115612aa357612aa36144ef565b03612b0f5760e08101805160009081526008602052604080822080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055915191517fa4a4e334c0e330143f9437484fe516c13bc560b86b5b0daf58e7084aaac228f29190a25b5050565b6000612b2084848461315f565b90508085101561282f5750929392505050565b600080612b4e888760a001518860c0015188888860016131eb565b90925090506000612b5f828461446f565b600089815260046020526040902060010180549192508291600c90612ba39084906c0100000000000000000000000090046bffffffffffffffffffffffff16614d01565b82546101009290920a6bffffffffffffffffffffffff81810219909316918316021790915560008a815260046020526040812060010180548594509092612bec9185911661446f565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff16021790555050965096945050505050565b60005473ffffffffffffffffffffffffffffffffffffffff16331461225b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e657200000000000000000000604482015260640161039e565b73ffffffffffffffffffffffffffffffffffffffff83166000908152600b602090815260408083208151608081018352905460ff80821615801584526101008304909116948301949094526bffffffffffffffffffffffff6201000082048116938301939093526e0100000000000000000000000000009004909116606082015290612ea3576000816060015185612d3f9190614d01565b90506000612d4d8583614d26565b90508083604001818151612d61919061446f565b6bffffffffffffffffffffffff16905250612d7c8582614d51565b83606001818151612d8d919061446f565b6bffffffffffffffffffffffff90811690915273ffffffffffffffffffffffffffffffffffffffff89166000908152600b602090815260409182902087518154928901519389015160608a015186166e010000000000000000000000000000027fffffffffffff000000000000000000000000ffffffffffffffffffffffffffff919096166201000002167fffffffffffff000000000000000000000000000000000000000000000000ffff60ff95909516610100027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff921515929092167fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000909416939093171792909216179190911790555050505b6040015190505b9392505050565b600060017f00000000000000000000000000000000000000000000000000000000000000006002811115612ee757612ee76144ef565b03612f6157606473ffffffffffffffffffffffffffffffffffffffff1663a3b1b31d6040518163ffffffff1660e01b8152600401602060405180830381865afa158015612f38573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612f5c9190614d85565b905090565b504390565b6000808a8a8a8a8a8a8a8a8a604051602001612f8a99989796959493929190614d9e565b604080518083037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe001815291905280516020909101207dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff167e01000000000000000000000000000000000000000000000000000000000000179b9a5050505050505050505050565b6000612786825490565b6000612eaa83836138c5565b6000612eaa8373ffffffffffffffffffffffffffffffffffffffff84166138ef565b6000612eaa8373ffffffffffffffffffffffffffffffffffffffff84166139e9565b3373ffffffffffffffffffffffffffffffffffffffff8216036130e9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c66000000000000000000604482015260640161039e565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b60008080856001811115613175576131756144ef565b03613184575062015f906131a3565b6001856001811115613198576131986144ef565b0361290657506201adb05b6131b463ffffffff85166014614584565b6131bf8460016144d6565b6131ce9060ff16611d4c614584565b6131d89083614494565b6131e29190614494565b95945050505050565b6000806000896080015161ffff16876132049190614584565b90508380156132125750803a105b1561321a57503a5b600060027f00000000000000000000000000000000000000000000000000000000000000006002811115613250576132506144ef565b036133af5760408051600081526020810190915285156132ae57600036604051806080016040528060488152602001614fc46048913960405160200161329893929190614e33565b6040516020818303038152906040529050613316565b6015546132ca90640100000000900463ffffffff166004614e5a565b63ffffffff1667ffffffffffffffff8111156132e8576132e8613eea565b6040519080825280601f01601f191660200182016040528015613312576020820181803683370190505b5090505b6040517f49948e0e00000000000000000000000000000000000000000000000000000000815273420000000000000000000000000000000000000f906349948e0e90613366908490600401613cbd565b602060405180830381865afa158015613383573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906133a79190614d85565b915050613509565b60017f000000000000000000000000000000000000000000000000000000000000000060028111156133e3576133e36144ef565b0361350957841561346557606c73ffffffffffffffffffffffffffffffffffffffff1663c6f7de0e6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561343a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061345e9190614d85565b9050613509565b6000606c73ffffffffffffffffffffffffffffffffffffffff166341b247a86040518163ffffffff1660e01b815260040160c060405180830381865afa1580156134b3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906134d79190614e7d565b50506015549294506134fa93505050640100000000900463ffffffff1682614584565b613505906010614584565b9150505b8461352557808b6080015161ffff166135229190614584565b90505b61353361ffff8716826145f0565b9050600087826135438c8e614494565b61354d9086614584565b6135579190614494565b61356990670de0b6b3a7640000614584565b61357391906145f0565b905060008c6040015163ffffffff1664e8d4a510006135929190614584565b898e6020015163ffffffff16858f886135ab9190614584565b6135b59190614494565b6135c390633b9aca00614584565b6135cd9190614584565b6135d791906145f0565b6135e19190614494565b90506b033b2e3c9fd0803ce80000006135fa8284614494565b1115613632576040517f2ad7547a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b909c909b509950505050505050505050565b6000808380602001905181019061365b9190614ec7565b835160c00151815191925063ffffffff908116911610156136b857847f405288ea7be309e16cfdf481367f90a413e1d4634fcdaf8966546db9b93012e8856040516136a69190613cbd565b60405180910390a26000915050612eaa565b6020810151158015906136df5750602081015181516136dc9063ffffffff16613a38565b14155b806136f857506136ed612eb1565b815163ffffffff1610155b1561372d57847f6aa7f60c176da7af894b384daea2249497448137f5943c1237ada8bc92bdc301856040516136a69190613cbd565b506001949350505050565b6000806000848060200190518101906137519190614f1f565b9050600086826000015183602001516040516020016137a893929190928352602083019190915260e01b7fffffffff0000000000000000000000000000000000000000000000000000000016604082015260440190565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152919052805160209091012060608301519091501580159061380a57508160600151613807836040015163ffffffff16613a38565b14155b806138265750613818612eb1565b826040015163ffffffff1610155b1561387057867f6aa7f60c176da7af894b384daea2249497448137f5943c1237ada8bc92bdc3018760405161385b9190613cbd565b60405180910390a260009350915061079f9050565b60008181526008602052604090205460ff16156138b757867f405288ea7be309e16cfdf481367f90a413e1d4634fcdaf8966546db9b93012e88760405161385b9190613cbd565b600197909650945050505050565b60008260000182815481106138dc576138dc6144a7565b9060005260206000200154905092915050565b600081815260018301602052604081205480156139d8576000613913600183614539565b855490915060009061392790600190614539565b905081811461398c576000866000018281548110613947576139476144a7565b906000526020600020015490508087600001848154811061396a5761396a6144a7565b6000918252602080832090910192909255918252600188019052604090208390555b855486908061399d5761399d614f94565b600190038181906000526020600020016000905590558560010160008681526020019081526020016000206000905560019350505050612786565b6000915050612786565b5092915050565b6000818152600183016020526040812054613a3057508154600181810184556000848152602080822090930184905584548482528286019093526040902091909155612786565b506000612786565b600060017f00000000000000000000000000000000000000000000000000000000000000006002811115613a6e57613a6e6144ef565b03613b88576000606473ffffffffffffffffffffffffffffffffffffffff1663a3b1b31d6040518163ffffffff1660e01b8152600401602060405180830381865afa158015613ac1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613ae59190614d85565b90508083101580613b005750610100613afe8483614539565b115b15613b0e5750600092915050565b6040517f2b407a8200000000000000000000000000000000000000000000000000000000815260048101849052606490632b407a8290602401602060405180830381865afa158015613b64573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612eaa9190614d85565b504090565b919050565b50805460008255906000526020600020908101906122209190613c3a565b828054828255906000526020600020908101928215613c2a579160200282015b82811115613c2a57825182547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff909116178255602090920191600190910190613bd0565b50613c36929150613c3a565b5090565b5b80821115613c365760008155600101613c3b565b60005b83811015613c6a578181015183820152602001613c52565b50506000910152565b60008151808452613c8b816020860160208601613c4f565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b602081526000612eaa6020830184613c73565b73ffffffffffffffffffffffffffffffffffffffff8116811461222057600080fd5b8035613b8d81613cd0565b60008083601f840112613d0f57600080fd5b50813567ffffffffffffffff811115613d2757600080fd5b602083019150836020828501011115613d3f57600080fd5b9250929050565b60008060008060608587031215613d5c57600080fd5b8435613d6781613cd0565b935060208501359250604085013567ffffffffffffffff811115613d8a57600080fd5b613d9687828801613cfd565b95989497509550505050565b600080600060408486031215613db757600080fd5b83359250602084013567ffffffffffffffff811115613dd557600080fd5b613de186828701613cfd565b9497909650939450505050565b60008083601f840112613e0057600080fd5b50813567ffffffffffffffff811115613e1857600080fd5b6020830191508360208260051b8501011115613d3f57600080fd5b60008060008060008060008060e0898b031215613e4f57600080fd5b606089018a811115613e6057600080fd5b8998503567ffffffffffffffff80821115613e7a57600080fd5b613e868c838d01613cfd565b909950975060808b0135915080821115613e9f57600080fd5b613eab8c838d01613dee565b909750955060a08b0135915080821115613ec457600080fd5b50613ed18b828c01613dee565b999c989b50969995989497949560c00135949350505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6040516101e0810167ffffffffffffffff81118282101715613f3d57613f3d613eea565b60405290565b60405160c0810167ffffffffffffffff81118282101715613f3d57613f3d613eea565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715613fad57613fad613eea565b604052919050565b600067ffffffffffffffff821115613fcf57613fcf613eea565b5060051b60200190565b600082601f830112613fea57600080fd5b81356020613fff613ffa83613fb5565b613f66565b82815260059290921b8401810191818101908684111561401e57600080fd5b8286015b8481101561404257803561403581613cd0565b8352918301918301614022565b509695505050505050565b803560ff81168114613b8d57600080fd5b63ffffffff8116811461222057600080fd5b8035613b8d8161405e565b62ffffff8116811461222057600080fd5b8035613b8d8161407b565b61ffff8116811461222057600080fd5b8035613b8d81614097565b6bffffffffffffffffffffffff8116811461222057600080fd5b8035613b8d816140b2565b60006101e082840312156140ea57600080fd5b6140f2613f19565b90506140fd82614070565b815261410b60208301614070565b602082015261411c60408301614070565b604082015261412d6060830161408c565b606082015261413e608083016140a7565b608082015261414f60a083016140cc565b60a082015261416060c08301614070565b60c082015261417160e08301614070565b60e0820152610100614184818401614070565b90820152610120614196838201614070565b90820152610140828101359082015261016080830135908201526101806141be818401613cf2565b908201526101a08281013567ffffffffffffffff8111156141de57600080fd5b6141ea85828601613fd9565b8284015250506101c06141fe818401613cf2565b9082015292915050565b803567ffffffffffffffff81168114613b8d57600080fd5b600082601f83011261423157600080fd5b813567ffffffffffffffff81111561424b5761424b613eea565b61427c60207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f84011601613f66565b81815284602083860101111561429157600080fd5b816020850160208301376000918101602001919091529392505050565b60008060008060008060c087890312156142c757600080fd5b863567ffffffffffffffff808211156142df57600080fd5b6142eb8a838b01613fd9565b9750602089013591508082111561430157600080fd5b61430d8a838b01613fd9565b965061431b60408a0161404d565b9550606089013591508082111561433157600080fd5b61433d8a838b016140d7565b945061434b60808a01614208565b935060a089013591508082111561436157600080fd5b5061436e89828a01614220565b9150509295509295509295565b60008060008060008060c0878903121561439457600080fd5b863567ffffffffffffffff808211156143ac57600080fd5b6143b88a838b01613fd9565b975060208901359150808211156143ce57600080fd5b6143da8a838b01613fd9565b96506143e860408a0161404d565b955060608901359150808211156143fe57600080fd5b61433d8a838b01614220565b60006020828403121561441c57600080fd5b8135612eaa81613cd0565b60006020828403121561443957600080fd5b5035919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b6bffffffffffffffffffffffff8181168382160190808211156139e2576139e2614440565b8082018082111561278657612786614440565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60ff818116838216019081111561278657612786614440565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b61ffff8181168382160190808211156139e2576139e2614440565b8181038181111561278657612786614440565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff820361457d5761457d614440565b5060010190565b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff04831182151516156145bc576145bc614440565b500290565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b6000826145ff576145ff6145c1565b500490565b6bffffffffffffffffffffffff851681528360208201528260408201526080606082015260006146376080830184613c73565b9695505050505050565b600060ff821660ff84168160ff048111821515161561466257614662614440565b029392505050565b63ffffffff8181168382160190808211156139e2576139e2614440565b600081518084526020808501945080840160005b838110156146cd57815173ffffffffffffffffffffffffffffffffffffffff168752958201959082019060010161469b565b509495945050505050565b602081526146ef60208201835163ffffffff169052565b60006020830151614708604084018263ffffffff169052565b50604083015163ffffffff8116606084015250606083015162ffffff8116608084015250608083015161ffff811660a08401525060a08301516bffffffffffffffffffffffff811660c08401525060c083015163ffffffff811660e08401525060e08301516101006147818185018363ffffffff169052565b840151905061012061479a8482018363ffffffff169052565b84015190506101406147b38482018363ffffffff169052565b840151610160848101919091528401516101808085019190915284015190506101a06147f68185018373ffffffffffffffffffffffffffffffffffffffff169052565b808501519150506101e06101c08181860152614816610200860184614687565b95015173ffffffffffffffffffffffffffffffffffffffff169301929092525090919050565b600061012063ffffffff808d1684528b6020850152808b1660408501525080606084015261486c8184018a614687565b905082810360808401526148808189614687565b905060ff871660a084015282810360c084015261489d8187613c73565b905067ffffffffffffffff851660e08401528281036101008401526148c28185613c73565b9c9b505050505050505050505050565b8051613b8d8161405e565b8051613b8d8161407b565b8051613b8d81614097565b8051613b8d816140b2565b8051613b8d81613cd0565b600082601f83011261491a57600080fd5b8151602061492a613ffa83613fb5565b82815260059290921b8401810191818101908684111561494957600080fd5b8286015b8481101561404257805161496081613cd0565b835291830191830161494d565b60006020828403121561497f57600080fd5b815167ffffffffffffffff8082111561499757600080fd5b908301906101e082860312156149ac57600080fd5b6149b4613f19565b6149bd836148d2565b81526149cb602084016148d2565b60208201526149dc604084016148d2565b60408201526149ed606084016148dd565b60608201526149fe608084016148e8565b6080820152614a0f60a084016148f3565b60a0820152614a2060c084016148d2565b60c0820152614a3160e084016148d2565b60e0820152610100614a448185016148d2565b90820152610120614a568482016148d2565b9082015261014083810151908201526101608084015190820152610180614a7e8185016148fe565b908201526101a08381015183811115614a9657600080fd5b614aa288828701614909565b8284015250506101c09150614ab88284016148fe565b91810191909152949350505050565b82815260406020820152600061282f6040830184613c73565b60008060408385031215614af357600080fd5b82518015158114614b0357600080fd5b6020939093015192949293505050565b8183823760009101908152919050565b8281526080810160608360208401379392505050565b600082601f830112614b4a57600080fd5b81356020614b5a613ffa83613fb5565b82815260059290921b84018101918181019086841115614b7957600080fd5b8286015b848110156140425780358352918301918301614b7d565b600082601f830112614ba557600080fd5b81356020614bb5613ffa83613fb5565b82815260059290921b84018101918181019086841115614bd457600080fd5b8286015b8481101561404257803567ffffffffffffffff811115614bf85760008081fd5b614c068986838b0101614220565b845250918301918301614bd8565b600060208284031215614c2657600080fd5b813567ffffffffffffffff80821115614c3e57600080fd5b9083019060c08286031215614c5257600080fd5b614c5a613f43565b8235815260208301356020820152604083013582811115614c7a57600080fd5b614c8687828601614b39565b604083015250606083013582811115614c9e57600080fd5b614caa87828601614b39565b606083015250608083013582811115614cc257600080fd5b614cce87828601614b94565b60808301525060a083013582811115614ce657600080fd5b614cf287828601614b94565b60a08301525095945050505050565b6bffffffffffffffffffffffff8281168282160390808211156139e2576139e2614440565b60006bffffffffffffffffffffffff80841680614d4557614d456145c1565b92169190910492915050565b60006bffffffffffffffffffffffff80831681851681830481118215151615614d7c57614d7c614440565b02949350505050565b600060208284031215614d9757600080fd5b5051919050565b60006101208b835273ffffffffffffffffffffffffffffffffffffffff8b16602084015267ffffffffffffffff808b166040850152816060850152614de58285018b614687565b91508382036080850152614df9828a614687565b915060ff881660a085015283820360c0850152614e168288613c73565b90861660e085015283810361010085015290506148c28185613c73565b828482376000838201600081528351614e50818360208801613c4f565b0195945050505050565b600063ffffffff80831681851681830481118215151615614d7c57614d7c614440565b60008060008060008060c08789031215614e9657600080fd5b865195506020870151945060408701519350606087015192506080870151915060a087015190509295509295509295565b600060408284031215614ed957600080fd5b6040516040810181811067ffffffffffffffff82111715614efc57614efc613eea565b6040528251614f0a8161405e565b81526020928301519281019290925250919050565b600060808284031215614f3157600080fd5b6040516080810181811067ffffffffffffffff82111715614f5457614f54613eea565b604052825181526020830151614f698161405e565b60208201526040830151614f7c8161405e565b60408201526060928301519281019290925250919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fdfe307866666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666a164736f6c6343000810000a", + Bin: "0x6101406040523480156200001257600080fd5b50604051620054d0380380620054d08339810160408190526200003591620003df565b80816001600160a01b0316634b4fd03b6040518163ffffffff1660e01b8152600401602060405180830381865afa15801562000075573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200009b919062000406565b826001600160a01b031663ca30e6036040518163ffffffff1660e01b8152600401602060405180830381865afa158015620000da573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620001009190620003df565b836001600160a01b031663b10b673c6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156200013f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620001659190620003df565b846001600160a01b0316636709d0e56040518163ffffffff1660e01b8152600401602060405180830381865afa158015620001a4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620001ca9190620003df565b856001600160a01b0316635425d8ac6040518163ffffffff1660e01b8152600401602060405180830381865afa15801562000209573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200022f9190620003df565b3380600081620002865760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b0384811691909117909155811615620002b957620002b9816200031b565b505050846002811115620002d157620002d162000429565b60e0816002811115620002e857620002e862000429565b9052506001600160a01b0393841660805291831660a052821660c0528116610100529190911661012052506200043f9050565b336001600160a01b03821603620003755760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c6600000000000000000060448201526064016200027d565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b6001600160a01b0381168114620003dc57600080fd5b50565b600060208284031215620003f257600080fd5b8151620003ff81620003c6565b9392505050565b6000602082840312156200041957600080fd5b815160038110620003ff57600080fd5b634e487b7160e01b600052602160045260246000fd5b60805160a05160c05160e051610100516101205161502f620004a16000396000818160d6015261016f01526000505060008181612eb701528181613220015281816133b30152613a4901526000505060005050600061043b015261502f6000f3fe608060405234801561001057600080fd5b50600436106100d45760003560e01c8063aed2e92911610081578063e29b753c1161005b578063e29b753c146102e8578063e3d0e712146102fb578063f2fde38b1461030e576100d4565b8063aed2e92914610262578063afcb95d71461028c578063b1dc65a4146102d5576100d4565b806381ff7048116100b257806381ff7048146101bc5780638da5cb5b14610231578063a4c0ed361461024f576100d4565b8063181f5a771461011b578063349e8cca1461016d57806379ba5097146101b4575b7f00000000000000000000000000000000000000000000000000000000000000003660008037600080366000845af43d6000803e808015610114573d6000f35b3d6000fd5b005b6101576040518060400160405280601481526020017f4b6565706572526567697374727920322e312e3000000000000000000000000081525081565b6040516101649190613cc8565b60405180910390f35b7f00000000000000000000000000000000000000000000000000000000000000005b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610164565b610119610321565b61020e60145460115463ffffffff780100000000000000000000000000000000000000000000000083048116937c01000000000000000000000000000000000000000000000000000000009093041691565b6040805163ffffffff948516815293909216602084015290820152606001610164565b60005473ffffffffffffffffffffffffffffffffffffffff1661018f565b61011961025d366004613d51565b610423565b610275610270366004613dad565b61063f565b604080519215158352602083019190915201610164565b601154601254604080516000815260208101939093527c010000000000000000000000000000000000000000000000000000000090910463ffffffff1690820152606001610164565b6101196102e3366004613e3e565b6107a7565b6101196102f63660046142b9565b6112ea565b610119610309366004614386565b6121e6565b61011961031c366004614415565b61220f565b60015473ffffffffffffffffffffffffffffffffffffffff1633146103a7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e65720000000000000000000060448201526064015b60405180910390fd5b60008054337fffffffffffffffffffffffff00000000000000000000000000000000000000008083168217845560018054909116905560405173ffffffffffffffffffffffffffffffffffffffff90921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b3373ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001614610492576040517fc8bad78d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b602081146104cc576040517fdfe9309000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60006104da82840184614432565b60008181526004602052604090205490915065010000000000900463ffffffff90811614610534576040517f9c0083a200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008181526004602052604090206001015461056f9085906c0100000000000000000000000090046bffffffffffffffffffffffff1661447a565b600082815260046020526040902060010180546bffffffffffffffffffffffff929092166c01000000000000000000000000027fffffffffffffffff000000000000000000000000ffffffffffffffffffffffff9092169190911790556018546105da90859061449f565b6018556040516bffffffffffffffffffffffff8516815273ffffffffffffffffffffffffffffffffffffffff86169082907fafd24114486da8ebfc32f3626dada8863652e187461aa74d4bfa7348915062039060200160405180910390a35050505050565b60008061064a612223565b6012546e010000000000000000000000000000900460ff1615610699576040517f24522f3400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600085815260046020908152604091829020825160e081018452815460ff811615158252610100810463ffffffff908116838601819052650100000000008304821684880152690100000000000000000090920473ffffffffffffffffffffffffffffffffffffffff16606084018190526001909401546bffffffffffffffffffffffff80821660808601526c0100000000000000000000000082041660a0850152780100000000000000000000000000000000000000000000000090041660c08301528451601f8901859004850281018501909552878552909361079893899089908190840183828082843760009201919091525061225d92505050565b9093509150505b935093915050565b60005a604080516101208101825260125460ff808216835261010080830463ffffffff90811660208601526501000000000084048116958501959095526901000000000000000000830462ffffff1660608501526c01000000000000000000000000830461ffff1660808501526e0100000000000000000000000000008304821615801560a08601526f010000000000000000000000000000008404909216151560c085015270010000000000000000000000000000000083046bffffffffffffffffffffffff1660e08501527c0100000000000000000000000000000000000000000000000000000000909204909316908201529192506108d5576040517f24522f3400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b336000908152600b602052604090205460ff1661091e576040517f1099ed7500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6011548a351461095a576040517fdfdcf8e700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b80516109679060016144e1565b60ff16861415806109785750858414155b156109af576040517f0244f71a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6109bf8a8a8a8a8a8a8a8a612468565b60006109cb8a8a6126d1565b9050600081604001515167ffffffffffffffff8111156109ed576109ed613ef5565b604051908082528060200260200182016040528015610ab157816020015b604080516101e0810182526000610100820181815261012083018290526101408301829052610160830182905261018083018290526101a083018290526101c0830182905282526020808301829052928201819052606082018190526080820181905260a0820181905260c0820181905260e082015282527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff909201910181610a0b5790505b5090506000805b836040015151811015610efa576004600085604001518381518110610adf57610adf6144b2565b6020908102919091018101518252818101929092526040908101600020815160e081018352815460ff811615158252610100810463ffffffff90811695830195909552650100000000008104851693820193909352690100000000000000000090920473ffffffffffffffffffffffffffffffffffffffff166060830152600101546bffffffffffffffffffffffff80821660808401526c0100000000000000000000000082041660a08301527801000000000000000000000000000000000000000000000000900490911660c08201528351849083908110610bc457610bc46144b2565b602002602001015160000181905250610bf984604001518281518110610bec57610bec6144b2565b602002602001015161278c565b838281518110610c0b57610c0b6144b2565b6020026020010151608001906001811115610c2857610c286144fa565b90816001811115610c3b57610c3b6144fa565b81525050610caf85848381518110610c5557610c556144b2565b60200260200101516080015186606001518481518110610c7757610c776144b2565b60200260200101518760a001518581518110610c9557610c956144b2565b602002602001015151886000015189602001516001612837565b838281518110610cc157610cc16144b2565b6020026020010151604001906bffffffffffffffffffffffff1690816bffffffffffffffffffffffff1681525050610d4d84604001518281518110610d0857610d086144b2565b602002602001015185608001518381518110610d2657610d266144b2565b6020026020010151858481518110610d4057610d406144b2565b6020026020010151612882565b848381518110610d5f57610d5f6144b2565b6020026020010151602001858481518110610d7c57610d7c6144b2565b602002602001015160e0018281525082151515158152505050828181518110610da757610da76144b2565b60200260200101516020015115610dca57610dc3600183614529565b9150610dcf565b610ee8565b610e35838281518110610de457610de46144b2565b6020026020010151600001516060015185606001518381518110610e0a57610e0a6144b2565b60200260200101518660a001518481518110610e2857610e286144b2565b602002602001015161225d565b848381518110610e4757610e476144b2565b6020026020010151606001858481518110610e6457610e646144b2565b602002602001015160a0018281525082151515158152505050828181518110610e8f57610e8f6144b2565b602002602001015160a0015186610ea69190614544565b9550610ee884604001518281518110610ec157610ec16144b2565b6020026020010151848381518110610edb57610edb6144b2565b6020026020010151612a01565b80610ef281614557565b915050610ab8565b508061ffff16600003610f115750505050506112e0565b8351610f1e9060016144e1565b610f2d9060ff1661044c61458f565b616b6c610f3b8d601061458f565b5a610f469089614544565b610f50919061449f565b610f5a919061449f565b610f64919061449f565b9450611b58610f7761ffff8316876145fb565b610f81919061449f565b945060008060008060005b87604001515181101561118257868181518110610fab57610fab6144b2565b60200260200101516020015115611170576110078a888381518110610fd257610fd26144b2565b6020026020010151608001518a60a001518481518110610ff457610ff46144b2565b6020026020010151518c60000151612b13565b878281518110611019576110196144b2565b602002602001015160c00181815250506110758989604001518381518110611043576110436144b2565b602002602001015189848151811061105d5761105d6144b2565b60200260200101518b600001518c602001518b612b33565b9093509150611084828561447a565b9350611090838661447a565b94508681815181106110a4576110a46144b2565b6020026020010151606001511515886040015182815181106110c8576110c86144b2565b60200260200101517fad8cc9579b21dfe2c2f6ea35ba15b656e46b4f5b0cb424f52739b8ce5cac9c5b84866110fd919061447a565b8a858151811061110f5761110f6144b2565b602002602001015160a001518b868151811061112d5761112d6144b2565b602002602001015160c001518d60800151878151811061114f5761114f6144b2565b6020026020010151604051611167949392919061460f565b60405180910390a35b8061117a81614557565b915050610f8c565b5050336000908152600b6020526040902080548492506002906111ba9084906201000090046bffffffffffffffffffffffff1661447a565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff16021790555080601260000160108282829054906101000a90046bffffffffffffffffffffffff16611214919061447a565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff16021790555060008f600160038110611257576112576144b2565b602002013560001c9050600060088264ffffffffff16901c905087610100015163ffffffff168163ffffffff1611156112d657601280547bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167c010000000000000000000000000000000000000000000000000000000063ffffffff8416021790555b5050505050505050505b5050505050505050565b6112f2612c26565b601f8651111561132e576040517f25d0209c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8360ff1660000361136b576040517fe77dba5600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8451865114158061138a575061138284600361464c565b60ff16865111155b156113c1576040517f1d2d1c5800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b601254600e547001000000000000000000000000000000009091046bffffffffffffffffffffffff169060005b816bffffffffffffffffffffffff1681101561145657611443600e828154811061141a5761141a6144b2565b60009182526020909120015473ffffffffffffffffffffffffffffffffffffffff168484612ca7565b508061144e81614557565b9150506113ee565b5060008060005b836bffffffffffffffffffffffff1681101561155f57600d8181548110611486576114866144b2565b600091825260209091200154600e805473ffffffffffffffffffffffffffffffffffffffff909216945090829081106114c1576114c16144b2565b600091825260208083209091015473ffffffffffffffffffffffffffffffffffffffff8681168452600c8352604080852080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00001690559116808452600b90925290912080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016905591508061155781614557565b91505061145d565b5061156c600d6000613b9d565b611578600e6000613b9d565b604080516080810182526000808252602082018190529181018290526060810182905290805b8c518110156119e157600c60008e83815181106115bd576115bd6144b2565b60209081029190910181015173ffffffffffffffffffffffffffffffffffffffff1682528101919091526040016000205460ff1615611628576040517f77cea0fa00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168d8281518110611652576116526144b2565b602002602001015173ffffffffffffffffffffffffffffffffffffffff16036116a7576040517f815e1d6400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60405180604001604052806001151581526020018260ff16815250600c60008f84815181106116d8576116d86144b2565b60209081029190910181015173ffffffffffffffffffffffffffffffffffffffff1682528181019290925260400160002082518154939092015160ff16610100027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff921515929092167fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000909316929092171790558b518c9082908110611780576117806144b2565b60200260200101519150600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16036117f0576040517f58a70a0a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff82166000908152600b60209081526040918290208251608081018452905460ff80821615801584526101008304909116938301939093526bffffffffffffffffffffffff6201000082048116948301949094526e010000000000000000000000000000900490921660608301529093506118ab576040517f6a7281ad00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001835260ff80821660208086019182526bffffffffffffffffffffffff808b166060880190815273ffffffffffffffffffffffffffffffffffffffff87166000908152600b909352604092839020885181549551948a0151925184166e010000000000000000000000000000027fffffffffffff000000000000000000000000ffffffffffffffffffffffffffff939094166201000002929092167fffffffffffff000000000000000000000000000000000000000000000000ffff94909616610100027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff921515929092167fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000090951694909417179190911692909217919091179055806119d981614557565b91505061159e565b50508a516119f79150600d9060208d0190613bbb565b508851611a0b90600e9060208c0190613bbb565b506040518061012001604052808960ff168152602001886000015163ffffffff168152602001886020015163ffffffff168152602001886060015162ffffff168152602001886080015161ffff1681526020016012600001600e9054906101000a900460ff16151581526020016012600001600f9054906101000a900460ff1615158152602001856bffffffffffffffffffffffff168152602001600063ffffffff16815250601260008201518160000160006101000a81548160ff021916908360ff16021790555060208201518160000160016101000a81548163ffffffff021916908363ffffffff16021790555060408201518160000160056101000a81548163ffffffff021916908363ffffffff16021790555060608201518160000160096101000a81548162ffffff021916908362ffffff160217905550608082015181600001600c6101000a81548161ffff021916908361ffff16021790555060a082015181600001600e6101000a81548160ff02191690831515021790555060c082015181600001600f6101000a81548160ff02191690831515021790555060e08201518160000160106101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff16021790555061010082015181600001601c6101000a81548163ffffffff021916908363ffffffff1602179055509050506040518061018001604052808860a001516bffffffffffffffffffffffff16815260200188610180015173ffffffffffffffffffffffffffffffffffffffff168152602001601360010160009054906101000a90046bffffffffffffffffffffffff166bffffffffffffffffffffffff168152602001886040015163ffffffff1681526020018860c0015163ffffffff168152602001601360010160149054906101000a900463ffffffff1663ffffffff168152602001601360010160189054906101000a900463ffffffff1663ffffffff1681526020016013600101601c9054906101000a900463ffffffff1663ffffffff1681526020018860e0015163ffffffff16815260200188610100015163ffffffff16815260200188610120015163ffffffff168152602001886101c0015173ffffffffffffffffffffffffffffffffffffffff16815250601360008201518160000160006101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff160217905550602082015181600001600c6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060408201518160010160006101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff160217905550606082015181600101600c6101000a81548163ffffffff021916908363ffffffff16021790555060808201518160010160106101000a81548163ffffffff021916908363ffffffff16021790555060a08201518160010160146101000a81548163ffffffff021916908363ffffffff16021790555060c08201518160010160186101000a81548163ffffffff021916908363ffffffff16021790555060e082015181600101601c6101000a81548163ffffffff021916908363ffffffff1602179055506101008201518160020160006101000a81548163ffffffff021916908363ffffffff1602179055506101208201518160020160046101000a81548163ffffffff021916908363ffffffff1602179055506101408201518160020160086101000a81548163ffffffff021916908363ffffffff16021790555061016082015181600201600c6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555090505086610140015160168190555086610160015160178190555060006013600101601c9054906101000a900463ffffffff169050611fcd612eb1565b601480547bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167c010000000000000000000000000000000000000000000000000000000063ffffffff93841602178082556001926018916120489185917801000000000000000000000000000000000000000000000000900416614675565b92506101000a81548163ffffffff021916908363ffffffff16021790555060008860405160200161207991906146e3565b604080518083037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe00181529190526014549091506120e290469030907801000000000000000000000000000000000000000000000000900463ffffffff168f8f8f878f8f612f66565b60115560005b6120f26009613010565b8110156121225761210f61210760098361301a565b600990613026565b508061211a81614557565b9150506120e8565b5060005b896101a0015151811015612179576121668a6101a00151828151811061214e5761214e6144b2565b6020026020010151600961304890919063ffffffff16565b508061217181614557565b915050612126565b507f1591690b8638f5fb2dbec82ac741805ac5da8b45dc5263f4875b0496fdce4e0582601154601360010160189054906101000a900463ffffffff168f8f8f878f8f6040516121d099989796959493929190614847565b60405180910390a1505050505050505050505050565b612207868686868060200190518101906122009190614978565b86866112ea565b505050505050565b612217612c26565b6122208161306a565b50565b321561225b576040517fb60ac5db00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b565b60125460009081906f01000000000000000000000000000000900460ff16156122b2576040517f37ed32e800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b601280547fffffffffffffffffffffffffffffffff00ffffffffffffffffffffffffffffff166f010000000000000000000000000000001790556040517f4585e33b000000000000000000000000000000000000000000000000000000009061231f908590602401613cc8565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff000000000000000000000000000000000000000000000000000000009094169390931790925290517f79188d1600000000000000000000000000000000000000000000000000000000815290935073ffffffffffffffffffffffffffffffffffffffff8616906379188d16906123f29087908790600401614ad2565b60408051808303816000875af1158015612410573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906124349190614aeb565b601280547fffffffffffffffffffffffffffffffff00ffffffffffffffffffffffffffffff16905590969095509350505050565b6000878760405161247a929190614b1e565b604051908190038120612491918b90602001614b2e565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081840301815282825280516020918201208383019092526000808452908301819052909250906000805b88811015612668576001858783602081106124fd576124fd6144b2565b61250a91901a601b6144e1565b8c8c8581811061251c5761251c6144b2565b905060200201358b8b86818110612535576125356144b2565b9050602002013560405160008152602001604052604051612572949392919093845260ff9290921660208401526040830152606082015260800190565b6020604051602081039080840390855afa158015612594573d6000803e3d6000fd5b5050604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081015173ffffffffffffffffffffffffffffffffffffffff81166000908152600c602090815290849020838501909452925460ff8082161515808552610100909204169383019390935290955093509050612642576040517f0f4c073700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b826020015160080260ff166001901b84019350808061266090614557565b9150506124e0565b50827e010101010101010101010101010101010101010101010101010101010101018416146126c3576040517fc103be2e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b505050505050505050505050565b61270a6040518060c001604052806000815260200160008152602001606081526020016060815260200160608152602001606081525090565b600061271883850185614c1f565b604081015151606082015151919250908114158061273b57508082608001515114155b8061274b5750808260a001515114155b15612782576040517fb55ac75400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5090505b92915050565b6000818160045b600f811015612819577fff0000000000000000000000000000000000000000000000000000000000000082168382602081106127d1576127d16144b2565b1a60f81b7effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff19161461280757506000949350505050565b8061281181614557565b915050612793565b5081600f1a600181111561282f5761282f6144fa565b949350505050565b60008061284988878b6000015161315f565b90506000806128648b8a63ffffffff16858a8a60018b6131eb565b9092509050612873818361447a565b9b9a5050505050505050505050565b60008080808460800151600181111561289d5761289d6144fa565b036128c1576128ad868686613644565b6128bc5760009250905061079f565b612938565b6001846080015160018111156128d9576128d96144fa565b036129065760006128eb878787613738565b9250905080612900575060009250905061079f565b50612938565b6040517ff2b2d41200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b612940612eb1565b84516040015163ffffffff161161299457857fc3237c8807c467c1b39b8d0395eff077313e691bf0a7388106792564ebfd5636866040516129819190613cc8565b60405180910390a260009250905061079f565b83604001516bffffffffffffffffffffffff16846000015160a001516bffffffffffffffffffffffff1610156129f457857f377c8b0c126ae5248d27aca1c76fac4608aff85673ee3caf09747e1044549e02866040516129819190613cc8565b6001969095509350505050565b600081608001516001811115612a1957612a196144fa565b03612a8b57612a26612eb1565b6000838152600460205260409020600101805463ffffffff929092167801000000000000000000000000000000000000000000000000027fffffffff00000000ffffffffffffffffffffffffffffffffffffffffffffffff9092169190911790555050565b600181608001516001811115612aa357612aa36144fa565b03612b0f5760e08101805160009081526008602052604080822080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055915191517fa4a4e334c0e330143f9437484fe516c13bc560b86b5b0daf58e7084aaac228f29190a25b5050565b6000612b2084848461315f565b90508085101561282f5750929392505050565b600080612b4e888760a001518860c0015188888860016131eb565b90925090506000612b5f828461447a565b600089815260046020526040902060010180549192508291600c90612ba39084906c0100000000000000000000000090046bffffffffffffffffffffffff16614d0c565b82546101009290920a6bffffffffffffffffffffffff81810219909316918316021790915560008a815260046020526040812060010180548594509092612bec9185911661447a565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff16021790555050965096945050505050565b60005473ffffffffffffffffffffffffffffffffffffffff16331461225b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e657200000000000000000000604482015260640161039e565b73ffffffffffffffffffffffffffffffffffffffff83166000908152600b602090815260408083208151608081018352905460ff80821615801584526101008304909116948301949094526bffffffffffffffffffffffff6201000082048116938301939093526e0100000000000000000000000000009004909116606082015290612ea3576000816060015185612d3f9190614d0c565b90506000612d4d8583614d31565b90508083604001818151612d61919061447a565b6bffffffffffffffffffffffff16905250612d7c8582614d5c565b83606001818151612d8d919061447a565b6bffffffffffffffffffffffff90811690915273ffffffffffffffffffffffffffffffffffffffff89166000908152600b602090815260409182902087518154928901519389015160608a015186166e010000000000000000000000000000027fffffffffffff000000000000000000000000ffffffffffffffffffffffffffff919096166201000002167fffffffffffff000000000000000000000000000000000000000000000000ffff60ff95909516610100027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff921515929092167fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000909416939093171792909216179190911790555050505b6040015190505b9392505050565b600060017f00000000000000000000000000000000000000000000000000000000000000006002811115612ee757612ee76144fa565b03612f6157606473ffffffffffffffffffffffffffffffffffffffff1663a3b1b31d6040518163ffffffff1660e01b8152600401602060405180830381865afa158015612f38573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612f5c9190614d90565b905090565b504390565b6000808a8a8a8a8a8a8a8a8a604051602001612f8a99989796959493929190614da9565b604080518083037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe001815291905280516020909101207dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff167e01000000000000000000000000000000000000000000000000000000000000179b9a5050505050505050505050565b6000612786825490565b6000612eaa83836138d0565b6000612eaa8373ffffffffffffffffffffffffffffffffffffffff84166138fa565b6000612eaa8373ffffffffffffffffffffffffffffffffffffffff84166139f4565b3373ffffffffffffffffffffffffffffffffffffffff8216036130e9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c66000000000000000000604482015260640161039e565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b60008080856001811115613175576131756144fa565b03613184575062015f906131a3565b6001856001811115613198576131986144fa565b0361290657506201adb05b6131b463ffffffff8516601461458f565b6131bf8460016144e1565b6131ce9060ff16611d4c61458f565b6131d8908361449f565b6131e2919061449f565b95945050505050565b6000806000896080015161ffff1687613204919061458f565b90508380156132125750803a105b1561321a57503a5b600060027f00000000000000000000000000000000000000000000000000000000000000006002811115613250576132506144fa565b036133af5760408051600081526020810190915285156132ae57600036604051806080016040528060488152602001614fdb6048913960405160200161329893929190614e3e565b6040516020818303038152906040529050613316565b6015546132ca90640100000000900463ffffffff166004614e65565b63ffffffff1667ffffffffffffffff8111156132e8576132e8613ef5565b6040519080825280601f01601f191660200182016040528015613312576020820181803683370190505b5090505b6040517f49948e0e00000000000000000000000000000000000000000000000000000000815273420000000000000000000000000000000000000f906349948e0e90613366908490600401613cc8565b602060405180830381865afa158015613383573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906133a79190614d90565b915050613509565b60017f000000000000000000000000000000000000000000000000000000000000000060028111156133e3576133e36144fa565b0361350957841561346557606c73ffffffffffffffffffffffffffffffffffffffff1663c6f7de0e6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561343a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061345e9190614d90565b9050613509565b6000606c73ffffffffffffffffffffffffffffffffffffffff166341b247a86040518163ffffffff1660e01b815260040160c060405180830381865afa1580156134b3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906134d79190614e88565b50506015549294506134fa93505050640100000000900463ffffffff168261458f565b61350590601061458f565b9150505b8461352557808b6080015161ffff16613522919061458f565b90505b61353361ffff8716826145fb565b9050600087826135438c8e61449f565b61354d908661458f565b613557919061449f565b61356990670de0b6b3a764000061458f565b61357391906145fb565b905060008c6040015163ffffffff1664e8d4a51000613592919061458f565b898e6020015163ffffffff16858f886135ab919061458f565b6135b5919061449f565b6135c390633b9aca0061458f565b6135cd919061458f565b6135d791906145fb565b6135e1919061449f565b90506b033b2e3c9fd0803ce80000006135fa828461449f565b1115613632576040517f2ad7547a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b909c909b509950505050505050505050565b6000808380602001905181019061365b9190614ed2565b835160c00151815191925063ffffffff908116911610156136b857847f405288ea7be309e16cfdf481367f90a413e1d4634fcdaf8966546db9b93012e8856040516136a69190613cc8565b60405180910390a26000915050612eaa565b6020810151158015906136df5750602081015181516136dc9063ffffffff16613a43565b14155b806136f857506136ed612eb1565b815163ffffffff1610155b1561372d57847f6aa7f60c176da7af894b384daea2249497448137f5943c1237ada8bc92bdc301856040516136a69190613cc8565b506001949350505050565b6000806000848060200190518101906137519190614f2a565b90506000868260000151836020015184604001516040516020016137b394939291909384526020840192909252604083015260e01b7fffffffff0000000000000000000000000000000000000000000000000000000016606082015260640190565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152919052805160209091012060808301519091501580159061381557508160800151613812836060015163ffffffff16613a43565b14155b806138315750613823612eb1565b826060015163ffffffff1610155b1561387b57867f6aa7f60c176da7af894b384daea2249497448137f5943c1237ada8bc92bdc301876040516138669190613cc8565b60405180910390a260009350915061079f9050565b60008181526008602052604090205460ff16156138c257867f405288ea7be309e16cfdf481367f90a413e1d4634fcdaf8966546db9b93012e8876040516138669190613cc8565b600197909650945050505050565b60008260000182815481106138e7576138e76144b2565b9060005260206000200154905092915050565b600081815260018301602052604081205480156139e357600061391e600183614544565b855490915060009061393290600190614544565b9050818114613997576000866000018281548110613952576139526144b2565b9060005260206000200154905080876000018481548110613975576139756144b2565b6000918252602080832090910192909255918252600188019052604090208390555b85548690806139a8576139a8614fab565b600190038181906000526020600020016000905590558560010160008681526020019081526020016000206000905560019350505050612786565b6000915050612786565b5092915050565b6000818152600183016020526040812054613a3b57508154600181810184556000848152602080822090930184905584548482528286019093526040902091909155612786565b506000612786565b600060017f00000000000000000000000000000000000000000000000000000000000000006002811115613a7957613a796144fa565b03613b93576000606473ffffffffffffffffffffffffffffffffffffffff1663a3b1b31d6040518163ffffffff1660e01b8152600401602060405180830381865afa158015613acc573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613af09190614d90565b90508083101580613b0b5750610100613b098483614544565b115b15613b195750600092915050565b6040517f2b407a8200000000000000000000000000000000000000000000000000000000815260048101849052606490632b407a8290602401602060405180830381865afa158015613b6f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612eaa9190614d90565b504090565b919050565b50805460008255906000526020600020908101906122209190613c45565b828054828255906000526020600020908101928215613c35579160200282015b82811115613c3557825182547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff909116178255602090920191600190910190613bdb565b50613c41929150613c45565b5090565b5b80821115613c415760008155600101613c46565b60005b83811015613c75578181015183820152602001613c5d565b50506000910152565b60008151808452613c96816020860160208601613c5a565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b602081526000612eaa6020830184613c7e565b73ffffffffffffffffffffffffffffffffffffffff8116811461222057600080fd5b8035613b9881613cdb565b60008083601f840112613d1a57600080fd5b50813567ffffffffffffffff811115613d3257600080fd5b602083019150836020828501011115613d4a57600080fd5b9250929050565b60008060008060608587031215613d6757600080fd5b8435613d7281613cdb565b935060208501359250604085013567ffffffffffffffff811115613d9557600080fd5b613da187828801613d08565b95989497509550505050565b600080600060408486031215613dc257600080fd5b83359250602084013567ffffffffffffffff811115613de057600080fd5b613dec86828701613d08565b9497909650939450505050565b60008083601f840112613e0b57600080fd5b50813567ffffffffffffffff811115613e2357600080fd5b6020830191508360208260051b8501011115613d4a57600080fd5b60008060008060008060008060e0898b031215613e5a57600080fd5b606089018a811115613e6b57600080fd5b8998503567ffffffffffffffff80821115613e8557600080fd5b613e918c838d01613d08565b909950975060808b0135915080821115613eaa57600080fd5b613eb68c838d01613df9565b909750955060a08b0135915080821115613ecf57600080fd5b50613edc8b828c01613df9565b999c989b50969995989497949560c00135949350505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6040516101e0810167ffffffffffffffff81118282101715613f4857613f48613ef5565b60405290565b60405160c0810167ffffffffffffffff81118282101715613f4857613f48613ef5565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715613fb857613fb8613ef5565b604052919050565b600067ffffffffffffffff821115613fda57613fda613ef5565b5060051b60200190565b600082601f830112613ff557600080fd5b8135602061400a61400583613fc0565b613f71565b82815260059290921b8401810191818101908684111561402957600080fd5b8286015b8481101561404d57803561404081613cdb565b835291830191830161402d565b509695505050505050565b803560ff81168114613b9857600080fd5b63ffffffff8116811461222057600080fd5b8035613b9881614069565b62ffffff8116811461222057600080fd5b8035613b9881614086565b61ffff8116811461222057600080fd5b8035613b98816140a2565b6bffffffffffffffffffffffff8116811461222057600080fd5b8035613b98816140bd565b60006101e082840312156140f557600080fd5b6140fd613f24565b90506141088261407b565b81526141166020830161407b565b60208201526141276040830161407b565b604082015261413860608301614097565b6060820152614149608083016140b2565b608082015261415a60a083016140d7565b60a082015261416b60c0830161407b565b60c082015261417c60e0830161407b565b60e082015261010061418f81840161407b565b908201526101206141a183820161407b565b90820152610140828101359082015261016080830135908201526101806141c9818401613cfd565b908201526101a08281013567ffffffffffffffff8111156141e957600080fd5b6141f585828601613fe4565b8284015250506101c0614209818401613cfd565b9082015292915050565b803567ffffffffffffffff81168114613b9857600080fd5b600082601f83011261423c57600080fd5b813567ffffffffffffffff81111561425657614256613ef5565b61428760207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f84011601613f71565b81815284602083860101111561429c57600080fd5b816020850160208301376000918101602001919091529392505050565b60008060008060008060c087890312156142d257600080fd5b863567ffffffffffffffff808211156142ea57600080fd5b6142f68a838b01613fe4565b9750602089013591508082111561430c57600080fd5b6143188a838b01613fe4565b965061432660408a01614058565b9550606089013591508082111561433c57600080fd5b6143488a838b016140e2565b945061435660808a01614213565b935060a089013591508082111561436c57600080fd5b5061437989828a0161422b565b9150509295509295509295565b60008060008060008060c0878903121561439f57600080fd5b863567ffffffffffffffff808211156143b757600080fd5b6143c38a838b01613fe4565b975060208901359150808211156143d957600080fd5b6143e58a838b01613fe4565b96506143f360408a01614058565b9550606089013591508082111561440957600080fd5b6143488a838b0161422b565b60006020828403121561442757600080fd5b8135612eaa81613cdb565b60006020828403121561444457600080fd5b5035919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b6bffffffffffffffffffffffff8181168382160190808211156139ed576139ed61444b565b808201808211156127865761278661444b565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60ff81811683821601908111156127865761278661444b565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b61ffff8181168382160190808211156139ed576139ed61444b565b818103818111156127865761278661444b565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82036145885761458861444b565b5060010190565b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff04831182151516156145c7576145c761444b565b500290565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b60008261460a5761460a6145cc565b500490565b6bffffffffffffffffffffffff851681528360208201528260408201526080606082015260006146426080830184613c7e565b9695505050505050565b600060ff821660ff84168160ff048111821515161561466d5761466d61444b565b029392505050565b63ffffffff8181168382160190808211156139ed576139ed61444b565b600081518084526020808501945080840160005b838110156146d857815173ffffffffffffffffffffffffffffffffffffffff16875295820195908201906001016146a6565b509495945050505050565b602081526146fa60208201835163ffffffff169052565b60006020830151614713604084018263ffffffff169052565b50604083015163ffffffff8116606084015250606083015162ffffff8116608084015250608083015161ffff811660a08401525060a08301516bffffffffffffffffffffffff811660c08401525060c083015163ffffffff811660e08401525060e083015161010061478c8185018363ffffffff169052565b84015190506101206147a58482018363ffffffff169052565b84015190506101406147be8482018363ffffffff169052565b840151610160848101919091528401516101808085019190915284015190506101a06148018185018373ffffffffffffffffffffffffffffffffffffffff169052565b808501519150506101e06101c08181860152614821610200860184614692565b95015173ffffffffffffffffffffffffffffffffffffffff169301929092525090919050565b600061012063ffffffff808d1684528b6020850152808b166040850152508060608401526148778184018a614692565b9050828103608084015261488b8189614692565b905060ff871660a084015282810360c08401526148a88187613c7e565b905067ffffffffffffffff851660e08401528281036101008401526148cd8185613c7e565b9c9b505050505050505050505050565b8051613b9881614069565b8051613b9881614086565b8051613b98816140a2565b8051613b98816140bd565b8051613b9881613cdb565b600082601f83011261492557600080fd5b8151602061493561400583613fc0565b82815260059290921b8401810191818101908684111561495457600080fd5b8286015b8481101561404d57805161496b81613cdb565b8352918301918301614958565b60006020828403121561498a57600080fd5b815167ffffffffffffffff808211156149a257600080fd5b908301906101e082860312156149b757600080fd5b6149bf613f24565b6149c8836148dd565b81526149d6602084016148dd565b60208201526149e7604084016148dd565b60408201526149f8606084016148e8565b6060820152614a09608084016148f3565b6080820152614a1a60a084016148fe565b60a0820152614a2b60c084016148dd565b60c0820152614a3c60e084016148dd565b60e0820152610100614a4f8185016148dd565b90820152610120614a618482016148dd565b9082015261014083810151908201526101608084015190820152610180614a89818501614909565b908201526101a08381015183811115614aa157600080fd5b614aad88828701614914565b8284015250506101c09150614ac3828401614909565b91810191909152949350505050565b82815260406020820152600061282f6040830184613c7e565b60008060408385031215614afe57600080fd5b82518015158114614b0e57600080fd5b6020939093015192949293505050565b8183823760009101908152919050565b8281526080810160608360208401379392505050565b600082601f830112614b5557600080fd5b81356020614b6561400583613fc0565b82815260059290921b84018101918181019086841115614b8457600080fd5b8286015b8481101561404d5780358352918301918301614b88565b600082601f830112614bb057600080fd5b81356020614bc061400583613fc0565b82815260059290921b84018101918181019086841115614bdf57600080fd5b8286015b8481101561404d57803567ffffffffffffffff811115614c035760008081fd5b614c118986838b010161422b565b845250918301918301614be3565b600060208284031215614c3157600080fd5b813567ffffffffffffffff80821115614c4957600080fd5b9083019060c08286031215614c5d57600080fd5b614c65613f4e565b8235815260208301356020820152604083013582811115614c8557600080fd5b614c9187828601614b44565b604083015250606083013582811115614ca957600080fd5b614cb587828601614b44565b606083015250608083013582811115614ccd57600080fd5b614cd987828601614b9f565b60808301525060a083013582811115614cf157600080fd5b614cfd87828601614b9f565b60a08301525095945050505050565b6bffffffffffffffffffffffff8281168282160390808211156139ed576139ed61444b565b60006bffffffffffffffffffffffff80841680614d5057614d506145cc565b92169190910492915050565b60006bffffffffffffffffffffffff80831681851681830481118215151615614d8757614d8761444b565b02949350505050565b600060208284031215614da257600080fd5b5051919050565b60006101208b835273ffffffffffffffffffffffffffffffffffffffff8b16602084015267ffffffffffffffff808b166040850152816060850152614df08285018b614692565b91508382036080850152614e04828a614692565b915060ff881660a085015283820360c0850152614e218288613c7e565b90861660e085015283810361010085015290506148cd8185613c7e565b828482376000838201600081528351614e5b818360208801613c5a565b0195945050505050565b600063ffffffff80831681851681830481118215151615614d8757614d8761444b565b60008060008060008060c08789031215614ea157600080fd5b865195506020870151945060408701519350606087015192506080870151915060a087015190509295509295509295565b600060408284031215614ee457600080fd5b6040516040810181811067ffffffffffffffff82111715614f0757614f07613ef5565b6040528251614f1581614069565b81526020928301519281019290925250919050565b600060a08284031215614f3c57600080fd5b60405160a0810181811067ffffffffffffffff82111715614f5f57614f5f613ef5565b806040525082518152602083015160208201526040830151614f8081614069565b60408201526060830151614f9381614069565b60608201526080928301519281019290925250919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fdfe307866666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666a164736f6c6343000810000a", } var KeeperRegistryABI = KeeperRegistryMetaData.ABI diff --git a/core/gethwrappers/generated/streams_lookup_upkeep_wrapper/streams_lookup_upkeep_wrapper.go b/core/gethwrappers/generated/streams_lookup_upkeep_wrapper/streams_lookup_upkeep_wrapper.go index e9d48584339..0ef24e516ec 100644 --- a/core/gethwrappers/generated/streams_lookup_upkeep_wrapper/streams_lookup_upkeep_wrapper.go +++ b/core/gethwrappers/generated/streams_lookup_upkeep_wrapper/streams_lookup_upkeep_wrapper.go @@ -31,8 +31,8 @@ var ( ) var StreamsLookupUpkeepMetaData = &bind.MetaData{ - ABI: "[{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_testRange\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_interval\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"_useArbBlock\",\"type\":\"bool\"},{\"internalType\":\"bool\",\"name\":\"_staging\",\"type\":\"bool\"},{\"internalType\":\"bool\",\"name\":\"_verify\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"feedParamKey\",\"type\":\"string\"},{\"internalType\":\"string[]\",\"name\":\"feeds\",\"type\":\"string[]\"},{\"internalType\":\"string\",\"name\":\"timeParamKey\",\"type\":\"string\"},{\"internalType\":\"uint256\",\"name\":\"time\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"extraData\",\"type\":\"bytes\"}],\"name\":\"StreamsLookup\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"blockNumber\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"v0\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"v1\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"verifiedV0\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"verifiedV1\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"ed\",\"type\":\"bytes\"}],\"name\":\"MercuryPerformEvent\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"callbackReturnBool\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes[]\",\"name\":\"values\",\"type\":\"bytes[]\"},{\"internalType\":\"bytes\",\"name\":\"extraData\",\"type\":\"bytes\"}],\"name\":\"checkCallback\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"checkUpkeep\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"counter\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"eligible\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"feedParamKey\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"feeds\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"initialBlock\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"interval\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"performData\",\"type\":\"bytes\"}],\"name\":\"performUpkeep\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"previousPerformBlock\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"reset\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bool\",\"name\":\"value\",\"type\":\"bool\"}],\"name\":\"setCallbackReturnBool\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"string[]\",\"name\":\"_feeds\",\"type\":\"string[]\"}],\"name\":\"setFeeds\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"_feedParamKey\",\"type\":\"string\"},{\"internalType\":\"string\",\"name\":\"_timeParamKey\",\"type\":\"string\"}],\"name\":\"setParamKeys\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bool\",\"name\":\"value\",\"type\":\"bool\"}],\"name\":\"setShouldRevertCallback\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"shouldRevertCallback\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"staging\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"testRange\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"timeParamKey\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"useArbBlock\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"verify\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"}]", - Bin: "0x60a06040523480156200001157600080fd5b5060405162001b9c38038062001b9c833981016040819052620000349162000232565b60008581556001859055600281905560038190556004558215156080526040805180820190915260098152680cccacac892c890caf60bb1b602082015260069062000080908262000335565b5060408051808201909152600b81526a313637b1b5a73ab6b132b960a91b6020820152600790620000b2908262000335565b50604051806040016040528060405180608001604052806042815260200162001b1860429139815260200160405180608001604052806042815260200162001b5a6042913990526200010990600590600262000145565b506008805463ff000000199215156101000261ff00199415159490941661ffff1990911617929092171663010000001790555062000401915050565b82805482825590600052602060002090810192821562000190579160200282015b828111156200019057825182906200017f908262000335565b509160200191906001019062000166565b506200019e929150620001a2565b5090565b808211156200019e576000620001b98282620001c3565b50600101620001a2565b508054620001d190620002a6565b6000825580601f10620001e2575050565b601f01602090049060005260206000209081019062000202919062000205565b50565b5b808211156200019e576000815560010162000206565b805180151581146200022d57600080fd5b919050565b600080600080600060a086880312156200024b57600080fd5b855194506020860151935062000264604087016200021c565b925062000274606087016200021c565b915062000284608087016200021c565b90509295509295909350565b634e487b7160e01b600052604160045260246000fd5b600181811c90821680620002bb57607f821691505b602082108103620002dc57634e487b7160e01b600052602260045260246000fd5b50919050565b601f8211156200033057600081815260208120601f850160051c810160208610156200030b5750805b601f850160051c820191505b818110156200032c5782815560010162000317565b5050505b505050565b81516001600160401b0381111562000351576200035162000290565b6200036981620003628454620002a6565b84620002e2565b602080601f831160018114620003a15760008415620003885750858301515b600019600386901b1c1916600185901b1785556200032c565b600085815260208120601f198616915b82811015620003d257888601518255948401946001909101908401620003b1565b5085821015620003f15787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b6080516116e662000432600039600081816103070152818161039001528181610a560152610bbe01526116e66000f3fe608060405234801561001057600080fd5b50600436106101825760003560e01c80636e04ff0d116100d8578063947a36fb1161008c578063d826f88f11610066578063d826f88f1461035e578063d832d92f14610372578063fc735e991461037a57600080fd5b8063947a36fb14610345578063afb28d1f1461034e578063c98f10b01461035657600080fd5b806386b728e2116100bd57806386b728e21461030257806386e330af14610329578063917d895f1461033c57600080fd5b80636e04ff0d146102dc5780638340507c146102ef57600080fd5b80634a5479f31161013a5780635b48391a116101145780635b48391a1461028357806361bc221a146102ca5780636250a13a146102d357600080fd5b80634a5479f3146101fc5780634b56a42e1461021c5780634bdb38621461023d57600080fd5b80631d1970b71161016b5780631d1970b7146101c35780632cb15864146101d05780634585e33b146101e757600080fd5b806302be021f14610187578063102d538b146101af575b600080fd5b60085461019a9062010000900460ff1681565b60405190151581526020015b60405180910390f35b60085461019a906301000000900460ff1681565b60085461019a9060ff1681565b6101d960035481565b6040519081526020016101a6565b6101fa6101f5366004610d52565b61038c565b005b61020f61020a366004610dc4565b610873565b6040516101a69190610e4b565b61022f61022a366004610fa3565b61091f565b6040516101a6929190611077565b6101fa61024b36600461109a565b6008805491151562010000027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ffff909216919091179055565b6101fa61029136600461109a565b600880549115156301000000027fffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ffffff909216919091179055565b6101d960045481565b6101d960005481565b61022f6102ea366004610d52565b6109fa565b6101fa6102fd3660046110bc565b610b59565b61019a7f000000000000000000000000000000000000000000000000000000000000000081565b6101fa610337366004611109565b610b77565b6101d960025481565b6101d960015481565b61020f610b8e565b61020f610b9b565b6101fa600060028190556003819055600455565b61019a610ba8565b60085461019a90610100900460ff1681565b60007f00000000000000000000000000000000000000000000000000000000000000001561042b57606473ffffffffffffffffffffffffffffffffffffffff1663a3b1b31d6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610400573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061042491906111ba565b905061042e565b50435b60035460000361043e5760038190555b60008061044d84860186610fa3565b60028590556004549193509150610465906001611202565b600455604080516020808201835260008083528351918201909352918252600854909190610100900460ff16156107df5760085460ff1615610642577360448b880c9f3b501af3f343da9284148bd7d77c73ffffffffffffffffffffffffffffffffffffffff16638e760afe856000815181106104e4576104e461121b565b60200260200101516040518263ffffffff1660e01b81526004016105089190610e4b565b6000604051808303816000875af1158015610527573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016820160405261056d919081019061124a565b91507360448b880c9f3b501af3f343da9284148bd7d77c73ffffffffffffffffffffffffffffffffffffffff16638e760afe856001815181106105b2576105b261121b565b60200260200101516040518263ffffffff1660e01b81526004016105d69190610e4b565b6000604051808303816000875af11580156105f5573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016820160405261063b919081019061124a565b90506107df565b7309dff56a4ff44e0f4436260a04f5cfa65636a48173ffffffffffffffffffffffffffffffffffffffff16638e760afe856000815181106106855761068561121b565b60200260200101516040518263ffffffff1660e01b81526004016106a99190610e4b565b6000604051808303816000875af11580156106c8573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016820160405261070e919081019061124a565b91507309dff56a4ff44e0f4436260a04f5cfa65636a48173ffffffffffffffffffffffffffffffffffffffff16638e760afe856001815181106107535761075361121b565b60200260200101516040518263ffffffff1660e01b81526004016107779190610e4b565b6000604051808303816000875af1158015610796573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01682016040526107dc919081019061124a565b90505b843373ffffffffffffffffffffffffffffffffffffffff167f1c85d6186f024e964616014c8247533455ec5129a5095711202292f8a7ea1d548660008151811061082b5761082b61121b565b6020026020010151876001815181106108465761084661121b565b60200260200101518686896040516108629594939291906112c1565b60405180910390a350505050505050565b6005818154811061088357600080fd5b90600052602060002001600091509050805461089e9061132e565b80601f01602080910402602001604051908101604052809291908181526020018280546108ca9061132e565b80156109175780601f106108ec57610100808354040283529160200191610917565b820191906000526020600020905b8154815290600101906020018083116108fa57829003601f168201915b505050505081565b60085460009060609062010000900460ff161561099d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601c60248201527f73686f756c6452657665727443616c6c6261636b20697320747275650000000060448201526064015b60405180910390fd5b600084846040516020016109b2929190611381565b604080518083037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe00181529190526008546301000000900460ff1693509150505b9250929050565b60006060610a06610ba8565b610a52576000848481818080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152509597509195506109f3945050505050565b60007f000000000000000000000000000000000000000000000000000000000000000015610af157606473ffffffffffffffffffffffffffffffffffffffff1663a3b1b31d6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610ac6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610aea91906111ba565b9050610af4565b50435b604080516c6400000000000000000000000060208201528151601481830301815260348201928390527ff055e4a200000000000000000000000000000000000000000000000000000000909252610994916006916005916007918691906038016114a7565b6006610b6583826115ac565b506007610b7282826115ac565b505050565b8051610b8a906005906020840190610c8d565b5050565b6006805461089e9061132e565b6007805461089e9061132e565b6000600354600003610bba5750600190565b60007f000000000000000000000000000000000000000000000000000000000000000015610c5957606473ffffffffffffffffffffffffffffffffffffffff1663a3b1b31d6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610c2e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c5291906111ba565b9050610c5c565b50435b600054600354610c6c90836116c6565b108015610c875750600154600254610c8490836116c6565b10155b91505090565b828054828255906000526020600020908101928215610cd3579160200282015b82811115610cd35782518290610cc390826115ac565b5091602001919060010190610cad565b50610cdf929150610ce3565b5090565b80821115610cdf576000610cf78282610d00565b50600101610ce3565b508054610d0c9061132e565b6000825580601f10610d1c575050565b601f016020900490600052602060002090810190610d3a9190610d3d565b50565b5b80821115610cdf5760008155600101610d3e565b60008060208385031215610d6557600080fd5b823567ffffffffffffffff80821115610d7d57600080fd5b818501915085601f830112610d9157600080fd5b813581811115610da057600080fd5b866020828501011115610db257600080fd5b60209290920196919550909350505050565b600060208284031215610dd657600080fd5b5035919050565b60005b83811015610df8578181015183820152602001610de0565b50506000910152565b60008151808452610e19816020860160208601610ddd565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b602081526000610e5e6020830184610e01565b9392505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715610edb57610edb610e65565b604052919050565b600067ffffffffffffffff821115610efd57610efd610e65565b5060051b60200190565b600067ffffffffffffffff821115610f2157610f21610e65565b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b600082601f830112610f5e57600080fd5b8135610f71610f6c82610f07565b610e94565b818152846020838601011115610f8657600080fd5b816020850160208301376000918101602001919091529392505050565b60008060408385031215610fb657600080fd5b823567ffffffffffffffff80821115610fce57600080fd5b818501915085601f830112610fe257600080fd5b81356020610ff2610f6c83610ee3565b82815260059290921b8401810191818101908984111561101157600080fd5b8286015b848110156110495780358681111561102d5760008081fd5b61103b8c86838b0101610f4d565b845250918301918301611015565b509650508601359250508082111561106057600080fd5b5061106d85828601610f4d565b9150509250929050565b82151581526040602082015260006110926040830184610e01565b949350505050565b6000602082840312156110ac57600080fd5b81358015158114610e5e57600080fd5b600080604083850312156110cf57600080fd5b823567ffffffffffffffff808211156110e757600080fd5b6110f386838701610f4d565b9350602085013591508082111561106057600080fd5b6000602080838503121561111c57600080fd5b823567ffffffffffffffff8082111561113457600080fd5b818501915085601f83011261114857600080fd5b8135611156610f6c82610ee3565b81815260059190911b8301840190848101908883111561117557600080fd5b8585015b838110156111ad578035858111156111915760008081fd5b61119f8b89838a0101610f4d565b845250918601918601611179565b5098975050505050505050565b6000602082840312156111cc57600080fd5b5051919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b80820180821115611215576112156111d3565b92915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60006020828403121561125c57600080fd5b815167ffffffffffffffff81111561127357600080fd5b8201601f8101841361128457600080fd5b8051611292610f6c82610f07565b8181528560208385010111156112a757600080fd5b6112b8826020830160208601610ddd565b95945050505050565b60a0815260006112d460a0830188610e01565b82810360208401526112e68188610e01565b905082810360408401526112fa8187610e01565b9050828103606084015261130e8186610e01565b905082810360808401526113228185610e01565b98975050505050505050565b600181811c9082168061134257607f821691505b60208210810361137b577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b50919050565b6000604082016040835280855180835260608501915060608160051b8601019250602080880160005b838110156113f6577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa08887030185526113e4868351610e01565b955093820193908201906001016113aa565b5050858403818701525050506112b88185610e01565b600081546114198161132e565b808552602060018381168015611436576001811461146e5761149c565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff008516838901528284151560051b890101955061149c565b866000528260002060005b858110156114945781548a8201860152908301908401611479565b890184019650505b505050505092915050565b60a0815260006114ba60a083018861140c565b6020838203818501528188548084528284019150828160051b8501018a6000528360002060005b8381101561152c577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe087840301855261151a838361140c565b948601949250600191820191016114e1565b50508681036040880152611540818b61140c565b94505050505084606084015282810360808401526113228185610e01565b601f821115610b7257600081815260208120601f850160051c810160208610156115855750805b601f850160051c820191505b818110156115a457828155600101611591565b505050505050565b815167ffffffffffffffff8111156115c6576115c6610e65565b6115da816115d4845461132e565b8461155e565b602080601f83116001811461162d57600084156115f75750858301515b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600386901b1c1916600185901b1785556115a4565b6000858152602081207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08616915b8281101561167a5788860151825594840194600190910190840161165b565b50858210156116b657878501517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600388901b60f8161c191681555b5050505050600190811b01905550565b81810381811115611215576112156111d356fea164736f6c6343000810000a307834353534343832643535353334343264343135323432343935343532353534643264353434353533353434653435353430303030303030303030303030303030307834323534343332643535353334343264343135323432343935343532353534643264353434353533353434653435353430303030303030303030303030303030", + ABI: "[{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_testRange\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_interval\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"_useArbBlock\",\"type\":\"bool\"},{\"internalType\":\"bool\",\"name\":\"_staging\",\"type\":\"bool\"},{\"internalType\":\"bool\",\"name\":\"_verify\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"feedParamKey\",\"type\":\"string\"},{\"internalType\":\"string[]\",\"name\":\"feeds\",\"type\":\"string[]\"},{\"internalType\":\"string\",\"name\":\"timeParamKey\",\"type\":\"string\"},{\"internalType\":\"uint256\",\"name\":\"time\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"extraData\",\"type\":\"bytes\"}],\"name\":\"StreamsLookup\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"blockNumber\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"v0\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"verifiedV0\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"ed\",\"type\":\"bytes\"}],\"name\":\"MercuryPerformEvent\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"callbackReturnBool\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes[]\",\"name\":\"values\",\"type\":\"bytes[]\"},{\"internalType\":\"bytes\",\"name\":\"extraData\",\"type\":\"bytes\"}],\"name\":\"checkCallback\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"checkUpkeep\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"counter\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"eligible\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"feedParamKey\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"feeds\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"initialBlock\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"interval\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"performData\",\"type\":\"bytes\"}],\"name\":\"performUpkeep\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"previousPerformBlock\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"reset\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bool\",\"name\":\"value\",\"type\":\"bool\"}],\"name\":\"setCallbackReturnBool\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"string[]\",\"name\":\"_feeds\",\"type\":\"string[]\"}],\"name\":\"setFeeds\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"_feedParamKey\",\"type\":\"string\"},{\"internalType\":\"string\",\"name\":\"_timeParamKey\",\"type\":\"string\"}],\"name\":\"setParamKeys\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bool\",\"name\":\"value\",\"type\":\"bool\"}],\"name\":\"setShouldRevertCallback\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"shouldRevertCallback\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"staging\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"testRange\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"timeParamKey\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"useArbBlock\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"verify\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"}]", + Bin: "0x60a06040523480156200001157600080fd5b5060405162001a6a38038062001a6a83398101604081905262000034916200020f565b60008581556001859055600281905560038190556004558215156080526040805180820190915260078152666665656449447360c81b60208201526006906200007e908262000312565b50604080518082019091526009815268074696d657374616d760bc1b6020820152600790620000ae908262000312565b50604051806020016040528060405180608001604052806042815260200162001a28604291399052620000e690600590600162000122565b506008805463ff000000199215156101000261ff00199415159490941661ffff19909116179290921716630100000017905550620003de915050565b8280548282559060005260206000209081019282156200016d579160200282015b828111156200016d57825182906200015c908262000312565b509160200191906001019062000143565b506200017b9291506200017f565b5090565b808211156200017b576000620001968282620001a0565b506001016200017f565b508054620001ae9062000283565b6000825580601f10620001bf575050565b601f016020900490600052602060002090810190620001df9190620001e2565b50565b5b808211156200017b5760008155600101620001e3565b805180151581146200020a57600080fd5b919050565b600080600080600060a086880312156200022857600080fd5b85519450602086015193506200024160408701620001f9565b92506200025160608701620001f9565b91506200026160808701620001f9565b90509295509295909350565b634e487b7160e01b600052604160045260246000fd5b600181811c908216806200029857607f821691505b602082108103620002b957634e487b7160e01b600052602260045260246000fd5b50919050565b601f8211156200030d57600081815260208120601f850160051c81016020861015620002e85750805b601f850160051c820191505b818110156200030957828155600101620002f4565b5050505b505050565b81516001600160401b038111156200032e576200032e6200026d565b62000346816200033f845462000283565b84620002bf565b602080601f8311600181146200037e5760008415620003655750858301515b600019600386901b1c1916600185901b17855562000309565b600085815260208120601f198616915b82811015620003af578886015182559484019460019091019084016200038e565b5085821015620003ce5787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b6080516116196200040f60003960008181610307015281816103900152818161090c0152610a7b01526116196000f3fe608060405234801561001057600080fd5b50600436106101825760003560e01c80636e04ff0d116100d8578063947a36fb1161008c578063d826f88f11610066578063d826f88f1461035e578063d832d92f14610372578063fc735e991461037a57600080fd5b8063947a36fb14610345578063afb28d1f1461034e578063c98f10b01461035657600080fd5b806386b728e2116100bd57806386b728e21461030257806386e330af14610329578063917d895f1461033c57600080fd5b80636e04ff0d146102dc5780638340507c146102ef57600080fd5b80634a5479f31161013a5780635b48391a116101145780635b48391a1461028357806361bc221a146102ca5780636250a13a146102d357600080fd5b80634a5479f3146101fc5780634b56a42e1461021c5780634bdb38621461023d57600080fd5b80631d1970b71161016b5780631d1970b7146101c35780632cb15864146101d05780634585e33b146101e757600080fd5b806302be021f14610187578063102d538b146101af575b600080fd5b60085461019a9062010000900460ff1681565b60405190151581526020015b60405180910390f35b60085461019a906301000000900460ff1681565b60085461019a9060ff1681565b6101d960035481565b6040519081526020016101a6565b6101fa6101f5366004610c0f565b61038c565b005b61020f61020a366004610c81565b6106b9565b6040516101a69190610d08565b61022f61022a366004610e60565b610765565b6040516101a6929190610f34565b6101fa61024b366004610f57565b6008805491151562010000027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ffff909216919091179055565b6101fa610291366004610f57565b600880549115156301000000027fffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ffffff909216919091179055565b6101d960045481565b6101d960005481565b61022f6102ea366004610c0f565b610840565b6101fa6102fd366004610f79565b610a16565b61019a7f000000000000000000000000000000000000000000000000000000000000000081565b6101fa610337366004610fc6565b610a34565b6101d960025481565b6101d960015481565b61020f610a4b565b61020f610a58565b6101fa600060028190556003819055600455565b61019a610a65565b60085461019a90610100900460ff1681565b60007f00000000000000000000000000000000000000000000000000000000000000001561042b57606473ffffffffffffffffffffffffffffffffffffffff1663a3b1b31d6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610400573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104249190611077565b905061042e565b50435b60035460000361043e5760038190555b60008061044d84860186610e60565b600285905560045491935091506104659060016110bf565b600455604080516020808201835260008083528351918201909352918252600854909190610100900460ff16156106435760085460ff1615610574577360448b880c9f3b501af3f343da9284148bd7d77c73ffffffffffffffffffffffffffffffffffffffff16638e760afe856000815181106104e4576104e46110d8565b60200260200101516040518263ffffffff1660e01b81526004016105089190610d08565b6000604051808303816000875af1158015610527573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016820160405261056d9190810190611107565b9150610643565b7309dff56a4ff44e0f4436260a04f5cfa65636a48173ffffffffffffffffffffffffffffffffffffffff16638e760afe856000815181106105b7576105b76110d8565b60200260200101516040518263ffffffff1660e01b81526004016105db9190610d08565b6000604051808303816000875af11580156105fa573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01682016040526106409190810190611107565b91505b843373ffffffffffffffffffffffffffffffffffffffff167ff0f72c0b235fc8687d6a67c02ca543473a3cef8a18b48490f10e475a8dda13908660008151811061068f5761068f6110d8565b602002602001015185876040516106a89392919061117e565b60405180910390a350505050505050565b600581815481106106c957600080fd5b9060005260206000200160009150905080546106e4906111c1565b80601f0160208091040260200160405190810160405280929190818152602001828054610710906111c1565b801561075d5780601f106107325761010080835404028352916020019161075d565b820191906000526020600020905b81548152906001019060200180831161074057829003601f168201915b505050505081565b60085460009060609062010000900460ff16156107e3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601c60248201527f73686f756c6452657665727443616c6c6261636b20697320747275650000000060448201526064015b60405180910390fd5b600084846040516020016107f8929190611214565b604080518083037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe00181529190526008546301000000900460ff1693509150505b9250929050565b6000606061084c610a65565b610898576000848481818080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250959750919550610839945050505050565b6040517f666565644964486578000000000000000000000000000000000000000000000060208201526000906029016040516020818303038152906040528051906020012060076040516020016108ef919061129f565b60405160208183030381529060405280519060200120036109ae577f0000000000000000000000000000000000000000000000000000000000000000156109a757606473ffffffffffffffffffffffffffffffffffffffff1663a3b1b31d6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561097c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109a09190611077565b90506109b1565b50436109b1565b50425b604080516c6400000000000000000000000060208201528151601481830301815260348201928390527ff055e4a2000000000000000000000000000000000000000000000000000000009092526107da916006916005916007918691906038016113ce565b6006610a2283826114df565b506007610a2f82826114df565b505050565b8051610a47906005906020840190610b4a565b5050565b600680546106e4906111c1565b600780546106e4906111c1565b6000600354600003610a775750600190565b60007f000000000000000000000000000000000000000000000000000000000000000015610b1657606473ffffffffffffffffffffffffffffffffffffffff1663a3b1b31d6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610aeb573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b0f9190611077565b9050610b19565b50435b600054600354610b2990836115f9565b108015610b445750600154600254610b4190836115f9565b10155b91505090565b828054828255906000526020600020908101928215610b90579160200282015b82811115610b905782518290610b8090826114df565b5091602001919060010190610b6a565b50610b9c929150610ba0565b5090565b80821115610b9c576000610bb48282610bbd565b50600101610ba0565b508054610bc9906111c1565b6000825580601f10610bd9575050565b601f016020900490600052602060002090810190610bf79190610bfa565b50565b5b80821115610b9c5760008155600101610bfb565b60008060208385031215610c2257600080fd5b823567ffffffffffffffff80821115610c3a57600080fd5b818501915085601f830112610c4e57600080fd5b813581811115610c5d57600080fd5b866020828501011115610c6f57600080fd5b60209290920196919550909350505050565b600060208284031215610c9357600080fd5b5035919050565b60005b83811015610cb5578181015183820152602001610c9d565b50506000910152565b60008151808452610cd6816020860160208601610c9a565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b602081526000610d1b6020830184610cbe565b9392505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715610d9857610d98610d22565b604052919050565b600067ffffffffffffffff821115610dba57610dba610d22565b5060051b60200190565b600067ffffffffffffffff821115610dde57610dde610d22565b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b600082601f830112610e1b57600080fd5b8135610e2e610e2982610dc4565b610d51565b818152846020838601011115610e4357600080fd5b816020850160208301376000918101602001919091529392505050565b60008060408385031215610e7357600080fd5b823567ffffffffffffffff80821115610e8b57600080fd5b818501915085601f830112610e9f57600080fd5b81356020610eaf610e2983610da0565b82815260059290921b84018101918181019089841115610ece57600080fd5b8286015b84811015610f0657803586811115610eea5760008081fd5b610ef88c86838b0101610e0a565b845250918301918301610ed2565b5096505086013592505080821115610f1d57600080fd5b50610f2a85828601610e0a565b9150509250929050565b8215158152604060208201526000610f4f6040830184610cbe565b949350505050565b600060208284031215610f6957600080fd5b81358015158114610d1b57600080fd5b60008060408385031215610f8c57600080fd5b823567ffffffffffffffff80821115610fa457600080fd5b610fb086838701610e0a565b93506020850135915080821115610f1d57600080fd5b60006020808385031215610fd957600080fd5b823567ffffffffffffffff80821115610ff157600080fd5b818501915085601f83011261100557600080fd5b8135611013610e2982610da0565b81815260059190911b8301840190848101908883111561103257600080fd5b8585015b8381101561106a5780358581111561104e5760008081fd5b61105c8b89838a0101610e0a565b845250918601918601611036565b5098975050505050505050565b60006020828403121561108957600080fd5b5051919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b808201808211156110d2576110d2611090565b92915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60006020828403121561111957600080fd5b815167ffffffffffffffff81111561113057600080fd5b8201601f8101841361114157600080fd5b805161114f610e2982610dc4565b81815285602083850101111561116457600080fd5b611175826020830160208601610c9a565b95945050505050565b6060815260006111916060830186610cbe565b82810360208401526111a38186610cbe565b905082810360408401526111b78185610cbe565b9695505050505050565b600181811c908216806111d557607f821691505b60208210810361120e577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b50919050565b6000604082016040835280855180835260608501915060608160051b8601019250602080880160005b83811015611289577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa0888703018552611277868351610cbe565b9550938201939082019060010161123d565b5050858403818701525050506111758185610cbe565b60008083546112ad816111c1565b600182811680156112c557600181146112f857611327565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0084168752821515830287019450611327565b8760005260208060002060005b8581101561131e5781548a820152908401908201611305565b50505082870194505b50929695505050505050565b60008154611340816111c1565b80855260206001838116801561135d5760018114611395576113c3565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff008516838901528284151560051b89010195506113c3565b866000528260002060005b858110156113bb5781548a82018601529083019084016113a0565b890184019650505b505050505092915050565b60a0815260006113e160a0830188611333565b6020838203818501528188548084528284019150828160051b8501018a6000528360002060005b83811015611453577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08784030185526114418383611333565b94860194925060019182019101611408565b50508681036040880152611467818b611333565b94505050505084606084015282810360808401526114858185610cbe565b98975050505050505050565b601f821115610a2f57600081815260208120601f850160051c810160208610156114b85750805b601f850160051c820191505b818110156114d7578281556001016114c4565b505050505050565b815167ffffffffffffffff8111156114f9576114f9610d22565b61150d8161150784546111c1565b84611491565b602080601f831160018114611560576000841561152a5750858301515b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600386901b1c1916600185901b1785556114d7565b6000858152602081207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08616915b828110156115ad5788860151825594840194600190910190840161158e565b50858210156115e957878501517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600388901b60f8161c191681555b5050505050600190811b01905550565b818103818111156110d2576110d261109056fea164736f6c6343000810000a307830303032386339313564366166306664363662626132643066633934303532323662636138643638303633333331323161376439383332313033643135363363", } var StreamsLookupUpkeepABI = StreamsLookupUpkeepMetaData.ABI @@ -661,9 +661,7 @@ type StreamsLookupUpkeepMercuryPerformEvent struct { Sender common.Address BlockNumber *big.Int V0 []byte - V1 []byte VerifiedV0 []byte - VerifiedV1 []byte Ed []byte Raw types.Log } @@ -749,7 +747,7 @@ func (_StreamsLookupUpkeep *StreamsLookupUpkeep) ParseLog(log types.Log) (genera } func (StreamsLookupUpkeepMercuryPerformEvent) Topic() common.Hash { - return common.HexToHash("0x1c85d6186f024e964616014c8247533455ec5129a5095711202292f8a7ea1d54") + return common.HexToHash("0xf0f72c0b235fc8687d6a67c02ca543473a3cef8a18b48490f10e475a8dda1390") } func (_StreamsLookupUpkeep *StreamsLookupUpkeep) Address() common.Address { diff --git a/core/gethwrappers/generated/verifiable_load_log_trigger_upkeep_wrapper/verifiable_load_log_trigger_upkeep_wrapper.go b/core/gethwrappers/generated/verifiable_load_log_trigger_upkeep_wrapper/verifiable_load_log_trigger_upkeep_wrapper.go index d88f15f96a2..a839e5d55d4 100644 --- a/core/gethwrappers/generated/verifiable_load_log_trigger_upkeep_wrapper/verifiable_load_log_trigger_upkeep_wrapper.go +++ b/core/gethwrappers/generated/verifiable_load_log_trigger_upkeep_wrapper/verifiable_load_log_trigger_upkeep_wrapper.go @@ -56,7 +56,7 @@ type Log struct { var VerifiableLoadLogTriggerUpkeepMetaData = &bind.MetaData{ ABI: "[{\"inputs\":[{\"internalType\":\"contractAutomationRegistrar2_1\",\"name\":\"_registrar\",\"type\":\"address\"},{\"internalType\":\"bool\",\"name\":\"_useArb\",\"type\":\"bool\"},{\"internalType\":\"bool\",\"name\":\"_useMercury\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"IndexOutOfRange\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"feedParamKey\",\"type\":\"string\"},{\"internalType\":\"string[]\",\"name\":\"feeds\",\"type\":\"string[]\"},{\"internalType\":\"string\",\"name\":\"timeParamKey\",\"type\":\"string\"},{\"internalType\":\"uint256\",\"name\":\"time\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"extraData\",\"type\":\"bytes\"}],\"name\":\"StreamsLookup\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"upkeepId\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"blockNum\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"addr\",\"type\":\"address\"}],\"name\":\"LogEmitted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"upkeepId\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"blockNum\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"addr\",\"type\":\"address\"}],\"name\":\"LogEmittedAgain\",\"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\":\"uint256\",\"name\":\"upkeepId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint96\",\"name\":\"amount\",\"type\":\"uint96\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"blockNum\",\"type\":\"uint256\"}],\"name\":\"UpkeepTopUp\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"BUCKET_SIZE\",\"outputs\":[{\"internalType\":\"uint16\",\"name\":\"\",\"type\":\"uint16\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"acceptOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"upkeepId\",\"type\":\"uint256\"},{\"internalType\":\"uint96\",\"name\":\"amount\",\"type\":\"uint96\"}],\"name\":\"addFunds\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"addLinkAmount\",\"outputs\":[{\"internalType\":\"uint96\",\"name\":\"\",\"type\":\"uint96\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256[]\",\"name\":\"upkeepIds\",\"type\":\"uint256[]\"}],\"name\":\"batchCancelUpkeeps\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256[]\",\"name\":\"upkeepIds\",\"type\":\"uint256[]\"},{\"internalType\":\"uint8\",\"name\":\"selector\",\"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\"}],\"name\":\"batchPreparingUpkeeps\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256[]\",\"name\":\"upkeepIds\",\"type\":\"uint256[]\"},{\"internalType\":\"uint8\",\"name\":\"log\",\"type\":\"uint8\"},{\"internalType\":\"uint8\",\"name\":\"selector\",\"type\":\"uint8\"}],\"name\":\"batchPreparingUpkeepsSimple\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint8\",\"name\":\"number\",\"type\":\"uint8\"},{\"internalType\":\"uint32\",\"name\":\"gasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint8\",\"name\":\"triggerType\",\"type\":\"uint8\"},{\"internalType\":\"bytes\",\"name\":\"triggerConfig\",\"type\":\"bytes\"},{\"internalType\":\"uint96\",\"name\":\"amount\",\"type\":\"uint96\"},{\"internalType\":\"uint256\",\"name\":\"checkGasToBurn\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"performGasToBurn\",\"type\":\"uint256\"}],\"name\":\"batchRegisterUpkeeps\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint8\",\"name\":\"log\",\"type\":\"uint8\"}],\"name\":\"batchSendLogs\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256[]\",\"name\":\"upkeepIds\",\"type\":\"uint256[]\"},{\"internalType\":\"uint32\",\"name\":\"interval\",\"type\":\"uint32\"}],\"name\":\"batchSetIntervals\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256[]\",\"name\":\"upkeepIds\",\"type\":\"uint256[]\"}],\"name\":\"batchUpdatePipelineData\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256[]\",\"name\":\"upkeepIds\",\"type\":\"uint256[]\"}],\"name\":\"batchWithdrawLinks\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"uint16\",\"name\":\"\",\"type\":\"uint16\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"bucketedDelays\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"buckets\",\"outputs\":[{\"internalType\":\"uint16\",\"name\":\"\",\"type\":\"uint16\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"upkeepId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"startGas\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"blockNum\",\"type\":\"uint256\"}],\"name\":\"burnPerformGas\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes[]\",\"name\":\"values\",\"type\":\"bytes[]\"},{\"internalType\":\"bytes\",\"name\":\"extraData\",\"type\":\"bytes\"}],\"name\":\"checkCallback\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"checkGasToBurns\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint256\",\"name\":\"index\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"txIndex\",\"type\":\"uint256\"},{\"internalType\":\"bytes32\",\"name\":\"txHash\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"blockNumber\",\"type\":\"uint256\"},{\"internalType\":\"bytes32\",\"name\":\"blockHash\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"source\",\"type\":\"address\"},{\"internalType\":\"bytes32[]\",\"name\":\"topics\",\"type\":\"bytes32[]\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"internalType\":\"structLog\",\"name\":\"log\",\"type\":\"tuple\"},{\"internalType\":\"bytes\",\"name\":\"checkData\",\"type\":\"bytes\"}],\"name\":\"checkLog\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"counters\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"delays\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"name\":\"dummyMap\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"upkeepId\",\"type\":\"uint256\"}],\"name\":\"eligible\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"emittedAgainSig\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"emittedSig\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"feedParamKey\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"feedsHex\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"firstPerformBlocks\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"gasLimits\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"startIndex\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"maxCount\",\"type\":\"uint256\"}],\"name\":\"getActiveUpkeepIDsDeployedByThisContract\",\"outputs\":[{\"internalType\":\"uint256[]\",\"name\":\"\",\"type\":\"uint256[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"startIndex\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"maxCount\",\"type\":\"uint256\"}],\"name\":\"getAllActiveUpkeepIDsOnRegistry\",\"outputs\":[{\"internalType\":\"uint256[]\",\"name\":\"\",\"type\":\"uint256[]\"}],\"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\":[{\"internalType\":\"uint256\",\"name\":\"upkeepId\",\"type\":\"uint256\"},{\"internalType\":\"uint16\",\"name\":\"bucket\",\"type\":\"uint16\"}],\"name\":\"getBucketedDelays\",\"outputs\":[{\"internalType\":\"uint256[]\",\"name\":\"\",\"type\":\"uint256[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"upkeepId\",\"type\":\"uint256\"}],\"name\":\"getBucketedDelaysLength\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"upkeepId\",\"type\":\"uint256\"}],\"name\":\"getDelays\",\"outputs\":[{\"internalType\":\"uint256[]\",\"name\":\"\",\"type\":\"uint256[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"upkeepId\",\"type\":\"uint256\"}],\"name\":\"getDelaysLength\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"upkeepID\",\"type\":\"uint256\"}],\"name\":\"getForwarder\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"addr\",\"type\":\"address\"},{\"internalType\":\"uint8\",\"name\":\"selector\",\"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\"}],\"name\":\"getLogTriggerConfig\",\"outputs\":[{\"internalType\":\"bytes\",\"name\":\"logTrigger\",\"type\":\"bytes\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"upkeepId\",\"type\":\"uint256\"}],\"name\":\"getMinBalanceForUpkeep\",\"outputs\":[{\"internalType\":\"uint96\",\"name\":\"\",\"type\":\"uint96\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"upkeepId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"p\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"n\",\"type\":\"uint256\"}],\"name\":\"getPxDelayLastNPerforms\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"upkeepId\",\"type\":\"uint256\"},{\"internalType\":\"uint16\",\"name\":\"bucket\",\"type\":\"uint16\"}],\"name\":\"getSumDelayInBucket\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"upkeepId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"n\",\"type\":\"uint256\"}],\"name\":\"getSumDelayLastNPerforms\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"upkeepId\",\"type\":\"uint256\"}],\"name\":\"getTriggerType\",\"outputs\":[{\"internalType\":\"uint8\",\"name\":\"\",\"type\":\"uint8\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"upkeepId\",\"type\":\"uint256\"}],\"name\":\"getUpkeepInfo\",\"outputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"internalType\":\"uint32\",\"name\":\"performGas\",\"type\":\"uint32\"},{\"internalType\":\"bytes\",\"name\":\"checkData\",\"type\":\"bytes\"},{\"internalType\":\"uint96\",\"name\":\"balance\",\"type\":\"uint96\"},{\"internalType\":\"address\",\"name\":\"admin\",\"type\":\"address\"},{\"internalType\":\"uint64\",\"name\":\"maxValidBlocknumber\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"lastPerformedBlockNumber\",\"type\":\"uint32\"},{\"internalType\":\"uint96\",\"name\":\"amountSpent\",\"type\":\"uint96\"},{\"internalType\":\"bool\",\"name\":\"paused\",\"type\":\"bool\"},{\"internalType\":\"bytes\",\"name\":\"offchainConfig\",\"type\":\"bytes\"}],\"internalType\":\"structKeeperRegistryBase2_1.UpkeepInfo\",\"name\":\"\",\"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\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"intervals\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"lastTopUpBlocks\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"linkToken\",\"outputs\":[{\"internalType\":\"contractLinkTokenInterface\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"logNum\",\"outputs\":[{\"internalType\":\"uint8\",\"name\":\"\",\"type\":\"uint8\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"minBalanceThresholdMultiplier\",\"outputs\":[{\"internalType\":\"uint8\",\"name\":\"\",\"type\":\"uint8\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"performDataSizes\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"performGasToBurns\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"performData\",\"type\":\"bytes\"}],\"name\":\"performUpkeep\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"previousPerformBlocks\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"registrar\",\"outputs\":[{\"internalType\":\"contractAutomationRegistrar2_1\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"registry\",\"outputs\":[{\"internalType\":\"contractIKeeperRegistryMaster\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"upkeepId\",\"type\":\"uint256\"},{\"internalType\":\"uint8\",\"name\":\"log\",\"type\":\"uint8\"}],\"name\":\"sendLog\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"contractAutomationRegistrar2_1\",\"name\":\"newRegistrar\",\"type\":\"address\"}],\"name\":\"setConfig\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"string[]\",\"name\":\"_feeds\",\"type\":\"string[]\"}],\"name\":\"setFeeds\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"upkeepId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_interval\",\"type\":\"uint256\"}],\"name\":\"setInterval\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint8\",\"name\":\"_log\",\"type\":\"uint8\"}],\"name\":\"setLog\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"_feedParamKey\",\"type\":\"string\"},{\"internalType\":\"string\",\"name\":\"_timeParamKey\",\"type\":\"string\"}],\"name\":\"setParamKeys\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"upkeepId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"setPerformDataSize\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"upkeepId\",\"type\":\"uint256\"},{\"internalType\":\"uint32\",\"name\":\"gasLimit\",\"type\":\"uint32\"}],\"name\":\"setUpkeepGasLimit\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"upkeepId\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"cfg\",\"type\":\"bytes\"}],\"name\":\"setUpkeepPrivilegeConfig\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"timeParamKey\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"upkeepId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"blockNum\",\"type\":\"uint256\"}],\"name\":\"topUpFund\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"upkeepId\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"addr\",\"type\":\"address\"},{\"internalType\":\"uint8\",\"name\":\"selector\",\"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\"}],\"name\":\"updateLogTriggerConfig1\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"upkeepId\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"cfg\",\"type\":\"bytes\"}],\"name\":\"updateLogTriggerConfig2\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"upkeepId\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"pipelineData\",\"type\":\"bytes\"}],\"name\":\"updateUpkeepPipelineData\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"upkeepTopUpCheckInterval\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"useArbitrumBlockNum\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"useMercury\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"withdrawLinks\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"upkeepId\",\"type\":\"uint256\"}],\"name\":\"withdrawLinks\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"stateMutability\":\"payable\",\"type\":\"receive\"}]", - Bin: "0x7f97009585a4d2440f981ab6f6eec514343e1e6b2aa9b991a26998e6806f41bf086080527fc76416badc8398ce17c93eab7b4f60f263241694cf503e4df24f233a8cc1c50d60a0526005601455601580546001600160681b0319166c140000000002c68af0bb140000179055606460e0526101c0604052604261014081815261010091829190620065b6610160398152602001604051806080016040528060428152602001620065f8604291399052620000be906016906002620003de565b506040805180820190915260098152680cccacac892c890caf60bb1b6020820152601790620000ee90826200055a565b5060408051808201909152600b81526a313637b1b5a73ab6b132b960a91b60208201526018906200012090826200055a565b503480156200012e57600080fd5b506040516200663a3803806200663a833981016040819052620001519162000652565b82823380600081620001aa5760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b0384811691909117909155811615620001dd57620001dd8162000333565b5050601180546001600160a01b0319166001600160a01b038516908117909155604080516330fe427560e21b815281516000945063c3f909d4926004808401939192918290030181865afa1580156200023a573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200026091906200069e565b50601380546001600160a01b0319166001600160a01b038381169190911790915560115460408051631b6b6d2360e01b81529051939450911691631b6b6d23916004808201926020929091908290030181865afa158015620002c6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620002ec9190620006cf565b601280546001600160a01b0319166001600160a01b039290921691909117905550151560c052506019805461ffff191691151561ff00191691909117905550620006f69050565b336001600160a01b038216036200038d5760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c660000000000000000006044820152606401620001a1565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b82805482825590600052602060002090810192821562000429579160200282015b828111156200042957825182906200041890826200055a565b5091602001919060010190620003ff565b50620004379291506200043b565b5090565b80821115620004375760006200045282826200045c565b506001016200043b565b5080546200046a90620004cb565b6000825580601f106200047b575050565b601f0160209004906000526020600020908101906200049b91906200049e565b50565b5b808211156200043757600081556001016200049f565b634e487b7160e01b600052604160045260246000fd5b600181811c90821680620004e057607f821691505b6020821081036200050157634e487b7160e01b600052602260045260246000fd5b50919050565b601f8211156200055557600081815260208120601f850160051c81016020861015620005305750805b601f850160051c820191505b8181101562000551578281556001016200053c565b5050505b505050565b81516001600160401b03811115620005765762000576620004b5565b6200058e81620005878454620004cb565b8462000507565b602080601f831160018114620005c65760008415620005ad5750858301515b600019600386901b1c1916600185901b17855562000551565b600085815260208120601f198616915b82811015620005f757888601518255948401946001909101908401620005d6565b5085821015620006165787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b6001600160a01b03811681146200049b57600080fd5b805180151581146200064d57600080fd5b919050565b6000806000606084860312156200066857600080fd5b8351620006758162000626565b925062000685602085016200063c565b915062000695604085016200063c565b90509250925092565b60008060408385031215620006b257600080fd5b8251620006bf8162000626565b6020939093015192949293505050565b600060208284031215620006e257600080fd5b8151620006ef8162000626565b9392505050565b60805160a05160c05160e051615e5c6200075a600039600081816105b901526124af015260008181610a2d0152613ff00152600081816108a601528181611fa80152613a3e015260008181610dca01528181611f780152613a130152615e5c6000f3fe6080604052600436106105265760003560e01c80637b103999116102af578063af953a4a11610179578063daee1aeb116100d6578063e83ce5581161008a578063fa333dfb1161006f578063fa333dfb14611066578063fba7ffa314611119578063fcdc1f631461114657600080fd5b8063e83ce55814611027578063f2fde38b1461104657600080fd5b8063de818253116100bb578063de81825314610f90578063e0114adb14610fe4578063e45530831461101157600080fd5b8063daee1aeb14610f50578063dbef701e14610f7057600080fd5b8063c41c815b1161012d578063d4c2490011610112578063d4c2490014610ef0578063d6051a7214610f10578063da6cba4714610f3057600080fd5b8063c41c815b14610ec1578063c98f10b014610edb57600080fd5b8063b657bc9c1161015e578063b657bc9c14610e61578063becde0e114610e81578063c041982214610ea157600080fd5b8063af953a4a14610e2c578063afb28d1f14610e4c57600080fd5b8063948108f7116102275780639d385eaa116101db578063a6548248116101c0578063a654824814610db8578063a6b5947514610dec578063a72aa27e14610e0c57600080fd5b80639d385eaa14610d785780639d6f1cc714610d9857600080fd5b80639ac542eb1161020c5780639ac542eb14610cf05780639b42935414610d1a5780639b51fb0d14610d4757600080fd5b8063948108f714610cb057806396cebc7c14610cd057600080fd5b806386e330af1161027e5780638da5cb5b116102635780638da5cb5b14610c385780638fcb3fba14610c63578063924ca57814610c9057600080fd5b806386e330af14610bf8578063873c758614610c1857600080fd5b80637b10399914610b6b5780637e7a46dc14610b985780638243444a14610bb85780638340507c14610bd857600080fd5b806345d2ec17116103f057806360457ff51161036857806373644cce1161031c578063776898c811610301578063776898c814610b1657806379ba509714610b3657806379ea994314610b4b57600080fd5b806373644cce14610abc5780637672130314610ae957600080fd5b8063642f6cef1161034d578063642f6cef14610a1b57806369cdbadb14610a5f5780637145f11b14610a8c57600080fd5b806360457ff5146109c9578063636092e8146109f657600080fd5b80635147cd59116103bf57806357970e93116103a457806357970e93146109675780635d4ee7f3146109945780635f17e616146109a957600080fd5b80635147cd591461091557806351c98be31461094757600080fd5b806345d2ec1714610867578063469820931461089457806346e7a63e146108c85780634b56a42e146108f557600080fd5b806320e3dbd41161049e5780632b20e397116104525780633ebe8d6c116104375780633ebe8d6c146107f957806340691db4146108195780634585e33b1461084757600080fd5b80632b20e3971461077a578063328ffd11146107cc57600080fd5b806328c4b57b1161048357806328c4b57b1461070d57806329e0a8411461072d5780632a9032d31461075a57600080fd5b806320e3dbd4146106cd5780632636aecf146106ed57600080fd5b806319d97a94116104f55780631e010439116104da5780631e0104391461063b578063206c32e814610678578063207b6516146106ad57600080fd5b806319d97a94146105ee5780631cdde2511461061b57600080fd5b806306c1cc0014610532578063077ac621146105545780630b7d33e61461058757806312c55027146105a757600080fd5b3661052d57005b600080fd5b34801561053e57600080fd5b5061055261054d366004614772565b611173565b005b34801561056057600080fd5b5061057461056f366004614825565b6113c2565b6040519081526020015b60405180910390f35b34801561059357600080fd5b506105526105a236600461485a565b611400565b3480156105b357600080fd5b506105db7f000000000000000000000000000000000000000000000000000000000000000081565b60405161ffff909116815260200161057e565b3480156105fa57600080fd5b5061060e6106093660046148a1565b61148e565b60405161057e9190614928565b34801561062757600080fd5b5061055261063636600461495d565b61154b565b34801561064757600080fd5b5061065b6106563660046148a1565b611688565b6040516bffffffffffffffffffffffff909116815260200161057e565b34801561068457600080fd5b506106986106933660046149c2565b61171d565b6040805192835260208301919091520161057e565b3480156106b957600080fd5b5061060e6106c83660046148a1565b6117a0565b3480156106d957600080fd5b506105526106e83660046149ee565b6117f8565b3480156106f957600080fd5b50610552610708366004614a50565b6119c2565b34801561071957600080fd5b50610574610728366004614aca565b611c8b565b34801561073957600080fd5b5061074d6107483660046148a1565b611cf6565b60405161057e9190614af6565b34801561076657600080fd5b50610552610775366004614c37565b611dfb565b34801561078657600080fd5b506011546107a79073ffffffffffffffffffffffffffffffffffffffff1681565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200161057e565b3480156107d857600080fd5b506105746107e73660046148a1565b60036020526000908152604090205481565b34801561080557600080fd5b506105746108143660046148a1565b611edc565b34801561082557600080fd5b50610839610834366004614c79565b611f45565b60405161057e929190614cdc565b34801561085357600080fd5b50610552610862366004614d39565b6123a9565b34801561087357600080fd5b506108876108823660046149c2565b6125f8565b60405161057e9190614d6f565b3480156108a057600080fd5b506105747f000000000000000000000000000000000000000000000000000000000000000081565b3480156108d457600080fd5b506105746108e33660046148a1565b600a6020526000908152604090205481565b34801561090157600080fd5b50610839610910366004614dd7565b612667565b34801561092157600080fd5b506109356109303660046148a1565b6126bb565b60405160ff909116815260200161057e565b34801561095357600080fd5b50610552610962366004614e94565b61274f565b34801561097357600080fd5b506012546107a79073ffffffffffffffffffffffffffffffffffffffff1681565b3480156109a057600080fd5b506105526127f3565b3480156109b557600080fd5b506105526109c4366004614eeb565b61292e565b3480156109d557600080fd5b506105746109e43660046148a1565b60076020526000908152604090205481565b348015610a0257600080fd5b5060155461065b906bffffffffffffffffffffffff1681565b348015610a2757600080fd5b50610a4f7f000000000000000000000000000000000000000000000000000000000000000081565b604051901515815260200161057e565b348015610a6b57600080fd5b50610574610a7a3660046148a1565b60086020526000908152604090205481565b348015610a9857600080fd5b50610a4f610aa73660046148a1565b600b6020526000908152604090205460ff1681565b348015610ac857600080fd5b50610574610ad73660046148a1565b6000908152600c602052604090205490565b348015610af557600080fd5b50610574610b043660046148a1565b60046020526000908152604090205481565b348015610b2257600080fd5b50610a4f610b313660046148a1565b6129fb565b348015610b4257600080fd5b50610552612a4d565b348015610b5757600080fd5b506107a7610b663660046148a1565b612b4a565b348015610b7757600080fd5b506013546107a79073ffffffffffffffffffffffffffffffffffffffff1681565b348015610ba457600080fd5b50610552610bb3366004614f0d565b612bde565b348015610bc457600080fd5b50610552610bd3366004614f0d565b612c6f565b348015610be457600080fd5b50610552610bf3366004614f59565b612cc9565b348015610c0457600080fd5b50610552610c13366004614fa6565b612ce7565b348015610c2457600080fd5b50610887610c33366004614eeb565b612cfa565b348015610c4457600080fd5b5060005473ffffffffffffffffffffffffffffffffffffffff166107a7565b348015610c6f57600080fd5b50610574610c7e3660046148a1565b60056020526000908152604090205481565b348015610c9c57600080fd5b50610552610cab366004614eeb565b612db7565b348015610cbc57600080fd5b50610552610ccb366004615057565b612ffc565b348015610cdc57600080fd5b50610552610ceb366004615087565b613114565b348015610cfc57600080fd5b50601554610935906c01000000000000000000000000900460ff1681565b348015610d2657600080fd5b50610552610d35366004614eeb565b60009182526009602052604090912055565b348015610d5357600080fd5b506105db610d623660046148a1565b600e6020526000908152604090205461ffff1681565b348015610d8457600080fd5b50610887610d933660046148a1565b61331e565b348015610da457600080fd5b5061060e610db33660046148a1565b613380565b348015610dc457600080fd5b506105747f000000000000000000000000000000000000000000000000000000000000000081565b348015610df857600080fd5b50610552610e07366004614aca565b61342c565b348015610e1857600080fd5b50610552610e273660046150a4565b613495565b348015610e3857600080fd5b50610552610e473660046148a1565b613540565b348015610e5857600080fd5b5061060e6135c6565b348015610e6d57600080fd5b5061065b610e7c3660046148a1565b6135d3565b348015610e8d57600080fd5b50610552610e9c366004614c37565b61362b565b348015610ead57600080fd5b50610887610ebc366004614eeb565b6136c5565b348015610ecd57600080fd5b50601954610a4f9060ff1681565b348015610ee757600080fd5b5061060e6137c2565b348015610efc57600080fd5b50610552610f0b3660046150c9565b6137cf565b348015610f1c57600080fd5b50610698610f2b366004614eeb565b61384e565b348015610f3c57600080fd5b50610552610f4b3660046150ee565b6138b7565b348015610f5c57600080fd5b50610552610f6b366004614c37565b613c1e565b348015610f7c57600080fd5b50610574610f8b366004614eeb565b613ce9565b348015610f9c57600080fd5b50610552610fab366004615087565b6019805460ff909216610100027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff909216919091179055565b348015610ff057600080fd5b50610574610fff3660046148a1565b60096020526000908152604090205481565b34801561101d57600080fd5b5061057460145481565b34801561103357600080fd5b5060195461093590610100900460ff1681565b34801561105257600080fd5b506105526110613660046149ee565b613d1a565b34801561107257600080fd5b5061060e611081366004615156565b6040805160c0808201835273ffffffffffffffffffffffffffffffffffffffff9890981680825260ff97881660208084019182528385019889526060808501988952608080860198895260a095860197885286519283019490945291519099168985015296519688019690965293519486019490945290519184019190915251828401528051808303909301835260e0909101905290565b34801561112557600080fd5b506105746111343660046148a1565b60066020526000908152604090205481565b34801561115257600080fd5b506105746111613660046148a1565b60026020526000908152604090205481565b6040805161018081018252600461014082019081527f746573740000000000000000000000000000000000000000000000000000000061016083015281528151602081810184526000808352818401929092523083850181905263ffffffff8b166060850152608084015260ff808a1660a08501528451808301865283815260c085015260e0840189905284519182019094529081526101008201526bffffffffffffffffffffffff8516610120820152601254601154919273ffffffffffffffffffffffffffffffffffffffff9182169263095ea7b3921690611259908c16886151de565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e085901b16815273ffffffffffffffffffffffffffffffffffffffff90921660048301526bffffffffffffffffffffffff1660248201526044016020604051808303816000875af11580156112d7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112fb9190615222565b5060008860ff1667ffffffffffffffff81111561131a5761131a614614565b604051908082528060200260200182016040528015611343578160200160208202803683370190505b50905060005b8960ff168160ff1610156113b657600061136284613d2e565b905080838360ff168151811061137a5761137a61523d565b602090810291909101810191909152600091825260088152604080832088905560079091529020849055806113ae8161526c565b915050611349565b50505050505050505050565b600d60205282600052604060002060205281600052604060002081815481106113ea57600080fd5b9060005260206000200160009250925050505481565b6013546040517f0b7d33e600000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff90911690630b7d33e690611458908590859060040161528b565b600060405180830381600087803b15801561147257600080fd5b505af1158015611486573d6000803e3d6000fd5b505050505050565b6013546040517f19d97a940000000000000000000000000000000000000000000000000000000081526004810183905260609173ffffffffffffffffffffffffffffffffffffffff16906319d97a94906024015b600060405180830381865afa1580156114ff573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016820160405261154591908101906152f1565b92915050565b6013546040517ffa333dfb00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff888116600483015260ff8816602483015260448201879052606482018690526084820185905260a4820184905290911690634ee88d35908990309063fa333dfb9060c401600060405180830381865afa1580156115ea573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016820160405261163091908101906152f1565b6040518363ffffffff1660e01b815260040161164d92919061528b565b600060405180830381600087803b15801561166757600080fd5b505af115801561167b573d6000803e3d6000fd5b5050505050505050505050565b6013546040517f1e0104390000000000000000000000000000000000000000000000000000000081526004810183905260009173ffffffffffffffffffffffffffffffffffffffff1690631e010439906024015b602060405180830381865afa1580156116f9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115459190615331565b6000828152600d6020908152604080832061ffff85168452825280832080548251818502810185019093528083528493849392919083018282801561178157602002820191906000526020600020905b81548152602001906001019080831161176d575b50505050509050611793818251613dfc565b92509250505b9250929050565b6013546040517f207b65160000000000000000000000000000000000000000000000000000000081526004810183905260609173ffffffffffffffffffffffffffffffffffffffff169063207b6516906024016114e2565b601180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff8316908117909155604080517fc3f909d400000000000000000000000000000000000000000000000000000000815281516000939263c3f909d492600480820193918290030181865afa15801561188e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118b29190615359565b50601380547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83811691909117909155601154604080517f1b6b6d230000000000000000000000000000000000000000000000000000000081529051939450911691631b6b6d23916004808201926020929091908290030181865afa158015611955573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119799190615387565b601280547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff929092169190911790555050565b8560005b81811015611c805760008989838181106119e2576119e261523d565b9050602002013590503073ffffffffffffffffffffffffffffffffffffffff16637e7a46dc8283604051602001611a1b91815260200190565b6040516020818303038152906040526040518363ffffffff1660e01b8152600401611a4792919061528b565b600060405180830381600087803b158015611a6157600080fd5b505af1158015611a75573d6000803e3d6000fd5b50506013546040517f5147cd59000000000000000000000000000000000000000000000000000000008152600481018590526000935073ffffffffffffffffffffffffffffffffffffffff9091169150635147cd5990602401602060405180830381865afa158015611aeb573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b0f91906153a4565b90508060ff16600103611c6b576040517ffa333dfb000000000000000000000000000000000000000000000000000000008152306004820181905260ff8b166024830152604482018a9052606482018890526084820188905260a4820187905260009163fa333dfb9060c401600060405180830381865afa158015611b98573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201604052611bde91908101906152f1565b6013546040517f4ee88d3500000000000000000000000000000000000000000000000000000000815291925073ffffffffffffffffffffffffffffffffffffffff1690634ee88d3590611c37908690859060040161528b565b600060405180830381600087803b158015611c5157600080fd5b505af1158015611c65573d6000803e3d6000fd5b50505050505b50508080611c78906153c1565b9150506119c6565b505050505050505050565b6000838152600c602090815260408083208054825181850281018501909352808352611cec93830182828015611ce057602002820191906000526020600020905b815481526020019060010190808311611ccc575b50505050508484613e81565b90505b9392505050565b604080516101408101825260008082526020820181905260609282018390528282018190526080820181905260a0820181905260c0820181905260e082018190526101008201526101208101919091526013546040517fc7c3a19a0000000000000000000000000000000000000000000000000000000081526004810184905273ffffffffffffffffffffffffffffffffffffffff9091169063c7c3a19a90602401600060405180830381865afa158015611db5573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201604052611545919081019061541c565b8060005b818160ff161015611ed65760135473ffffffffffffffffffffffffffffffffffffffff1663c8048022858560ff8516818110611e3d57611e3d61523d565b905060200201356040518263ffffffff1660e01b8152600401611e6291815260200190565b600060405180830381600087803b158015611e7c57600080fd5b505af1158015611e90573d6000803e3d6000fd5b50505050611ec384848360ff16818110611eac57611eac61523d565b90506020020135600f613fe090919063ffffffff16565b5080611ece8161526c565b915050611dff565b50505050565b6000818152600e602052604081205461ffff1681805b8261ffff168161ffff1611611f3d576000858152600d6020908152604080832061ffff85168452909152902054611f29908361553b565b915080611f358161554e565b915050611ef2565b509392505050565b6000606060005a90506000611f58613fec565b9050600085806020019051810190611f70919061556f565b6019549091507f000000000000000000000000000000000000000000000000000000000000000090610100900460ff1615611fc857507f00000000000000000000000000000000000000000000000000000000000000005b80611fd660c08a018a615588565b6000818110611fe757611fe761523d565b905060200201350361234757600061200260c08a018a615588565b60018181106120135761201361523d565b9050602002013560405160200161202c91815260200190565b6040516020818303038152906040529050600081806020019051810190612053919061556f565b90508381146120c3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f75706b6565702069647320646f6e2774206d617463680000000000000000000060448201526064015b60405180910390fd5b60006120d260c08c018c615588565b60028181106120e3576120e361523d565b905060200201356040516020016120fc91815260200190565b6040516020818303038152906040529050600081806020019051810190612123919061556f565b9050600061213460c08e018e615588565b60038181106121455761214561523d565b9050602002013560405160200161215e91815260200190565b60405160208183030381529060405290506000818060200190518101906121859190615387565b6000868152600860205260409020549091505b805a6121a4908d6155f0565b6121b090613a9861553b565b10156121f15783406000908152600b6020526040902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169055612198565b60195460ff161561229957604080516020810188905290810185905273ffffffffffffffffffffffffffffffffffffffff831660608201526017906016906018908790608001604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152908290527ff055e4a20000000000000000000000000000000000000000000000000000000082526120ba95949392916004016156f1565b60408051600280825260608201909252600091816020015b60608152602001906001900390816122b15790505060408051602081018a905290810187905273ffffffffffffffffffffffffffffffffffffffff851660608201529091506000906080016040516020818303038152906040529050600182826040516020016123229291906157b4565b6040516020818303038152906040529e509e5050505050505050505050505050611799565b6040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f756e6578706563746564206576656e742073696700000000000000000000000060448201526064016120ba565b60005a90506000806123bd84860186614dd7565b915091506000806000838060200190518101906123da9190615848565b6000838152600560209081526040808320546004909252822054949750929550909350909190612408613fec565b90508260000361242857600086815260056020526040902081905561256c565b600061243486836155f0565b6000888152600e6020908152604080832054600d835281842061ffff9091168085529083528184208054835181860281018601909452808452959650909491929091908301828280156124a657602002820191906000526020600020905b815481526020019060010190808311612492575b505050505090507f000000000000000000000000000000000000000000000000000000000000000061ffff1681510361252157816124e38161554e565b60008b8152600e6020526040902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00001661ffff83161790559250505b506000888152600d6020908152604080832061ffff9094168352928152828220805460018181018355918452828420018590558a8352600c8252928220805493840181558252902001555b60008681526006602052604081205461258690600161553b565b60008881526006602090815260408083208490556004909152902083905590506125b08783612db7565b6040513090839089907f97009585a4d2440f981ab6f6eec514343e1e6b2aa9b991a26998e6806f41bf0890600090a46125ea878b8461342c565b505050505050505050505050565b6000828152600d6020908152604080832061ffff8516845282529182902080548351818402810184019094528084526060939283018282801561265a57602002820191906000526020600020905b815481526020019060010190808311612646575b5050505050905092915050565b60006060600084846040516020016126809291906157b4565b604080518083037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe00181529190526001969095509350505050565b6013546040517f5147cd590000000000000000000000000000000000000000000000000000000081526004810183905260009173ffffffffffffffffffffffffffffffffffffffff1690635147cd5990602401602060405180830381865afa15801561272b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061154591906153a4565b8160005b818110156127ec5730635f17e6168686848181106127735761277361523d565b90506020020135856040518363ffffffff1660e01b81526004016127a792919091825263ffffffff16602082015260400190565b600060405180830381600087803b1580156127c157600080fd5b505af11580156127d5573d6000803e3d6000fd5b5050505080806127e4906153c1565b915050612753565b5050505050565b6127fb61408e565b6012546040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015260009173ffffffffffffffffffffffffffffffffffffffff16906370a0823190602401602060405180830381865afa15801561286a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061288e919061556f565b6012546040517fa9059cbb0000000000000000000000000000000000000000000000000000000081523360048201526024810183905291925073ffffffffffffffffffffffffffffffffffffffff169063a9059cbb906044016020604051808303816000875af1158015612906573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061292a9190615222565b5050565b60008281526003602090815260408083208490556005825280832083905560068252808320839055600c909152812061296691614513565b6000828152600e602052604081205461ffff16905b8161ffff168161ffff16116129c2576000848152600d6020908152604080832061ffff8516845290915281206129b091614513565b806129ba8161554e565b91505061297b565b5050506000908152600e6020526040902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000169055565b6000818152600560205260408120548103612a1857506001919050565b600082815260036020908152604080832054600490925290912054612a3b613fec565b612a4591906155f0565b101592915050565b60015473ffffffffffffffffffffffffffffffffffffffff163314612ace576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e65720000000000000000000060448201526064016120ba565b60008054337fffffffffffffffffffffffff00000000000000000000000000000000000000008083168217845560018054909116905560405173ffffffffffffffffffffffffffffffffffffffff90921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b6013546040517f79ea99430000000000000000000000000000000000000000000000000000000081526004810183905260009173ffffffffffffffffffffffffffffffffffffffff16906379ea994390602401602060405180830381865afa158015612bba573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115459190615387565b6013546040517fcd7f71b500000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff9091169063cd7f71b590612c3890869086908690600401615876565b600060405180830381600087803b158015612c5257600080fd5b505af1158015612c66573d6000803e3d6000fd5b50505050505050565b6013546040517f4ee88d3500000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff90911690634ee88d3590612c3890869086908690600401615876565b6017612cd58382615910565b506018612ce28282615910565b505050565b805161292a906016906020840190614531565b6013546040517f06e3b632000000000000000000000000000000000000000000000000000000008152600481018490526024810183905260609173ffffffffffffffffffffffffffffffffffffffff16906306e3b63290604401600060405180830381865afa158015612d71573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201604052611cef9190810190615a2a565b601454600083815260026020526040902054612dd390836155f0565b111561292a576013546040517fc7c3a19a0000000000000000000000000000000000000000000000000000000081526004810184905260009173ffffffffffffffffffffffffffffffffffffffff169063c7c3a19a90602401600060405180830381865afa158015612e49573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201604052612e8f919081019061541c565b6013546040517fb657bc9c0000000000000000000000000000000000000000000000000000000081526004810186905291925060009173ffffffffffffffffffffffffffffffffffffffff9091169063b657bc9c90602401602060405180830381865afa158015612f04573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612f289190615331565b601554909150612f4c9082906c01000000000000000000000000900460ff166151de565b6bffffffffffffffffffffffff1682606001516bffffffffffffffffffffffff161015611ed657601554612f8f9085906bffffffffffffffffffffffff16612ffc565b60008481526002602090815260409182902085905560155482518781526bffffffffffffffffffffffff909116918101919091529081018490527f49d4100ab0124eb4a9a65dc4ea08d6412a43f6f05c49194983f5b322bcc0a5c09060600160405180910390a150505050565b6012546013546040517f095ea7b300000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff91821660048201526bffffffffffffffffffffffff8416602482015291169063095ea7b3906044016020604051808303816000875af1158015613084573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906130a89190615222565b506013546040517f948108f7000000000000000000000000000000000000000000000000000000008152600481018490526bffffffffffffffffffffffff8316602482015273ffffffffffffffffffffffffffffffffffffffff9091169063948108f790604401611458565b6040517fc04198220000000000000000000000000000000000000000000000000000000081526000600482018190526024820181905290309063c041982290604401600060405180830381865afa158015613173573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01682016040526131b99190810190615a2a565b805190915060006131c8613fec565b905060005b828110156127ec5760008482815181106131e9576131e961523d565b60209081029190910101516013546040517f5147cd590000000000000000000000000000000000000000000000000000000081526004810183905291925060009173ffffffffffffffffffffffffffffffffffffffff90911690635147cd5990602401602060405180830381865afa158015613269573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061328d91906153a4565b90508060ff16600103613309578660ff166000036132d9576040513090859084907f97009585a4d2440f981ab6f6eec514343e1e6b2aa9b991a26998e6806f41bf0890600090a4613309565b6040513090859084907fc76416badc8398ce17c93eab7b4f60f263241694cf503e4df24f233a8cc1c50d90600090a45b50508080613316906153c1565b9150506131cd565b6000818152600c602090815260409182902080548351818402810184019094528084526060939283018282801561337457602002820191906000526020600020905b815481526020019060010190808311613360575b50505050509050919050565b6016818154811061339057600080fd5b9060005260206000200160009150905080546133ab90615603565b80601f01602080910402602001604051908101604052809291908181526020018280546133d790615603565b80156134245780601f106133f957610100808354040283529160200191613424565b820191906000526020600020905b81548152906001019060200180831161340757829003601f168201915b505050505081565b6000838152600760205260409020545b805a61344890856155f0565b6134549061271061553b565b1015611ed65781406000908152600b6020526040902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016905561343c565b6013546040517fa72aa27e0000000000000000000000000000000000000000000000000000000081526004810184905263ffffffff8316602482015273ffffffffffffffffffffffffffffffffffffffff9091169063a72aa27e90604401600060405180830381600087803b15801561350d57600080fd5b505af1158015613521573d6000803e3d6000fd5b505050600092835250600a602052604090912063ffffffff9091169055565b6013546040517f744bfe610000000000000000000000000000000000000000000000000000000081526004810183905230602482015273ffffffffffffffffffffffffffffffffffffffff9091169063744bfe6190604401600060405180830381600087803b1580156135b257600080fd5b505af11580156127ec573d6000803e3d6000fd5b601780546133ab90615603565b6013546040517fb657bc9c0000000000000000000000000000000000000000000000000000000081526004810183905260009173ffffffffffffffffffffffffffffffffffffffff169063b657bc9c906024016116dc565b8060005b818163ffffffff161015611ed6573063af953a4a858563ffffffff851681811061365b5761365b61523d565b905060200201356040518263ffffffff1660e01b815260040161368091815260200190565b600060405180830381600087803b15801561369a57600080fd5b505af11580156136ae573d6000803e3d6000fd5b5050505080806136bd90615abb565b91505061362f565b606060006136d3600f614111565b905080841061370e576040517f1390f2a100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b826000036137235761372084826155f0565b92505b60008367ffffffffffffffff81111561373e5761373e614614565b604051908082528060200260200182016040528015613767578160200160208202803683370190505b50905060005b848110156137b95761378a613782828861553b565b600f9061411b565b82828151811061379c5761379c61523d565b6020908102919091010152806137b1816153c1565b91505061376d565b50949350505050565b601880546133ab90615603565b60006137d9613fec565b90508160ff1660000361381a576040513090829085907f97009585a4d2440f981ab6f6eec514343e1e6b2aa9b991a26998e6806f41bf0890600090a4505050565b6040513090829085907fc76416badc8398ce17c93eab7b4f60f263241694cf503e4df24f233a8cc1c50d90600090a4505050565b6000828152600c602090815260408083208054825181850281018501909352808352849384939291908301828280156138a657602002820191906000526020600020905b815481526020019060010190808311613892575b505050505090506117938185613dfc565b8260005b818110156114865760008686838181106138d7576138d761523d565b9050602002013590503073ffffffffffffffffffffffffffffffffffffffff16637e7a46dc828360405160200161391091815260200190565b6040516020818303038152906040526040518363ffffffff1660e01b815260040161393c92919061528b565b600060405180830381600087803b15801561395657600080fd5b505af115801561396a573d6000803e3d6000fd5b50506013546040517f5147cd59000000000000000000000000000000000000000000000000000000008152600481018590526000935073ffffffffffffffffffffffffffffffffffffffff9091169150635147cd5990602401602060405180830381865afa1580156139e0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613a0491906153a4565b90508060ff16600103613c09577f000000000000000000000000000000000000000000000000000000000000000060ff871615613a5e57507f00000000000000000000000000000000000000000000000000000000000000005b60003073ffffffffffffffffffffffffffffffffffffffff1663fa333dfb30898588604051602001613a9291815260200190565b604051602081830303815290604052613aaa90615ad4565b60405160e086901b7fffffffff0000000000000000000000000000000000000000000000000000000016815273ffffffffffffffffffffffffffffffffffffffff909416600485015260ff90921660248401526044830152606482015260006084820181905260a482015260c401600060405180830381865afa158015613b35573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201604052613b7b91908101906152f1565b6013546040517f4ee88d3500000000000000000000000000000000000000000000000000000000815291925073ffffffffffffffffffffffffffffffffffffffff1690634ee88d3590613bd4908790859060040161528b565b600060405180830381600087803b158015613bee57600080fd5b505af1158015613c02573d6000803e3d6000fd5b5050505050505b50508080613c16906153c1565b9150506138bb565b8060005b81811015611ed6576000848483818110613c3e57613c3e61523d565b9050602002013590503073ffffffffffffffffffffffffffffffffffffffff16637e7a46dc8283604051602001613c7791815260200190565b6040516020818303038152906040526040518363ffffffff1660e01b8152600401613ca392919061528b565b600060405180830381600087803b158015613cbd57600080fd5b505af1158015613cd1573d6000803e3d6000fd5b50505050508080613ce1906153c1565b915050613c22565b600c6020528160005260406000208181548110613d0557600080fd5b90600052602060002001600091509150505481565b613d2261408e565b613d2b81614127565b50565b6011546040517f3f678e11000000000000000000000000000000000000000000000000000000008152600091829173ffffffffffffffffffffffffffffffffffffffff90911690633f678e1190613d89908690600401615b16565b6020604051808303816000875af1158015613da8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613dcc919061556f565b9050613dd9600f8261421c565b506060909201516000838152600a6020526040902063ffffffff90911690555090565b815160009081908190841580613e125750808510155b15613e1b578094505b60008092505b85831015613e7757866001613e3685856155f0565b613e4091906155f0565b81518110613e5057613e5061523d565b602002602001015181613e63919061553b565b905082613e6f816153c1565b935050613e21565b9694955050505050565b82516000908190831580613e955750808410155b15613e9e578093505b60008467ffffffffffffffff811115613eb957613eb9614614565b604051908082528060200260200182016040528015613ee2578160200160208202803683370190505b509050600092505b84831015613f5057866001613eff85856155f0565b613f0991906155f0565b81518110613f1957613f1961523d565b6020026020010151818481518110613f3357613f3361523d565b602090810291909101015282613f48816153c1565b935050613eea565b613f6981600060018451613f6491906155f0565b614228565b85606403613fa2578060018251613f8091906155f0565b81518110613f9057613f9061523d565b60200260200101519350505050611cef565b806064825188613fb29190615c68565b613fbc9190615cd4565b81518110613fcc57613fcc61523d565b602002602001015193505050509392505050565b6000611cef83836143a0565b60007f00000000000000000000000000000000000000000000000000000000000000001561408957606473ffffffffffffffffffffffffffffffffffffffff1663a3b1b31d6040518163ffffffff1660e01b8152600401602060405180830381865afa158015614060573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614084919061556f565b905090565b504390565b60005473ffffffffffffffffffffffffffffffffffffffff16331461410f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e65720000000000000000000060448201526064016120ba565b565b6000611545825490565b6000611cef838361449a565b3373ffffffffffffffffffffffffffffffffffffffff8216036141a6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c6600000000000000000060448201526064016120ba565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b6000611cef83836144c4565b8181808203614238575050505050565b60008560026142478787615ce8565b6142519190615d08565b61425b9087615d70565b8151811061426b5761426b61523d565b602002602001015190505b81831361437a575b808684815181106142915761429161523d565b602002602001015110156142b157826142a981615d98565b93505061427e565b8582815181106142c3576142c361523d565b60200260200101518110156142e457816142dc81615dc9565b9250506142b1565b818313614375578582815181106142fd576142fd61523d565b60200260200101518684815181106143175761431761523d565b60200260200101518785815181106143315761433161523d565b6020026020010188858151811061434a5761434a61523d565b6020908102919091010191909152528261436381615d98565b935050818061437190615dc9565b9250505b614276565b8185121561438d5761438d868684614228565b8383121561148657611486868486614228565b600081815260018301602052604081205480156144895760006143c46001836155f0565b85549091506000906143d8906001906155f0565b905081811461443d5760008660000182815481106143f8576143f861523d565b906000526020600020015490508087600001848154811061441b5761441b61523d565b6000918252602080832090910192909255918252600188019052604090208390555b855486908061444e5761444e615e20565b600190038181906000526020600020016000905590558560010160008681526020019081526020016000206000905560019350505050611545565b6000915050611545565b5092915050565b60008260000182815481106144b1576144b161523d565b9060005260206000200154905092915050565b600081815260018301602052604081205461450b57508154600181810184556000848152602080822090930184905584548482528286019093526040902091909155611545565b506000611545565b5080546000825590600052602060002090810190613d2b9190614587565b828054828255906000526020600020908101928215614577579160200282015b8281111561457757825182906145679082615910565b5091602001919060010190614551565b5061458392915061459c565b5090565b5b808211156145835760008155600101614588565b808211156145835760006145b082826145b9565b5060010161459c565b5080546145c590615603565b6000825580601f106145d5575050565b601f016020900490600052602060002090810190613d2b9190614587565b60ff81168114613d2b57600080fd5b63ffffffff81168114613d2b57600080fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051610140810167ffffffffffffffff8111828210171561466757614667614614565b60405290565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff811182821017156146b4576146b4614614565b604052919050565b600067ffffffffffffffff8211156146d6576146d6614614565b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b600082601f83011261471357600080fd5b8135614726614721826146bc565b61466d565b81815284602083860101111561473b57600080fd5b816020850160208301376000918101602001919091529392505050565b6bffffffffffffffffffffffff81168114613d2b57600080fd5b600080600080600080600060e0888a03121561478d57600080fd5b8735614798816145f3565b965060208801356147a881614602565b955060408801356147b8816145f3565b9450606088013567ffffffffffffffff8111156147d457600080fd5b6147e08a828b01614702565b94505060808801356147f181614758565b9699959850939692959460a0840135945060c09093013592915050565b803561ffff8116811461482057600080fd5b919050565b60008060006060848603121561483a57600080fd5b8335925061484a6020850161480e565b9150604084013590509250925092565b6000806040838503121561486d57600080fd5b82359150602083013567ffffffffffffffff81111561488b57600080fd5b61489785828601614702565b9150509250929050565b6000602082840312156148b357600080fd5b5035919050565b60005b838110156148d55781810151838201526020016148bd565b50506000910152565b600081518084526148f68160208601602086016148ba565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b602081526000611cef60208301846148de565b73ffffffffffffffffffffffffffffffffffffffff81168114613d2b57600080fd5b600080600080600080600060e0888a03121561497857600080fd5b87359650602088013561498a8161493b565b9550604088013561499a816145f3565b969995985095966060810135965060808101359560a0820135955060c0909101359350915050565b600080604083850312156149d557600080fd5b823591506149e56020840161480e565b90509250929050565b600060208284031215614a0057600080fd5b8135611cef8161493b565b60008083601f840112614a1d57600080fd5b50813567ffffffffffffffff811115614a3557600080fd5b6020830191508360208260051b850101111561179957600080fd5b600080600080600080600060c0888a031215614a6b57600080fd5b873567ffffffffffffffff811115614a8257600080fd5b614a8e8a828b01614a0b565b9098509650506020880135614aa2816145f3565b96999598509596604081013596506060810135956080820135955060a0909101359350915050565b600080600060608486031215614adf57600080fd5b505081359360208301359350604090920135919050565b60208152614b1d60208201835173ffffffffffffffffffffffffffffffffffffffff169052565b60006020830151614b36604084018263ffffffff169052565b506040830151610140806060850152614b536101608501836148de565b91506060850151614b7460808601826bffffffffffffffffffffffff169052565b50608085015173ffffffffffffffffffffffffffffffffffffffff811660a08601525060a085015167ffffffffffffffff811660c08601525060c085015163ffffffff811660e08601525060e0850151610100614be0818701836bffffffffffffffffffffffff169052565b8601519050610120614bf58682018315159052565b8601518584037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe001838701529050614c2d83826148de565b9695505050505050565b60008060208385031215614c4a57600080fd5b823567ffffffffffffffff811115614c6157600080fd5b614c6d85828601614a0b565b90969095509350505050565b60008060408385031215614c8c57600080fd5b823567ffffffffffffffff80821115614ca457600080fd5b908401906101008287031215614cb957600080fd5b90925060208401359080821115614ccf57600080fd5b5061489785828601614702565b8215158152604060208201526000611cec60408301846148de565b60008083601f840112614d0957600080fd5b50813567ffffffffffffffff811115614d2157600080fd5b60208301915083602082850101111561179957600080fd5b60008060208385031215614d4c57600080fd5b823567ffffffffffffffff811115614d6357600080fd5b614c6d85828601614cf7565b6020808252825182820181905260009190848201906040850190845b81811015614da757835183529284019291840191600101614d8b565b50909695505050505050565b600067ffffffffffffffff821115614dcd57614dcd614614565b5060051b60200190565b60008060408385031215614dea57600080fd5b823567ffffffffffffffff80821115614e0257600080fd5b818501915085601f830112614e1657600080fd5b81356020614e2661472183614db3565b82815260059290921b84018101918181019089841115614e4557600080fd5b8286015b84811015614e7d57803586811115614e615760008081fd5b614e6f8c86838b0101614702565b845250918301918301614e49565b5096505086013592505080821115614ccf57600080fd5b600080600060408486031215614ea957600080fd5b833567ffffffffffffffff811115614ec057600080fd5b614ecc86828701614a0b565b9094509250506020840135614ee081614602565b809150509250925092565b60008060408385031215614efe57600080fd5b50508035926020909101359150565b600080600060408486031215614f2257600080fd5b83359250602084013567ffffffffffffffff811115614f4057600080fd5b614f4c86828701614cf7565b9497909650939450505050565b60008060408385031215614f6c57600080fd5b823567ffffffffffffffff80821115614f8457600080fd5b614f9086838701614702565b93506020850135915080821115614ccf57600080fd5b60006020808385031215614fb957600080fd5b823567ffffffffffffffff80821115614fd157600080fd5b818501915085601f830112614fe557600080fd5b8135614ff361472182614db3565b81815260059190911b8301840190848101908883111561501257600080fd5b8585015b8381101561504a5780358581111561502e5760008081fd5b61503c8b89838a0101614702565b845250918601918601615016565b5098975050505050505050565b6000806040838503121561506a57600080fd5b82359150602083013561507c81614758565b809150509250929050565b60006020828403121561509957600080fd5b8135611cef816145f3565b600080604083850312156150b757600080fd5b82359150602083013561507c81614602565b600080604083850312156150dc57600080fd5b82359150602083013561507c816145f3565b6000806000806060858703121561510457600080fd5b843567ffffffffffffffff81111561511b57600080fd5b61512787828801614a0b565b909550935050602085013561513b816145f3565b9150604085013561514b816145f3565b939692955090935050565b60008060008060008060c0878903121561516f57600080fd5b863561517a8161493b565b9550602087013561518a816145f3565b95989597505050506040840135936060810135936080820135935060a0909101359150565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60006bffffffffffffffffffffffff80831681851681830481118215151615615209576152096151af565b02949350505050565b8051801515811461482057600080fd5b60006020828403121561523457600080fd5b611cef82615212565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b600060ff821660ff8103615282576152826151af565b60010192915050565b828152604060208201526000611cec60408301846148de565b600082601f8301126152b557600080fd5b81516152c3614721826146bc565b8181528460208386010111156152d857600080fd5b6152e98260208301602087016148ba565b949350505050565b60006020828403121561530357600080fd5b815167ffffffffffffffff81111561531a57600080fd5b6152e9848285016152a4565b805161482081614758565b60006020828403121561534357600080fd5b8151611cef81614758565b80516148208161493b565b6000806040838503121561536c57600080fd5b82516153778161493b565b6020939093015192949293505050565b60006020828403121561539957600080fd5b8151611cef8161493b565b6000602082840312156153b657600080fd5b8151611cef816145f3565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82036153f2576153f26151af565b5060010190565b805161482081614602565b805167ffffffffffffffff8116811461482057600080fd5b60006020828403121561542e57600080fd5b815167ffffffffffffffff8082111561544657600080fd5b90830190610140828603121561545b57600080fd5b615463614643565b61546c8361534e565b815261547a602084016153f9565b602082015260408301518281111561549157600080fd5b61549d878286016152a4565b6040830152506154af60608401615326565b60608201526154c06080840161534e565b60808201526154d160a08401615404565b60a08201526154e260c084016153f9565b60c08201526154f360e08401615326565b60e0820152610100615506818501615212565b90820152610120838101518381111561551e57600080fd5b61552a888287016152a4565b918301919091525095945050505050565b80820180821115611545576115456151af565b600061ffff808316818103615565576155656151af565b6001019392505050565b60006020828403121561558157600080fd5b5051919050565b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe18436030181126155bd57600080fd5b83018035915067ffffffffffffffff8211156155d857600080fd5b6020019150600581901b360382131561179957600080fd5b81810381811115611545576115456151af565b600181811c9082168061561757607f821691505b602082108103615650577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b50919050565b6000815461566381615603565b80855260206001838116801561568057600181146156b8576156e6565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff008516838901528284151560051b89010195506156e6565b866000528260002060005b858110156156de5781548a82018601529083019084016156c3565b890184019650505b505050505092915050565b60a08152600061570460a0830188615656565b6020838203818501528188548084528284019150828160051b8501018a6000528360002060005b83811015615776577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08784030185526157648383615656565b9486019492506001918201910161572b565b5050868103604088015261578a818b615656565b94505050505084606084015282810360808401526157a881856148de565b98975050505050505050565b6000604082016040835280855180835260608501915060608160051b8601019250602080880160005b83811015615829577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa08887030185526158178683516148de565b955093820193908201906001016157dd565b50508584038187015250505061583f81856148de565b95945050505050565b60008060006060848603121561585d57600080fd5b83519250602084015191506040840151614ee08161493b565b83815260406020820152816040820152818360608301376000818301606090810191909152601f9092017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016010192915050565b601f821115612ce257600081815260208120601f850160051c810160208610156158f15750805b601f850160051c820191505b81811015611486578281556001016158fd565b815167ffffffffffffffff81111561592a5761592a614614565b61593e816159388454615603565b846158ca565b602080601f831160018114615991576000841561595b5750858301515b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600386901b1c1916600185901b178555611486565b6000858152602081207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08616915b828110156159de578886015182559484019460019091019084016159bf565b5085821015615a1a57878501517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600388901b60f8161c191681555b5050505050600190811b01905550565b60006020808385031215615a3d57600080fd5b825167ffffffffffffffff811115615a5457600080fd5b8301601f81018513615a6557600080fd5b8051615a7361472182614db3565b81815260059190911b82018301908381019087831115615a9257600080fd5b928401925b82841015615ab057835182529284019290840190615a97565b979650505050505050565b600063ffffffff808316818103615565576155656151af565b80516020808301519190811015615650577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60209190910360031b1b16919050565b6020815260008251610140806020850152615b356101608501836148de565b915060208501517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe080868503016040870152615b7184836148de565b935060408701519150615b9c606087018373ffffffffffffffffffffffffffffffffffffffff169052565b606087015163ffffffff811660808801529150608087015173ffffffffffffffffffffffffffffffffffffffff811660a0880152915060a087015160ff811660c0880152915060c08701519150808685030160e0870152615bfd84836148de565b935060e08701519150610100818786030181880152615c1c85846148de565b945080880151925050610120818786030181880152615c3b85846148de565b94508088015192505050615c5e828601826bffffffffffffffffffffffff169052565b5090949350505050565b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0483118215151615615ca057615ca06151af565b500290565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b600082615ce357615ce3615ca5565b500490565b8181036000831280158383131683831282161715614493576144936151af565b600082615d1757615d17615ca5565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff83147f800000000000000000000000000000000000000000000000000000000000000083141615615d6b57615d6b6151af565b500590565b8082018281126000831280158216821582161715615d9057615d906151af565b505092915050565b60007f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82036153f2576153f26151af565b60007f80000000000000000000000000000000000000000000000000000000000000008203615dfa57615dfa6151af565b507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0190565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fdfea164736f6c6343000810000a307834353534343832643535353334343264343135323432343935343532353534643264353434353533353434653435353430303030303030303030303030303030307834323534343332643535353334343264343135323432343935343532353534643264353434353533353434653435353430303030303030303030303030303030", + Bin: "0x7f97009585a4d2440f981ab6f6eec514343e1e6b2aa9b991a26998e6806f41bf086080527fc76416badc8398ce17c93eab7b4f60f263241694cf503e4df24f233a8cc1c50d60a0526005601455601580546001600160681b0319166c140000000002c68af0bb140000179055606460e0526101c0604052604261014081815261010091829190620066ec6101603981526020016040518060800160405280604281526020016200672e604291399052620000be906016906002620003de565b506040805180820190915260098152680cccacac892c890caf60bb1b6020820152601790620000ee90826200055a565b5060408051808201909152600b81526a313637b1b5a73ab6b132b960a91b60208201526018906200012090826200055a565b503480156200012e57600080fd5b506040516200677038038062006770833981016040819052620001519162000652565b82823380600081620001aa5760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b0384811691909117909155811615620001dd57620001dd8162000333565b5050601180546001600160a01b0319166001600160a01b038516908117909155604080516330fe427560e21b815281516000945063c3f909d4926004808401939192918290030181865afa1580156200023a573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200026091906200069e565b50601380546001600160a01b0319166001600160a01b038381169190911790915560115460408051631b6b6d2360e01b81529051939450911691631b6b6d23916004808201926020929091908290030181865afa158015620002c6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620002ec9190620006cf565b601280546001600160a01b0319166001600160a01b039290921691909117905550151560c052506019805461ffff191691151561ff00191691909117905550620006f69050565b336001600160a01b038216036200038d5760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c660000000000000000006044820152606401620001a1565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b82805482825590600052602060002090810192821562000429579160200282015b828111156200042957825182906200041890826200055a565b5091602001919060010190620003ff565b50620004379291506200043b565b5090565b80821115620004375760006200045282826200045c565b506001016200043b565b5080546200046a90620004cb565b6000825580601f106200047b575050565b601f0160209004906000526020600020908101906200049b91906200049e565b50565b5b808211156200043757600081556001016200049f565b634e487b7160e01b600052604160045260246000fd5b600181811c90821680620004e057607f821691505b6020821081036200050157634e487b7160e01b600052602260045260246000fd5b50919050565b601f8211156200055557600081815260208120601f850160051c81016020861015620005305750805b601f850160051c820191505b8181101562000551578281556001016200053c565b5050505b505050565b81516001600160401b03811115620005765762000576620004b5565b6200058e81620005878454620004cb565b8462000507565b602080601f831160018114620005c65760008415620005ad5750858301515b600019600386901b1c1916600185901b17855562000551565b600085815260208120601f198616915b82811015620005f757888601518255948401946001909101908401620005d6565b5085821015620006165787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b6001600160a01b03811681146200049b57600080fd5b805180151581146200064d57600080fd5b919050565b6000806000606084860312156200066857600080fd5b8351620006758162000626565b925062000685602085016200063c565b915062000695604085016200063c565b90509250925092565b60008060408385031215620006b257600080fd5b8251620006bf8162000626565b6020939093015192949293505050565b600060208284031215620006e257600080fd5b8151620006ef8162000626565b9392505050565b60805160a05160c05160e051615f926200075a600039600081816105b90152612551015260008181610a2d01526140920152600081816108a601528181611fa80152613ae0015260008181610dca01528181611f780152613ab50152615f926000f3fe6080604052600436106105265760003560e01c80637b103999116102af578063af953a4a11610179578063daee1aeb116100d6578063e83ce5581161008a578063fa333dfb1161006f578063fa333dfb14611066578063fba7ffa314611119578063fcdc1f631461114657600080fd5b8063e83ce55814611027578063f2fde38b1461104657600080fd5b8063de818253116100bb578063de81825314610f90578063e0114adb14610fe4578063e45530831461101157600080fd5b8063daee1aeb14610f50578063dbef701e14610f7057600080fd5b8063c41c815b1161012d578063d4c2490011610112578063d4c2490014610ef0578063d6051a7214610f10578063da6cba4714610f3057600080fd5b8063c41c815b14610ec1578063c98f10b014610edb57600080fd5b8063b657bc9c1161015e578063b657bc9c14610e61578063becde0e114610e81578063c041982214610ea157600080fd5b8063af953a4a14610e2c578063afb28d1f14610e4c57600080fd5b8063948108f7116102275780639d385eaa116101db578063a6548248116101c0578063a654824814610db8578063a6b5947514610dec578063a72aa27e14610e0c57600080fd5b80639d385eaa14610d785780639d6f1cc714610d9857600080fd5b80639ac542eb1161020c5780639ac542eb14610cf05780639b42935414610d1a5780639b51fb0d14610d4757600080fd5b8063948108f714610cb057806396cebc7c14610cd057600080fd5b806386e330af1161027e5780638da5cb5b116102635780638da5cb5b14610c385780638fcb3fba14610c63578063924ca57814610c9057600080fd5b806386e330af14610bf8578063873c758614610c1857600080fd5b80637b10399914610b6b5780637e7a46dc14610b985780638243444a14610bb85780638340507c14610bd857600080fd5b806345d2ec17116103f057806360457ff51161036857806373644cce1161031c578063776898c811610301578063776898c814610b1657806379ba509714610b3657806379ea994314610b4b57600080fd5b806373644cce14610abc5780637672130314610ae957600080fd5b8063642f6cef1161034d578063642f6cef14610a1b57806369cdbadb14610a5f5780637145f11b14610a8c57600080fd5b806360457ff5146109c9578063636092e8146109f657600080fd5b80635147cd59116103bf57806357970e93116103a457806357970e93146109675780635d4ee7f3146109945780635f17e616146109a957600080fd5b80635147cd591461091557806351c98be31461094757600080fd5b806345d2ec1714610867578063469820931461089457806346e7a63e146108c85780634b56a42e146108f557600080fd5b806320e3dbd41161049e5780632b20e397116104525780633ebe8d6c116104375780633ebe8d6c146107f957806340691db4146108195780634585e33b1461084757600080fd5b80632b20e3971461077a578063328ffd11146107cc57600080fd5b806328c4b57b1161048357806328c4b57b1461070d57806329e0a8411461072d5780632a9032d31461075a57600080fd5b806320e3dbd4146106cd5780632636aecf146106ed57600080fd5b806319d97a94116104f55780631e010439116104da5780631e0104391461063b578063206c32e814610678578063207b6516146106ad57600080fd5b806319d97a94146105ee5780631cdde2511461061b57600080fd5b806306c1cc0014610532578063077ac621146105545780630b7d33e61461058757806312c55027146105a757600080fd5b3661052d57005b600080fd5b34801561053e57600080fd5b5061055261054d366004614814565b611173565b005b34801561056057600080fd5b5061057461056f3660046148c7565b6113c2565b6040519081526020015b60405180910390f35b34801561059357600080fd5b506105526105a23660046148fc565b611400565b3480156105b357600080fd5b506105db7f000000000000000000000000000000000000000000000000000000000000000081565b60405161ffff909116815260200161057e565b3480156105fa57600080fd5b5061060e610609366004614943565b61148e565b60405161057e91906149ca565b34801561062757600080fd5b506105526106363660046149ff565b61154b565b34801561064757600080fd5b5061065b610656366004614943565b611688565b6040516bffffffffffffffffffffffff909116815260200161057e565b34801561068457600080fd5b50610698610693366004614a64565b61171d565b6040805192835260208301919091520161057e565b3480156106b957600080fd5b5061060e6106c8366004614943565b6117a0565b3480156106d957600080fd5b506105526106e8366004614a90565b6117f8565b3480156106f957600080fd5b50610552610708366004614af2565b6119c2565b34801561071957600080fd5b50610574610728366004614b6c565b611c8b565b34801561073957600080fd5b5061074d610748366004614943565b611cf6565b60405161057e9190614b98565b34801561076657600080fd5b50610552610775366004614cd9565b611dfb565b34801561078657600080fd5b506011546107a79073ffffffffffffffffffffffffffffffffffffffff1681565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200161057e565b3480156107d857600080fd5b506105746107e7366004614943565b60036020526000908152604090205481565b34801561080557600080fd5b50610574610814366004614943565b611edc565b34801561082557600080fd5b50610839610834366004614d1b565b611f45565b60405161057e929190614d7e565b34801561085357600080fd5b50610552610862366004614ddb565b61244b565b34801561087357600080fd5b50610887610882366004614a64565b61269a565b60405161057e9190614e11565b3480156108a057600080fd5b506105747f000000000000000000000000000000000000000000000000000000000000000081565b3480156108d457600080fd5b506105746108e3366004614943565b600a6020526000908152604090205481565b34801561090157600080fd5b50610839610910366004614e79565b612709565b34801561092157600080fd5b50610935610930366004614943565b61275d565b60405160ff909116815260200161057e565b34801561095357600080fd5b50610552610962366004614f36565b6127f1565b34801561097357600080fd5b506012546107a79073ffffffffffffffffffffffffffffffffffffffff1681565b3480156109a057600080fd5b50610552612895565b3480156109b557600080fd5b506105526109c4366004614f8d565b6129d0565b3480156109d557600080fd5b506105746109e4366004614943565b60076020526000908152604090205481565b348015610a0257600080fd5b5060155461065b906bffffffffffffffffffffffff1681565b348015610a2757600080fd5b50610a4f7f000000000000000000000000000000000000000000000000000000000000000081565b604051901515815260200161057e565b348015610a6b57600080fd5b50610574610a7a366004614943565b60086020526000908152604090205481565b348015610a9857600080fd5b50610a4f610aa7366004614943565b600b6020526000908152604090205460ff1681565b348015610ac857600080fd5b50610574610ad7366004614943565b6000908152600c602052604090205490565b348015610af557600080fd5b50610574610b04366004614943565b60046020526000908152604090205481565b348015610b2257600080fd5b50610a4f610b31366004614943565b612a9d565b348015610b4257600080fd5b50610552612aef565b348015610b5757600080fd5b506107a7610b66366004614943565b612bec565b348015610b7757600080fd5b506013546107a79073ffffffffffffffffffffffffffffffffffffffff1681565b348015610ba457600080fd5b50610552610bb3366004614faf565b612c80565b348015610bc457600080fd5b50610552610bd3366004614faf565b612d11565b348015610be457600080fd5b50610552610bf3366004614ffb565b612d6b565b348015610c0457600080fd5b50610552610c13366004615048565b612d89565b348015610c2457600080fd5b50610887610c33366004614f8d565b612d9c565b348015610c4457600080fd5b5060005473ffffffffffffffffffffffffffffffffffffffff166107a7565b348015610c6f57600080fd5b50610574610c7e366004614943565b60056020526000908152604090205481565b348015610c9c57600080fd5b50610552610cab366004614f8d565b612e59565b348015610cbc57600080fd5b50610552610ccb3660046150f9565b61309e565b348015610cdc57600080fd5b50610552610ceb366004615129565b6131b6565b348015610cfc57600080fd5b50601554610935906c01000000000000000000000000900460ff1681565b348015610d2657600080fd5b50610552610d35366004614f8d565b60009182526009602052604090912055565b348015610d5357600080fd5b506105db610d62366004614943565b600e6020526000908152604090205461ffff1681565b348015610d8457600080fd5b50610887610d93366004614943565b6133c0565b348015610da457600080fd5b5061060e610db3366004614943565b613422565b348015610dc457600080fd5b506105747f000000000000000000000000000000000000000000000000000000000000000081565b348015610df857600080fd5b50610552610e07366004614b6c565b6134ce565b348015610e1857600080fd5b50610552610e27366004615146565b613537565b348015610e3857600080fd5b50610552610e47366004614943565b6135e2565b348015610e5857600080fd5b5061060e613668565b348015610e6d57600080fd5b5061065b610e7c366004614943565b613675565b348015610e8d57600080fd5b50610552610e9c366004614cd9565b6136cd565b348015610ead57600080fd5b50610887610ebc366004614f8d565b613767565b348015610ecd57600080fd5b50601954610a4f9060ff1681565b348015610ee757600080fd5b5061060e613864565b348015610efc57600080fd5b50610552610f0b36600461516b565b613871565b348015610f1c57600080fd5b50610698610f2b366004614f8d565b6138f0565b348015610f3c57600080fd5b50610552610f4b366004615190565b613959565b348015610f5c57600080fd5b50610552610f6b366004614cd9565b613cc0565b348015610f7c57600080fd5b50610574610f8b366004614f8d565b613d8b565b348015610f9c57600080fd5b50610552610fab366004615129565b6019805460ff909216610100027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff909216919091179055565b348015610ff057600080fd5b50610574610fff366004614943565b60096020526000908152604090205481565b34801561101d57600080fd5b5061057460145481565b34801561103357600080fd5b5060195461093590610100900460ff1681565b34801561105257600080fd5b50610552611061366004614a90565b613dbc565b34801561107257600080fd5b5061060e6110813660046151f8565b6040805160c0808201835273ffffffffffffffffffffffffffffffffffffffff9890981680825260ff97881660208084019182528385019889526060808501988952608080860198895260a095860197885286519283019490945291519099168985015296519688019690965293519486019490945290519184019190915251828401528051808303909301835260e0909101905290565b34801561112557600080fd5b50610574611134366004614943565b60066020526000908152604090205481565b34801561115257600080fd5b50610574611161366004614943565b60026020526000908152604090205481565b6040805161018081018252600461014082019081527f746573740000000000000000000000000000000000000000000000000000000061016083015281528151602081810184526000808352818401929092523083850181905263ffffffff8b166060850152608084015260ff808a1660a08501528451808301865283815260c085015260e0840189905284519182019094529081526101008201526bffffffffffffffffffffffff8516610120820152601254601154919273ffffffffffffffffffffffffffffffffffffffff9182169263095ea7b3921690611259908c1688615280565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e085901b16815273ffffffffffffffffffffffffffffffffffffffff90921660048301526bffffffffffffffffffffffff1660248201526044016020604051808303816000875af11580156112d7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112fb91906152c4565b5060008860ff1667ffffffffffffffff81111561131a5761131a6146b6565b604051908082528060200260200182016040528015611343578160200160208202803683370190505b50905060005b8960ff168160ff1610156113b657600061136284613dd0565b905080838360ff168151811061137a5761137a6152df565b602090810291909101810191909152600091825260088152604080832088905560079091529020849055806113ae8161530e565b915050611349565b50505050505050505050565b600d60205282600052604060002060205281600052604060002081815481106113ea57600080fd5b9060005260206000200160009250925050505481565b6013546040517f0b7d33e600000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff90911690630b7d33e690611458908590859060040161532d565b600060405180830381600087803b15801561147257600080fd5b505af1158015611486573d6000803e3d6000fd5b505050505050565b6013546040517f19d97a940000000000000000000000000000000000000000000000000000000081526004810183905260609173ffffffffffffffffffffffffffffffffffffffff16906319d97a94906024015b600060405180830381865afa1580156114ff573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01682016040526115459190810190615393565b92915050565b6013546040517ffa333dfb00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff888116600483015260ff8816602483015260448201879052606482018690526084820185905260a4820184905290911690634ee88d35908990309063fa333dfb9060c401600060405180830381865afa1580156115ea573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01682016040526116309190810190615393565b6040518363ffffffff1660e01b815260040161164d92919061532d565b600060405180830381600087803b15801561166757600080fd5b505af115801561167b573d6000803e3d6000fd5b5050505050505050505050565b6013546040517f1e0104390000000000000000000000000000000000000000000000000000000081526004810183905260009173ffffffffffffffffffffffffffffffffffffffff1690631e010439906024015b602060405180830381865afa1580156116f9573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061154591906153d3565b6000828152600d6020908152604080832061ffff85168452825280832080548251818502810185019093528083528493849392919083018282801561178157602002820191906000526020600020905b81548152602001906001019080831161176d575b50505050509050611793818251613e9e565b92509250505b9250929050565b6013546040517f207b65160000000000000000000000000000000000000000000000000000000081526004810183905260609173ffffffffffffffffffffffffffffffffffffffff169063207b6516906024016114e2565b601180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff8316908117909155604080517fc3f909d400000000000000000000000000000000000000000000000000000000815281516000939263c3f909d492600480820193918290030181865afa15801561188e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118b291906153fb565b50601380547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83811691909117909155601154604080517f1b6b6d230000000000000000000000000000000000000000000000000000000081529051939450911691631b6b6d23916004808201926020929091908290030181865afa158015611955573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119799190615429565b601280547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff929092169190911790555050565b8560005b81811015611c805760008989838181106119e2576119e26152df565b9050602002013590503073ffffffffffffffffffffffffffffffffffffffff16637e7a46dc8283604051602001611a1b91815260200190565b6040516020818303038152906040526040518363ffffffff1660e01b8152600401611a4792919061532d565b600060405180830381600087803b158015611a6157600080fd5b505af1158015611a75573d6000803e3d6000fd5b50506013546040517f5147cd59000000000000000000000000000000000000000000000000000000008152600481018590526000935073ffffffffffffffffffffffffffffffffffffffff9091169150635147cd5990602401602060405180830381865afa158015611aeb573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b0f9190615446565b90508060ff16600103611c6b576040517ffa333dfb000000000000000000000000000000000000000000000000000000008152306004820181905260ff8b166024830152604482018a9052606482018890526084820188905260a4820187905260009163fa333dfb9060c401600060405180830381865afa158015611b98573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201604052611bde9190810190615393565b6013546040517f4ee88d3500000000000000000000000000000000000000000000000000000000815291925073ffffffffffffffffffffffffffffffffffffffff1690634ee88d3590611c37908690859060040161532d565b600060405180830381600087803b158015611c5157600080fd5b505af1158015611c65573d6000803e3d6000fd5b50505050505b50508080611c7890615463565b9150506119c6565b505050505050505050565b6000838152600c602090815260408083208054825181850281018501909352808352611cec93830182828015611ce057602002820191906000526020600020905b815481526020019060010190808311611ccc575b50505050508484613f23565b90505b9392505050565b604080516101408101825260008082526020820181905260609282018390528282018190526080820181905260a0820181905260c0820181905260e082018190526101008201526101208101919091526013546040517fc7c3a19a0000000000000000000000000000000000000000000000000000000081526004810184905273ffffffffffffffffffffffffffffffffffffffff9091169063c7c3a19a90602401600060405180830381865afa158015611db5573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016820160405261154591908101906154be565b8060005b818160ff161015611ed65760135473ffffffffffffffffffffffffffffffffffffffff1663c8048022858560ff8516818110611e3d57611e3d6152df565b905060200201356040518263ffffffff1660e01b8152600401611e6291815260200190565b600060405180830381600087803b158015611e7c57600080fd5b505af1158015611e90573d6000803e3d6000fd5b50505050611ec384848360ff16818110611eac57611eac6152df565b90506020020135600f61408290919063ffffffff16565b5080611ece8161530e565b915050611dff565b50505050565b6000818152600e602052604081205461ffff1681805b8261ffff168161ffff1611611f3d576000858152600d6020908152604080832061ffff85168452909152902054611f2990836155dd565b915080611f35816155f0565b915050611ef2565b509392505050565b6000606060005a90506000611f5861408e565b9050600085806020019051810190611f709190615611565b6019549091507f000000000000000000000000000000000000000000000000000000000000000090610100900460ff1615611fc857507f00000000000000000000000000000000000000000000000000000000000000005b80611fd660c08a018a61562a565b6000818110611fe757611fe76152df565b90506020020135036123e957600061200260c08a018a61562a565b6001818110612013576120136152df565b9050602002013560405160200161202c91815260200190565b60405160208183030381529060405290506000818060200190518101906120539190615611565b90508381146120c3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f75706b6565702069647320646f6e2774206d617463680000000000000000000060448201526064015b60405180910390fd5b60006120d260c08c018c61562a565b60028181106120e3576120e36152df565b905060200201356040516020016120fc91815260200190565b60405160208183030381529060405290506000818060200190518101906121239190615611565b9050600061213460c08e018e61562a565b6003818110612145576121456152df565b9050602002013560405160200161215e91815260200190565b60405160208183030381529060405290506000818060200190518101906121859190615429565b6000868152600860205260409020549091505b805a6121a4908d615692565b6121b090613a986155dd565b10156121f15783406000908152600b6020526040902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169055612198565b6040517f6665656449644865780000000000000000000000000000000000000000000000602082015260009060290160405160208183030381529060405280519060200120601860405160200161224891906156f8565b604051602081830303815290604052805190602001200361226a57508361226d565b50425b60195460ff161561231557604080516020810189905290810186905273ffffffffffffffffffffffffffffffffffffffff841660608201526017906016906018908490608001604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152908290527ff055e4a20000000000000000000000000000000000000000000000000000000082526120ba9594939291600401615827565b60165460009067ffffffffffffffff811115612333576123336146b6565b60405190808252806020026020018201604052801561236657816020015b60608152602001906001900390816123515790505b5060408051602081018b905290810188905273ffffffffffffffffffffffffffffffffffffffff861660608201529091506000906080016040516020818303038152906040529050600182826040516020016123c39291906158ea565b6040516020818303038152906040529f509f505050505050505050505050505050611799565b6040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f756e6578706563746564206576656e742073696700000000000000000000000060448201526064016120ba565b60005a905060008061245f84860186614e79565b9150915060008060008380602001905181019061247c919061597e565b60008381526005602090815260408083205460049092528220549497509295509093509091906124aa61408e565b9050826000036124ca57600086815260056020526040902081905561260e565b60006124d68683615692565b6000888152600e6020908152604080832054600d835281842061ffff90911680855290835281842080548351818602810186019094528084529596509094919290919083018282801561254857602002820191906000526020600020905b815481526020019060010190808311612534575b505050505090507f000000000000000000000000000000000000000000000000000000000000000061ffff168151036125c35781612585816155f0565b60008b8152600e6020526040902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00001661ffff83161790559250505b506000888152600d6020908152604080832061ffff9094168352928152828220805460018181018355918452828420018590558a8352600c8252928220805493840181558252902001555b6000868152600660205260408120546126289060016155dd565b60008881526006602090815260408083208490556004909152902083905590506126528783612e59565b6040513090839089907f97009585a4d2440f981ab6f6eec514343e1e6b2aa9b991a26998e6806f41bf0890600090a461268c878b846134ce565b505050505050505050505050565b6000828152600d6020908152604080832061ffff851684528252918290208054835181840281018401909452808452606093928301828280156126fc57602002820191906000526020600020905b8154815260200190600101908083116126e8575b5050505050905092915050565b60006060600084846040516020016127229291906158ea565b604080518083037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe00181529190526001969095509350505050565b6013546040517f5147cd590000000000000000000000000000000000000000000000000000000081526004810183905260009173ffffffffffffffffffffffffffffffffffffffff1690635147cd5990602401602060405180830381865afa1580156127cd573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115459190615446565b8160005b8181101561288e5730635f17e616868684818110612815576128156152df565b90506020020135856040518363ffffffff1660e01b815260040161284992919091825263ffffffff16602082015260400190565b600060405180830381600087803b15801561286357600080fd5b505af1158015612877573d6000803e3d6000fd5b50505050808061288690615463565b9150506127f5565b5050505050565b61289d614130565b6012546040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015260009173ffffffffffffffffffffffffffffffffffffffff16906370a0823190602401602060405180830381865afa15801561290c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906129309190615611565b6012546040517fa9059cbb0000000000000000000000000000000000000000000000000000000081523360048201526024810183905291925073ffffffffffffffffffffffffffffffffffffffff169063a9059cbb906044016020604051808303816000875af11580156129a8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906129cc91906152c4565b5050565b60008281526003602090815260408083208490556005825280832083905560068252808320839055600c9091528120612a08916145b5565b6000828152600e602052604081205461ffff16905b8161ffff168161ffff1611612a64576000848152600d6020908152604080832061ffff851684529091528120612a52916145b5565b80612a5c816155f0565b915050612a1d565b5050506000908152600e6020526040902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000169055565b6000818152600560205260408120548103612aba57506001919050565b600082815260036020908152604080832054600490925290912054612add61408e565b612ae79190615692565b101592915050565b60015473ffffffffffffffffffffffffffffffffffffffff163314612b70576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e65720000000000000000000060448201526064016120ba565b60008054337fffffffffffffffffffffffff00000000000000000000000000000000000000008083168217845560018054909116905560405173ffffffffffffffffffffffffffffffffffffffff90921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b6013546040517f79ea99430000000000000000000000000000000000000000000000000000000081526004810183905260009173ffffffffffffffffffffffffffffffffffffffff16906379ea994390602401602060405180830381865afa158015612c5c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115459190615429565b6013546040517fcd7f71b500000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff9091169063cd7f71b590612cda908690869086906004016159ac565b600060405180830381600087803b158015612cf457600080fd5b505af1158015612d08573d6000803e3d6000fd5b50505050505050565b6013546040517f4ee88d3500000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff90911690634ee88d3590612cda908690869086906004016159ac565b6017612d778382615a46565b506018612d848282615a46565b505050565b80516129cc9060169060208401906145d3565b6013546040517f06e3b632000000000000000000000000000000000000000000000000000000008152600481018490526024810183905260609173ffffffffffffffffffffffffffffffffffffffff16906306e3b63290604401600060405180830381865afa158015612e13573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201604052611cef9190810190615b60565b601454600083815260026020526040902054612e759083615692565b11156129cc576013546040517fc7c3a19a0000000000000000000000000000000000000000000000000000000081526004810184905260009173ffffffffffffffffffffffffffffffffffffffff169063c7c3a19a90602401600060405180830381865afa158015612eeb573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201604052612f3191908101906154be565b6013546040517fb657bc9c0000000000000000000000000000000000000000000000000000000081526004810186905291925060009173ffffffffffffffffffffffffffffffffffffffff9091169063b657bc9c90602401602060405180830381865afa158015612fa6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612fca91906153d3565b601554909150612fee9082906c01000000000000000000000000900460ff16615280565b6bffffffffffffffffffffffff1682606001516bffffffffffffffffffffffff161015611ed6576015546130319085906bffffffffffffffffffffffff1661309e565b60008481526002602090815260409182902085905560155482518781526bffffffffffffffffffffffff909116918101919091529081018490527f49d4100ab0124eb4a9a65dc4ea08d6412a43f6f05c49194983f5b322bcc0a5c09060600160405180910390a150505050565b6012546013546040517f095ea7b300000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff91821660048201526bffffffffffffffffffffffff8416602482015291169063095ea7b3906044016020604051808303816000875af1158015613126573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061314a91906152c4565b506013546040517f948108f7000000000000000000000000000000000000000000000000000000008152600481018490526bffffffffffffffffffffffff8316602482015273ffffffffffffffffffffffffffffffffffffffff9091169063948108f790604401611458565b6040517fc04198220000000000000000000000000000000000000000000000000000000081526000600482018190526024820181905290309063c041982290604401600060405180830381865afa158015613215573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016820160405261325b9190810190615b60565b8051909150600061326a61408e565b905060005b8281101561288e57600084828151811061328b5761328b6152df565b60209081029190910101516013546040517f5147cd590000000000000000000000000000000000000000000000000000000081526004810183905291925060009173ffffffffffffffffffffffffffffffffffffffff90911690635147cd5990602401602060405180830381865afa15801561330b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061332f9190615446565b90508060ff166001036133ab578660ff1660000361337b576040513090859084907f97009585a4d2440f981ab6f6eec514343e1e6b2aa9b991a26998e6806f41bf0890600090a46133ab565b6040513090859084907fc76416badc8398ce17c93eab7b4f60f263241694cf503e4df24f233a8cc1c50d90600090a45b505080806133b890615463565b91505061326f565b6000818152600c602090815260409182902080548351818402810184019094528084526060939283018282801561341657602002820191906000526020600020905b815481526020019060010190808311613402575b50505050509050919050565b6016818154811061343257600080fd5b90600052602060002001600091509050805461344d906156a5565b80601f0160208091040260200160405190810160405280929190818152602001828054613479906156a5565b80156134c65780601f1061349b576101008083540402835291602001916134c6565b820191906000526020600020905b8154815290600101906020018083116134a957829003601f168201915b505050505081565b6000838152600760205260409020545b805a6134ea9085615692565b6134f6906127106155dd565b1015611ed65781406000908152600b6020526040902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001690556134de565b6013546040517fa72aa27e0000000000000000000000000000000000000000000000000000000081526004810184905263ffffffff8316602482015273ffffffffffffffffffffffffffffffffffffffff9091169063a72aa27e90604401600060405180830381600087803b1580156135af57600080fd5b505af11580156135c3573d6000803e3d6000fd5b505050600092835250600a602052604090912063ffffffff9091169055565b6013546040517f744bfe610000000000000000000000000000000000000000000000000000000081526004810183905230602482015273ffffffffffffffffffffffffffffffffffffffff9091169063744bfe6190604401600060405180830381600087803b15801561365457600080fd5b505af115801561288e573d6000803e3d6000fd5b6017805461344d906156a5565b6013546040517fb657bc9c0000000000000000000000000000000000000000000000000000000081526004810183905260009173ffffffffffffffffffffffffffffffffffffffff169063b657bc9c906024016116dc565b8060005b818163ffffffff161015611ed6573063af953a4a858563ffffffff85168181106136fd576136fd6152df565b905060200201356040518263ffffffff1660e01b815260040161372291815260200190565b600060405180830381600087803b15801561373c57600080fd5b505af1158015613750573d6000803e3d6000fd5b50505050808061375f90615bf1565b9150506136d1565b60606000613775600f6141b3565b90508084106137b0576040517f1390f2a100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b826000036137c5576137c28482615692565b92505b60008367ffffffffffffffff8111156137e0576137e06146b6565b604051908082528060200260200182016040528015613809578160200160208202803683370190505b50905060005b8481101561385b5761382c61382482886155dd565b600f906141bd565b82828151811061383e5761383e6152df565b60209081029190910101528061385381615463565b91505061380f565b50949350505050565b6018805461344d906156a5565b600061387b61408e565b90508160ff166000036138bc576040513090829085907f97009585a4d2440f981ab6f6eec514343e1e6b2aa9b991a26998e6806f41bf0890600090a4505050565b6040513090829085907fc76416badc8398ce17c93eab7b4f60f263241694cf503e4df24f233a8cc1c50d90600090a4505050565b6000828152600c6020908152604080832080548251818502810185019093528083528493849392919083018282801561394857602002820191906000526020600020905b815481526020019060010190808311613934575b505050505090506117938185613e9e565b8260005b81811015611486576000868683818110613979576139796152df565b9050602002013590503073ffffffffffffffffffffffffffffffffffffffff16637e7a46dc82836040516020016139b291815260200190565b6040516020818303038152906040526040518363ffffffff1660e01b81526004016139de92919061532d565b600060405180830381600087803b1580156139f857600080fd5b505af1158015613a0c573d6000803e3d6000fd5b50506013546040517f5147cd59000000000000000000000000000000000000000000000000000000008152600481018590526000935073ffffffffffffffffffffffffffffffffffffffff9091169150635147cd5990602401602060405180830381865afa158015613a82573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613aa69190615446565b90508060ff16600103613cab577f000000000000000000000000000000000000000000000000000000000000000060ff871615613b0057507f00000000000000000000000000000000000000000000000000000000000000005b60003073ffffffffffffffffffffffffffffffffffffffff1663fa333dfb30898588604051602001613b3491815260200190565b604051602081830303815290604052613b4c90615c0a565b60405160e086901b7fffffffff0000000000000000000000000000000000000000000000000000000016815273ffffffffffffffffffffffffffffffffffffffff909416600485015260ff90921660248401526044830152606482015260006084820181905260a482015260c401600060405180830381865afa158015613bd7573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201604052613c1d9190810190615393565b6013546040517f4ee88d3500000000000000000000000000000000000000000000000000000000815291925073ffffffffffffffffffffffffffffffffffffffff1690634ee88d3590613c76908790859060040161532d565b600060405180830381600087803b158015613c9057600080fd5b505af1158015613ca4573d6000803e3d6000fd5b5050505050505b50508080613cb890615463565b91505061395d565b8060005b81811015611ed6576000848483818110613ce057613ce06152df565b9050602002013590503073ffffffffffffffffffffffffffffffffffffffff16637e7a46dc8283604051602001613d1991815260200190565b6040516020818303038152906040526040518363ffffffff1660e01b8152600401613d4592919061532d565b600060405180830381600087803b158015613d5f57600080fd5b505af1158015613d73573d6000803e3d6000fd5b50505050508080613d8390615463565b915050613cc4565b600c6020528160005260406000208181548110613da757600080fd5b90600052602060002001600091509150505481565b613dc4614130565b613dcd816141c9565b50565b6011546040517f3f678e11000000000000000000000000000000000000000000000000000000008152600091829173ffffffffffffffffffffffffffffffffffffffff90911690633f678e1190613e2b908690600401615c4c565b6020604051808303816000875af1158015613e4a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613e6e9190615611565b9050613e7b600f826142be565b506060909201516000838152600a6020526040902063ffffffff90911690555090565b815160009081908190841580613eb45750808510155b15613ebd578094505b60008092505b85831015613f1957866001613ed88585615692565b613ee29190615692565b81518110613ef257613ef26152df565b602002602001015181613f0591906155dd565b905082613f1181615463565b935050613ec3565b9694955050505050565b82516000908190831580613f375750808410155b15613f40578093505b60008467ffffffffffffffff811115613f5b57613f5b6146b6565b604051908082528060200260200182016040528015613f84578160200160208202803683370190505b509050600092505b84831015613ff257866001613fa18585615692565b613fab9190615692565b81518110613fbb57613fbb6152df565b6020026020010151818481518110613fd557613fd56152df565b602090810291909101015282613fea81615463565b935050613f8c565b61400b816000600184516140069190615692565b6142ca565b856064036140445780600182516140229190615692565b81518110614032576140326152df565b60200260200101519350505050611cef565b8060648251886140549190615d9e565b61405e9190615e0a565b8151811061406e5761406e6152df565b602002602001015193505050509392505050565b6000611cef8383614442565b60007f00000000000000000000000000000000000000000000000000000000000000001561412b57606473ffffffffffffffffffffffffffffffffffffffff1663a3b1b31d6040518163ffffffff1660e01b8152600401602060405180830381865afa158015614102573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906141269190615611565b905090565b504390565b60005473ffffffffffffffffffffffffffffffffffffffff1633146141b1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e65720000000000000000000060448201526064016120ba565b565b6000611545825490565b6000611cef838361453c565b3373ffffffffffffffffffffffffffffffffffffffff821603614248576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c6600000000000000000060448201526064016120ba565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b6000611cef8383614566565b81818082036142da575050505050565b60008560026142e98787615e1e565b6142f39190615e3e565b6142fd9087615ea6565b8151811061430d5761430d6152df565b602002602001015190505b81831361441c575b80868481518110614333576143336152df565b60200260200101511015614353578261434b81615ece565b935050614320565b858281518110614365576143656152df565b6020026020010151811015614386578161437e81615eff565b925050614353565b8183136144175785828151811061439f5761439f6152df565b60200260200101518684815181106143b9576143b96152df565b60200260200101518785815181106143d3576143d36152df565b602002602001018885815181106143ec576143ec6152df565b6020908102919091010191909152528261440581615ece565b935050818061441390615eff565b9250505b614318565b8185121561442f5761442f8686846142ca565b83831215611486576114868684866142ca565b6000818152600183016020526040812054801561452b576000614466600183615692565b855490915060009061447a90600190615692565b90508181146144df57600086600001828154811061449a5761449a6152df565b90600052602060002001549050808760000184815481106144bd576144bd6152df565b6000918252602080832090910192909255918252600188019052604090208390555b85548690806144f0576144f0615f56565b600190038181906000526020600020016000905590558560010160008681526020019081526020016000206000905560019350505050611545565b6000915050611545565b5092915050565b6000826000018281548110614553576145536152df565b9060005260206000200154905092915050565b60008181526001830160205260408120546145ad57508154600181810184556000848152602080822090930184905584548482528286019093526040902091909155611545565b506000611545565b5080546000825590600052602060002090810190613dcd9190614629565b828054828255906000526020600020908101928215614619579160200282015b8281111561461957825182906146099082615a46565b50916020019190600101906145f3565b5061462592915061463e565b5090565b5b80821115614625576000815560010161462a565b80821115614625576000614652828261465b565b5060010161463e565b508054614667906156a5565b6000825580601f10614677575050565b601f016020900490600052602060002090810190613dcd9190614629565b60ff81168114613dcd57600080fd5b63ffffffff81168114613dcd57600080fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051610140810167ffffffffffffffff81118282101715614709576147096146b6565b60405290565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715614756576147566146b6565b604052919050565b600067ffffffffffffffff821115614778576147786146b6565b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b600082601f8301126147b557600080fd5b81356147c86147c38261475e565b61470f565b8181528460208386010111156147dd57600080fd5b816020850160208301376000918101602001919091529392505050565b6bffffffffffffffffffffffff81168114613dcd57600080fd5b600080600080600080600060e0888a03121561482f57600080fd5b873561483a81614695565b9650602088013561484a816146a4565b9550604088013561485a81614695565b9450606088013567ffffffffffffffff81111561487657600080fd5b6148828a828b016147a4565b9450506080880135614893816147fa565b9699959850939692959460a0840135945060c09093013592915050565b803561ffff811681146148c257600080fd5b919050565b6000806000606084860312156148dc57600080fd5b833592506148ec602085016148b0565b9150604084013590509250925092565b6000806040838503121561490f57600080fd5b82359150602083013567ffffffffffffffff81111561492d57600080fd5b614939858286016147a4565b9150509250929050565b60006020828403121561495557600080fd5b5035919050565b60005b8381101561497757818101518382015260200161495f565b50506000910152565b6000815180845261499881602086016020860161495c565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b602081526000611cef6020830184614980565b73ffffffffffffffffffffffffffffffffffffffff81168114613dcd57600080fd5b600080600080600080600060e0888a031215614a1a57600080fd5b873596506020880135614a2c816149dd565b95506040880135614a3c81614695565b969995985095966060810135965060808101359560a0820135955060c0909101359350915050565b60008060408385031215614a7757600080fd5b82359150614a87602084016148b0565b90509250929050565b600060208284031215614aa257600080fd5b8135611cef816149dd565b60008083601f840112614abf57600080fd5b50813567ffffffffffffffff811115614ad757600080fd5b6020830191508360208260051b850101111561179957600080fd5b600080600080600080600060c0888a031215614b0d57600080fd5b873567ffffffffffffffff811115614b2457600080fd5b614b308a828b01614aad565b9098509650506020880135614b4481614695565b96999598509596604081013596506060810135956080820135955060a0909101359350915050565b600080600060608486031215614b8157600080fd5b505081359360208301359350604090920135919050565b60208152614bbf60208201835173ffffffffffffffffffffffffffffffffffffffff169052565b60006020830151614bd8604084018263ffffffff169052565b506040830151610140806060850152614bf5610160850183614980565b91506060850151614c1660808601826bffffffffffffffffffffffff169052565b50608085015173ffffffffffffffffffffffffffffffffffffffff811660a08601525060a085015167ffffffffffffffff811660c08601525060c085015163ffffffff811660e08601525060e0850151610100614c82818701836bffffffffffffffffffffffff169052565b8601519050610120614c978682018315159052565b8601518584037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe001838701529050614ccf8382614980565b9695505050505050565b60008060208385031215614cec57600080fd5b823567ffffffffffffffff811115614d0357600080fd5b614d0f85828601614aad565b90969095509350505050565b60008060408385031215614d2e57600080fd5b823567ffffffffffffffff80821115614d4657600080fd5b908401906101008287031215614d5b57600080fd5b90925060208401359080821115614d7157600080fd5b50614939858286016147a4565b8215158152604060208201526000611cec6040830184614980565b60008083601f840112614dab57600080fd5b50813567ffffffffffffffff811115614dc357600080fd5b60208301915083602082850101111561179957600080fd5b60008060208385031215614dee57600080fd5b823567ffffffffffffffff811115614e0557600080fd5b614d0f85828601614d99565b6020808252825182820181905260009190848201906040850190845b81811015614e4957835183529284019291840191600101614e2d565b50909695505050505050565b600067ffffffffffffffff821115614e6f57614e6f6146b6565b5060051b60200190565b60008060408385031215614e8c57600080fd5b823567ffffffffffffffff80821115614ea457600080fd5b818501915085601f830112614eb857600080fd5b81356020614ec86147c383614e55565b82815260059290921b84018101918181019089841115614ee757600080fd5b8286015b84811015614f1f57803586811115614f035760008081fd5b614f118c86838b01016147a4565b845250918301918301614eeb565b5096505086013592505080821115614d7157600080fd5b600080600060408486031215614f4b57600080fd5b833567ffffffffffffffff811115614f6257600080fd5b614f6e86828701614aad565b9094509250506020840135614f82816146a4565b809150509250925092565b60008060408385031215614fa057600080fd5b50508035926020909101359150565b600080600060408486031215614fc457600080fd5b83359250602084013567ffffffffffffffff811115614fe257600080fd5b614fee86828701614d99565b9497909650939450505050565b6000806040838503121561500e57600080fd5b823567ffffffffffffffff8082111561502657600080fd5b615032868387016147a4565b93506020850135915080821115614d7157600080fd5b6000602080838503121561505b57600080fd5b823567ffffffffffffffff8082111561507357600080fd5b818501915085601f83011261508757600080fd5b81356150956147c382614e55565b81815260059190911b830184019084810190888311156150b457600080fd5b8585015b838110156150ec578035858111156150d05760008081fd5b6150de8b89838a01016147a4565b8452509186019186016150b8565b5098975050505050505050565b6000806040838503121561510c57600080fd5b82359150602083013561511e816147fa565b809150509250929050565b60006020828403121561513b57600080fd5b8135611cef81614695565b6000806040838503121561515957600080fd5b82359150602083013561511e816146a4565b6000806040838503121561517e57600080fd5b82359150602083013561511e81614695565b600080600080606085870312156151a657600080fd5b843567ffffffffffffffff8111156151bd57600080fd5b6151c987828801614aad565b90955093505060208501356151dd81614695565b915060408501356151ed81614695565b939692955090935050565b60008060008060008060c0878903121561521157600080fd5b863561521c816149dd565b9550602087013561522c81614695565b95989597505050506040840135936060810135936080820135935060a0909101359150565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60006bffffffffffffffffffffffff808316818516818304811182151516156152ab576152ab615251565b02949350505050565b805180151581146148c257600080fd5b6000602082840312156152d657600080fd5b611cef826152b4565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b600060ff821660ff810361532457615324615251565b60010192915050565b828152604060208201526000611cec6040830184614980565b600082601f83011261535757600080fd5b81516153656147c38261475e565b81815284602083860101111561537a57600080fd5b61538b82602083016020870161495c565b949350505050565b6000602082840312156153a557600080fd5b815167ffffffffffffffff8111156153bc57600080fd5b61538b84828501615346565b80516148c2816147fa565b6000602082840312156153e557600080fd5b8151611cef816147fa565b80516148c2816149dd565b6000806040838503121561540e57600080fd5b8251615419816149dd565b6020939093015192949293505050565b60006020828403121561543b57600080fd5b8151611cef816149dd565b60006020828403121561545857600080fd5b8151611cef81614695565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff820361549457615494615251565b5060010190565b80516148c2816146a4565b805167ffffffffffffffff811681146148c257600080fd5b6000602082840312156154d057600080fd5b815167ffffffffffffffff808211156154e857600080fd5b9083019061014082860312156154fd57600080fd5b6155056146e5565b61550e836153f0565b815261551c6020840161549b565b602082015260408301518281111561553357600080fd5b61553f87828601615346565b604083015250615551606084016153c8565b6060820152615562608084016153f0565b608082015261557360a084016154a6565b60a082015261558460c0840161549b565b60c082015261559560e084016153c8565b60e08201526101006155a88185016152b4565b9082015261012083810151838111156155c057600080fd5b6155cc88828701615346565b918301919091525095945050505050565b8082018082111561154557611545615251565b600061ffff80831681810361560757615607615251565b6001019392505050565b60006020828403121561562357600080fd5b5051919050565b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe184360301811261565f57600080fd5b83018035915067ffffffffffffffff82111561567a57600080fd5b6020019150600581901b360382131561179957600080fd5b8181038181111561154557611545615251565b600181811c908216806156b957607f821691505b6020821081036156f2577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b50919050565b6000808354615706816156a5565b6001828116801561571e576001811461575157615780565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0084168752821515830287019450615780565b8760005260208060002060005b858110156157775781548a82015290840190820161575e565b50505082870194505b50929695505050505050565b60008154615799816156a5565b8085526020600183811680156157b657600181146157ee5761581c565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff008516838901528284151560051b890101955061581c565b866000528260002060005b858110156158145781548a82018601529083019084016157f9565b890184019650505b505050505092915050565b60a08152600061583a60a083018861578c565b6020838203818501528188548084528284019150828160051b8501018a6000528360002060005b838110156158ac577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe087840301855261589a838361578c565b94860194925060019182019101615861565b505086810360408801526158c0818b61578c565b94505050505084606084015282810360808401526158de8185614980565b98975050505050505050565b6000604082016040835280855180835260608501915060608160051b8601019250602080880160005b8381101561595f577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa088870301855261594d868351614980565b95509382019390820190600101615913565b5050858403818701525050506159758185614980565b95945050505050565b60008060006060848603121561599357600080fd5b83519250602084015191506040840151614f82816149dd565b83815260406020820152816040820152818360608301376000818301606090810191909152601f9092017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016010192915050565b601f821115612d8457600081815260208120601f850160051c81016020861015615a275750805b601f850160051c820191505b8181101561148657828155600101615a33565b815167ffffffffffffffff811115615a6057615a606146b6565b615a7481615a6e84546156a5565b84615a00565b602080601f831160018114615ac75760008415615a915750858301515b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600386901b1c1916600185901b178555611486565b6000858152602081207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08616915b82811015615b1457888601518255948401946001909101908401615af5565b5085821015615b5057878501517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600388901b60f8161c191681555b5050505050600190811b01905550565b60006020808385031215615b7357600080fd5b825167ffffffffffffffff811115615b8a57600080fd5b8301601f81018513615b9b57600080fd5b8051615ba96147c382614e55565b81815260059190911b82018301908381019087831115615bc857600080fd5b928401925b82841015615be657835182529284019290840190615bcd565b979650505050505050565b600063ffffffff80831681810361560757615607615251565b805160208083015191908110156156f2577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60209190910360031b1b16919050565b6020815260008251610140806020850152615c6b610160850183614980565b915060208501517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe080868503016040870152615ca78483614980565b935060408701519150615cd2606087018373ffffffffffffffffffffffffffffffffffffffff169052565b606087015163ffffffff811660808801529150608087015173ffffffffffffffffffffffffffffffffffffffff811660a0880152915060a087015160ff811660c0880152915060c08701519150808685030160e0870152615d338483614980565b935060e08701519150610100818786030181880152615d528584614980565b945080880151925050610120818786030181880152615d718584614980565b94508088015192505050615d94828601826bffffffffffffffffffffffff169052565b5090949350505050565b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0483118215151615615dd657615dd6615251565b500290565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b600082615e1957615e19615ddb565b500490565b818103600083128015838313168383128216171561453557614535615251565b600082615e4d57615e4d615ddb565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff83147f800000000000000000000000000000000000000000000000000000000000000083141615615ea157615ea1615251565b500590565b8082018281126000831280158216821582161715615ec657615ec6615251565b505092915050565b60007f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff820361549457615494615251565b60007f80000000000000000000000000000000000000000000000000000000000000008203615f3057615f30615251565b507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0190565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fdfea164736f6c6343000810000a307834353534343832643535353334343264343135323432343935343532353534643264353434353533353434653435353430303030303030303030303030303030307834323534343332643535353334343264343135323432343935343532353534643264353434353533353434653435353430303030303030303030303030303030", } var VerifiableLoadLogTriggerUpkeepABI = VerifiableLoadLogTriggerUpkeepMetaData.ABI diff --git a/core/gethwrappers/generated/verifiable_load_streams_lookup_upkeep_wrapper/verifiable_load_streams_lookup_upkeep_wrapper.go b/core/gethwrappers/generated/verifiable_load_streams_lookup_upkeep_wrapper/verifiable_load_streams_lookup_upkeep_wrapper.go index 1ff616ee12b..75bea5079a2 100644 --- a/core/gethwrappers/generated/verifiable_load_streams_lookup_upkeep_wrapper/verifiable_load_streams_lookup_upkeep_wrapper.go +++ b/core/gethwrappers/generated/verifiable_load_streams_lookup_upkeep_wrapper/verifiable_load_streams_lookup_upkeep_wrapper.go @@ -45,7 +45,7 @@ type KeeperRegistryBase21UpkeepInfo struct { var VerifiableLoadStreamsLookupUpkeepMetaData = &bind.MetaData{ ABI: "[{\"inputs\":[{\"internalType\":\"contractAutomationRegistrar2_1\",\"name\":\"_registrar\",\"type\":\"address\"},{\"internalType\":\"bool\",\"name\":\"_useArb\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"IndexOutOfRange\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"feedParamKey\",\"type\":\"string\"},{\"internalType\":\"string[]\",\"name\":\"feeds\",\"type\":\"string[]\"},{\"internalType\":\"string\",\"name\":\"timeParamKey\",\"type\":\"string\"},{\"internalType\":\"uint256\",\"name\":\"time\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"extraData\",\"type\":\"bytes\"}],\"name\":\"StreamsLookup\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"upkeepId\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"blockNum\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"addr\",\"type\":\"address\"}],\"name\":\"LogEmitted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"upkeepId\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"blockNum\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"addr\",\"type\":\"address\"}],\"name\":\"LogEmittedAgain\",\"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\":\"uint256\",\"name\":\"upkeepId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint96\",\"name\":\"amount\",\"type\":\"uint96\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"blockNum\",\"type\":\"uint256\"}],\"name\":\"UpkeepTopUp\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"BUCKET_SIZE\",\"outputs\":[{\"internalType\":\"uint16\",\"name\":\"\",\"type\":\"uint16\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"acceptOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"upkeepId\",\"type\":\"uint256\"},{\"internalType\":\"uint96\",\"name\":\"amount\",\"type\":\"uint96\"}],\"name\":\"addFunds\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"addLinkAmount\",\"outputs\":[{\"internalType\":\"uint96\",\"name\":\"\",\"type\":\"uint96\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256[]\",\"name\":\"upkeepIds\",\"type\":\"uint256[]\"}],\"name\":\"batchCancelUpkeeps\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256[]\",\"name\":\"upkeepIds\",\"type\":\"uint256[]\"},{\"internalType\":\"uint8\",\"name\":\"selector\",\"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\"}],\"name\":\"batchPreparingUpkeeps\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256[]\",\"name\":\"upkeepIds\",\"type\":\"uint256[]\"},{\"internalType\":\"uint8\",\"name\":\"log\",\"type\":\"uint8\"},{\"internalType\":\"uint8\",\"name\":\"selector\",\"type\":\"uint8\"}],\"name\":\"batchPreparingUpkeepsSimple\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint8\",\"name\":\"number\",\"type\":\"uint8\"},{\"internalType\":\"uint32\",\"name\":\"gasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint8\",\"name\":\"triggerType\",\"type\":\"uint8\"},{\"internalType\":\"bytes\",\"name\":\"triggerConfig\",\"type\":\"bytes\"},{\"internalType\":\"uint96\",\"name\":\"amount\",\"type\":\"uint96\"},{\"internalType\":\"uint256\",\"name\":\"checkGasToBurn\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"performGasToBurn\",\"type\":\"uint256\"}],\"name\":\"batchRegisterUpkeeps\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint8\",\"name\":\"log\",\"type\":\"uint8\"}],\"name\":\"batchSendLogs\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256[]\",\"name\":\"upkeepIds\",\"type\":\"uint256[]\"},{\"internalType\":\"uint32\",\"name\":\"interval\",\"type\":\"uint32\"}],\"name\":\"batchSetIntervals\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256[]\",\"name\":\"upkeepIds\",\"type\":\"uint256[]\"}],\"name\":\"batchUpdatePipelineData\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256[]\",\"name\":\"upkeepIds\",\"type\":\"uint256[]\"}],\"name\":\"batchWithdrawLinks\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"uint16\",\"name\":\"\",\"type\":\"uint16\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"bucketedDelays\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"buckets\",\"outputs\":[{\"internalType\":\"uint16\",\"name\":\"\",\"type\":\"uint16\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"upkeepId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"startGas\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"blockNum\",\"type\":\"uint256\"}],\"name\":\"burnPerformGas\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes[]\",\"name\":\"values\",\"type\":\"bytes[]\"},{\"internalType\":\"bytes\",\"name\":\"extraData\",\"type\":\"bytes\"}],\"name\":\"checkCallback\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"checkGasToBurns\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"checkData\",\"type\":\"bytes\"}],\"name\":\"checkUpkeep\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"counters\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"delays\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"name\":\"dummyMap\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"upkeepId\",\"type\":\"uint256\"}],\"name\":\"eligible\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"emittedAgainSig\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"emittedSig\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"feedParamKey\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"feedsHex\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"firstPerformBlocks\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"gasLimits\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"startIndex\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"maxCount\",\"type\":\"uint256\"}],\"name\":\"getActiveUpkeepIDsDeployedByThisContract\",\"outputs\":[{\"internalType\":\"uint256[]\",\"name\":\"\",\"type\":\"uint256[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"startIndex\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"maxCount\",\"type\":\"uint256\"}],\"name\":\"getAllActiveUpkeepIDsOnRegistry\",\"outputs\":[{\"internalType\":\"uint256[]\",\"name\":\"\",\"type\":\"uint256[]\"}],\"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\":[{\"internalType\":\"uint256\",\"name\":\"upkeepId\",\"type\":\"uint256\"},{\"internalType\":\"uint16\",\"name\":\"bucket\",\"type\":\"uint16\"}],\"name\":\"getBucketedDelays\",\"outputs\":[{\"internalType\":\"uint256[]\",\"name\":\"\",\"type\":\"uint256[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"upkeepId\",\"type\":\"uint256\"}],\"name\":\"getBucketedDelaysLength\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"upkeepId\",\"type\":\"uint256\"}],\"name\":\"getDelays\",\"outputs\":[{\"internalType\":\"uint256[]\",\"name\":\"\",\"type\":\"uint256[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"upkeepId\",\"type\":\"uint256\"}],\"name\":\"getDelaysLength\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"upkeepID\",\"type\":\"uint256\"}],\"name\":\"getForwarder\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"addr\",\"type\":\"address\"},{\"internalType\":\"uint8\",\"name\":\"selector\",\"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\"}],\"name\":\"getLogTriggerConfig\",\"outputs\":[{\"internalType\":\"bytes\",\"name\":\"logTrigger\",\"type\":\"bytes\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"upkeepId\",\"type\":\"uint256\"}],\"name\":\"getMinBalanceForUpkeep\",\"outputs\":[{\"internalType\":\"uint96\",\"name\":\"\",\"type\":\"uint96\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"upkeepId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"p\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"n\",\"type\":\"uint256\"}],\"name\":\"getPxDelayLastNPerforms\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"upkeepId\",\"type\":\"uint256\"},{\"internalType\":\"uint16\",\"name\":\"bucket\",\"type\":\"uint16\"}],\"name\":\"getSumDelayInBucket\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"upkeepId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"n\",\"type\":\"uint256\"}],\"name\":\"getSumDelayLastNPerforms\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"upkeepId\",\"type\":\"uint256\"}],\"name\":\"getTriggerType\",\"outputs\":[{\"internalType\":\"uint8\",\"name\":\"\",\"type\":\"uint8\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"upkeepId\",\"type\":\"uint256\"}],\"name\":\"getUpkeepInfo\",\"outputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"internalType\":\"uint32\",\"name\":\"performGas\",\"type\":\"uint32\"},{\"internalType\":\"bytes\",\"name\":\"checkData\",\"type\":\"bytes\"},{\"internalType\":\"uint96\",\"name\":\"balance\",\"type\":\"uint96\"},{\"internalType\":\"address\",\"name\":\"admin\",\"type\":\"address\"},{\"internalType\":\"uint64\",\"name\":\"maxValidBlocknumber\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"lastPerformedBlockNumber\",\"type\":\"uint32\"},{\"internalType\":\"uint96\",\"name\":\"amountSpent\",\"type\":\"uint96\"},{\"internalType\":\"bool\",\"name\":\"paused\",\"type\":\"bool\"},{\"internalType\":\"bytes\",\"name\":\"offchainConfig\",\"type\":\"bytes\"}],\"internalType\":\"structKeeperRegistryBase2_1.UpkeepInfo\",\"name\":\"\",\"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\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"intervals\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"lastTopUpBlocks\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"linkToken\",\"outputs\":[{\"internalType\":\"contractLinkTokenInterface\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"minBalanceThresholdMultiplier\",\"outputs\":[{\"internalType\":\"uint8\",\"name\":\"\",\"type\":\"uint8\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"performDataSizes\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"performGasToBurns\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"performData\",\"type\":\"bytes\"}],\"name\":\"performUpkeep\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"previousPerformBlocks\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"registrar\",\"outputs\":[{\"internalType\":\"contractAutomationRegistrar2_1\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"registry\",\"outputs\":[{\"internalType\":\"contractIKeeperRegistryMaster\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"upkeepId\",\"type\":\"uint256\"},{\"internalType\":\"uint8\",\"name\":\"log\",\"type\":\"uint8\"}],\"name\":\"sendLog\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"contractAutomationRegistrar2_1\",\"name\":\"newRegistrar\",\"type\":\"address\"}],\"name\":\"setConfig\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"string[]\",\"name\":\"_feeds\",\"type\":\"string[]\"}],\"name\":\"setFeeds\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"upkeepId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_interval\",\"type\":\"uint256\"}],\"name\":\"setInterval\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"_feedParamKey\",\"type\":\"string\"},{\"internalType\":\"string\",\"name\":\"_timeParamKey\",\"type\":\"string\"}],\"name\":\"setParamKeys\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"upkeepId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"setPerformDataSize\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"upkeepId\",\"type\":\"uint256\"},{\"internalType\":\"uint32\",\"name\":\"gasLimit\",\"type\":\"uint32\"}],\"name\":\"setUpkeepGasLimit\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"upkeepId\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"cfg\",\"type\":\"bytes\"}],\"name\":\"setUpkeepPrivilegeConfig\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"timeParamKey\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"upkeepId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"blockNum\",\"type\":\"uint256\"}],\"name\":\"topUpFund\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"upkeepId\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"addr\",\"type\":\"address\"},{\"internalType\":\"uint8\",\"name\":\"selector\",\"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\"}],\"name\":\"updateLogTriggerConfig1\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"upkeepId\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"cfg\",\"type\":\"bytes\"}],\"name\":\"updateLogTriggerConfig2\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"upkeepId\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"pipelineData\",\"type\":\"bytes\"}],\"name\":\"updateUpkeepPipelineData\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"upkeepTopUpCheckInterval\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"useArbitrumBlockNum\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"withdrawLinks\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"upkeepId\",\"type\":\"uint256\"}],\"name\":\"withdrawLinks\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"stateMutability\":\"payable\",\"type\":\"receive\"}]", - Bin: "0x7f97009585a4d2440f981ab6f6eec514343e1e6b2aa9b991a26998e6806f41bf086080527fc76416badc8398ce17c93eab7b4f60f263241694cf503e4df24f233a8cc1c50d60a0526005601455601580546001600160681b0319166c140000000002c68af0bb140000179055606460e0526101c0604052604261014081815261010091829190620060c161016039815260200160405180608001604052806042815260200162006103604291399052620000be906016906002620003c7565b506040805180820190915260098152680cccacac892c890caf60bb1b6020820152601790620000ee908262000543565b5060408051808201909152600b81526a313637b1b5a73ab6b132b960a91b602082015260189062000120908262000543565b503480156200012e57600080fd5b506040516200614538038062006145833981016040819052620001519162000625565b81813380600081620001aa5760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b0384811691909117909155811615620001dd57620001dd816200031c565b5050601180546001600160a01b0319166001600160a01b038516908117909155604080516330fe427560e21b815281516000945063c3f909d4926004808401939192918290030181865afa1580156200023a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062000260919062000668565b50601380546001600160a01b0319166001600160a01b038381169190911790915560115460408051631b6b6d2360e01b81529051939450911691631b6b6d23916004808201926020929091908290030181865afa158015620002c6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620002ec919062000699565b601280546001600160a01b0319166001600160a01b039290921691909117905550151560c05250620006c0915050565b336001600160a01b03821603620003765760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c660000000000000000006044820152606401620001a1565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b82805482825590600052602060002090810192821562000412579160200282015b8281111562000412578251829062000401908262000543565b5091602001919060010190620003e8565b506200042092915062000424565b5090565b80821115620004205760006200043b828262000445565b5060010162000424565b5080546200045390620004b4565b6000825580601f1062000464575050565b601f01602090049060005260206000209081019062000484919062000487565b50565b5b8082111562000420576000815560010162000488565b634e487b7160e01b600052604160045260246000fd5b600181811c90821680620004c957607f821691505b602082108103620004ea57634e487b7160e01b600052602260045260246000fd5b50919050565b601f8211156200053e57600081815260208120601f850160051c81016020861015620005195750805b601f850160051c820191505b818110156200053a5782815560010162000525565b5050505b505050565b81516001600160401b038111156200055f576200055f6200049e565b6200057781620005708454620004b4565b84620004f0565b602080601f831160018114620005af5760008415620005965750858301515b600019600386901b1c1916600185901b1785556200053a565b600085815260208120601f198616915b82811015620005e057888601518255948401946001909101908401620005bf565b5085821015620005ff5787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b6001600160a01b03811681146200048457600080fd5b600080604083850312156200063957600080fd5b825162000646816200060f565b602084015190925080151581146200065d57600080fd5b809150509250929050565b600080604083850312156200067c57600080fd5b825162000689816200060f565b6020939093015192949293505050565b600060208284031215620006ac57600080fd5b8151620006b9816200060f565b9392505050565b60805160a05160c05160e0516159ab62000716600039600081816105680152611f7a0152600081816109bc0152613c2b0152600081816108270152613679015260008181610d79015261364e01526159ab6000f3fe6080604052600436106104d55760003560e01c806379ea994311610279578063a6b594751161015e578063d6051a72116100d6578063e45530831161008a578063fa333dfb1161006f578063fa333dfb14610f88578063fba7ffa31461103b578063fcdc1f631461106857600080fd5b8063e455308314610f52578063f2fde38b14610f6857600080fd5b8063daee1aeb116100bb578063daee1aeb14610ee5578063dbef701e14610f05578063e0114adb14610f2557600080fd5b8063d6051a7214610ea5578063da6cba4714610ec557600080fd5b8063b657bc9c1161012d578063c041982211610112578063c041982214610e50578063c98f10b014610e70578063d4c2490014610e8557600080fd5b8063b657bc9c14610e10578063becde0e114610e3057600080fd5b8063a6b5947514610d9b578063a72aa27e14610dbb578063af953a4a14610ddb578063afb28d1f14610dfb57600080fd5b8063924ca578116101f15780639b429354116101c05780639d385eaa116101a55780639d385eaa14610d275780639d6f1cc714610d47578063a654824814610d6757600080fd5b80639b42935414610cc95780639b51fb0d14610cf657600080fd5b8063924ca57814610c3f578063948108f714610c5f57806396cebc7c14610c7f5780639ac542eb14610c9f57600080fd5b80638340507c11610248578063873c75861161022d578063873c758614610bc75780638da5cb5b14610be75780638fcb3fba14610c1257600080fd5b80638340507c14610b8757806386e330af14610ba757600080fd5b806379ea994314610afa5780637b10399914610b1a5780637e7a46dc14610b475780638243444a14610b6757600080fd5b806345d2ec17116103ba57806360457ff5116103325780637145f11b116102e657806376721303116102cb5780637672130314610a98578063776898c814610ac557806379ba509714610ae557600080fd5b80637145f11b14610a3b57806373644cce14610a6b57600080fd5b8063642f6cef11610317578063642f6cef146109aa57806369cdbadb146109ee5780636e04ff0d14610a1b57600080fd5b806360457ff514610958578063636092e81461098557600080fd5b80635147cd591161038957806357970e931161036e57806357970e93146108f65780635d4ee7f3146109235780635f17e6161461093857600080fd5b80635147cd59146108a457806351c98be3146108d657600080fd5b806345d2ec17146107e8578063469820931461081557806346e7a63e146108495780634b56a42e1461087657600080fd5b806320e3dbd41161044d5780632a9032d31161041c578063328ffd1111610401578063328ffd111461077b5780633ebe8d6c146107a85780634585e33b146107c857600080fd5b80632a9032d3146107095780632b20e3971461072957600080fd5b806320e3dbd41461067c5780632636aecf1461069c57806328c4b57b146106bc57806329e0a841146106dc57600080fd5b806319d97a94116104a45780631e010439116104895780631e010439146105ea578063206c32e814610627578063207b65161461065c57600080fd5b806319d97a941461059d5780631cdde251146105ca57600080fd5b806306c1cc00146104e1578063077ac621146105035780630b7d33e61461053657806312c550271461055657600080fd5b366104dc57005b600080fd5b3480156104ed57600080fd5b506105016104fc3660046143ad565b611095565b005b34801561050f57600080fd5b5061052361051e366004614460565b6112e4565b6040519081526020015b60405180910390f35b34801561054257600080fd5b50610501610551366004614495565b611322565b34801561056257600080fd5b5061058a7f000000000000000000000000000000000000000000000000000000000000000081565b60405161ffff909116815260200161052d565b3480156105a957600080fd5b506105bd6105b83660046144dc565b6113b0565b60405161052d9190614563565b3480156105d657600080fd5b506105016105e5366004614598565b61146d565b3480156105f657600080fd5b5061060a6106053660046144dc565b6115aa565b6040516bffffffffffffffffffffffff909116815260200161052d565b34801561063357600080fd5b506106476106423660046145fd565b61163f565b6040805192835260208301919091520161052d565b34801561066857600080fd5b506105bd6106773660046144dc565b6116c2565b34801561068857600080fd5b50610501610697366004614629565b61171a565b3480156106a857600080fd5b506105016106b736600461468b565b6118e4565b3480156106c857600080fd5b506105236106d7366004614705565b611bad565b3480156106e857600080fd5b506106fc6106f73660046144dc565b611c18565b60405161052d9190614731565b34801561071557600080fd5b50610501610724366004614872565b611d1d565b34801561073557600080fd5b506011546107569073ffffffffffffffffffffffffffffffffffffffff1681565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200161052d565b34801561078757600080fd5b506105236107963660046144dc565b60036020526000908152604090205481565b3480156107b457600080fd5b506105236107c33660046144dc565b611dfe565b3480156107d457600080fd5b506105016107e33660046148f6565b611e67565b3480156107f457600080fd5b506108086108033660046145fd565b612086565b60405161052d919061492c565b34801561082157600080fd5b506105237f000000000000000000000000000000000000000000000000000000000000000081565b34801561085557600080fd5b506105236108643660046144dc565b600a6020526000908152604090205481565b34801561088257600080fd5b50610896610891366004614994565b6120f5565b60405161052d929190614a5e565b3480156108b057600080fd5b506108c46108bf3660046144dc565b612149565b60405160ff909116815260200161052d565b3480156108e257600080fd5b506105016108f1366004614a79565b6121dd565b34801561090257600080fd5b506012546107569073ffffffffffffffffffffffffffffffffffffffff1681565b34801561092f57600080fd5b50610501612281565b34801561094457600080fd5b50610501610953366004614ad0565b6123bc565b34801561096457600080fd5b506105236109733660046144dc565b60076020526000908152604090205481565b34801561099157600080fd5b5060155461060a906bffffffffffffffffffffffff1681565b3480156109b657600080fd5b506109de7f000000000000000000000000000000000000000000000000000000000000000081565b604051901515815260200161052d565b3480156109fa57600080fd5b50610523610a093660046144dc565b60086020526000908152604090205481565b348015610a2757600080fd5b50610896610a363660046148f6565b612489565b348015610a4757600080fd5b506109de610a563660046144dc565b600b6020526000908152604090205460ff1681565b348015610a7757600080fd5b50610523610a863660046144dc565b6000908152600c602052604090205490565b348015610aa457600080fd5b50610523610ab33660046144dc565b60046020526000908152604090205481565b348015610ad157600080fd5b506109de610ae03660046144dc565b612636565b348015610af157600080fd5b50610501612688565b348015610b0657600080fd5b50610756610b153660046144dc565b612785565b348015610b2657600080fd5b506013546107569073ffffffffffffffffffffffffffffffffffffffff1681565b348015610b5357600080fd5b50610501610b62366004614af2565b612819565b348015610b7357600080fd5b50610501610b82366004614af2565b6128aa565b348015610b9357600080fd5b50610501610ba2366004614b3e565b612904565b348015610bb357600080fd5b50610501610bc2366004614b8b565b612922565b348015610bd357600080fd5b50610808610be2366004614ad0565b612935565b348015610bf357600080fd5b5060005473ffffffffffffffffffffffffffffffffffffffff16610756565b348015610c1e57600080fd5b50610523610c2d3660046144dc565b60056020526000908152604090205481565b348015610c4b57600080fd5b50610501610c5a366004614ad0565b6129f2565b348015610c6b57600080fd5b50610501610c7a366004614c3c565b612c37565b348015610c8b57600080fd5b50610501610c9a366004614c6c565b612d4f565b348015610cab57600080fd5b506015546108c4906c01000000000000000000000000900460ff1681565b348015610cd557600080fd5b50610501610ce4366004614ad0565b60009182526009602052604090912055565b348015610d0257600080fd5b5061058a610d113660046144dc565b600e6020526000908152604090205461ffff1681565b348015610d3357600080fd5b50610808610d423660046144dc565b612f59565b348015610d5357600080fd5b506105bd610d623660046144dc565b612fbb565b348015610d7357600080fd5b506105237f000000000000000000000000000000000000000000000000000000000000000081565b348015610da757600080fd5b50610501610db6366004614705565b613067565b348015610dc757600080fd5b50610501610dd6366004614c89565b6130d0565b348015610de757600080fd5b50610501610df63660046144dc565b61317b565b348015610e0757600080fd5b506105bd613201565b348015610e1c57600080fd5b5061060a610e2b3660046144dc565b61320e565b348015610e3c57600080fd5b50610501610e4b366004614872565b613266565b348015610e5c57600080fd5b50610808610e6b366004614ad0565b613300565b348015610e7c57600080fd5b506105bd6133fd565b348015610e9157600080fd5b50610501610ea0366004614cae565b61340a565b348015610eb157600080fd5b50610647610ec0366004614ad0565b613489565b348015610ed157600080fd5b50610501610ee0366004614cd3565b6134f2565b348015610ef157600080fd5b50610501610f00366004614872565b613859565b348015610f1157600080fd5b50610523610f20366004614ad0565b613924565b348015610f3157600080fd5b50610523610f403660046144dc565b60096020526000908152604090205481565b348015610f5e57600080fd5b5061052360145481565b348015610f7457600080fd5b50610501610f83366004614629565b613955565b348015610f9457600080fd5b506105bd610fa3366004614d3b565b6040805160c0808201835273ffffffffffffffffffffffffffffffffffffffff9890981680825260ff97881660208084019182528385019889526060808501988952608080860198895260a095860197885286519283019490945291519099168985015296519688019690965293519486019490945290519184019190915251828401528051808303909301835260e0909101905290565b34801561104757600080fd5b506105236110563660046144dc565b60066020526000908152604090205481565b34801561107457600080fd5b506105236110833660046144dc565b60026020526000908152604090205481565b6040805161018081018252600461014082019081527f746573740000000000000000000000000000000000000000000000000000000061016083015281528151602081810184526000808352818401929092523083850181905263ffffffff8b166060850152608084015260ff808a1660a08501528451808301865283815260c085015260e0840189905284519182019094529081526101008201526bffffffffffffffffffffffff8516610120820152601254601154919273ffffffffffffffffffffffffffffffffffffffff9182169263095ea7b392169061117b908c1688614dc3565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e085901b16815273ffffffffffffffffffffffffffffffffffffffff90921660048301526bffffffffffffffffffffffff1660248201526044016020604051808303816000875af11580156111f9573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061121d9190614e07565b5060008860ff1667ffffffffffffffff81111561123c5761123c61424f565b604051908082528060200260200182016040528015611265578160200160208202803683370190505b50905060005b8960ff168160ff1610156112d857600061128484613969565b905080838360ff168151811061129c5761129c614e22565b602090810291909101810191909152600091825260088152604080832088905560079091529020849055806112d081614e51565b91505061126b565b50505050505050505050565b600d602052826000526040600020602052816000526040600020818154811061130c57600080fd5b9060005260206000200160009250925050505481565b6013546040517f0b7d33e600000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff90911690630b7d33e69061137a9085908590600401614e70565b600060405180830381600087803b15801561139457600080fd5b505af11580156113a8573d6000803e3d6000fd5b505050505050565b6013546040517f19d97a940000000000000000000000000000000000000000000000000000000081526004810183905260609173ffffffffffffffffffffffffffffffffffffffff16906319d97a94906024015b600060405180830381865afa158015611421573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01682016040526114679190810190614ed6565b92915050565b6013546040517ffa333dfb00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff888116600483015260ff8816602483015260448201879052606482018690526084820185905260a4820184905290911690634ee88d35908990309063fa333dfb9060c401600060405180830381865afa15801561150c573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01682016040526115529190810190614ed6565b6040518363ffffffff1660e01b815260040161156f929190614e70565b600060405180830381600087803b15801561158957600080fd5b505af115801561159d573d6000803e3d6000fd5b5050505050505050505050565b6013546040517f1e0104390000000000000000000000000000000000000000000000000000000081526004810183905260009173ffffffffffffffffffffffffffffffffffffffff1690631e010439906024015b602060405180830381865afa15801561161b573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114679190614f16565b6000828152600d6020908152604080832061ffff8516845282528083208054825181850281018501909352808352849384939291908301828280156116a357602002820191906000526020600020905b81548152602001906001019080831161168f575b505050505090506116b5818251613a37565b92509250505b9250929050565b6013546040517f207b65160000000000000000000000000000000000000000000000000000000081526004810183905260609173ffffffffffffffffffffffffffffffffffffffff169063207b651690602401611404565b601180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff8316908117909155604080517fc3f909d400000000000000000000000000000000000000000000000000000000815281516000939263c3f909d492600480820193918290030181865afa1580156117b0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117d49190614f3e565b50601380547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83811691909117909155601154604080517f1b6b6d230000000000000000000000000000000000000000000000000000000081529051939450911691631b6b6d23916004808201926020929091908290030181865afa158015611877573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061189b9190614f6c565b601280547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff929092169190911790555050565b8560005b81811015611ba257600089898381811061190457611904614e22565b9050602002013590503073ffffffffffffffffffffffffffffffffffffffff16637e7a46dc828360405160200161193d91815260200190565b6040516020818303038152906040526040518363ffffffff1660e01b8152600401611969929190614e70565b600060405180830381600087803b15801561198357600080fd5b505af1158015611997573d6000803e3d6000fd5b50506013546040517f5147cd59000000000000000000000000000000000000000000000000000000008152600481018590526000935073ffffffffffffffffffffffffffffffffffffffff9091169150635147cd5990602401602060405180830381865afa158015611a0d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a319190614f89565b90508060ff16600103611b8d576040517ffa333dfb000000000000000000000000000000000000000000000000000000008152306004820181905260ff8b166024830152604482018a9052606482018890526084820188905260a4820187905260009163fa333dfb9060c401600060405180830381865afa158015611aba573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201604052611b009190810190614ed6565b6013546040517f4ee88d3500000000000000000000000000000000000000000000000000000000815291925073ffffffffffffffffffffffffffffffffffffffff1690634ee88d3590611b599086908590600401614e70565b600060405180830381600087803b158015611b7357600080fd5b505af1158015611b87573d6000803e3d6000fd5b50505050505b50508080611b9a90614fa6565b9150506118e8565b505050505050505050565b6000838152600c602090815260408083208054825181850281018501909352808352611c0e93830182828015611c0257602002820191906000526020600020905b815481526020019060010190808311611bee575b50505050508484613abc565b90505b9392505050565b604080516101408101825260008082526020820181905260609282018390528282018190526080820181905260a0820181905260c0820181905260e082018190526101008201526101208101919091526013546040517fc7c3a19a0000000000000000000000000000000000000000000000000000000081526004810184905273ffffffffffffffffffffffffffffffffffffffff9091169063c7c3a19a90602401600060405180830381865afa158015611cd7573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01682016040526114679190810190615001565b8060005b818160ff161015611df85760135473ffffffffffffffffffffffffffffffffffffffff1663c8048022858560ff8516818110611d5f57611d5f614e22565b905060200201356040518263ffffffff1660e01b8152600401611d8491815260200190565b600060405180830381600087803b158015611d9e57600080fd5b505af1158015611db2573d6000803e3d6000fd5b50505050611de584848360ff16818110611dce57611dce614e22565b90506020020135600f613c1b90919063ffffffff16565b5080611df081614e51565b915050611d21565b50505050565b6000818152600e602052604081205461ffff1681805b8261ffff168161ffff1611611e5f576000858152600d6020908152604080832061ffff85168452909152902054611e4b9083615120565b915080611e5781615133565b915050611e14565b509392505050565b60005a9050600080611e7b84860186614994565b91509150600081806020019051810190611e959190615154565b60008181526005602090815260408083205460049092528220549293509190611ebc613c27565b905082600003611edc576000848152600560205260409020819055612037565b600084815260036020526040812054611ef5848461516d565b611eff919061516d565b6000868152600e6020908152604080832054600d835281842061ffff909116808552908352818420805483518186028101860190945280845295965090949192909190830182828015611f7157602002820191906000526020600020905b815481526020019060010190808311611f5d575b505050505090507f000000000000000000000000000000000000000000000000000000000000000061ffff16815103611fec5781611fae81615133565b6000898152600e6020526040902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00001661ffff83161790559250505b506000868152600d6020908152604080832061ffff909416835292815282822080546001818101835591845282842001859055888352600c8252928220805493840181558252902001555b600084815260066020526040812054612051906001615120565b600086815260066020908152604080832084905560049091529020839055905061207b85836129f2565b6112d8858984613067565b6000828152600d6020908152604080832061ffff851684528252918290208054835181840281018401909452808452606093928301828280156120e857602002820191906000526020600020905b8154815260200190600101908083116120d4575b5050505050905092915050565b600060606000848460405160200161210e929190615180565b604080518083037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe00181529190526001969095509350505050565b6013546040517f5147cd590000000000000000000000000000000000000000000000000000000081526004810183905260009173ffffffffffffffffffffffffffffffffffffffff1690635147cd5990602401602060405180830381865afa1580156121b9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114679190614f89565b8160005b8181101561227a5730635f17e61686868481811061220157612201614e22565b90506020020135856040518363ffffffff1660e01b815260040161223592919091825263ffffffff16602082015260400190565b600060405180830381600087803b15801561224f57600080fd5b505af1158015612263573d6000803e3d6000fd5b50505050808061227290614fa6565b9150506121e1565b5050505050565b612289613cc9565b6012546040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015260009173ffffffffffffffffffffffffffffffffffffffff16906370a0823190602401602060405180830381865afa1580156122f8573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061231c9190615154565b6012546040517fa9059cbb0000000000000000000000000000000000000000000000000000000081523360048201526024810183905291925073ffffffffffffffffffffffffffffffffffffffff169063a9059cbb906044016020604051808303816000875af1158015612394573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123b89190614e07565b5050565b60008281526003602090815260408083208490556005825280832083905560068252808320839055600c90915281206123f49161414e565b6000828152600e602052604081205461ffff16905b8161ffff168161ffff1611612450576000848152600d6020908152604080832061ffff85168452909152812061243e9161414e565b8061244881615133565b915050612409565b5050506000908152600e6020526040902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000169055565b6000606060005a905060006124a0858701876144dc565b60008181526009602090815260408083205460089092528220549293509190838367ffffffffffffffff8111156124d9576124d961424f565b6040519080825280601f01601f191660200182016040528015612503576020820181803683370190505b50604051602001612515929190614e70565b60405160208183030381529060405290506000612530613c27565b9050600061253d86612636565b90505b835a61254c908961516d565b61255890612710615120565b10156125995781406000908152600b6020526040902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169055612540565b806125b15760008398509850505050505050506116bb565b60176016601884896040516020016125cb91815260200190565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152908290527ff055e4a200000000000000000000000000000000000000000000000000000000825261262d9594939291600401615302565b60405180910390fd5b600081815260056020526040812054810361265357506001919050565b600082815260036020908152604080832054600490925290912054612676613c27565b612680919061516d565b101592915050565b60015473ffffffffffffffffffffffffffffffffffffffff163314612709576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e657200000000000000000000604482015260640161262d565b60008054337fffffffffffffffffffffffff00000000000000000000000000000000000000008083168217845560018054909116905560405173ffffffffffffffffffffffffffffffffffffffff90921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b6013546040517f79ea99430000000000000000000000000000000000000000000000000000000081526004810183905260009173ffffffffffffffffffffffffffffffffffffffff16906379ea994390602401602060405180830381865afa1580156127f5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114679190614f6c565b6013546040517fcd7f71b500000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff9091169063cd7f71b590612873908690869086906004016153c5565b600060405180830381600087803b15801561288d57600080fd5b505af11580156128a1573d6000803e3d6000fd5b50505050505050565b6013546040517f4ee88d3500000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff90911690634ee88d3590612873908690869086906004016153c5565b6017612910838261545f565b50601861291d828261545f565b505050565b80516123b890601690602084019061416c565b6013546040517f06e3b632000000000000000000000000000000000000000000000000000000008152600481018490526024810183905260609173ffffffffffffffffffffffffffffffffffffffff16906306e3b63290604401600060405180830381865afa1580156129ac573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201604052611c119190810190615579565b601454600083815260026020526040902054612a0e908361516d565b11156123b8576013546040517fc7c3a19a0000000000000000000000000000000000000000000000000000000081526004810184905260009173ffffffffffffffffffffffffffffffffffffffff169063c7c3a19a90602401600060405180830381865afa158015612a84573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201604052612aca9190810190615001565b6013546040517fb657bc9c0000000000000000000000000000000000000000000000000000000081526004810186905291925060009173ffffffffffffffffffffffffffffffffffffffff9091169063b657bc9c90602401602060405180830381865afa158015612b3f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612b639190614f16565b601554909150612b879082906c01000000000000000000000000900460ff16614dc3565b6bffffffffffffffffffffffff1682606001516bffffffffffffffffffffffff161015611df857601554612bca9085906bffffffffffffffffffffffff16612c37565b60008481526002602090815260409182902085905560155482518781526bffffffffffffffffffffffff909116918101919091529081018490527f49d4100ab0124eb4a9a65dc4ea08d6412a43f6f05c49194983f5b322bcc0a5c09060600160405180910390a150505050565b6012546013546040517f095ea7b300000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff91821660048201526bffffffffffffffffffffffff8416602482015291169063095ea7b3906044016020604051808303816000875af1158015612cbf573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612ce39190614e07565b506013546040517f948108f7000000000000000000000000000000000000000000000000000000008152600481018490526bffffffffffffffffffffffff8316602482015273ffffffffffffffffffffffffffffffffffffffff9091169063948108f79060440161137a565b6040517fc04198220000000000000000000000000000000000000000000000000000000081526000600482018190526024820181905290309063c041982290604401600060405180830381865afa158015612dae573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201604052612df49190810190615579565b80519091506000612e03613c27565b905060005b8281101561227a576000848281518110612e2457612e24614e22565b60209081029190910101516013546040517f5147cd590000000000000000000000000000000000000000000000000000000081526004810183905291925060009173ffffffffffffffffffffffffffffffffffffffff90911690635147cd5990602401602060405180830381865afa158015612ea4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612ec89190614f89565b90508060ff16600103612f44578660ff16600003612f14576040513090859084907f97009585a4d2440f981ab6f6eec514343e1e6b2aa9b991a26998e6806f41bf0890600090a4612f44565b6040513090859084907fc76416badc8398ce17c93eab7b4f60f263241694cf503e4df24f233a8cc1c50d90600090a45b50508080612f5190614fa6565b915050612e08565b6000818152600c6020908152604091829020805483518184028101840190945280845260609392830182828015612faf57602002820191906000526020600020905b815481526020019060010190808311612f9b575b50505050509050919050565b60168181548110612fcb57600080fd5b906000526020600020016000915090508054612fe690615214565b80601f016020809104026020016040519081016040528092919081815260200182805461301290615214565b801561305f5780601f106130345761010080835404028352916020019161305f565b820191906000526020600020905b81548152906001019060200180831161304257829003601f168201915b505050505081565b6000838152600760205260409020545b805a613083908561516d565b61308f90612710615120565b1015611df85781406000908152600b6020526040902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169055613077565b6013546040517fa72aa27e0000000000000000000000000000000000000000000000000000000081526004810184905263ffffffff8316602482015273ffffffffffffffffffffffffffffffffffffffff9091169063a72aa27e90604401600060405180830381600087803b15801561314857600080fd5b505af115801561315c573d6000803e3d6000fd5b505050600092835250600a602052604090912063ffffffff9091169055565b6013546040517f744bfe610000000000000000000000000000000000000000000000000000000081526004810183905230602482015273ffffffffffffffffffffffffffffffffffffffff9091169063744bfe6190604401600060405180830381600087803b1580156131ed57600080fd5b505af115801561227a573d6000803e3d6000fd5b60178054612fe690615214565b6013546040517fb657bc9c0000000000000000000000000000000000000000000000000000000081526004810183905260009173ffffffffffffffffffffffffffffffffffffffff169063b657bc9c906024016115fe565b8060005b818163ffffffff161015611df8573063af953a4a858563ffffffff851681811061329657613296614e22565b905060200201356040518263ffffffff1660e01b81526004016132bb91815260200190565b600060405180830381600087803b1580156132d557600080fd5b505af11580156132e9573d6000803e3d6000fd5b5050505080806132f89061560a565b91505061326a565b6060600061330e600f613d4c565b9050808410613349576040517f1390f2a100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8260000361335e5761335b848261516d565b92505b60008367ffffffffffffffff8111156133795761337961424f565b6040519080825280602002602001820160405280156133a2578160200160208202803683370190505b50905060005b848110156133f4576133c56133bd8288615120565b600f90613d56565b8282815181106133d7576133d7614e22565b6020908102919091010152806133ec81614fa6565b9150506133a8565b50949350505050565b60188054612fe690615214565b6000613414613c27565b90508160ff16600003613455576040513090829085907f97009585a4d2440f981ab6f6eec514343e1e6b2aa9b991a26998e6806f41bf0890600090a4505050565b6040513090829085907fc76416badc8398ce17c93eab7b4f60f263241694cf503e4df24f233a8cc1c50d90600090a4505050565b6000828152600c602090815260408083208054825181850281018501909352808352849384939291908301828280156134e157602002820191906000526020600020905b8154815260200190600101908083116134cd575b505050505090506116b58185613a37565b8260005b818110156113a857600086868381811061351257613512614e22565b9050602002013590503073ffffffffffffffffffffffffffffffffffffffff16637e7a46dc828360405160200161354b91815260200190565b6040516020818303038152906040526040518363ffffffff1660e01b8152600401613577929190614e70565b600060405180830381600087803b15801561359157600080fd5b505af11580156135a5573d6000803e3d6000fd5b50506013546040517f5147cd59000000000000000000000000000000000000000000000000000000008152600481018590526000935073ffffffffffffffffffffffffffffffffffffffff9091169150635147cd5990602401602060405180830381865afa15801561361b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061363f9190614f89565b90508060ff16600103613844577f000000000000000000000000000000000000000000000000000000000000000060ff87161561369957507f00000000000000000000000000000000000000000000000000000000000000005b60003073ffffffffffffffffffffffffffffffffffffffff1663fa333dfb308985886040516020016136cd91815260200190565b6040516020818303038152906040526136e590615623565b60405160e086901b7fffffffff0000000000000000000000000000000000000000000000000000000016815273ffffffffffffffffffffffffffffffffffffffff909416600485015260ff90921660248401526044830152606482015260006084820181905260a482015260c401600060405180830381865afa158015613770573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01682016040526137b69190810190614ed6565b6013546040517f4ee88d3500000000000000000000000000000000000000000000000000000000815291925073ffffffffffffffffffffffffffffffffffffffff1690634ee88d359061380f9087908590600401614e70565b600060405180830381600087803b15801561382957600080fd5b505af115801561383d573d6000803e3d6000fd5b5050505050505b5050808061385190614fa6565b9150506134f6565b8060005b81811015611df857600084848381811061387957613879614e22565b9050602002013590503073ffffffffffffffffffffffffffffffffffffffff16637e7a46dc82836040516020016138b291815260200190565b6040516020818303038152906040526040518363ffffffff1660e01b81526004016138de929190614e70565b600060405180830381600087803b1580156138f857600080fd5b505af115801561390c573d6000803e3d6000fd5b5050505050808061391c90614fa6565b91505061385d565b600c602052816000526040600020818154811061394057600080fd5b90600052602060002001600091509150505481565b61395d613cc9565b61396681613d62565b50565b6011546040517f3f678e11000000000000000000000000000000000000000000000000000000008152600091829173ffffffffffffffffffffffffffffffffffffffff90911690633f678e11906139c4908690600401615665565b6020604051808303816000875af11580156139e3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613a079190615154565b9050613a14600f82613e57565b506060909201516000838152600a6020526040902063ffffffff90911690555090565b815160009081908190841580613a4d5750808510155b15613a56578094505b60008092505b85831015613ab257866001613a71858561516d565b613a7b919061516d565b81518110613a8b57613a8b614e22565b602002602001015181613a9e9190615120565b905082613aaa81614fa6565b935050613a5c565b9694955050505050565b82516000908190831580613ad05750808410155b15613ad9578093505b60008467ffffffffffffffff811115613af457613af461424f565b604051908082528060200260200182016040528015613b1d578160200160208202803683370190505b509050600092505b84831015613b8b57866001613b3a858561516d565b613b44919061516d565b81518110613b5457613b54614e22565b6020026020010151818481518110613b6e57613b6e614e22565b602090810291909101015282613b8381614fa6565b935050613b25565b613ba481600060018451613b9f919061516d565b613e63565b85606403613bdd578060018251613bbb919061516d565b81518110613bcb57613bcb614e22565b60200260200101519350505050611c11565b806064825188613bed91906157b7565b613bf79190615823565b81518110613c0757613c07614e22565b602002602001015193505050509392505050565b6000611c118383613fdb565b60007f000000000000000000000000000000000000000000000000000000000000000015613cc457606473ffffffffffffffffffffffffffffffffffffffff1663a3b1b31d6040518163ffffffff1660e01b8152600401602060405180830381865afa158015613c9b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613cbf9190615154565b905090565b504390565b60005473ffffffffffffffffffffffffffffffffffffffff163314613d4a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e657200000000000000000000604482015260640161262d565b565b6000611467825490565b6000611c1183836140d5565b3373ffffffffffffffffffffffffffffffffffffffff821603613de1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c66000000000000000000604482015260640161262d565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b6000611c1183836140ff565b8181808203613e73575050505050565b6000856002613e828787615837565b613e8c9190615857565b613e9690876158bf565b81518110613ea657613ea6614e22565b602002602001015190505b818313613fb5575b80868481518110613ecc57613ecc614e22565b60200260200101511015613eec5782613ee4816158e7565b935050613eb9565b858281518110613efe57613efe614e22565b6020026020010151811015613f1f5781613f1781615918565b925050613eec565b818313613fb057858281518110613f3857613f38614e22565b6020026020010151868481518110613f5257613f52614e22565b6020026020010151878581518110613f6c57613f6c614e22565b60200260200101888581518110613f8557613f85614e22565b60209081029190910101919091525282613f9e816158e7565b9350508180613fac90615918565b9250505b613eb1565b81851215613fc857613fc8868684613e63565b838312156113a8576113a8868486613e63565b600081815260018301602052604081205480156140c4576000613fff60018361516d565b85549091506000906140139060019061516d565b905081811461407857600086600001828154811061403357614033614e22565b906000526020600020015490508087600001848154811061405657614056614e22565b6000918252602080832090910192909255918252600188019052604090208390555b85548690806140895761408961596f565b600190038181906000526020600020016000905590558560010160008681526020019081526020016000206000905560019350505050611467565b6000915050611467565b5092915050565b60008260000182815481106140ec576140ec614e22565b9060005260206000200154905092915050565b600081815260018301602052604081205461414657508154600181810184556000848152602080822090930184905584548482528286019093526040902091909155611467565b506000611467565b508054600082559060005260206000209081019061396691906141c2565b8280548282559060005260206000209081019282156141b2579160200282015b828111156141b257825182906141a2908261545f565b509160200191906001019061418c565b506141be9291506141d7565b5090565b5b808211156141be57600081556001016141c3565b808211156141be5760006141eb82826141f4565b506001016141d7565b50805461420090615214565b6000825580601f10614210575050565b601f01602090049060005260206000209081019061396691906141c2565b60ff8116811461396657600080fd5b63ffffffff8116811461396657600080fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051610140810167ffffffffffffffff811182821017156142a2576142a261424f565b60405290565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff811182821017156142ef576142ef61424f565b604052919050565b600067ffffffffffffffff8211156143115761431161424f565b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b600082601f83011261434e57600080fd5b813561436161435c826142f7565b6142a8565b81815284602083860101111561437657600080fd5b816020850160208301376000918101602001919091529392505050565b6bffffffffffffffffffffffff8116811461396657600080fd5b600080600080600080600060e0888a0312156143c857600080fd5b87356143d38161422e565b965060208801356143e38161423d565b955060408801356143f38161422e565b9450606088013567ffffffffffffffff81111561440f57600080fd5b61441b8a828b0161433d565b945050608088013561442c81614393565b9699959850939692959460a0840135945060c09093013592915050565b803561ffff8116811461445b57600080fd5b919050565b60008060006060848603121561447557600080fd5b8335925061448560208501614449565b9150604084013590509250925092565b600080604083850312156144a857600080fd5b82359150602083013567ffffffffffffffff8111156144c657600080fd5b6144d28582860161433d565b9150509250929050565b6000602082840312156144ee57600080fd5b5035919050565b60005b838110156145105781810151838201526020016144f8565b50506000910152565b600081518084526145318160208601602086016144f5565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b602081526000611c116020830184614519565b73ffffffffffffffffffffffffffffffffffffffff8116811461396657600080fd5b600080600080600080600060e0888a0312156145b357600080fd5b8735965060208801356145c581614576565b955060408801356145d58161422e565b969995985095966060810135965060808101359560a0820135955060c0909101359350915050565b6000806040838503121561461057600080fd5b8235915061462060208401614449565b90509250929050565b60006020828403121561463b57600080fd5b8135611c1181614576565b60008083601f84011261465857600080fd5b50813567ffffffffffffffff81111561467057600080fd5b6020830191508360208260051b85010111156116bb57600080fd5b600080600080600080600060c0888a0312156146a657600080fd5b873567ffffffffffffffff8111156146bd57600080fd5b6146c98a828b01614646565b90985096505060208801356146dd8161422e565b96999598509596604081013596506060810135956080820135955060a0909101359350915050565b60008060006060848603121561471a57600080fd5b505081359360208301359350604090920135919050565b6020815261475860208201835173ffffffffffffffffffffffffffffffffffffffff169052565b60006020830151614771604084018263ffffffff169052565b50604083015161014080606085015261478e610160850183614519565b915060608501516147af60808601826bffffffffffffffffffffffff169052565b50608085015173ffffffffffffffffffffffffffffffffffffffff811660a08601525060a085015167ffffffffffffffff811660c08601525060c085015163ffffffff811660e08601525060e085015161010061481b818701836bffffffffffffffffffffffff169052565b86015190506101206148308682018315159052565b8601518584037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0018387015290506148688382614519565b9695505050505050565b6000806020838503121561488557600080fd5b823567ffffffffffffffff81111561489c57600080fd5b6148a885828601614646565b90969095509350505050565b60008083601f8401126148c657600080fd5b50813567ffffffffffffffff8111156148de57600080fd5b6020830191508360208285010111156116bb57600080fd5b6000806020838503121561490957600080fd5b823567ffffffffffffffff81111561492057600080fd5b6148a8858286016148b4565b6020808252825182820181905260009190848201906040850190845b8181101561496457835183529284019291840191600101614948565b50909695505050505050565b600067ffffffffffffffff82111561498a5761498a61424f565b5060051b60200190565b600080604083850312156149a757600080fd5b823567ffffffffffffffff808211156149bf57600080fd5b818501915085601f8301126149d357600080fd5b813560206149e361435c83614970565b82815260059290921b84018101918181019089841115614a0257600080fd5b8286015b84811015614a3a57803586811115614a1e5760008081fd5b614a2c8c86838b010161433d565b845250918301918301614a06565b5096505086013592505080821115614a5157600080fd5b506144d28582860161433d565b8215158152604060208201526000611c0e6040830184614519565b600080600060408486031215614a8e57600080fd5b833567ffffffffffffffff811115614aa557600080fd5b614ab186828701614646565b9094509250506020840135614ac58161423d565b809150509250925092565b60008060408385031215614ae357600080fd5b50508035926020909101359150565b600080600060408486031215614b0757600080fd5b83359250602084013567ffffffffffffffff811115614b2557600080fd5b614b31868287016148b4565b9497909650939450505050565b60008060408385031215614b5157600080fd5b823567ffffffffffffffff80821115614b6957600080fd5b614b758683870161433d565b93506020850135915080821115614a5157600080fd5b60006020808385031215614b9e57600080fd5b823567ffffffffffffffff80821115614bb657600080fd5b818501915085601f830112614bca57600080fd5b8135614bd861435c82614970565b81815260059190911b83018401908481019088831115614bf757600080fd5b8585015b83811015614c2f57803585811115614c135760008081fd5b614c218b89838a010161433d565b845250918601918601614bfb565b5098975050505050505050565b60008060408385031215614c4f57600080fd5b823591506020830135614c6181614393565b809150509250929050565b600060208284031215614c7e57600080fd5b8135611c118161422e565b60008060408385031215614c9c57600080fd5b823591506020830135614c618161423d565b60008060408385031215614cc157600080fd5b823591506020830135614c618161422e565b60008060008060608587031215614ce957600080fd5b843567ffffffffffffffff811115614d0057600080fd5b614d0c87828801614646565b9095509350506020850135614d208161422e565b91506040850135614d308161422e565b939692955090935050565b60008060008060008060c08789031215614d5457600080fd5b8635614d5f81614576565b95506020870135614d6f8161422e565b95989597505050506040840135936060810135936080820135935060a0909101359150565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60006bffffffffffffffffffffffff80831681851681830481118215151615614dee57614dee614d94565b02949350505050565b8051801515811461445b57600080fd5b600060208284031215614e1957600080fd5b611c1182614df7565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b600060ff821660ff8103614e6757614e67614d94565b60010192915050565b828152604060208201526000611c0e6040830184614519565b600082601f830112614e9a57600080fd5b8151614ea861435c826142f7565b818152846020838601011115614ebd57600080fd5b614ece8260208301602087016144f5565b949350505050565b600060208284031215614ee857600080fd5b815167ffffffffffffffff811115614eff57600080fd5b614ece84828501614e89565b805161445b81614393565b600060208284031215614f2857600080fd5b8151611c1181614393565b805161445b81614576565b60008060408385031215614f5157600080fd5b8251614f5c81614576565b6020939093015192949293505050565b600060208284031215614f7e57600080fd5b8151611c1181614576565b600060208284031215614f9b57600080fd5b8151611c118161422e565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203614fd757614fd7614d94565b5060010190565b805161445b8161423d565b805167ffffffffffffffff8116811461445b57600080fd5b60006020828403121561501357600080fd5b815167ffffffffffffffff8082111561502b57600080fd5b90830190610140828603121561504057600080fd5b61504861427e565b61505183614f33565b815261505f60208401614fde565b602082015260408301518281111561507657600080fd5b61508287828601614e89565b60408301525061509460608401614f0b565b60608201526150a560808401614f33565b60808201526150b660a08401614fe9565b60a08201526150c760c08401614fde565b60c08201526150d860e08401614f0b565b60e08201526101006150eb818501614df7565b90820152610120838101518381111561510357600080fd5b61510f88828701614e89565b918301919091525095945050505050565b8082018082111561146757611467614d94565b600061ffff80831681810361514a5761514a614d94565b6001019392505050565b60006020828403121561516657600080fd5b5051919050565b8181038181111561146757611467614d94565b6000604082016040835280855180835260608501915060608160051b8601019250602080880160005b838110156151f5577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa08887030185526151e3868351614519565b955093820193908201906001016151a9565b50508584038187015250505061520b8185614519565b95945050505050565b600181811c9082168061522857607f821691505b602082108103615261577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b50919050565b6000815461527481615214565b80855260206001838116801561529157600181146152c9576152f7565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff008516838901528284151560051b89010195506152f7565b866000528260002060005b858110156152ef5781548a82018601529083019084016152d4565b890184019650505b505050505092915050565b60a08152600061531560a0830188615267565b6020838203818501528188548084528284019150828160051b8501018a6000528360002060005b83811015615387577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08784030185526153758383615267565b9486019492506001918201910161533c565b5050868103604088015261539b818b615267565b94505050505084606084015282810360808401526153b98185614519565b98975050505050505050565b83815260406020820152816040820152818360608301376000818301606090810191909152601f9092017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016010192915050565b601f82111561291d57600081815260208120601f850160051c810160208610156154405750805b601f850160051c820191505b818110156113a85782815560010161544c565b815167ffffffffffffffff8111156154795761547961424f565b61548d816154878454615214565b84615419565b602080601f8311600181146154e057600084156154aa5750858301515b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600386901b1c1916600185901b1785556113a8565b6000858152602081207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08616915b8281101561552d5788860151825594840194600190910190840161550e565b508582101561556957878501517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600388901b60f8161c191681555b5050505050600190811b01905550565b6000602080838503121561558c57600080fd5b825167ffffffffffffffff8111156155a357600080fd5b8301601f810185136155b457600080fd5b80516155c261435c82614970565b81815260059190911b820183019083810190878311156155e157600080fd5b928401925b828410156155ff578351825292840192908401906155e6565b979650505050505050565b600063ffffffff80831681810361514a5761514a614d94565b80516020808301519190811015615261577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60209190910360031b1b16919050565b6020815260008251610140806020850152615684610160850183614519565b915060208501517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0808685030160408701526156c08483614519565b9350604087015191506156eb606087018373ffffffffffffffffffffffffffffffffffffffff169052565b606087015163ffffffff811660808801529150608087015173ffffffffffffffffffffffffffffffffffffffff811660a0880152915060a087015160ff811660c0880152915060c08701519150808685030160e087015261574c8483614519565b935060e0870151915061010081878603018188015261576b8584614519565b94508088015192505061012081878603018188015261578a8584614519565b945080880151925050506157ad828601826bffffffffffffffffffffffff169052565b5090949350505050565b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff04831182151516156157ef576157ef614d94565b500290565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b600082615832576158326157f4565b500490565b81810360008312801583831316838312821617156140ce576140ce614d94565b600082615866576158666157f4565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff83147f8000000000000000000000000000000000000000000000000000000000000000831416156158ba576158ba614d94565b500590565b80820182811260008312801582168215821617156158df576158df614d94565b505092915050565b60007f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203614fd757614fd7614d94565b60007f8000000000000000000000000000000000000000000000000000000000000000820361594957615949614d94565b507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0190565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fdfea164736f6c6343000810000a307834353534343832643535353334343264343135323432343935343532353534643264353434353533353434653435353430303030303030303030303030303030307834323534343332643535353334343264343135323432343935343532353534643264353434353533353434653435353430303030303030303030303030303030", + Bin: "0x7f97009585a4d2440f981ab6f6eec514343e1e6b2aa9b991a26998e6806f41bf086080527fc76416badc8398ce17c93eab7b4f60f263241694cf503e4df24f233a8cc1c50d60a0526005601455601580546001600160681b0319166c140000000002c68af0bb140000179055606460e0526101c0604052604261014081815261010091829190620061d161016039815260200160405180608001604052806042815260200162006213604291399052620000be906016906002620003c7565b506040805180820190915260098152680cccacac892c890caf60bb1b6020820152601790620000ee908262000543565b5060408051808201909152600b81526a313637b1b5a73ab6b132b960a91b602082015260189062000120908262000543565b503480156200012e57600080fd5b506040516200625538038062006255833981016040819052620001519162000625565b81813380600081620001aa5760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b0384811691909117909155811615620001dd57620001dd816200031c565b5050601180546001600160a01b0319166001600160a01b038516908117909155604080516330fe427560e21b815281516000945063c3f909d4926004808401939192918290030181865afa1580156200023a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062000260919062000668565b50601380546001600160a01b0319166001600160a01b038381169190911790915560115460408051631b6b6d2360e01b81529051939450911691631b6b6d23916004808201926020929091908290030181865afa158015620002c6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620002ec919062000699565b601280546001600160a01b0319166001600160a01b039290921691909117905550151560c05250620006c0915050565b336001600160a01b03821603620003765760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c660000000000000000006044820152606401620001a1565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b82805482825590600052602060002090810192821562000412579160200282015b8281111562000412578251829062000401908262000543565b5091602001919060010190620003e8565b506200042092915062000424565b5090565b80821115620004205760006200043b828262000445565b5060010162000424565b5080546200045390620004b4565b6000825580601f1062000464575050565b601f01602090049060005260206000209081019062000484919062000487565b50565b5b8082111562000420576000815560010162000488565b634e487b7160e01b600052604160045260246000fd5b600181811c90821680620004c957607f821691505b602082108103620004ea57634e487b7160e01b600052602260045260246000fd5b50919050565b601f8211156200053e57600081815260208120601f850160051c81016020861015620005195750805b601f850160051c820191505b818110156200053a5782815560010162000525565b5050505b505050565b81516001600160401b038111156200055f576200055f6200049e565b6200057781620005708454620004b4565b84620004f0565b602080601f831160018114620005af5760008415620005965750858301515b600019600386901b1c1916600185901b1785556200053a565b600085815260208120601f198616915b82811015620005e057888601518255948401946001909101908401620005bf565b5085821015620005ff5787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b6001600160a01b03811681146200048457600080fd5b600080604083850312156200063957600080fd5b825162000646816200060f565b602084015190925080151581146200065d57600080fd5b809150509250929050565b600080604083850312156200067c57600080fd5b825162000689816200060f565b6020939093015192949293505050565b600060208284031215620006ac57600080fd5b8151620006b9816200060f565b9392505050565b60805160a05160c05160e051615abb62000716600039600081816105680152611f7a0152600081816109bc0152613ca701526000818161082701526136f5015260008181610d7901526136ca0152615abb6000f3fe6080604052600436106104d55760003560e01c806379ea994311610279578063a6b594751161015e578063d6051a72116100d6578063e45530831161008a578063fa333dfb1161006f578063fa333dfb14610f88578063fba7ffa31461103b578063fcdc1f631461106857600080fd5b8063e455308314610f52578063f2fde38b14610f6857600080fd5b8063daee1aeb116100bb578063daee1aeb14610ee5578063dbef701e14610f05578063e0114adb14610f2557600080fd5b8063d6051a7214610ea5578063da6cba4714610ec557600080fd5b8063b657bc9c1161012d578063c041982211610112578063c041982214610e50578063c98f10b014610e70578063d4c2490014610e8557600080fd5b8063b657bc9c14610e10578063becde0e114610e3057600080fd5b8063a6b5947514610d9b578063a72aa27e14610dbb578063af953a4a14610ddb578063afb28d1f14610dfb57600080fd5b8063924ca578116101f15780639b429354116101c05780639d385eaa116101a55780639d385eaa14610d275780639d6f1cc714610d47578063a654824814610d6757600080fd5b80639b42935414610cc95780639b51fb0d14610cf657600080fd5b8063924ca57814610c3f578063948108f714610c5f57806396cebc7c14610c7f5780639ac542eb14610c9f57600080fd5b80638340507c11610248578063873c75861161022d578063873c758614610bc75780638da5cb5b14610be75780638fcb3fba14610c1257600080fd5b80638340507c14610b8757806386e330af14610ba757600080fd5b806379ea994314610afa5780637b10399914610b1a5780637e7a46dc14610b475780638243444a14610b6757600080fd5b806345d2ec17116103ba57806360457ff5116103325780637145f11b116102e657806376721303116102cb5780637672130314610a98578063776898c814610ac557806379ba509714610ae557600080fd5b80637145f11b14610a3b57806373644cce14610a6b57600080fd5b8063642f6cef11610317578063642f6cef146109aa57806369cdbadb146109ee5780636e04ff0d14610a1b57600080fd5b806360457ff514610958578063636092e81461098557600080fd5b80635147cd591161038957806357970e931161036e57806357970e93146108f65780635d4ee7f3146109235780635f17e6161461093857600080fd5b80635147cd59146108a457806351c98be3146108d657600080fd5b806345d2ec17146107e8578063469820931461081557806346e7a63e146108495780634b56a42e1461087657600080fd5b806320e3dbd41161044d5780632a9032d31161041c578063328ffd1111610401578063328ffd111461077b5780633ebe8d6c146107a85780634585e33b146107c857600080fd5b80632a9032d3146107095780632b20e3971461072957600080fd5b806320e3dbd41461067c5780632636aecf1461069c57806328c4b57b146106bc57806329e0a841146106dc57600080fd5b806319d97a94116104a45780631e010439116104895780631e010439146105ea578063206c32e814610627578063207b65161461065c57600080fd5b806319d97a941461059d5780631cdde251146105ca57600080fd5b806306c1cc00146104e1578063077ac621146105035780630b7d33e61461053657806312c550271461055657600080fd5b366104dc57005b600080fd5b3480156104ed57600080fd5b506105016104fc366004614429565b611095565b005b34801561050f57600080fd5b5061052361051e3660046144dc565b6112e4565b6040519081526020015b60405180910390f35b34801561054257600080fd5b50610501610551366004614511565b611322565b34801561056257600080fd5b5061058a7f000000000000000000000000000000000000000000000000000000000000000081565b60405161ffff909116815260200161052d565b3480156105a957600080fd5b506105bd6105b8366004614558565b6113b0565b60405161052d91906145df565b3480156105d657600080fd5b506105016105e5366004614614565b61146d565b3480156105f657600080fd5b5061060a610605366004614558565b6115aa565b6040516bffffffffffffffffffffffff909116815260200161052d565b34801561063357600080fd5b50610647610642366004614679565b61163f565b6040805192835260208301919091520161052d565b34801561066857600080fd5b506105bd610677366004614558565b6116c2565b34801561068857600080fd5b506105016106973660046146a5565b61171a565b3480156106a857600080fd5b506105016106b7366004614707565b6118e4565b3480156106c857600080fd5b506105236106d7366004614781565b611bad565b3480156106e857600080fd5b506106fc6106f7366004614558565b611c18565b60405161052d91906147ad565b34801561071557600080fd5b506105016107243660046148ee565b611d1d565b34801561073557600080fd5b506011546107569073ffffffffffffffffffffffffffffffffffffffff1681565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200161052d565b34801561078757600080fd5b50610523610796366004614558565b60036020526000908152604090205481565b3480156107b457600080fd5b506105236107c3366004614558565b611dfe565b3480156107d457600080fd5b506105016107e3366004614972565b611e67565b3480156107f457600080fd5b50610808610803366004614679565b612086565b60405161052d91906149a8565b34801561082157600080fd5b506105237f000000000000000000000000000000000000000000000000000000000000000081565b34801561085557600080fd5b50610523610864366004614558565b600a6020526000908152604090205481565b34801561088257600080fd5b50610896610891366004614a10565b6120f5565b60405161052d929190614ada565b3480156108b057600080fd5b506108c46108bf366004614558565b612149565b60405160ff909116815260200161052d565b3480156108e257600080fd5b506105016108f1366004614af5565b6121dd565b34801561090257600080fd5b506012546107569073ffffffffffffffffffffffffffffffffffffffff1681565b34801561092f57600080fd5b50610501612281565b34801561094457600080fd5b50610501610953366004614b4c565b6123bc565b34801561096457600080fd5b50610523610973366004614558565b60076020526000908152604090205481565b34801561099157600080fd5b5060155461060a906bffffffffffffffffffffffff1681565b3480156109b657600080fd5b506109de7f000000000000000000000000000000000000000000000000000000000000000081565b604051901515815260200161052d565b3480156109fa57600080fd5b50610523610a09366004614558565b60086020526000908152604090205481565b348015610a2757600080fd5b50610896610a36366004614972565b612489565b348015610a4757600080fd5b506109de610a56366004614558565b600b6020526000908152604090205460ff1681565b348015610a7757600080fd5b50610523610a86366004614558565b6000908152600c602052604090205490565b348015610aa457600080fd5b50610523610ab3366004614558565b60046020526000908152604090205481565b348015610ad157600080fd5b506109de610ae0366004614558565b6126b2565b348015610af157600080fd5b50610501612704565b348015610b0657600080fd5b50610756610b15366004614558565b612801565b348015610b2657600080fd5b506013546107569073ffffffffffffffffffffffffffffffffffffffff1681565b348015610b5357600080fd5b50610501610b62366004614b6e565b612895565b348015610b7357600080fd5b50610501610b82366004614b6e565b612926565b348015610b9357600080fd5b50610501610ba2366004614bba565b612980565b348015610bb357600080fd5b50610501610bc2366004614c07565b61299e565b348015610bd357600080fd5b50610808610be2366004614b4c565b6129b1565b348015610bf357600080fd5b5060005473ffffffffffffffffffffffffffffffffffffffff16610756565b348015610c1e57600080fd5b50610523610c2d366004614558565b60056020526000908152604090205481565b348015610c4b57600080fd5b50610501610c5a366004614b4c565b612a6e565b348015610c6b57600080fd5b50610501610c7a366004614cb8565b612cb3565b348015610c8b57600080fd5b50610501610c9a366004614ce8565b612dcb565b348015610cab57600080fd5b506015546108c4906c01000000000000000000000000900460ff1681565b348015610cd557600080fd5b50610501610ce4366004614b4c565b60009182526009602052604090912055565b348015610d0257600080fd5b5061058a610d11366004614558565b600e6020526000908152604090205461ffff1681565b348015610d3357600080fd5b50610808610d42366004614558565b612fd5565b348015610d5357600080fd5b506105bd610d62366004614558565b613037565b348015610d7357600080fd5b506105237f000000000000000000000000000000000000000000000000000000000000000081565b348015610da757600080fd5b50610501610db6366004614781565b6130e3565b348015610dc757600080fd5b50610501610dd6366004614d05565b61314c565b348015610de757600080fd5b50610501610df6366004614558565b6131f7565b348015610e0757600080fd5b506105bd61327d565b348015610e1c57600080fd5b5061060a610e2b366004614558565b61328a565b348015610e3c57600080fd5b50610501610e4b3660046148ee565b6132e2565b348015610e5c57600080fd5b50610808610e6b366004614b4c565b61337c565b348015610e7c57600080fd5b506105bd613479565b348015610e9157600080fd5b50610501610ea0366004614d2a565b613486565b348015610eb157600080fd5b50610647610ec0366004614b4c565b613505565b348015610ed157600080fd5b50610501610ee0366004614d4f565b61356e565b348015610ef157600080fd5b50610501610f003660046148ee565b6138d5565b348015610f1157600080fd5b50610523610f20366004614b4c565b6139a0565b348015610f3157600080fd5b50610523610f40366004614558565b60096020526000908152604090205481565b348015610f5e57600080fd5b5061052360145481565b348015610f7457600080fd5b50610501610f833660046146a5565b6139d1565b348015610f9457600080fd5b506105bd610fa3366004614db7565b6040805160c0808201835273ffffffffffffffffffffffffffffffffffffffff9890981680825260ff97881660208084019182528385019889526060808501988952608080860198895260a095860197885286519283019490945291519099168985015296519688019690965293519486019490945290519184019190915251828401528051808303909301835260e0909101905290565b34801561104757600080fd5b50610523611056366004614558565b60066020526000908152604090205481565b34801561107457600080fd5b50610523611083366004614558565b60026020526000908152604090205481565b6040805161018081018252600461014082019081527f746573740000000000000000000000000000000000000000000000000000000061016083015281528151602081810184526000808352818401929092523083850181905263ffffffff8b166060850152608084015260ff808a1660a08501528451808301865283815260c085015260e0840189905284519182019094529081526101008201526bffffffffffffffffffffffff8516610120820152601254601154919273ffffffffffffffffffffffffffffffffffffffff9182169263095ea7b392169061117b908c1688614e3f565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e085901b16815273ffffffffffffffffffffffffffffffffffffffff90921660048301526bffffffffffffffffffffffff1660248201526044016020604051808303816000875af11580156111f9573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061121d9190614e83565b5060008860ff1667ffffffffffffffff81111561123c5761123c6142cb565b604051908082528060200260200182016040528015611265578160200160208202803683370190505b50905060005b8960ff168160ff1610156112d8576000611284846139e5565b905080838360ff168151811061129c5761129c614e9e565b602090810291909101810191909152600091825260088152604080832088905560079091529020849055806112d081614ecd565b91505061126b565b50505050505050505050565b600d602052826000526040600020602052816000526040600020818154811061130c57600080fd5b9060005260206000200160009250925050505481565b6013546040517f0b7d33e600000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff90911690630b7d33e69061137a9085908590600401614eec565b600060405180830381600087803b15801561139457600080fd5b505af11580156113a8573d6000803e3d6000fd5b505050505050565b6013546040517f19d97a940000000000000000000000000000000000000000000000000000000081526004810183905260609173ffffffffffffffffffffffffffffffffffffffff16906319d97a94906024015b600060405180830381865afa158015611421573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01682016040526114679190810190614f52565b92915050565b6013546040517ffa333dfb00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff888116600483015260ff8816602483015260448201879052606482018690526084820185905260a4820184905290911690634ee88d35908990309063fa333dfb9060c401600060405180830381865afa15801561150c573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01682016040526115529190810190614f52565b6040518363ffffffff1660e01b815260040161156f929190614eec565b600060405180830381600087803b15801561158957600080fd5b505af115801561159d573d6000803e3d6000fd5b5050505050505050505050565b6013546040517f1e0104390000000000000000000000000000000000000000000000000000000081526004810183905260009173ffffffffffffffffffffffffffffffffffffffff1690631e010439906024015b602060405180830381865afa15801561161b573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114679190614f92565b6000828152600d6020908152604080832061ffff8516845282528083208054825181850281018501909352808352849384939291908301828280156116a357602002820191906000526020600020905b81548152602001906001019080831161168f575b505050505090506116b5818251613ab3565b92509250505b9250929050565b6013546040517f207b65160000000000000000000000000000000000000000000000000000000081526004810183905260609173ffffffffffffffffffffffffffffffffffffffff169063207b651690602401611404565b601180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff8316908117909155604080517fc3f909d400000000000000000000000000000000000000000000000000000000815281516000939263c3f909d492600480820193918290030181865afa1580156117b0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117d49190614fba565b50601380547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83811691909117909155601154604080517f1b6b6d230000000000000000000000000000000000000000000000000000000081529051939450911691631b6b6d23916004808201926020929091908290030181865afa158015611877573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061189b9190614fe8565b601280547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff929092169190911790555050565b8560005b81811015611ba257600089898381811061190457611904614e9e565b9050602002013590503073ffffffffffffffffffffffffffffffffffffffff16637e7a46dc828360405160200161193d91815260200190565b6040516020818303038152906040526040518363ffffffff1660e01b8152600401611969929190614eec565b600060405180830381600087803b15801561198357600080fd5b505af1158015611997573d6000803e3d6000fd5b50506013546040517f5147cd59000000000000000000000000000000000000000000000000000000008152600481018590526000935073ffffffffffffffffffffffffffffffffffffffff9091169150635147cd5990602401602060405180830381865afa158015611a0d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a319190615005565b90508060ff16600103611b8d576040517ffa333dfb000000000000000000000000000000000000000000000000000000008152306004820181905260ff8b166024830152604482018a9052606482018890526084820188905260a4820187905260009163fa333dfb9060c401600060405180830381865afa158015611aba573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201604052611b009190810190614f52565b6013546040517f4ee88d3500000000000000000000000000000000000000000000000000000000815291925073ffffffffffffffffffffffffffffffffffffffff1690634ee88d3590611b599086908590600401614eec565b600060405180830381600087803b158015611b7357600080fd5b505af1158015611b87573d6000803e3d6000fd5b50505050505b50508080611b9a90615022565b9150506118e8565b505050505050505050565b6000838152600c602090815260408083208054825181850281018501909352808352611c0e93830182828015611c0257602002820191906000526020600020905b815481526020019060010190808311611bee575b50505050508484613b38565b90505b9392505050565b604080516101408101825260008082526020820181905260609282018390528282018190526080820181905260a0820181905260c0820181905260e082018190526101008201526101208101919091526013546040517fc7c3a19a0000000000000000000000000000000000000000000000000000000081526004810184905273ffffffffffffffffffffffffffffffffffffffff9091169063c7c3a19a90602401600060405180830381865afa158015611cd7573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201604052611467919081019061507d565b8060005b818160ff161015611df85760135473ffffffffffffffffffffffffffffffffffffffff1663c8048022858560ff8516818110611d5f57611d5f614e9e565b905060200201356040518263ffffffff1660e01b8152600401611d8491815260200190565b600060405180830381600087803b158015611d9e57600080fd5b505af1158015611db2573d6000803e3d6000fd5b50505050611de584848360ff16818110611dce57611dce614e9e565b90506020020135600f613c9790919063ffffffff16565b5080611df081614ecd565b915050611d21565b50505050565b6000818152600e602052604081205461ffff1681805b8261ffff168161ffff1611611e5f576000858152600d6020908152604080832061ffff85168452909152902054611e4b908361519c565b915080611e57816151af565b915050611e14565b509392505050565b60005a9050600080611e7b84860186614a10565b91509150600081806020019051810190611e9591906151d0565b60008181526005602090815260408083205460049092528220549293509190611ebc613ca3565b905082600003611edc576000848152600560205260409020819055612037565b600084815260036020526040812054611ef584846151e9565b611eff91906151e9565b6000868152600e6020908152604080832054600d835281842061ffff909116808552908352818420805483518186028101860190945280845295965090949192909190830182828015611f7157602002820191906000526020600020905b815481526020019060010190808311611f5d575b505050505090507f000000000000000000000000000000000000000000000000000000000000000061ffff16815103611fec5781611fae816151af565b6000898152600e6020526040902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00001661ffff83161790559250505b506000868152600d6020908152604080832061ffff909416835292815282822080546001818101835591845282842001859055888352600c8252928220805493840181558252902001555b60008481526006602052604081205461205190600161519c565b600086815260066020908152604080832084905560049091529020839055905061207b8583612a6e565b6112d88589846130e3565b6000828152600d6020908152604080832061ffff851684528252918290208054835181840281018401909452808452606093928301828280156120e857602002820191906000526020600020905b8154815260200190600101908083116120d4575b5050505050905092915050565b600060606000848460405160200161210e9291906151fc565b604080518083037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe00181529190526001969095509350505050565b6013546040517f5147cd590000000000000000000000000000000000000000000000000000000081526004810183905260009173ffffffffffffffffffffffffffffffffffffffff1690635147cd5990602401602060405180830381865afa1580156121b9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114679190615005565b8160005b8181101561227a5730635f17e61686868481811061220157612201614e9e565b90506020020135856040518363ffffffff1660e01b815260040161223592919091825263ffffffff16602082015260400190565b600060405180830381600087803b15801561224f57600080fd5b505af1158015612263573d6000803e3d6000fd5b50505050808061227290615022565b9150506121e1565b5050505050565b612289613d45565b6012546040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015260009173ffffffffffffffffffffffffffffffffffffffff16906370a0823190602401602060405180830381865afa1580156122f8573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061231c91906151d0565b6012546040517fa9059cbb0000000000000000000000000000000000000000000000000000000081523360048201526024810183905291925073ffffffffffffffffffffffffffffffffffffffff169063a9059cbb906044016020604051808303816000875af1158015612394573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123b89190614e83565b5050565b60008281526003602090815260408083208490556005825280832083905560068252808320839055600c90915281206123f4916141ca565b6000828152600e602052604081205461ffff16905b8161ffff168161ffff1611612450576000848152600d6020908152604080832061ffff85168452909152812061243e916141ca565b80612448816151af565b915050612409565b5050506000908152600e6020526040902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000169055565b6000606060005a905060006124a085870187614558565b60008181526009602090815260408083205460089092528220549293509190838367ffffffffffffffff8111156124d9576124d96142cb565b6040519080825280601f01601f191660200182016040528015612503576020820181803683370190505b50604051602001612515929190614eec565b60405160208183030381529060405290506000612530613ca3565b9050600061253d866126b2565b90505b835a61254c90896151e9565b6125589061271061519c565b10156125995781406000908152600b6020526040902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169055612540565b806125b15760008398509850505050505050506116bb565b6040517f6665656449644865780000000000000000000000000000000000000000000000602082015260009060290160405160208183030381529060405280519060200120601860405160200161260891906152e3565b604051602081830303815290604052805190602001200361262a57508161262d565b50425b601760166018838a60405160200161264791815260200190565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152908290527ff055e4a20000000000000000000000000000000000000000000000000000000082526126a99594939291600401615412565b60405180910390fd5b60008181526005602052604081205481036126cf57506001919050565b6000828152600360209081526040808320546004909252909120546126f2613ca3565b6126fc91906151e9565b101592915050565b60015473ffffffffffffffffffffffffffffffffffffffff163314612785576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e65720000000000000000000060448201526064016126a9565b60008054337fffffffffffffffffffffffff00000000000000000000000000000000000000008083168217845560018054909116905560405173ffffffffffffffffffffffffffffffffffffffff90921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b6013546040517f79ea99430000000000000000000000000000000000000000000000000000000081526004810183905260009173ffffffffffffffffffffffffffffffffffffffff16906379ea994390602401602060405180830381865afa158015612871573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114679190614fe8565b6013546040517fcd7f71b500000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff9091169063cd7f71b5906128ef908690869086906004016154d5565b600060405180830381600087803b15801561290957600080fd5b505af115801561291d573d6000803e3d6000fd5b50505050505050565b6013546040517f4ee88d3500000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff90911690634ee88d35906128ef908690869086906004016154d5565b601761298c838261556f565b506018612999828261556f565b505050565b80516123b89060169060208401906141e8565b6013546040517f06e3b632000000000000000000000000000000000000000000000000000000008152600481018490526024810183905260609173ffffffffffffffffffffffffffffffffffffffff16906306e3b63290604401600060405180830381865afa158015612a28573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201604052611c119190810190615689565b601454600083815260026020526040902054612a8a90836151e9565b11156123b8576013546040517fc7c3a19a0000000000000000000000000000000000000000000000000000000081526004810184905260009173ffffffffffffffffffffffffffffffffffffffff169063c7c3a19a90602401600060405180830381865afa158015612b00573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201604052612b46919081019061507d565b6013546040517fb657bc9c0000000000000000000000000000000000000000000000000000000081526004810186905291925060009173ffffffffffffffffffffffffffffffffffffffff9091169063b657bc9c90602401602060405180830381865afa158015612bbb573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612bdf9190614f92565b601554909150612c039082906c01000000000000000000000000900460ff16614e3f565b6bffffffffffffffffffffffff1682606001516bffffffffffffffffffffffff161015611df857601554612c469085906bffffffffffffffffffffffff16612cb3565b60008481526002602090815260409182902085905560155482518781526bffffffffffffffffffffffff909116918101919091529081018490527f49d4100ab0124eb4a9a65dc4ea08d6412a43f6f05c49194983f5b322bcc0a5c09060600160405180910390a150505050565b6012546013546040517f095ea7b300000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff91821660048201526bffffffffffffffffffffffff8416602482015291169063095ea7b3906044016020604051808303816000875af1158015612d3b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612d5f9190614e83565b506013546040517f948108f7000000000000000000000000000000000000000000000000000000008152600481018490526bffffffffffffffffffffffff8316602482015273ffffffffffffffffffffffffffffffffffffffff9091169063948108f79060440161137a565b6040517fc04198220000000000000000000000000000000000000000000000000000000081526000600482018190526024820181905290309063c041982290604401600060405180830381865afa158015612e2a573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201604052612e709190810190615689565b80519091506000612e7f613ca3565b905060005b8281101561227a576000848281518110612ea057612ea0614e9e565b60209081029190910101516013546040517f5147cd590000000000000000000000000000000000000000000000000000000081526004810183905291925060009173ffffffffffffffffffffffffffffffffffffffff90911690635147cd5990602401602060405180830381865afa158015612f20573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612f449190615005565b90508060ff16600103612fc0578660ff16600003612f90576040513090859084907f97009585a4d2440f981ab6f6eec514343e1e6b2aa9b991a26998e6806f41bf0890600090a4612fc0565b6040513090859084907fc76416badc8398ce17c93eab7b4f60f263241694cf503e4df24f233a8cc1c50d90600090a45b50508080612fcd90615022565b915050612e84565b6000818152600c602090815260409182902080548351818402810184019094528084526060939283018282801561302b57602002820191906000526020600020905b815481526020019060010190808311613017575b50505050509050919050565b6016818154811061304757600080fd5b90600052602060002001600091509050805461306290615290565b80601f016020809104026020016040519081016040528092919081815260200182805461308e90615290565b80156130db5780601f106130b0576101008083540402835291602001916130db565b820191906000526020600020905b8154815290600101906020018083116130be57829003601f168201915b505050505081565b6000838152600760205260409020545b805a6130ff90856151e9565b61310b9061271061519c565b1015611df85781406000908152600b6020526040902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001690556130f3565b6013546040517fa72aa27e0000000000000000000000000000000000000000000000000000000081526004810184905263ffffffff8316602482015273ffffffffffffffffffffffffffffffffffffffff9091169063a72aa27e90604401600060405180830381600087803b1580156131c457600080fd5b505af11580156131d8573d6000803e3d6000fd5b505050600092835250600a602052604090912063ffffffff9091169055565b6013546040517f744bfe610000000000000000000000000000000000000000000000000000000081526004810183905230602482015273ffffffffffffffffffffffffffffffffffffffff9091169063744bfe6190604401600060405180830381600087803b15801561326957600080fd5b505af115801561227a573d6000803e3d6000fd5b6017805461306290615290565b6013546040517fb657bc9c0000000000000000000000000000000000000000000000000000000081526004810183905260009173ffffffffffffffffffffffffffffffffffffffff169063b657bc9c906024016115fe565b8060005b818163ffffffff161015611df8573063af953a4a858563ffffffff851681811061331257613312614e9e565b905060200201356040518263ffffffff1660e01b815260040161333791815260200190565b600060405180830381600087803b15801561335157600080fd5b505af1158015613365573d6000803e3d6000fd5b5050505080806133749061571a565b9150506132e6565b6060600061338a600f613dc8565b90508084106133c5576040517f1390f2a100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b826000036133da576133d784826151e9565b92505b60008367ffffffffffffffff8111156133f5576133f56142cb565b60405190808252806020026020018201604052801561341e578160200160208202803683370190505b50905060005b8481101561347057613441613439828861519c565b600f90613dd2565b82828151811061345357613453614e9e565b60209081029190910101528061346881615022565b915050613424565b50949350505050565b6018805461306290615290565b6000613490613ca3565b90508160ff166000036134d1576040513090829085907f97009585a4d2440f981ab6f6eec514343e1e6b2aa9b991a26998e6806f41bf0890600090a4505050565b6040513090829085907fc76416badc8398ce17c93eab7b4f60f263241694cf503e4df24f233a8cc1c50d90600090a4505050565b6000828152600c6020908152604080832080548251818502810185019093528083528493849392919083018282801561355d57602002820191906000526020600020905b815481526020019060010190808311613549575b505050505090506116b58185613ab3565b8260005b818110156113a857600086868381811061358e5761358e614e9e565b9050602002013590503073ffffffffffffffffffffffffffffffffffffffff16637e7a46dc82836040516020016135c791815260200190565b6040516020818303038152906040526040518363ffffffff1660e01b81526004016135f3929190614eec565b600060405180830381600087803b15801561360d57600080fd5b505af1158015613621573d6000803e3d6000fd5b50506013546040517f5147cd59000000000000000000000000000000000000000000000000000000008152600481018590526000935073ffffffffffffffffffffffffffffffffffffffff9091169150635147cd5990602401602060405180830381865afa158015613697573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906136bb9190615005565b90508060ff166001036138c0577f000000000000000000000000000000000000000000000000000000000000000060ff87161561371557507f00000000000000000000000000000000000000000000000000000000000000005b60003073ffffffffffffffffffffffffffffffffffffffff1663fa333dfb3089858860405160200161374991815260200190565b60405160208183030381529060405261376190615733565b60405160e086901b7fffffffff0000000000000000000000000000000000000000000000000000000016815273ffffffffffffffffffffffffffffffffffffffff909416600485015260ff90921660248401526044830152606482015260006084820181905260a482015260c401600060405180830381865afa1580156137ec573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01682016040526138329190810190614f52565b6013546040517f4ee88d3500000000000000000000000000000000000000000000000000000000815291925073ffffffffffffffffffffffffffffffffffffffff1690634ee88d359061388b9087908590600401614eec565b600060405180830381600087803b1580156138a557600080fd5b505af11580156138b9573d6000803e3d6000fd5b5050505050505b505080806138cd90615022565b915050613572565b8060005b81811015611df85760008484838181106138f5576138f5614e9e565b9050602002013590503073ffffffffffffffffffffffffffffffffffffffff16637e7a46dc828360405160200161392e91815260200190565b6040516020818303038152906040526040518363ffffffff1660e01b815260040161395a929190614eec565b600060405180830381600087803b15801561397457600080fd5b505af1158015613988573d6000803e3d6000fd5b5050505050808061399890615022565b9150506138d9565b600c60205281600052604060002081815481106139bc57600080fd5b90600052602060002001600091509150505481565b6139d9613d45565b6139e281613dde565b50565b6011546040517f3f678e11000000000000000000000000000000000000000000000000000000008152600091829173ffffffffffffffffffffffffffffffffffffffff90911690633f678e1190613a40908690600401615775565b6020604051808303816000875af1158015613a5f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613a8391906151d0565b9050613a90600f82613ed3565b506060909201516000838152600a6020526040902063ffffffff90911690555090565b815160009081908190841580613ac95750808510155b15613ad2578094505b60008092505b85831015613b2e57866001613aed85856151e9565b613af791906151e9565b81518110613b0757613b07614e9e565b602002602001015181613b1a919061519c565b905082613b2681615022565b935050613ad8565b9694955050505050565b82516000908190831580613b4c5750808410155b15613b55578093505b60008467ffffffffffffffff811115613b7057613b706142cb565b604051908082528060200260200182016040528015613b99578160200160208202803683370190505b509050600092505b84831015613c0757866001613bb685856151e9565b613bc091906151e9565b81518110613bd057613bd0614e9e565b6020026020010151818481518110613bea57613bea614e9e565b602090810291909101015282613bff81615022565b935050613ba1565b613c2081600060018451613c1b91906151e9565b613edf565b85606403613c59578060018251613c3791906151e9565b81518110613c4757613c47614e9e565b60200260200101519350505050611c11565b806064825188613c6991906158c7565b613c739190615933565b81518110613c8357613c83614e9e565b602002602001015193505050509392505050565b6000611c118383614057565b60007f000000000000000000000000000000000000000000000000000000000000000015613d4057606473ffffffffffffffffffffffffffffffffffffffff1663a3b1b31d6040518163ffffffff1660e01b8152600401602060405180830381865afa158015613d17573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613d3b91906151d0565b905090565b504390565b60005473ffffffffffffffffffffffffffffffffffffffff163314613dc6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e65720000000000000000000060448201526064016126a9565b565b6000611467825490565b6000611c118383614151565b3373ffffffffffffffffffffffffffffffffffffffff821603613e5d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c6600000000000000000060448201526064016126a9565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b6000611c11838361417b565b8181808203613eef575050505050565b6000856002613efe8787615947565b613f089190615967565b613f1290876159cf565b81518110613f2257613f22614e9e565b602002602001015190505b818313614031575b80868481518110613f4857613f48614e9e565b60200260200101511015613f685782613f60816159f7565b935050613f35565b858281518110613f7a57613f7a614e9e565b6020026020010151811015613f9b5781613f9381615a28565b925050613f68565b81831361402c57858281518110613fb457613fb4614e9e565b6020026020010151868481518110613fce57613fce614e9e565b6020026020010151878581518110613fe857613fe8614e9e565b6020026020010188858151811061400157614001614e9e565b6020908102919091010191909152528261401a816159f7565b935050818061402890615a28565b9250505b613f2d565b8185121561404457614044868684613edf565b838312156113a8576113a8868486613edf565b6000818152600183016020526040812054801561414057600061407b6001836151e9565b855490915060009061408f906001906151e9565b90508181146140f45760008660000182815481106140af576140af614e9e565b90600052602060002001549050808760000184815481106140d2576140d2614e9e565b6000918252602080832090910192909255918252600188019052604090208390555b855486908061410557614105615a7f565b600190038181906000526020600020016000905590558560010160008681526020019081526020016000206000905560019350505050611467565b6000915050611467565b5092915050565b600082600001828154811061416857614168614e9e565b9060005260206000200154905092915050565b60008181526001830160205260408120546141c257508154600181810184556000848152602080822090930184905584548482528286019093526040902091909155611467565b506000611467565b50805460008255906000526020600020908101906139e2919061423e565b82805482825590600052602060002090810192821561422e579160200282015b8281111561422e578251829061421e908261556f565b5091602001919060010190614208565b5061423a929150614253565b5090565b5b8082111561423a576000815560010161423f565b8082111561423a5760006142678282614270565b50600101614253565b50805461427c90615290565b6000825580601f1061428c575050565b601f0160209004906000526020600020908101906139e2919061423e565b60ff811681146139e257600080fd5b63ffffffff811681146139e257600080fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051610140810167ffffffffffffffff8111828210171561431e5761431e6142cb565b60405290565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff8111828210171561436b5761436b6142cb565b604052919050565b600067ffffffffffffffff82111561438d5761438d6142cb565b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b600082601f8301126143ca57600080fd5b81356143dd6143d882614373565b614324565b8181528460208386010111156143f257600080fd5b816020850160208301376000918101602001919091529392505050565b6bffffffffffffffffffffffff811681146139e257600080fd5b600080600080600080600060e0888a03121561444457600080fd5b873561444f816142aa565b9650602088013561445f816142b9565b9550604088013561446f816142aa565b9450606088013567ffffffffffffffff81111561448b57600080fd5b6144978a828b016143b9565b94505060808801356144a88161440f565b9699959850939692959460a0840135945060c09093013592915050565b803561ffff811681146144d757600080fd5b919050565b6000806000606084860312156144f157600080fd5b83359250614501602085016144c5565b9150604084013590509250925092565b6000806040838503121561452457600080fd5b82359150602083013567ffffffffffffffff81111561454257600080fd5b61454e858286016143b9565b9150509250929050565b60006020828403121561456a57600080fd5b5035919050565b60005b8381101561458c578181015183820152602001614574565b50506000910152565b600081518084526145ad816020860160208601614571565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b602081526000611c116020830184614595565b73ffffffffffffffffffffffffffffffffffffffff811681146139e257600080fd5b600080600080600080600060e0888a03121561462f57600080fd5b873596506020880135614641816145f2565b95506040880135614651816142aa565b969995985095966060810135965060808101359560a0820135955060c0909101359350915050565b6000806040838503121561468c57600080fd5b8235915061469c602084016144c5565b90509250929050565b6000602082840312156146b757600080fd5b8135611c11816145f2565b60008083601f8401126146d457600080fd5b50813567ffffffffffffffff8111156146ec57600080fd5b6020830191508360208260051b85010111156116bb57600080fd5b600080600080600080600060c0888a03121561472257600080fd5b873567ffffffffffffffff81111561473957600080fd5b6147458a828b016146c2565b9098509650506020880135614759816142aa565b96999598509596604081013596506060810135956080820135955060a0909101359350915050565b60008060006060848603121561479657600080fd5b505081359360208301359350604090920135919050565b602081526147d460208201835173ffffffffffffffffffffffffffffffffffffffff169052565b600060208301516147ed604084018263ffffffff169052565b50604083015161014080606085015261480a610160850183614595565b9150606085015161482b60808601826bffffffffffffffffffffffff169052565b50608085015173ffffffffffffffffffffffffffffffffffffffff811660a08601525060a085015167ffffffffffffffff811660c08601525060c085015163ffffffff811660e08601525060e0850151610100614897818701836bffffffffffffffffffffffff169052565b86015190506101206148ac8682018315159052565b8601518584037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0018387015290506148e48382614595565b9695505050505050565b6000806020838503121561490157600080fd5b823567ffffffffffffffff81111561491857600080fd5b614924858286016146c2565b90969095509350505050565b60008083601f84011261494257600080fd5b50813567ffffffffffffffff81111561495a57600080fd5b6020830191508360208285010111156116bb57600080fd5b6000806020838503121561498557600080fd5b823567ffffffffffffffff81111561499c57600080fd5b61492485828601614930565b6020808252825182820181905260009190848201906040850190845b818110156149e0578351835292840192918401916001016149c4565b50909695505050505050565b600067ffffffffffffffff821115614a0657614a066142cb565b5060051b60200190565b60008060408385031215614a2357600080fd5b823567ffffffffffffffff80821115614a3b57600080fd5b818501915085601f830112614a4f57600080fd5b81356020614a5f6143d8836149ec565b82815260059290921b84018101918181019089841115614a7e57600080fd5b8286015b84811015614ab657803586811115614a9a5760008081fd5b614aa88c86838b01016143b9565b845250918301918301614a82565b5096505086013592505080821115614acd57600080fd5b5061454e858286016143b9565b8215158152604060208201526000611c0e6040830184614595565b600080600060408486031215614b0a57600080fd5b833567ffffffffffffffff811115614b2157600080fd5b614b2d868287016146c2565b9094509250506020840135614b41816142b9565b809150509250925092565b60008060408385031215614b5f57600080fd5b50508035926020909101359150565b600080600060408486031215614b8357600080fd5b83359250602084013567ffffffffffffffff811115614ba157600080fd5b614bad86828701614930565b9497909650939450505050565b60008060408385031215614bcd57600080fd5b823567ffffffffffffffff80821115614be557600080fd5b614bf1868387016143b9565b93506020850135915080821115614acd57600080fd5b60006020808385031215614c1a57600080fd5b823567ffffffffffffffff80821115614c3257600080fd5b818501915085601f830112614c4657600080fd5b8135614c546143d8826149ec565b81815260059190911b83018401908481019088831115614c7357600080fd5b8585015b83811015614cab57803585811115614c8f5760008081fd5b614c9d8b89838a01016143b9565b845250918601918601614c77565b5098975050505050505050565b60008060408385031215614ccb57600080fd5b823591506020830135614cdd8161440f565b809150509250929050565b600060208284031215614cfa57600080fd5b8135611c11816142aa565b60008060408385031215614d1857600080fd5b823591506020830135614cdd816142b9565b60008060408385031215614d3d57600080fd5b823591506020830135614cdd816142aa565b60008060008060608587031215614d6557600080fd5b843567ffffffffffffffff811115614d7c57600080fd5b614d88878288016146c2565b9095509350506020850135614d9c816142aa565b91506040850135614dac816142aa565b939692955090935050565b60008060008060008060c08789031215614dd057600080fd5b8635614ddb816145f2565b95506020870135614deb816142aa565b95989597505050506040840135936060810135936080820135935060a0909101359150565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60006bffffffffffffffffffffffff80831681851681830481118215151615614e6a57614e6a614e10565b02949350505050565b805180151581146144d757600080fd5b600060208284031215614e9557600080fd5b611c1182614e73565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b600060ff821660ff8103614ee357614ee3614e10565b60010192915050565b828152604060208201526000611c0e6040830184614595565b600082601f830112614f1657600080fd5b8151614f246143d882614373565b818152846020838601011115614f3957600080fd5b614f4a826020830160208701614571565b949350505050565b600060208284031215614f6457600080fd5b815167ffffffffffffffff811115614f7b57600080fd5b614f4a84828501614f05565b80516144d78161440f565b600060208284031215614fa457600080fd5b8151611c118161440f565b80516144d7816145f2565b60008060408385031215614fcd57600080fd5b8251614fd8816145f2565b6020939093015192949293505050565b600060208284031215614ffa57600080fd5b8151611c11816145f2565b60006020828403121561501757600080fd5b8151611c11816142aa565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff820361505357615053614e10565b5060010190565b80516144d7816142b9565b805167ffffffffffffffff811681146144d757600080fd5b60006020828403121561508f57600080fd5b815167ffffffffffffffff808211156150a757600080fd5b9083019061014082860312156150bc57600080fd5b6150c46142fa565b6150cd83614faf565b81526150db6020840161505a565b60208201526040830151828111156150f257600080fd5b6150fe87828601614f05565b60408301525061511060608401614f87565b606082015261512160808401614faf565b608082015261513260a08401615065565b60a082015261514360c0840161505a565b60c082015261515460e08401614f87565b60e0820152610100615167818501614e73565b90820152610120838101518381111561517f57600080fd5b61518b88828701614f05565b918301919091525095945050505050565b8082018082111561146757611467614e10565b600061ffff8083168181036151c6576151c6614e10565b6001019392505050565b6000602082840312156151e257600080fd5b5051919050565b8181038181111561146757611467614e10565b6000604082016040835280855180835260608501915060608160051b8601019250602080880160005b83811015615271577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa088870301855261525f868351614595565b95509382019390820190600101615225565b5050858403818701525050506152878185614595565b95945050505050565b600181811c908216806152a457607f821691505b6020821081036152dd577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b50919050565b60008083546152f181615290565b60018281168015615309576001811461533c5761536b565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff008416875282151583028701945061536b565b8760005260208060002060005b858110156153625781548a820152908401908201615349565b50505082870194505b50929695505050505050565b6000815461538481615290565b8085526020600183811680156153a157600181146153d957615407565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff008516838901528284151560051b8901019550615407565b866000528260002060005b858110156153ff5781548a82018601529083019084016153e4565b890184019650505b505050505092915050565b60a08152600061542560a0830188615377565b6020838203818501528188548084528284019150828160051b8501018a6000528360002060005b83811015615497577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08784030185526154858383615377565b9486019492506001918201910161544c565b505086810360408801526154ab818b615377565b94505050505084606084015282810360808401526154c98185614595565b98975050505050505050565b83815260406020820152816040820152818360608301376000818301606090810191909152601f9092017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016010192915050565b601f82111561299957600081815260208120601f850160051c810160208610156155505750805b601f850160051c820191505b818110156113a85782815560010161555c565b815167ffffffffffffffff811115615589576155896142cb565b61559d816155978454615290565b84615529565b602080601f8311600181146155f057600084156155ba5750858301515b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600386901b1c1916600185901b1785556113a8565b6000858152602081207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08616915b8281101561563d5788860151825594840194600190910190840161561e565b508582101561567957878501517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600388901b60f8161c191681555b5050505050600190811b01905550565b6000602080838503121561569c57600080fd5b825167ffffffffffffffff8111156156b357600080fd5b8301601f810185136156c457600080fd5b80516156d26143d8826149ec565b81815260059190911b820183019083810190878311156156f157600080fd5b928401925b8284101561570f578351825292840192908401906156f6565b979650505050505050565b600063ffffffff8083168181036151c6576151c6614e10565b805160208083015191908110156152dd577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60209190910360031b1b16919050565b6020815260008251610140806020850152615794610160850183614595565b915060208501517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0808685030160408701526157d08483614595565b9350604087015191506157fb606087018373ffffffffffffffffffffffffffffffffffffffff169052565b606087015163ffffffff811660808801529150608087015173ffffffffffffffffffffffffffffffffffffffff811660a0880152915060a087015160ff811660c0880152915060c08701519150808685030160e087015261585c8483614595565b935060e0870151915061010081878603018188015261587b8584614595565b94508088015192505061012081878603018188015261589a8584614595565b945080880151925050506158bd828601826bffffffffffffffffffffffff169052565b5090949350505050565b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff04831182151516156158ff576158ff614e10565b500290565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b60008261594257615942615904565b500490565b818103600083128015838313168383128216171561414a5761414a614e10565b60008261597657615976615904565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff83147f8000000000000000000000000000000000000000000000000000000000000000831416156159ca576159ca614e10565b500590565b80820182811260008312801582168215821617156159ef576159ef614e10565b505092915050565b60007f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff820361505357615053614e10565b60007f80000000000000000000000000000000000000000000000000000000000000008203615a5957615a59614e10565b507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0190565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fdfea164736f6c6343000810000a307834353534343832643535353334343264343135323432343935343532353534643264353434353533353434653435353430303030303030303030303030303030307834323534343332643535353334343264343135323432343935343532353534643264353434353533353434653435353430303030303030303030303030303030", } var VerifiableLoadStreamsLookupUpkeepABI = VerifiableLoadStreamsLookupUpkeepMetaData.ABI diff --git a/core/gethwrappers/generated/vrf_coordinator_v2plus/vrf_coordinator_v2plus.go b/core/gethwrappers/generated/vrf_coordinator_v2plus/vrf_coordinator_v2plus.go index 710e2ae2ab7..53dab6a4788 100644 --- a/core/gethwrappers/generated/vrf_coordinator_v2plus/vrf_coordinator_v2plus.go +++ b/core/gethwrappers/generated/vrf_coordinator_v2plus/vrf_coordinator_v2plus.go @@ -66,8 +66,8 @@ type VRFV2PlusClientRandomWordsRequest struct { } var VRFCoordinatorV2PlusMetaData = &bind.MetaData{ - ABI: "[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"blockhashStore\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"internalBalance\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"externalBalance\",\"type\":\"uint256\"}],\"name\":\"BalanceInvariantViolated\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"blockNum\",\"type\":\"uint256\"}],\"name\":\"BlockhashNotInStore\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"coordinatorAddress\",\"type\":\"address\"}],\"name\":\"CoordinatorAlreadyRegistered\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"coordinatorAddress\",\"type\":\"address\"}],\"name\":\"CoordinatorNotRegistered\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"FailedToSendEther\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"FailedToTransferLink\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"have\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"want\",\"type\":\"uint32\"}],\"name\":\"GasLimitTooBig\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"IncorrectCommitment\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"IndexOutOfRange\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InsufficientBalance\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"have\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"want\",\"type\":\"uint256\"}],\"name\":\"InsufficientGasForConsumer\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidCalldata\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"consumer\",\"type\":\"address\"}],\"name\":\"InvalidConsumer\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidExtraArgsTag\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"int256\",\"name\":\"linkWei\",\"type\":\"int256\"}],\"name\":\"InvalidLinkWeiPrice\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint16\",\"name\":\"have\",\"type\":\"uint16\"},{\"internalType\":\"uint16\",\"name\":\"min\",\"type\":\"uint16\"},{\"internalType\":\"uint16\",\"name\":\"max\",\"type\":\"uint16\"}],\"name\":\"InvalidRequestConfirmations\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidSubscription\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"LinkAlreadySet\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"proposedOwner\",\"type\":\"address\"}],\"name\":\"MustBeRequestedOwner\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"}],\"name\":\"MustBeSubOwner\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"NoCorrespondingRequest\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"keyHash\",\"type\":\"bytes32\"}],\"name\":\"NoSuchProvingKey\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"have\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"want\",\"type\":\"uint32\"}],\"name\":\"NumWordsTooBig\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableFromLink\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"PaymentTooLarge\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"PendingRequestExists\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"keyHash\",\"type\":\"bytes32\"}],\"name\":\"ProvingKeyAlreadyRegistered\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"Reentrant\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"TooManyConsumers\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint16\",\"name\":\"minimumRequestConfirmations\",\"type\":\"uint16\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"maxGasLimit\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"stalenessSeconds\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"gasAfterPaymentCalculation\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"int256\",\"name\":\"fallbackWeiPerUnitLink\",\"type\":\"int256\"},{\"components\":[{\"internalType\":\"uint32\",\"name\":\"fulfillmentFlatFeeLinkPPM\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"fulfillmentFlatFeeEthPPM\",\"type\":\"uint32\"}],\"indexed\":false,\"internalType\":\"structVRFCoordinatorV2Plus.FeeConfig\",\"name\":\"feeConfig\",\"type\":\"tuple\"}],\"name\":\"ConfigSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"coordinatorAddress\",\"type\":\"address\"}],\"name\":\"CoordinatorDeregistered\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"coordinatorAddress\",\"type\":\"address\"}],\"name\":\"CoordinatorRegistered\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"EthFundsRecovered\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"FundsRecovered\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"newCoordinator\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"}],\"name\":\"MigrationCompleted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"OwnershipTransferRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"keyHash\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"oracle\",\"type\":\"address\"}],\"name\":\"ProvingKeyDeregistered\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"keyHash\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"oracle\",\"type\":\"address\"}],\"name\":\"ProvingKeyRegistered\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"requestId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"outputSeed\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"subID\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint96\",\"name\":\"payment\",\"type\":\"uint96\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"success\",\"type\":\"bool\"}],\"name\":\"RandomWordsFulfilled\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"keyHash\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"requestId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"preSeed\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint16\",\"name\":\"minimumRequestConfirmations\",\"type\":\"uint16\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"callbackGasLimit\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"numWords\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"extraArgs\",\"type\":\"bytes\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RandomWordsRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amountLink\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amountEth\",\"type\":\"uint256\"}],\"name\":\"SubscriptionCanceled\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"consumer\",\"type\":\"address\"}],\"name\":\"SubscriptionConsumerAdded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"consumer\",\"type\":\"address\"}],\"name\":\"SubscriptionConsumerRemoved\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"}],\"name\":\"SubscriptionCreated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"oldBalance\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newBalance\",\"type\":\"uint256\"}],\"name\":\"SubscriptionFunded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"oldEthBalance\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newEthBalance\",\"type\":\"uint256\"}],\"name\":\"SubscriptionFundedWithEth\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"SubscriptionOwnerTransferRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"SubscriptionOwnerTransferred\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"BLOCKHASH_STORE\",\"outputs\":[{\"internalType\":\"contractBlockhashStoreInterface\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"LINK\",\"outputs\":[{\"internalType\":\"contractLinkTokenInterface\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"LINK_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\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"}],\"name\":\"acceptSubscriptionOwnerTransfer\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"consumer\",\"type\":\"address\"}],\"name\":\"addConsumer\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"cancelSubscription\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"createSubscription\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"}],\"name\":\"deregisterMigratableCoordinator\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256[2]\",\"name\":\"publicProvingKey\",\"type\":\"uint256[2]\"}],\"name\":\"deregisterProvingKey\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint256[2]\",\"name\":\"pk\",\"type\":\"uint256[2]\"},{\"internalType\":\"uint256[2]\",\"name\":\"gamma\",\"type\":\"uint256[2]\"},{\"internalType\":\"uint256\",\"name\":\"c\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"s\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"seed\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"uWitness\",\"type\":\"address\"},{\"internalType\":\"uint256[2]\",\"name\":\"cGammaWitness\",\"type\":\"uint256[2]\"},{\"internalType\":\"uint256[2]\",\"name\":\"sHashWitness\",\"type\":\"uint256[2]\"},{\"internalType\":\"uint256\",\"name\":\"zInv\",\"type\":\"uint256\"}],\"internalType\":\"structVRF.Proof\",\"name\":\"proof\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"uint64\",\"name\":\"blockNum\",\"type\":\"uint64\"},{\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"},{\"internalType\":\"uint32\",\"name\":\"callbackGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"numWords\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"extraArgs\",\"type\":\"bytes\"}],\"internalType\":\"structVRFCoordinatorV2Plus.RequestCommitment\",\"name\":\"rc\",\"type\":\"tuple\"}],\"name\":\"fulfillRandomWords\",\"outputs\":[{\"internalType\":\"uint96\",\"name\":\"\",\"type\":\"uint96\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"}],\"name\":\"fundSubscriptionWithEth\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"startIndex\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"maxCount\",\"type\":\"uint256\"}],\"name\":\"getActiveSubscriptionIds\",\"outputs\":[{\"internalType\":\"uint256[]\",\"name\":\"\",\"type\":\"uint256[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getRequestConfig\",\"outputs\":[{\"internalType\":\"uint16\",\"name\":\"\",\"type\":\"uint16\"},{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"},{\"internalType\":\"bytes32[]\",\"name\":\"\",\"type\":\"bytes32[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"}],\"name\":\"getSubscription\",\"outputs\":[{\"internalType\":\"uint96\",\"name\":\"balance\",\"type\":\"uint96\"},{\"internalType\":\"uint96\",\"name\":\"ethBalance\",\"type\":\"uint96\"},{\"internalType\":\"uint64\",\"name\":\"reqCount\",\"type\":\"uint64\"},{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"internalType\":\"address[]\",\"name\":\"consumers\",\"type\":\"address[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256[2]\",\"name\":\"publicKey\",\"type\":\"uint256[2]\"}],\"name\":\"hashOfKey\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"newCoordinator\",\"type\":\"address\"}],\"name\":\"migrate\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"migrationVersion\",\"outputs\":[{\"internalType\":\"uint8\",\"name\":\"version\",\"type\":\"uint8\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"onTokenTransfer\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"uint96\",\"name\":\"amount\",\"type\":\"uint96\"}],\"name\":\"oracleWithdraw\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"addresspayable\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"uint96\",\"name\":\"amount\",\"type\":\"uint96\"}],\"name\":\"oracleWithdrawEth\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"}],\"name\":\"ownerCancelSubscription\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"}],\"name\":\"pendingRequestExists\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"addresspayable\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"recoverEthFunds\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"recoverFunds\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"}],\"name\":\"registerMigratableCoordinator\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"oracle\",\"type\":\"address\"},{\"internalType\":\"uint256[2]\",\"name\":\"publicProvingKey\",\"type\":\"uint256[2]\"}],\"name\":\"registerProvingKey\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"consumer\",\"type\":\"address\"}],\"name\":\"removeConsumer\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"bytes32\",\"name\":\"keyHash\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"},{\"internalType\":\"uint16\",\"name\":\"requestConfirmations\",\"type\":\"uint16\"},{\"internalType\":\"uint32\",\"name\":\"callbackGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"numWords\",\"type\":\"uint32\"},{\"internalType\":\"bytes\",\"name\":\"extraArgs\",\"type\":\"bytes\"}],\"internalType\":\"structVRFV2PlusClient.RandomWordsRequest\",\"name\":\"req\",\"type\":\"tuple\"}],\"name\":\"requestRandomWords\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"requestSubscriptionOwnerTransfer\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_config\",\"outputs\":[{\"internalType\":\"uint16\",\"name\":\"minimumRequestConfirmations\",\"type\":\"uint16\"},{\"internalType\":\"uint32\",\"name\":\"maxGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"bool\",\"name\":\"reentrancyLock\",\"type\":\"bool\"},{\"internalType\":\"uint32\",\"name\":\"stalenessSeconds\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"gasAfterPaymentCalculation\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_currentSubNonce\",\"outputs\":[{\"internalType\":\"uint64\",\"name\":\"\",\"type\":\"uint64\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_fallbackWeiPerUnitLink\",\"outputs\":[{\"internalType\":\"int256\",\"name\":\"\",\"type\":\"int256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_feeConfig\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"fulfillmentFlatFeeLinkPPM\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"fulfillmentFlatFeeEthPPM\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"s_provingKeyHashes\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"name\":\"s_provingKeys\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"s_requestCommitments\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_totalBalance\",\"outputs\":[{\"internalType\":\"uint96\",\"name\":\"\",\"type\":\"uint96\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_totalEthBalance\",\"outputs\":[{\"internalType\":\"uint96\",\"name\":\"\",\"type\":\"uint96\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint16\",\"name\":\"minimumRequestConfirmations\",\"type\":\"uint16\"},{\"internalType\":\"uint32\",\"name\":\"maxGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"stalenessSeconds\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"gasAfterPaymentCalculation\",\"type\":\"uint32\"},{\"internalType\":\"int256\",\"name\":\"fallbackWeiPerUnitLink\",\"type\":\"int256\"},{\"components\":[{\"internalType\":\"uint32\",\"name\":\"fulfillmentFlatFeeLinkPPM\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"fulfillmentFlatFeeEthPPM\",\"type\":\"uint32\"}],\"internalType\":\"structVRFCoordinatorV2Plus.FeeConfig\",\"name\":\"feeConfig\",\"type\":\"tuple\"}],\"name\":\"setConfig\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"link\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"linkEthFeed\",\"type\":\"address\"}],\"name\":\"setLINKAndLINKETHFeed\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", - Bin: "0x60a06040523480156200001157600080fd5b50604051620060fa380380620060fa833981016040819052620000349162000183565b33806000816200008b5760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b0384811691909117909155811615620000be57620000be81620000d7565b50505060601b6001600160601b031916608052620001b5565b6001600160a01b038116331415620001325760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c66000000000000000000604482015260640162000082565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b6000602082840312156200019657600080fd5b81516001600160a01b0381168114620001ae57600080fd5b9392505050565b60805160601c615f1f620001db600039600081816105ee0152613a340152615f1f6000f3fe6080604052600436106102dc5760003560e01c80638da5cb5b1161017f578063bec4c08c116100e1578063dc311dd31161008a578063e95704bd11610064578063e95704bd1461095d578063ee9d2d3814610984578063f2fde38b146109b157600080fd5b8063dc311dd3146108f9578063e72f6e301461092a578063e8509bff1461094a57600080fd5b8063d98e620e116100bb578063d98e620e14610883578063da2f2610146108a3578063dac83d29146108d957600080fd5b8063bec4c08c14610823578063caf70c4a14610843578063cb6317971461086357600080fd5b8063a8cb447b11610143578063aefb212f1161011d578063aefb212f146107b6578063b08c8795146107e3578063b2a7cac51461080357600080fd5b8063a8cb447b14610756578063aa433aff14610776578063ad1783611461079657600080fd5b80638da5cb5b146106ab5780639b1c385e146106c95780639d40a6fd146106e9578063a21a23e414610721578063a4c0ed361461073657600080fd5b806340d6bb821161024357806366316d8d116101ec5780636f64f03f116101c65780636f64f03f1461065657806379ba50971461067657806386fe91c71461068b57600080fd5b806366316d8d146105bc578063689c4517146105dc5780636b6feccc1461061057600080fd5b806357133e641161021d57806357133e64146105675780635d06b4ab1461058757806364d51a2a146105a757600080fd5b806340d6bb82146104ec57806341af6c871461051757806346d8d4861461054757600080fd5b80630ae09540116102a5578063294daa491161027f578063294daa4914610478578063330987b314610494578063405b84fa146104cc57600080fd5b80630ae09540146103f857806315c48b84146104185780631b6b6d231461044057600080fd5b8062012291146102e157806304104edb1461030e578063043bd6ae14610330578063088070f51461035457806308821d58146103d8575b600080fd5b3480156102ed57600080fd5b506102f66109d1565b60405161030593929190615a83565b60405180910390f35b34801561031a57600080fd5b5061032e6103293660046153d0565b610a4d565b005b34801561033c57600080fd5b5061034660115481565b604051908152602001610305565b34801561036057600080fd5b50600d546103a09061ffff81169063ffffffff62010000820481169160ff600160301b820416916701000000000000008204811691600160581b90041685565b6040805161ffff909616865263ffffffff9485166020870152921515928501929092528216606084015216608082015260a001610305565b3480156103e457600080fd5b5061032e6103f3366004615510565b610c0f565b34801561040457600080fd5b5061032e6104133660046157b2565b610da3565b34801561042457600080fd5b5061042d60c881565b60405161ffff9091168152602001610305565b34801561044c57600080fd5b50600254610460906001600160a01b031681565b6040516001600160a01b039091168152602001610305565b34801561048457600080fd5b5060405160018152602001610305565b3480156104a057600080fd5b506104b46104af3660046155e2565b610e71565b6040516001600160601b039091168152602001610305565b3480156104d857600080fd5b5061032e6104e73660046157b2565b61135b565b3480156104f857600080fd5b506105026101f481565b60405163ffffffff9091168152602001610305565b34801561052357600080fd5b50610537610532366004615565565b611782565b6040519015158152602001610305565b34801561055357600080fd5b5061032e6105623660046153ed565b611983565b34801561057357600080fd5b5061032e610582366004615422565b611b00565b34801561059357600080fd5b5061032e6105a23660046153d0565b611b60565b3480156105b357600080fd5b5061042d606481565b3480156105c857600080fd5b5061032e6105d73660046153ed565b611c1e565b3480156105e857600080fd5b506104607f000000000000000000000000000000000000000000000000000000000000000081565b34801561061c57600080fd5b506012546106399063ffffffff8082169164010000000090041682565b6040805163ffffffff938416815292909116602083015201610305565b34801561066257600080fd5b5061032e61067136600461545b565b611dbd565b34801561068257600080fd5b5061032e611ebc565b34801561069757600080fd5b50600a546104b4906001600160601b031681565b3480156106b757600080fd5b506000546001600160a01b0316610460565b3480156106d557600080fd5b506103466106e43660046156bf565b611f6d565b3480156106f557600080fd5b50600754610709906001600160401b031681565b6040516001600160401b039091168152602001610305565b34801561072d57600080fd5b50610346612362565b34801561074257600080fd5b5061032e610751366004615488565b6125b2565b34801561076257600080fd5b5061032e6107713660046153d0565b612752565b34801561078257600080fd5b5061032e610791366004615565565b61286d565b3480156107a257600080fd5b50600354610460906001600160a01b031681565b3480156107c257600080fd5b506107d66107d13660046157d7565b6128cd565b60405161030591906159e8565b3480156107ef57600080fd5b5061032e6107fe366004615714565b6129ce565b34801561080f57600080fd5b5061032e61081e366004615565565b612b62565b34801561082f57600080fd5b5061032e61083e3660046157b2565b612c98565b34801561084f57600080fd5b5061034661085e36600461552c565b612e34565b34801561086f57600080fd5b5061032e61087e3660046157b2565b612e64565b34801561088f57600080fd5b5061034661089e366004615565565b613167565b3480156108af57600080fd5b506104606108be366004615565565b600e602052600090815260409020546001600160a01b031681565b3480156108e557600080fd5b5061032e6108f43660046157b2565b613188565b34801561090557600080fd5b50610919610914366004615565565b6132a7565b604051610305959493929190615beb565b34801561093657600080fd5b5061032e6109453660046153d0565b6133a2565b61032e610958366004615565565b613561565b34801561096957600080fd5b50600a546104b490600160601b90046001600160601b031681565b34801561099057600080fd5b5061034661099f366004615565565b60106020526000908152604090205481565b3480156109bd57600080fd5b5061032e6109cc3660046153d0565b6136a0565b600d54600f805460408051602080840282018101909252828152600094859460609461ffff8316946201000090930463ffffffff16939192839190830182828015610a3b57602002820191906000526020600020905b815481526020019060010190808311610a27575b50505050509050925092509250909192565b610a556136b1565b60135460005b81811015610be257826001600160a01b031660138281548110610a8057610a80615ec3565b6000918252602090912001546001600160a01b03161415610bd0576013610aa8600184615dbc565b81548110610ab857610ab8615ec3565b600091825260209091200154601380546001600160a01b039092169183908110610ae457610ae4615ec3565b600091825260209091200180546001600160a01b0319166001600160a01b0392909216919091179055826013610b1b600185615dbc565b81548110610b2b57610b2b615ec3565b9060005260206000200160006101000a8154816001600160a01b0302191690836001600160a01b031602179055506013805480610b6a57610b6a615ead565b6000828152602090819020600019908301810180546001600160a01b03191690559091019091556040516001600160a01b03851681527ff80a1a97fd42251f3c33cda98635e7399253033a6774fe37cd3f650b5282af37910160405180910390a1505050565b80610bda81615e2b565b915050610a5b565b50604051635428d44960e01b81526001600160a01b03831660048201526024015b60405180910390fd5b50565b610c176136b1565b604080518082018252600091610c46919084906002908390839080828437600092019190915250612e34915050565b6000818152600e60205260409020549091506001600160a01b031680610c8257604051631dfd6e1360e21b815260048101839052602401610c03565b6000828152600e6020526040812080546001600160a01b03191690555b600f54811015610d5a5782600f8281548110610cbd57610cbd615ec3565b90600052602060002001541415610d4857600f805460009190610ce290600190615dbc565b81548110610cf257610cf2615ec3565b9060005260206000200154905080600f8381548110610d1357610d13615ec3565b600091825260209091200155600f805480610d3057610d30615ead565b60019003818190600052602060002001600090559055505b80610d5281615e2b565b915050610c9f565b50806001600160a01b03167f72be339577868f868798bac2c93e52d6f034fef4689a9848996c14ebb7416c0d83604051610d9691815260200190565b60405180910390a2505050565b60008281526005602052604090205482906001600160a01b031680610ddb57604051630fb532db60e11b815260040160405180910390fd5b336001600160a01b03821614610e0f57604051636c51fda960e11b81526001600160a01b0382166004820152602401610c03565b600d54600160301b900460ff1615610e3a5760405163769dd35360e11b815260040160405180910390fd5b610e4384611782565b15610e6157604051631685ecdd60e31b815260040160405180910390fd5b610e6b848461370d565b50505050565b600d54600090600160301b900460ff1615610e9f5760405163769dd35360e11b815260040160405180910390fd5b60005a90506000610eb085856138c9565b90506000846060015163ffffffff166001600160401b03811115610ed657610ed6615ed9565b604051908082528060200260200182016040528015610eff578160200160208202803683370190505b50905060005b856060015163ffffffff16811015610f7f57826040015181604051602001610f37929190918252602082015260400190565b6040516020818303038152906040528051906020012060001c828281518110610f6257610f62615ec3565b602090810291909101015280610f7781615e2b565b915050610f05565b5060208083018051600090815260109092526040808320839055905190518291631fe543e360e01b91610fb791908690602401615af6565b60408051601f198184030181529181526020820180516001600160e01b03166001600160e01b031990941693909317909252600d805466ff0000000000001916600160301b17905590880151608089015191925060009161101f9163ffffffff169084613b56565b600d805466ff00000000000019169055602089810151600090815260069091526040902054909150600160c01b90046001600160401b0316611062816001615d3c565b6020808b0151600090815260069091526040812080546001600160401b0393909316600160c01b026001600160c01b039093169290921790915560a08a015180516110af90600190615dbc565b815181106110bf576110bf615ec3565b602091010151600d5460f89190911c60011491506000906110f0908a90600160581b900463ffffffff163a85613ba4565b905081156111f9576020808c01516000908152600690915260409020546001600160601b03808316600160601b90920416101561114057604051631e9acf1760e31b815260040160405180910390fd5b60208b81015160009081526006909152604090208054829190600c90611177908490600160601b90046001600160601b0316615dd3565b82546101009290920a6001600160601b0381810219909316918316021790915589516000908152600e60209081526040808320546001600160a01b03168352600c9091528120805485945090926111d091859116615d67565b92506101000a8154816001600160601b0302191690836001600160601b031602179055506112e5565b6020808c01516000908152600690915260409020546001600160601b038083169116101561123a57604051631e9acf1760e31b815260040160405180910390fd5b6020808c0151600090815260069091526040812080548392906112679084906001600160601b0316615dd3565b82546101009290920a6001600160601b0381810219909316918316021790915589516000908152600e60209081526040808320546001600160a01b03168352600b9091528120805485945090926112c091859116615d67565b92506101000a8154816001600160601b0302191690836001600160601b031602179055505b8a6020015188602001517f49580fdfd9497e1ed5c1b1cec0495087ae8e3f1267470ec2fb015db32e3d6aa78a604001518488604051611342939291909283526001600160601b039190911660208301521515604082015260600190565b60405180910390a3985050505050505050505b92915050565b600d54600160301b900460ff16156113865760405163769dd35360e11b815260040160405180910390fd5b61138f81613bf4565b6113b757604051635428d44960e01b81526001600160a01b0382166004820152602401610c03565b6000806000806113c6866132a7565b945094505093509350336001600160a01b0316826001600160a01b0316146114305760405162461bcd60e51b815260206004820152601660248201527f4e6f7420737562736372697074696f6e206f776e6572000000000000000000006044820152606401610c03565b61143986611782565b156114865760405162461bcd60e51b815260206004820152601660248201527f50656e64696e67207265717565737420657869737473000000000000000000006044820152606401610c03565b60006040518060c0016040528061149b600190565b60ff168152602001888152602001846001600160a01b03168152602001838152602001866001600160601b03168152602001856001600160601b031681525090506000816040516020016114ef9190615a0e565b604051602081830303815290604052905061150988613c5e565b505060405163ce3f471960e01b81526001600160a01b0388169063ce3f4719906001600160601b038816906115429085906004016159fb565b6000604051808303818588803b15801561155b57600080fd5b505af115801561156f573d6000803e3d6000fd5b50506002546001600160a01b031615801593509150611598905057506001600160601b03861615155b156116775760025460405163a9059cbb60e01b81526001600160a01b0389811660048301526001600160601b03891660248301529091169063a9059cbb90604401602060405180830381600087803b1580156115f357600080fd5b505af1158015611607573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061162b9190615548565b6116775760405162461bcd60e51b815260206004820152601260248201527f696e73756666696369656e742066756e647300000000000000000000000000006044820152606401610c03565b600d805466ff0000000000001916600160301b17905560005b8351811015611725578381815181106116ab576116ab615ec3565b6020908102919091010151604051638ea9811760e01b81526001600160a01b038a8116600483015290911690638ea9811790602401600060405180830381600087803b1580156116fa57600080fd5b505af115801561170e573d6000803e3d6000fd5b50505050808061171d90615e2b565b915050611690565b50600d805466ff00000000000019169055604080516001600160a01b0389168152602081018a90527fd63ca8cb945956747ee69bfdc3ea754c24a4caf7418db70e46052f7850be4187910160405180910390a15050505050505050565b6000818152600560209081526040808320815160608101835281546001600160a01b039081168252600183015416818501526002820180548451818702810187018652818152879693958601939092919083018282801561180c57602002820191906000526020600020905b81546001600160a01b031681526001909101906020018083116117ee575b505050505081525050905060005b8160400151518110156119795760005b600f5481101561196657600061192f600f838154811061184c5761184c615ec3565b90600052602060002001548560400151858151811061186d5761186d615ec3565b602002602001015188600460008960400151898151811061189057611890615ec3565b6020908102919091018101516001600160a01b03908116835282820193909352604091820160009081208e82528252829020548251808301889052959093168583015260608501939093526001600160401b039091166080808501919091528151808503909101815260a08401825280519083012060c084019490945260e0808401859052815180850390910181526101009093019052815191012091565b50600081815260106020526040902054909150156119535750600195945050505050565b508061195e81615e2b565b91505061182a565b508061197181615e2b565b91505061181a565b5060009392505050565b600d54600160301b900460ff16156119ae5760405163769dd35360e11b815260040160405180910390fd5b336000908152600c60205260409020546001600160601b03808316911610156119ea57604051631e9acf1760e31b815260040160405180910390fd5b336000908152600c602052604081208054839290611a129084906001600160601b0316615dd3565b92506101000a8154816001600160601b0302191690836001600160601b0316021790555080600a600c8282829054906101000a90046001600160601b0316611a5a9190615dd3565b92506101000a8154816001600160601b0302191690836001600160601b031602179055506000826001600160a01b0316826001600160601b031660405160006040518083038185875af1925050503d8060008114611ad4576040519150601f19603f3d011682016040523d82523d6000602084013e611ad9565b606091505b5050905080611afb57604051630dcf35db60e41b815260040160405180910390fd5b505050565b611b086136b1565b6002546001600160a01b031615611b3257604051631688c53760e11b815260040160405180910390fd5b600280546001600160a01b039384166001600160a01b03199182161790915560038054929093169116179055565b611b686136b1565b611b7181613bf4565b15611b9a5760405163ac8a27ef60e01b81526001600160a01b0382166004820152602401610c03565b601380546001810182556000919091527f66de8ffda797e3de9c05e8fc57b3bf0ec28a930d40b0d285d93c06501cf6a0900180546001600160a01b0319166001600160a01b0383169081179091556040519081527fb7cabbfc11e66731fc77de0444614282023bcbd41d16781c753a431d0af016259060200160405180910390a150565b600d54600160301b900460ff1615611c495760405163769dd35360e11b815260040160405180910390fd5b336000908152600b60205260409020546001600160601b0380831691161015611c8557604051631e9acf1760e31b815260040160405180910390fd5b336000908152600b602052604081208054839290611cad9084906001600160601b0316615dd3565b92506101000a8154816001600160601b0302191690836001600160601b0316021790555080600a60008282829054906101000a90046001600160601b0316611cf59190615dd3565b82546101009290920a6001600160601b0381810219909316918316021790915560025460405163a9059cbb60e01b81526001600160a01b03868116600483015292851660248201529116915063a9059cbb90604401602060405180830381600087803b158015611d6457600080fd5b505af1158015611d78573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d9c9190615548565b611db957604051631e9acf1760e31b815260040160405180910390fd5b5050565b611dc56136b1565b604080518082018252600091611df4919084906002908390839080828437600092019190915250612e34915050565b6000818152600e60205260409020549091506001600160a01b031615611e3057604051634a0b8fa760e01b815260048101829052602401610c03565b6000818152600e6020908152604080832080546001600160a01b0319166001600160a01b038816908117909155600f805460018101825594527f8d1108e10bcb7c27dddfc02ed9d693a074039d026cf4ea4240b40f7d581ac802909301849055518381527fe729ae16526293f74ade739043022254f1489f616295a25bf72dfb4511ed73b89101610d96565b6001546001600160a01b03163314611f165760405162461bcd60e51b815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e6572000000000000000000006044820152606401610c03565b60008054336001600160a01b0319808316821784556001805490911690556040516001600160a01b0390921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b600d54600090600160301b900460ff1615611f9b5760405163769dd35360e11b815260040160405180910390fd5b6020808301356000908152600590915260409020546001600160a01b0316611fd657604051630fb532db60e11b815260040160405180910390fd5b3360009081526004602090815260408083208583013584529091529020546001600160401b031680612027576040516379bfd40160e01b815260208401356004820152336024820152604401610c03565b600d5461ffff1661203e60608501604086016156f9565b61ffff161080612061575060c861205b60608501604086016156f9565b61ffff16115b156120a75761207660608401604085016156f9565b600d5460405163539c34bb60e11b815261ffff92831660048201529116602482015260c86044820152606401610c03565b600d5462010000900463ffffffff166120c660808501606086016157f9565b63ffffffff161115612116576120e260808401606085016157f9565b600d54604051637aebf00f60e11b815263ffffffff9283166004820152620100009091049091166024820152604401610c03565b6101f461212960a08501608086016157f9565b63ffffffff16111561216f5761214560a08401608085016157f9565b6040516311ce1afb60e21b815263ffffffff90911660048201526101f46024820152604401610c03565b600061217c826001615d3c565b604080518635602080830182905233838501528089013560608401526001600160401b0385166080808501919091528451808503909101815260a0808501865281519183019190912060c085019390935260e08085018490528551808603909101815261010090940190945282519201919091209293509060009061220c9061220790890189615c40565b613ead565b9050600061221982613f2a565b905083612224613f9b565b60208a013561223960808c0160608d016157f9565b61224960a08d0160808e016157f9565b33866040516020016122619796959493929190615b4e565b604051602081830303815290604052805190602001206010600086815260200190815260200160002081905550336001600160a01b0316886020013589600001357feb0e3652e0f44f417695e6e90f2f42c99b65cd7169074c5a654b16b9748c3a4e87878d60400160208101906122d891906156f9565b8e60600160208101906122eb91906157f9565b8f60800160208101906122fe91906157f9565b8960405161231196959493929190615b0f565b60405180910390a450503360009081526004602090815260408083208983013584529091529020805467ffffffffffffffff19166001600160401b039490941693909317909255925050505b919050565b600d54600090600160301b900460ff16156123905760405163769dd35360e11b815260040160405180910390fd5b60003361239e600143615dbc565b600754604051606093841b6bffffffffffffffffffffffff199081166020830152924060348201523090931b909116605483015260c01b6001600160c01b031916606882015260700160408051601f198184030181529190528051602090910120600780549192506001600160401b0390911690600061241d83615e46565b91906101000a8154816001600160401b0302191690836001600160401b03160217905550506000806001600160401b0381111561245c5761245c615ed9565b604051908082528060200260200182016040528015612485578160200160208202803683370190505b506040805160608082018352600080835260208084018281528486018381528984526006835286842095518654925191516001600160601b039182166001600160c01b031990941693909317600160601b9190921602176001600160c01b0316600160c01b6001600160401b039092169190910217909355835191820184523382528183018181528285018681528883526005855294909120825181546001600160a01b03199081166001600160a01b03928316178355925160018301805490941691161790915592518051949550909361256692600285019201906150e6565b5061257691506008905083614034565b5060405133815282907f1d3015d7ba850fa198dc7b1a3f5d42779313a681035f77c8c03764c61005518d9060200160405180910390a250905090565b600d54600160301b900460ff16156125dd5760405163769dd35360e11b815260040160405180910390fd5b6002546001600160a01b03163314612608576040516344b0e3c360e01b815260040160405180910390fd5b6020811461262957604051638129bbcd60e01b815260040160405180910390fd5b600061263782840184615565565b6000818152600560205260409020549091506001600160a01b031661266f57604051630fb532db60e11b815260040160405180910390fd5b600081815260066020526040812080546001600160601b0316918691906126968385615d67565b92506101000a8154816001600160601b0302191690836001600160601b0316021790555084600a60008282829054906101000a90046001600160601b03166126de9190615d67565b92506101000a8154816001600160601b0302191690836001600160601b03160217905550817f1ced9348ff549fceab2ac57cd3a9de38edaaab274b725ee82c23e8fc8c4eec7a8287846127319190615d24565b604080519283526020830191909152015b60405180910390a2505050505050565b61275a6136b1565b600a544790600160601b90046001600160601b03168181111561279a576040516354ced18160e11b81526004810182905260248101839052604401610c03565b81811015611afb5760006127ae8284615dbc565b90506000846001600160a01b03168260405160006040518083038185875af1925050503d80600081146127fd576040519150601f19603f3d011682016040523d82523d6000602084013e612802565b606091505b505090508061282457604051630dcf35db60e41b815260040160405180910390fd5b604080516001600160a01b0387168152602081018490527f879c9ea2b9d5345b84ccd12610b032602808517cebdb795007f3dcb4df377317910160405180910390a15050505050565b6128756136b1565b6000818152600560205260409020546001600160a01b03166128aa57604051630fb532db60e11b815260040160405180910390fd5b600081815260056020526040902054610c0c9082906001600160a01b031661370d565b606060006128db6008614040565b90508084106128fd57604051631390f2a160e01b815260040160405180910390fd5b60006129098486615d24565b905081811180612917575083155b6129215780612923565b815b905060006129318683615dbc565b6001600160401b0381111561294857612948615ed9565b604051908082528060200260200182016040528015612971578160200160208202803683370190505b50905060005b81518110156129c45761299561298d8883615d24565b60089061404a565b8282815181106129a7576129a7615ec3565b6020908102919091010152806129bc81615e2b565b915050612977565b5095945050505050565b6129d66136b1565b60c861ffff87161115612a105760405163539c34bb60e11b815261ffff871660048201819052602482015260c86044820152606401610c03565b60008213612a34576040516321ea67b360e11b815260048101839052602401610c03565b6040805160a0808201835261ffff891680835263ffffffff89811660208086018290526000868801528a831660608088018290528b85166080988901819052600d805465ffffffffffff19168817620100008702176effffffffffffffffff000000000000191667010000000000000085026effffffff0000000000000000000000191617600160581b83021790558a51601280548d87015192891667ffffffffffffffff199091161764010000000092891692909202919091179081905560118d90558a519788528785019590955298860191909152840196909652938201879052838116928201929092529190921c90911660c08201527f777357bb93f63d088f18112d3dba38457aec633eb8f1341e1d418380ad328e789060e00160405180910390a1505050505050565b600d54600160301b900460ff1615612b8d5760405163769dd35360e11b815260040160405180910390fd5b6000818152600560205260409020546001600160a01b0316612bc257604051630fb532db60e11b815260040160405180910390fd5b6000818152600560205260409020600101546001600160a01b03163314612c1b576000818152600560205260409081902060010154905163d084e97560e01b81526001600160a01b039091166004820152602401610c03565b6000818152600560209081526040918290208054336001600160a01b0319808316821784556001909301805490931690925583516001600160a01b0390911680825292810191909152909183917fd4114ab6e9af9f597c52041f32d62dc57c5c4e4c0d4427006069635e216c938691015b60405180910390a25050565b60008281526005602052604090205482906001600160a01b031680612cd057604051630fb532db60e11b815260040160405180910390fd5b336001600160a01b03821614612d0457604051636c51fda960e11b81526001600160a01b0382166004820152602401610c03565b600d54600160301b900460ff1615612d2f5760405163769dd35360e11b815260040160405180910390fd5b60008481526005602052604090206002015460641415612d62576040516305a48e0f60e01b815260040160405180910390fd5b6001600160a01b03831660009081526004602090815260408083208784529091529020546001600160401b031615612d9957610e6b565b6001600160a01b03831660008181526004602090815260408083208884528252808320805467ffffffffffffffff19166001908117909155600583528184206002018054918201815584529282902090920180546001600160a01b03191684179055905191825285917f1e980d04aa7648e205713e5e8ea3808672ac163d10936d36f91b2c88ac1575e191015b60405180910390a250505050565b600081604051602001612e4791906159da565b604051602081830303815290604052805190602001209050919050565b60008281526005602052604090205482906001600160a01b031680612e9c57604051630fb532db60e11b815260040160405180910390fd5b336001600160a01b03821614612ed057604051636c51fda960e11b81526001600160a01b0382166004820152602401610c03565b600d54600160301b900460ff1615612efb5760405163769dd35360e11b815260040160405180910390fd5b612f0484611782565b15612f2257604051631685ecdd60e31b815260040160405180910390fd5b6001600160a01b03831660009081526004602090815260408083208784529091529020546001600160401b0316612f7e576040516379bfd40160e01b8152600481018590526001600160a01b0384166024820152604401610c03565b600084815260056020908152604080832060020180548251818502810185019093528083529192909190830182828015612fe157602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311612fc3575b50505050509050600060018251612ff89190615dbc565b905060005b825181101561310457856001600160a01b031683828151811061302257613022615ec3565b60200260200101516001600160a01b031614156130f257600083838151811061304d5761304d615ec3565b6020026020010151905080600560008a8152602001908152602001600020600201838154811061307f5761307f615ec3565b600091825260208083209190910180546001600160a01b0319166001600160a01b0394909416939093179092558981526005909152604090206002018054806130ca576130ca615ead565b600082815260209020810160001990810180546001600160a01b031916905501905550613104565b806130fc81615e2b565b915050612ffd565b506001600160a01b03851660008181526004602090815260408083208a8452825291829020805467ffffffffffffffff19169055905191825287917f32158c6058347c1601b2d12bc696ac6901d8a9a9aa3ba10c27ab0a983e8425a79101612742565b600f818154811061317757600080fd5b600091825260209091200154905081565b60008281526005602052604090205482906001600160a01b0316806131c057604051630fb532db60e11b815260040160405180910390fd5b336001600160a01b038216146131f457604051636c51fda960e11b81526001600160a01b0382166004820152602401610c03565b600d54600160301b900460ff161561321f5760405163769dd35360e11b815260040160405180910390fd5b6000848152600560205260409020600101546001600160a01b03848116911614610e6b5760008481526005602090815260409182902060010180546001600160a01b0319166001600160a01b03871690811790915582513381529182015285917f21a4dad170a6bf476c31bbcf4a16628295b0e450672eec25d7c93308e05344a19101612e26565b6000818152600560205260408120548190819081906060906001600160a01b03166132e557604051630fb532db60e11b815260040160405180910390fd5b60008681526006602090815260408083205460058352928190208054600290910180548351818602810186019094528084526001600160601b0380871696600160601b810490911695600160c01b9091046001600160401b0316946001600160a01b039094169391839183018282801561338857602002820191906000526020600020905b81546001600160a01b0316815260019091019060200180831161336a575b505050505090509450945094509450945091939590929450565b6133aa6136b1565b6002546040516370a0823160e01b81523060048201526000916001600160a01b0316906370a082319060240160206040518083038186803b1580156133ee57600080fd5b505afa158015613402573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613426919061557e565b600a549091506001600160601b031681811115613460576040516354ced18160e11b81526004810182905260248101839052604401610c03565b81811015611afb5760006134748284615dbc565b60025460405163a9059cbb60e01b81526001600160a01b0387811660048301526024820184905292935091169063a9059cbb90604401602060405180830381600087803b1580156134c457600080fd5b505af11580156134d8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906134fc9190615548565b61351957604051631f01ff1360e21b815260040160405180910390fd5b604080516001600160a01b0386168152602081018390527f59bfc682b673f8cbf945f1e454df9334834abf7dfe7f92237ca29ecb9b436600910160405180910390a150505050565b600d54600160301b900460ff161561358c5760405163769dd35360e11b815260040160405180910390fd5b6000818152600560205260409020546001600160a01b03166135c157604051630fb532db60e11b815260040160405180910390fd5b60008181526006602052604090208054600160601b90046001600160601b0316903490600c6135f08385615d67565b92506101000a8154816001600160601b0302191690836001600160601b0316021790555034600a600c8282829054906101000a90046001600160601b03166136389190615d67565b92506101000a8154816001600160601b0302191690836001600160601b03160217905550817f3f1ddc3ab1bdb39001ad76ca51a0e6f57ce6627c69f251d1de41622847721cde82348461368b9190615d24565b60408051928352602083019190915201612c8c565b6136a86136b1565b610c0c81614056565b6000546001600160a01b0316331461370b5760405162461bcd60e51b815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e6572000000000000000000006044820152606401610c03565b565b60008061371984613c5e565b60025491935091506001600160a01b03161580159061374057506001600160601b03821615155b156137f05760025460405163a9059cbb60e01b81526001600160a01b0385811660048301526001600160601b03851660248301529091169063a9059cbb90604401602060405180830381600087803b15801561379b57600080fd5b505af11580156137af573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906137d39190615548565b6137f057604051631e9acf1760e31b815260040160405180910390fd5b6000836001600160a01b0316826001600160601b031660405160006040518083038185875af1925050503d8060008114613846576040519150601f19603f3d011682016040523d82523d6000602084013e61384b565b606091505b505090508061386d57604051630dcf35db60e41b815260040160405180910390fd5b604080516001600160a01b03861681526001600160601b038581166020830152841681830152905186917f8c74ce8b8cf87f5eb001275c8be27eb34ea2b62bfab6814fcc62192bb63e81c4919081900360600190a25050505050565b604080516060810182526000808252602082018190529181019190915260006138f58460000151612e34565b6000818152600e60205260409020549091506001600160a01b03168061393157604051631dfd6e1360e21b815260048101839052602401610c03565b6000828660800151604051602001613953929190918252602082015260400190565b60408051601f198184030181529181528151602092830120600081815260109093529120549091508061399957604051631b44092560e11b815260040160405180910390fd5b85516020808801516040808a015160608b015160808c015160a08d015193516139c8978a979096959101615b98565b6040516020818303038152906040528051906020012081146139fd5760405163354a450b60e21b815260040160405180910390fd5b6000613a0c8760000151614100565b905080613ae4578651604051631d2827a760e31b81526001600160401b0390911660048201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063e9413d389060240160206040518083038186803b158015613a7e57600080fd5b505afa158015613a92573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613ab6919061557e565b905080613ae457865160405163175dadad60e01b81526001600160401b039091166004820152602401610c03565b6000886080015182604051602001613b06929190918252602082015260400190565b6040516020818303038152906040528051906020012060001c90506000613b2d8a836141ea565b604080516060810182529889526020890196909652948701949094525093979650505050505050565b60005a611388811015613b6857600080fd5b611388810390508460408204820311613b8057600080fd5b50823b613b8c57600080fd5b60008083516020850160008789f190505b9392505050565b60008115613bd257601254613bcb9086908690640100000000900463ffffffff1686614255565b9050613bec565b601254613be9908690869063ffffffff16866142bf565b90505b949350505050565b6000805b601354811015613c5557826001600160a01b031660138281548110613c1f57613c1f615ec3565b6000918252602090912001546001600160a01b03161415613c435750600192915050565b80613c4d81615e2b565b915050613bf8565b50600092915050565b6000818152600560209081526040808320815160608101835281546001600160a01b03908116825260018301541681850152600282018054845181870281018701865281815287968796949594860193919290830182828015613cea57602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311613ccc575b505050919092525050506000858152600660209081526040808320815160608101835290546001600160601b03808216808452600160601b8304909116948301859052600160c01b9091046001600160401b0316928201929092529096509094509192505b826040015151811015613dc7576004600084604001518381518110613d7657613d76615ec3565b6020908102919091018101516001600160a01b0316825281810192909252604090810160009081208982529092529020805467ffffffffffffffff1916905580613dbf81615e2b565b915050613d4f565b50600085815260056020526040812080546001600160a01b03199081168255600182018054909116905590613dff600283018261514b565b5050600085815260066020526040812055613e1b6008866143ad565b50600a8054859190600090613e3a9084906001600160601b0316615dd3565b92506101000a8154816001600160601b0302191690836001600160601b0316021790555082600a600c8282829054906101000a90046001600160601b0316613e829190615dd3565b92506101000a8154816001600160601b0302191690836001600160601b031602179055505050915091565b60408051602081019091526000815281613ed65750604080516020810190915260008152611355565b63125fa26760e31b613ee88385615dfb565b6001600160e01b03191614613f1057604051632923fee760e11b815260040160405180910390fd5b613f1d8260048186615cfa565b810190613b9d9190615597565b60607f92fd13387c7fe7befbc38d303d6468778fb9731bc4583f17d92989c6fcfdeaaa82604051602401613f6391511515815260200190565b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b03199093169290921790915292915050565b60004661a4b1811480613fb0575062066eed81145b1561402d5760646001600160a01b031663a3b1b31d6040518163ffffffff1660e01b815260040160206040518083038186803b158015613fef57600080fd5b505afa158015614003573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614027919061557e565b91505090565b4391505090565b6000613b9d83836143b9565b6000611355825490565b6000613b9d8383614408565b6001600160a01b0381163314156140af5760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c660000000000000000006044820152606401610c03565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b60004661a4b1811480614115575062066eed81145b156141db57610100836001600160401b031661412f613f9b565b6141399190615dbc565b11806141555750614148613f9b565b836001600160401b031610155b156141635750600092915050565b6040516315a03d4160e11b81526001600160401b0384166004820152606490632b407a829060240160206040518083038186803b1580156141a357600080fd5b505afa1580156141b7573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613b9d919061557e565b50506001600160401b03164090565b600061421e8360000151846020015185604001518660600151868860a001518960c001518a60e001518b6101000151614432565b60038360200151604051602001614236929190615ae2565b60408051601f1981840301815291905280516020909101209392505050565b60008061426061465d565b905060005a61426f8888615d24565b6142799190615dbc565b6142839085615d9d565b9050600061429c63ffffffff871664e8d4a51000615d9d565b9050826142a98284615d24565b6142b39190615d24565b98975050505050505050565b6000806142ca6146b9565b9050600081136142f0576040516321ea67b360e11b815260048101829052602401610c03565b60006142fa61465d565b9050600082825a61430b8b8b615d24565b6143159190615dbc565b61431f9088615d9d565b6143299190615d24565b61433b90670de0b6b3a7640000615d9d565b6143459190615d89565b9050600061435e63ffffffff881664e8d4a51000615d9d565b9050614376816b033b2e3c9fd0803ce8000000615dbc565b8211156143965760405163e80fa38160e01b815260040160405180910390fd5b6143a08183615d24565b9998505050505050505050565b6000613b9d8383614788565b600081815260018301602052604081205461440057508154600181810184556000848152602080822090930184905584548482528286019093526040902091909155611355565b506000611355565b600082600001828154811061441f5761441f615ec3565b9060005260206000200154905092915050565b61443b8961487b565b6144875760405162461bcd60e51b815260206004820152601a60248201527f7075626c6963206b6579206973206e6f74206f6e2063757276650000000000006044820152606401610c03565b6144908861487b565b6144dc5760405162461bcd60e51b815260206004820152601560248201527f67616d6d61206973206e6f74206f6e20637572766500000000000000000000006044820152606401610c03565b6144e58361487b565b6145315760405162461bcd60e51b815260206004820152601d60248201527f6347616d6d615769746e657373206973206e6f74206f6e2063757276650000006044820152606401610c03565b61453a8261487b565b6145865760405162461bcd60e51b815260206004820152601c60248201527f73486173685769746e657373206973206e6f74206f6e206375727665000000006044820152606401610c03565b614592878a8887614954565b6145de5760405162461bcd60e51b815260206004820152601960248201527f6164647228632a706b2b732a6729213d5f755769746e657373000000000000006044820152606401610c03565b60006145ea8a87614a77565b905060006145fd898b878b868989614adb565b9050600061460e838d8d8a86614bfb565b9050808a1461464f5760405162461bcd60e51b815260206004820152600d60248201526c34b73b30b634b210383937b7b360991b6044820152606401610c03565b505050505050505050505050565b60004661a4b1811480614672575062066eed81145b156146b157606c6001600160a01b031663c6f7de0e6040518163ffffffff1660e01b815260040160206040518083038186803b158015613fef57600080fd5b600091505090565b600d5460035460408051633fabe5a360e21b81529051600093670100000000000000900463ffffffff169283151592859283926001600160a01b03169163feaf968c9160048083019260a0929190829003018186803b15801561471b57600080fd5b505afa15801561472f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906147539190615814565b509450909250849150508015614777575061476e8242615dbc565b8463ffffffff16105b15613bec5750601154949350505050565b600081815260018301602052604081205480156148715760006147ac600183615dbc565b85549091506000906147c090600190615dbc565b90508181146148255760008660000182815481106147e0576147e0615ec3565b906000526020600020015490508087600001848154811061480357614803615ec3565b6000918252602080832090910192909255918252600188019052604090208390555b855486908061483657614836615ead565b600190038181906000526020600020016000905590558560010160008681526020019081526020016000206000905560019350505050611355565b6000915050611355565b80516000906401000003d019116148d45760405162461bcd60e51b815260206004820152601260248201527f696e76616c696420782d6f7264696e61746500000000000000000000000000006044820152606401610c03565b60208201516401000003d0191161492d5760405162461bcd60e51b815260206004820152601260248201527f696e76616c696420792d6f7264696e61746500000000000000000000000000006044820152606401610c03565b60208201516401000003d01990800961494d8360005b6020020151614c3b565b1492915050565b60006001600160a01b03821661499a5760405162461bcd60e51b815260206004820152600b60248201526a626164207769746e65737360a81b6044820152606401610c03565b6020840151600090600116156149b157601c6149b4565b601b5b9050600070014551231950b75fc4402da1732fc9bebe1985876000602002015109865170014551231950b75fc4402da1732fc9bebe19918203925060009190890987516040805160008082526020820180845287905260ff88169282019290925260608101929092526080820183905291925060019060a0016020604051602081039080840390855afa158015614a4f573d6000803e3d6000fd5b5050604051601f1901516001600160a01b039081169088161495505050505050949350505050565b614a7f615169565b614aac60018484604051602001614a98939291906159b9565b604051602081830303815290604052614c5f565b90505b614ab88161487b565b611355578051604080516020810192909252614ad49101614a98565b9050614aaf565b614ae3615169565b825186516401000003d0199081900691061415614b425760405162461bcd60e51b815260206004820152601e60248201527f706f696e747320696e2073756d206d7573742062652064697374696e637400006044820152606401610c03565b614b4d878988614cad565b614b995760405162461bcd60e51b815260206004820152601660248201527f4669727374206d756c20636865636b206661696c6564000000000000000000006044820152606401610c03565b614ba4848685614cad565b614bf05760405162461bcd60e51b815260206004820152601760248201527f5365636f6e64206d756c20636865636b206661696c65640000000000000000006044820152606401610c03565b6142b3868484614dd5565b600060028686868587604051602001614c199695949392919061595a565b60408051601f1981840301815291905280516020909101209695505050505050565b6000806401000003d01980848509840990506401000003d019600782089392505050565b614c67615169565b614c7082614e9c565b8152614c85614c80826000614943565b614ed7565b60208201819052600290066001141561235d576020810180516401000003d019039052919050565b600082614cea5760405162461bcd60e51b815260206004820152600b60248201526a3d32b9379039b1b0b630b960a91b6044820152606401610c03565b83516020850151600090614d0090600290615e6d565b15614d0c57601c614d0f565b601b5b9050600070014551231950b75fc4402da1732fc9bebe198387096040805160008082526020820180845281905260ff86169282019290925260608101869052608081018390529192509060019060a0016020604051602081039080840390855afa158015614d81573d6000803e3d6000fd5b505050602060405103519050600086604051602001614da09190615948565b60408051601f1981840301815291905280516020909101206001600160a01b0392831692169190911498975050505050505050565b614ddd615169565b835160208086015185519186015160009384938493614dfe93909190614ef7565b919450925090506401000003d019858209600114614e5e5760405162461bcd60e51b815260206004820152601960248201527f696e765a206d75737420626520696e7665727365206f66207a000000000000006044820152606401610c03565b60405180604001604052806401000003d01980614e7d57614e7d615e97565b87860981526020016401000003d0198785099052979650505050505050565b805160208201205b6401000003d019811061235d57604080516020808201939093528151808203840181529082019091528051910120614ea4565b6000611355826002614ef06401000003d0196001615d24565b901c614fd7565b60008080600180826401000003d019896401000003d019038808905060006401000003d0198b6401000003d019038a0890506000614f3783838585615079565b9098509050614f4888828e8861509d565b9098509050614f5988828c8761509d565b90985090506000614f6c8d878b8561509d565b9098509050614f7d88828686615079565b9098509050614f8e88828e8961509d565b9098509050818114614fc3576401000003d019818a0998506401000003d01982890997506401000003d0198183099650614fc7565b8196505b5050505050509450945094915050565b600080614fe2615187565b6020808252818101819052604082015260608101859052608081018490526401000003d01960a08201526150146151a5565b60208160c0846005600019fa92508261506f5760405162461bcd60e51b815260206004820152601260248201527f6269674d6f64457870206661696c7572652100000000000000000000000000006044820152606401610c03565b5195945050505050565b6000806401000003d0198487096401000003d0198487099097909650945050505050565b600080806401000003d019878509905060006401000003d01987876401000003d019030990506401000003d0198183086401000003d01986890990999098509650505050505050565b82805482825590600052602060002090810192821561513b579160200282015b8281111561513b57825182546001600160a01b0319166001600160a01b03909116178255602090920191600190910190615106565b506151479291506151c3565b5090565b5080546000825590600052602060002090810190610c0c91906151c3565b60405180604001604052806002906020820280368337509192915050565b6040518060c001604052806006906020820280368337509192915050565b60405180602001604052806001906020820280368337509192915050565b5b8082111561514757600081556001016151c4565b803561235d81615eef565b806040810183101561135557600080fd5b600082601f83011261520557600080fd5b61520d615c8d565b80838560408601111561521f57600080fd5b60005b6002811015615241578135845260209384019390910190600101615222565b509095945050505050565b600082601f83011261525d57600080fd5b81356001600160401b038082111561527757615277615ed9565b604051601f8301601f19908116603f0116810190828211818310171561529f5761529f615ed9565b816040528381528660208588010111156152b857600080fd5b836020870160208301376000602085830101528094505050505092915050565b600060c082840312156152ea57600080fd5b6152f2615cb5565b905081356001600160401b03808216821461530c57600080fd5b818352602084013560208401526153256040850161538b565b60408401526153366060850161538b565b6060840152615347608085016151d8565b608084015260a084013591508082111561536057600080fd5b5061536d8482850161524c565b60a08301525092915050565b803561ffff8116811461235d57600080fd5b803563ffffffff8116811461235d57600080fd5b805169ffffffffffffffffffff8116811461235d57600080fd5b80356001600160601b038116811461235d57600080fd5b6000602082840312156153e257600080fd5b8135613b9d81615eef565b6000806040838503121561540057600080fd5b823561540b81615eef565b9150615419602084016153b9565b90509250929050565b6000806040838503121561543557600080fd5b823561544081615eef565b9150602083013561545081615eef565b809150509250929050565b6000806060838503121561546e57600080fd5b823561547981615eef565b915061541984602085016151e3565b6000806000806060858703121561549e57600080fd5b84356154a981615eef565b93506020850135925060408501356001600160401b03808211156154cc57600080fd5b818701915087601f8301126154e057600080fd5b8135818111156154ef57600080fd5b88602082850101111561550157600080fd5b95989497505060200194505050565b60006040828403121561552257600080fd5b613b9d83836151e3565b60006040828403121561553e57600080fd5b613b9d83836151f4565b60006020828403121561555a57600080fd5b8151613b9d81615f04565b60006020828403121561557757600080fd5b5035919050565b60006020828403121561559057600080fd5b5051919050565b6000602082840312156155a957600080fd5b604051602081018181106001600160401b03821117156155cb576155cb615ed9565b60405282356155d981615f04565b81529392505050565b6000808284036101c08112156155f757600080fd5b6101a08082121561560757600080fd5b61560f615cd7565b915061561b86866151f4565b825261562a86604087016151f4565b60208301526080850135604083015260a0850135606083015260c0850135608083015261565960e086016151d8565b60a083015261010061566d878288016151f4565b60c08401526156808761014088016151f4565b60e0840152610180860135908301529092508301356001600160401b038111156156a957600080fd5b6156b5858286016152d8565b9150509250929050565b6000602082840312156156d157600080fd5b81356001600160401b038111156156e757600080fd5b820160c08185031215613b9d57600080fd5b60006020828403121561570b57600080fd5b613b9d82615379565b60008060008060008086880360e081121561572e57600080fd5b61573788615379565b96506157456020890161538b565b95506157536040890161538b565b94506157616060890161538b565b9350608088013592506040609f198201121561577c57600080fd5b50615785615c8d565b61579160a0890161538b565b815261579f60c0890161538b565b6020820152809150509295509295509295565b600080604083850312156157c557600080fd5b82359150602083013561545081615eef565b600080604083850312156157ea57600080fd5b50508035926020909101359150565b60006020828403121561580b57600080fd5b613b9d8261538b565b600080600080600060a0868803121561582c57600080fd5b6158358661539f565b94506020860151935060408601519250606086015191506158586080870161539f565b90509295509295909350565b600081518084526020808501945080840160005b8381101561589d5781516001600160a01b031687529582019590820190600101615878565b509495945050505050565b8060005b6002811015610e6b5781518452602093840193909101906001016158ac565b600081518084526020808501945080840160005b8381101561589d578151875295820195908201906001016158df565b6000815180845260005b8181101561592157602081850181015186830182015201615905565b81811115615933576000602083870101525b50601f01601f19169290920160200192915050565b61595281836158a8565b604001919050565b86815261596a60208201876158a8565b61597760608201866158a8565b61598460a08201856158a8565b61599160e08201846158a8565b60609190911b6bffffffffffffffffffffffff19166101208201526101340195945050505050565b8381526159c960208201846158a8565b606081019190915260800192915050565b6040810161135582846158a8565b602081526000613b9d60208301846158cb565b602081526000613b9d60208301846158fb565b6020815260ff8251166020820152602082015160408201526001600160a01b0360408301511660608201526000606083015160c06080840152615a5460e0840182615864565b905060808401516001600160601b0380821660a08601528060a08701511660c086015250508091505092915050565b60006060820161ffff86168352602063ffffffff86168185015260606040850152818551808452608086019150828701935060005b81811015615ad457845183529383019391830191600101615ab8565b509098975050505050505050565b82815260608101613b9d60208301846158a8565b828152604060208201526000613bec60408301846158cb565b86815285602082015261ffff85166040820152600063ffffffff808616606084015280851660808401525060c060a08301526142b360c08301846158fb565b878152866020820152856040820152600063ffffffff80871660608401528086166080840152506001600160a01b03841660a083015260e060c08301526143a060e08301846158fb565b8781526001600160401b0387166020820152856040820152600063ffffffff80871660608401528086166080840152506001600160a01b03841660a083015260e060c08301526143a060e08301846158fb565b60006001600160601b0380881683528087166020840152506001600160401b03851660408301526001600160a01b038416606083015260a06080830152615c3560a0830184615864565b979650505050505050565b6000808335601e19843603018112615c5757600080fd5b8301803591506001600160401b03821115615c7157600080fd5b602001915036819003821315615c8657600080fd5b9250929050565b604080519081016001600160401b0381118282101715615caf57615caf615ed9565b60405290565b60405160c081016001600160401b0381118282101715615caf57615caf615ed9565b60405161012081016001600160401b0381118282101715615caf57615caf615ed9565b60008085851115615d0a57600080fd5b83861115615d1757600080fd5b5050820193919092039150565b60008219821115615d3757615d37615e81565b500190565b60006001600160401b03808316818516808303821115615d5e57615d5e615e81565b01949350505050565b60006001600160601b03808316818516808303821115615d5e57615d5e615e81565b600082615d9857615d98615e97565b500490565b6000816000190483118215151615615db757615db7615e81565b500290565b600082821015615dce57615dce615e81565b500390565b60006001600160601b0383811690831681811015615df357615df3615e81565b039392505050565b6001600160e01b03198135818116916004851015615e235780818660040360031b1b83161692505b505092915050565b6000600019821415615e3f57615e3f615e81565b5060010190565b60006001600160401b0380831681811415615e6357615e63615e81565b6001019392505050565b600082615e7c57615e7c615e97565b500690565b634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052601260045260246000fd5b634e487b7160e01b600052603160045260246000fd5b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052604160045260246000fd5b6001600160a01b0381168114610c0c57600080fd5b8015158114610c0c57600080fdfea164736f6c6343000806000a", + ABI: "[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"blockhashStore\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"internalBalance\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"externalBalance\",\"type\":\"uint256\"}],\"name\":\"BalanceInvariantViolated\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"blockNum\",\"type\":\"uint256\"}],\"name\":\"BlockhashNotInStore\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"coordinatorAddress\",\"type\":\"address\"}],\"name\":\"CoordinatorAlreadyRegistered\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"coordinatorAddress\",\"type\":\"address\"}],\"name\":\"CoordinatorNotRegistered\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"FailedToSendEther\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"FailedToTransferLink\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"have\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"want\",\"type\":\"uint32\"}],\"name\":\"GasLimitTooBig\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"IncorrectCommitment\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"IndexOutOfRange\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InsufficientBalance\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"have\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"want\",\"type\":\"uint256\"}],\"name\":\"InsufficientGasForConsumer\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidCalldata\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"consumer\",\"type\":\"address\"}],\"name\":\"InvalidConsumer\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidExtraArgsTag\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"int256\",\"name\":\"linkWei\",\"type\":\"int256\"}],\"name\":\"InvalidLinkWeiPrice\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint16\",\"name\":\"have\",\"type\":\"uint16\"},{\"internalType\":\"uint16\",\"name\":\"min\",\"type\":\"uint16\"},{\"internalType\":\"uint16\",\"name\":\"max\",\"type\":\"uint16\"}],\"name\":\"InvalidRequestConfirmations\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidSubscription\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"LinkAlreadySet\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"LinkNotSet\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"proposedOwner\",\"type\":\"address\"}],\"name\":\"MustBeRequestedOwner\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"}],\"name\":\"MustBeSubOwner\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"NoCorrespondingRequest\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"keyHash\",\"type\":\"bytes32\"}],\"name\":\"NoSuchProvingKey\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"have\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"want\",\"type\":\"uint32\"}],\"name\":\"NumWordsTooBig\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableFromLink\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"PaymentTooLarge\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"PendingRequestExists\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"keyHash\",\"type\":\"bytes32\"}],\"name\":\"ProvingKeyAlreadyRegistered\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"Reentrant\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"TooManyConsumers\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint16\",\"name\":\"minimumRequestConfirmations\",\"type\":\"uint16\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"maxGasLimit\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"stalenessSeconds\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"gasAfterPaymentCalculation\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"int256\",\"name\":\"fallbackWeiPerUnitLink\",\"type\":\"int256\"},{\"components\":[{\"internalType\":\"uint32\",\"name\":\"fulfillmentFlatFeeLinkPPM\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"fulfillmentFlatFeeEthPPM\",\"type\":\"uint32\"}],\"indexed\":false,\"internalType\":\"structVRFCoordinatorV2Plus.FeeConfig\",\"name\":\"feeConfig\",\"type\":\"tuple\"}],\"name\":\"ConfigSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"coordinatorAddress\",\"type\":\"address\"}],\"name\":\"CoordinatorDeregistered\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"coordinatorAddress\",\"type\":\"address\"}],\"name\":\"CoordinatorRegistered\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"EthFundsRecovered\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"FundsRecovered\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"newCoordinator\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"}],\"name\":\"MigrationCompleted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"OwnershipTransferRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"keyHash\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"oracle\",\"type\":\"address\"}],\"name\":\"ProvingKeyDeregistered\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"keyHash\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"oracle\",\"type\":\"address\"}],\"name\":\"ProvingKeyRegistered\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"requestId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"outputSeed\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"subID\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint96\",\"name\":\"payment\",\"type\":\"uint96\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"success\",\"type\":\"bool\"}],\"name\":\"RandomWordsFulfilled\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"keyHash\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"requestId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"preSeed\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint16\",\"name\":\"minimumRequestConfirmations\",\"type\":\"uint16\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"callbackGasLimit\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"numWords\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"extraArgs\",\"type\":\"bytes\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RandomWordsRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amountLink\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amountEth\",\"type\":\"uint256\"}],\"name\":\"SubscriptionCanceled\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"consumer\",\"type\":\"address\"}],\"name\":\"SubscriptionConsumerAdded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"consumer\",\"type\":\"address\"}],\"name\":\"SubscriptionConsumerRemoved\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"}],\"name\":\"SubscriptionCreated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"oldBalance\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newBalance\",\"type\":\"uint256\"}],\"name\":\"SubscriptionFunded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"oldEthBalance\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newEthBalance\",\"type\":\"uint256\"}],\"name\":\"SubscriptionFundedWithEth\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"SubscriptionOwnerTransferRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"SubscriptionOwnerTransferred\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"BLOCKHASH_STORE\",\"outputs\":[{\"internalType\":\"contractBlockhashStoreInterface\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"LINK\",\"outputs\":[{\"internalType\":\"contractLinkTokenInterface\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"LINK_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\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"}],\"name\":\"acceptSubscriptionOwnerTransfer\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"consumer\",\"type\":\"address\"}],\"name\":\"addConsumer\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"cancelSubscription\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"createSubscription\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"}],\"name\":\"deregisterMigratableCoordinator\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256[2]\",\"name\":\"publicProvingKey\",\"type\":\"uint256[2]\"}],\"name\":\"deregisterProvingKey\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint256[2]\",\"name\":\"pk\",\"type\":\"uint256[2]\"},{\"internalType\":\"uint256[2]\",\"name\":\"gamma\",\"type\":\"uint256[2]\"},{\"internalType\":\"uint256\",\"name\":\"c\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"s\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"seed\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"uWitness\",\"type\":\"address\"},{\"internalType\":\"uint256[2]\",\"name\":\"cGammaWitness\",\"type\":\"uint256[2]\"},{\"internalType\":\"uint256[2]\",\"name\":\"sHashWitness\",\"type\":\"uint256[2]\"},{\"internalType\":\"uint256\",\"name\":\"zInv\",\"type\":\"uint256\"}],\"internalType\":\"structVRF.Proof\",\"name\":\"proof\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"uint64\",\"name\":\"blockNum\",\"type\":\"uint64\"},{\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"},{\"internalType\":\"uint32\",\"name\":\"callbackGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"numWords\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"extraArgs\",\"type\":\"bytes\"}],\"internalType\":\"structVRFCoordinatorV2Plus.RequestCommitment\",\"name\":\"rc\",\"type\":\"tuple\"}],\"name\":\"fulfillRandomWords\",\"outputs\":[{\"internalType\":\"uint96\",\"name\":\"\",\"type\":\"uint96\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"}],\"name\":\"fundSubscriptionWithEth\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"startIndex\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"maxCount\",\"type\":\"uint256\"}],\"name\":\"getActiveSubscriptionIds\",\"outputs\":[{\"internalType\":\"uint256[]\",\"name\":\"\",\"type\":\"uint256[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getRequestConfig\",\"outputs\":[{\"internalType\":\"uint16\",\"name\":\"\",\"type\":\"uint16\"},{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"},{\"internalType\":\"bytes32[]\",\"name\":\"\",\"type\":\"bytes32[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"}],\"name\":\"getSubscription\",\"outputs\":[{\"internalType\":\"uint96\",\"name\":\"balance\",\"type\":\"uint96\"},{\"internalType\":\"uint96\",\"name\":\"ethBalance\",\"type\":\"uint96\"},{\"internalType\":\"uint64\",\"name\":\"reqCount\",\"type\":\"uint64\"},{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"internalType\":\"address[]\",\"name\":\"consumers\",\"type\":\"address[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256[2]\",\"name\":\"publicKey\",\"type\":\"uint256[2]\"}],\"name\":\"hashOfKey\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"newCoordinator\",\"type\":\"address\"}],\"name\":\"migrate\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"migrationVersion\",\"outputs\":[{\"internalType\":\"uint8\",\"name\":\"version\",\"type\":\"uint8\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"onTokenTransfer\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"uint96\",\"name\":\"amount\",\"type\":\"uint96\"}],\"name\":\"oracleWithdraw\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"addresspayable\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"uint96\",\"name\":\"amount\",\"type\":\"uint96\"}],\"name\":\"oracleWithdrawEth\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"}],\"name\":\"ownerCancelSubscription\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"}],\"name\":\"pendingRequestExists\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"addresspayable\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"recoverEthFunds\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"recoverFunds\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"}],\"name\":\"registerMigratableCoordinator\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"oracle\",\"type\":\"address\"},{\"internalType\":\"uint256[2]\",\"name\":\"publicProvingKey\",\"type\":\"uint256[2]\"}],\"name\":\"registerProvingKey\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"consumer\",\"type\":\"address\"}],\"name\":\"removeConsumer\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"bytes32\",\"name\":\"keyHash\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"},{\"internalType\":\"uint16\",\"name\":\"requestConfirmations\",\"type\":\"uint16\"},{\"internalType\":\"uint32\",\"name\":\"callbackGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"numWords\",\"type\":\"uint32\"},{\"internalType\":\"bytes\",\"name\":\"extraArgs\",\"type\":\"bytes\"}],\"internalType\":\"structVRFV2PlusClient.RandomWordsRequest\",\"name\":\"req\",\"type\":\"tuple\"}],\"name\":\"requestRandomWords\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"requestSubscriptionOwnerTransfer\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_config\",\"outputs\":[{\"internalType\":\"uint16\",\"name\":\"minimumRequestConfirmations\",\"type\":\"uint16\"},{\"internalType\":\"uint32\",\"name\":\"maxGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"bool\",\"name\":\"reentrancyLock\",\"type\":\"bool\"},{\"internalType\":\"uint32\",\"name\":\"stalenessSeconds\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"gasAfterPaymentCalculation\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_currentSubNonce\",\"outputs\":[{\"internalType\":\"uint64\",\"name\":\"\",\"type\":\"uint64\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_fallbackWeiPerUnitLink\",\"outputs\":[{\"internalType\":\"int256\",\"name\":\"\",\"type\":\"int256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_feeConfig\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"fulfillmentFlatFeeLinkPPM\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"fulfillmentFlatFeeEthPPM\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"s_provingKeyHashes\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"name\":\"s_provingKeys\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"s_requestCommitments\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_totalBalance\",\"outputs\":[{\"internalType\":\"uint96\",\"name\":\"\",\"type\":\"uint96\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_totalEthBalance\",\"outputs\":[{\"internalType\":\"uint96\",\"name\":\"\",\"type\":\"uint96\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint16\",\"name\":\"minimumRequestConfirmations\",\"type\":\"uint16\"},{\"internalType\":\"uint32\",\"name\":\"maxGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"stalenessSeconds\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"gasAfterPaymentCalculation\",\"type\":\"uint32\"},{\"internalType\":\"int256\",\"name\":\"fallbackWeiPerUnitLink\",\"type\":\"int256\"},{\"components\":[{\"internalType\":\"uint32\",\"name\":\"fulfillmentFlatFeeLinkPPM\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"fulfillmentFlatFeeEthPPM\",\"type\":\"uint32\"}],\"internalType\":\"structVRFCoordinatorV2Plus.FeeConfig\",\"name\":\"feeConfig\",\"type\":\"tuple\"}],\"name\":\"setConfig\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"link\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"linkEthFeed\",\"type\":\"address\"}],\"name\":\"setLINKAndLINKETHFeed\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", + Bin: "0x60a06040523480156200001157600080fd5b506040516200614c3803806200614c833981016040819052620000349162000183565b33806000816200008b5760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b0384811691909117909155811615620000be57620000be81620000d7565b50505060601b6001600160601b031916608052620001b5565b6001600160a01b038116331415620001325760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c66000000000000000000604482015260640162000082565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b6000602082840312156200019657600080fd5b81516001600160a01b0381168114620001ae57600080fd5b9392505050565b60805160601c615f71620001db600039600081816105ee0152613a860152615f716000f3fe6080604052600436106102dc5760003560e01c80638da5cb5b1161017f578063bec4c08c116100e1578063dc311dd31161008a578063e95704bd11610064578063e95704bd1461095d578063ee9d2d3814610984578063f2fde38b146109b157600080fd5b8063dc311dd3146108f9578063e72f6e301461092a578063e8509bff1461094a57600080fd5b8063d98e620e116100bb578063d98e620e14610883578063da2f2610146108a3578063dac83d29146108d957600080fd5b8063bec4c08c14610823578063caf70c4a14610843578063cb6317971461086357600080fd5b8063a8cb447b11610143578063aefb212f1161011d578063aefb212f146107b6578063b08c8795146107e3578063b2a7cac51461080357600080fd5b8063a8cb447b14610756578063aa433aff14610776578063ad1783611461079657600080fd5b80638da5cb5b146106ab5780639b1c385e146106c95780639d40a6fd146106e9578063a21a23e414610721578063a4c0ed361461073657600080fd5b806340d6bb821161024357806366316d8d116101ec5780636f64f03f116101c65780636f64f03f1461065657806379ba50971461067657806386fe91c71461068b57600080fd5b806366316d8d146105bc578063689c4517146105dc5780636b6feccc1461061057600080fd5b806357133e641161021d57806357133e64146105675780635d06b4ab1461058757806364d51a2a146105a757600080fd5b806340d6bb82146104ec57806341af6c871461051757806346d8d4861461054757600080fd5b80630ae09540116102a5578063294daa491161027f578063294daa4914610478578063330987b314610494578063405b84fa146104cc57600080fd5b80630ae09540146103f857806315c48b84146104185780631b6b6d231461044057600080fd5b8062012291146102e157806304104edb1461030e578063043bd6ae14610330578063088070f51461035457806308821d58146103d8575b600080fd5b3480156102ed57600080fd5b506102f66109d1565b60405161030593929190615ad5565b60405180910390f35b34801561031a57600080fd5b5061032e610329366004615422565b610a4d565b005b34801561033c57600080fd5b5061034660115481565b604051908152602001610305565b34801561036057600080fd5b50600d546103a09061ffff81169063ffffffff62010000820481169160ff600160301b820416916701000000000000008204811691600160581b90041685565b6040805161ffff909616865263ffffffff9485166020870152921515928501929092528216606084015216608082015260a001610305565b3480156103e457600080fd5b5061032e6103f3366004615562565b610c0f565b34801561040457600080fd5b5061032e610413366004615804565b610da3565b34801561042457600080fd5b5061042d60c881565b60405161ffff9091168152602001610305565b34801561044c57600080fd5b50600254610460906001600160a01b031681565b6040516001600160a01b039091168152602001610305565b34801561048457600080fd5b5060405160018152602001610305565b3480156104a057600080fd5b506104b46104af366004615634565b610e71565b6040516001600160601b039091168152602001610305565b3480156104d857600080fd5b5061032e6104e7366004615804565b61135b565b3480156104f857600080fd5b506105026101f481565b60405163ffffffff9091168152602001610305565b34801561052357600080fd5b506105376105323660046155b7565b611782565b6040519015158152602001610305565b34801561055357600080fd5b5061032e61056236600461543f565b611983565b34801561057357600080fd5b5061032e610582366004615474565b611b00565b34801561059357600080fd5b5061032e6105a2366004615422565b611b60565b3480156105b357600080fd5b5061042d606481565b3480156105c857600080fd5b5061032e6105d736600461543f565b611c1e565b3480156105e857600080fd5b506104607f000000000000000000000000000000000000000000000000000000000000000081565b34801561061c57600080fd5b506012546106399063ffffffff8082169164010000000090041682565b6040805163ffffffff938416815292909116602083015201610305565b34801561066257600080fd5b5061032e6106713660046154ad565b611de6565b34801561068257600080fd5b5061032e611ee5565b34801561069757600080fd5b50600a546104b4906001600160601b031681565b3480156106b757600080fd5b506000546001600160a01b0316610460565b3480156106d557600080fd5b506103466106e4366004615711565b611f96565b3480156106f557600080fd5b50600754610709906001600160401b031681565b6040516001600160401b039091168152602001610305565b34801561072d57600080fd5b5061034661238b565b34801561074257600080fd5b5061032e6107513660046154da565b6125db565b34801561076257600080fd5b5061032e610771366004615422565b61277b565b34801561078257600080fd5b5061032e6107913660046155b7565b612896565b3480156107a257600080fd5b50600354610460906001600160a01b031681565b3480156107c257600080fd5b506107d66107d1366004615829565b6128f6565b6040516103059190615a3a565b3480156107ef57600080fd5b5061032e6107fe366004615766565b6129f7565b34801561080f57600080fd5b5061032e61081e3660046155b7565b612b8b565b34801561082f57600080fd5b5061032e61083e366004615804565b612cc1565b34801561084f57600080fd5b5061034661085e36600461557e565b612e5d565b34801561086f57600080fd5b5061032e61087e366004615804565b612e8d565b34801561088f57600080fd5b5061034661089e3660046155b7565b613190565b3480156108af57600080fd5b506104606108be3660046155b7565b600e602052600090815260409020546001600160a01b031681565b3480156108e557600080fd5b5061032e6108f4366004615804565b6131b1565b34801561090557600080fd5b506109196109143660046155b7565b6132d0565b604051610305959493929190615c3d565b34801561093657600080fd5b5061032e610945366004615422565b6133cb565b61032e6109583660046155b7565b6135b3565b34801561096957600080fd5b50600a546104b490600160601b90046001600160601b031681565b34801561099057600080fd5b5061034661099f3660046155b7565b60106020526000908152604090205481565b3480156109bd57600080fd5b5061032e6109cc366004615422565b6136f2565b600d54600f805460408051602080840282018101909252828152600094859460609461ffff8316946201000090930463ffffffff16939192839190830182828015610a3b57602002820191906000526020600020905b815481526020019060010190808311610a27575b50505050509050925092509250909192565b610a55613703565b60135460005b81811015610be257826001600160a01b031660138281548110610a8057610a80615f15565b6000918252602090912001546001600160a01b03161415610bd0576013610aa8600184615e0e565b81548110610ab857610ab8615f15565b600091825260209091200154601380546001600160a01b039092169183908110610ae457610ae4615f15565b600091825260209091200180546001600160a01b0319166001600160a01b0392909216919091179055826013610b1b600185615e0e565b81548110610b2b57610b2b615f15565b9060005260206000200160006101000a8154816001600160a01b0302191690836001600160a01b031602179055506013805480610b6a57610b6a615eff565b6000828152602090819020600019908301810180546001600160a01b03191690559091019091556040516001600160a01b03851681527ff80a1a97fd42251f3c33cda98635e7399253033a6774fe37cd3f650b5282af37910160405180910390a1505050565b80610bda81615e7d565b915050610a5b565b50604051635428d44960e01b81526001600160a01b03831660048201526024015b60405180910390fd5b50565b610c17613703565b604080518082018252600091610c46919084906002908390839080828437600092019190915250612e5d915050565b6000818152600e60205260409020549091506001600160a01b031680610c8257604051631dfd6e1360e21b815260048101839052602401610c03565b6000828152600e6020526040812080546001600160a01b03191690555b600f54811015610d5a5782600f8281548110610cbd57610cbd615f15565b90600052602060002001541415610d4857600f805460009190610ce290600190615e0e565b81548110610cf257610cf2615f15565b9060005260206000200154905080600f8381548110610d1357610d13615f15565b600091825260209091200155600f805480610d3057610d30615eff565b60019003818190600052602060002001600090559055505b80610d5281615e7d565b915050610c9f565b50806001600160a01b03167f72be339577868f868798bac2c93e52d6f034fef4689a9848996c14ebb7416c0d83604051610d9691815260200190565b60405180910390a2505050565b60008281526005602052604090205482906001600160a01b031680610ddb57604051630fb532db60e11b815260040160405180910390fd5b336001600160a01b03821614610e0f57604051636c51fda960e11b81526001600160a01b0382166004820152602401610c03565b600d54600160301b900460ff1615610e3a5760405163769dd35360e11b815260040160405180910390fd5b610e4384611782565b15610e6157604051631685ecdd60e31b815260040160405180910390fd5b610e6b848461375f565b50505050565b600d54600090600160301b900460ff1615610e9f5760405163769dd35360e11b815260040160405180910390fd5b60005a90506000610eb0858561391b565b90506000846060015163ffffffff166001600160401b03811115610ed657610ed6615f2b565b604051908082528060200260200182016040528015610eff578160200160208202803683370190505b50905060005b856060015163ffffffff16811015610f7f57826040015181604051602001610f37929190918252602082015260400190565b6040516020818303038152906040528051906020012060001c828281518110610f6257610f62615f15565b602090810291909101015280610f7781615e7d565b915050610f05565b5060208083018051600090815260109092526040808320839055905190518291631fe543e360e01b91610fb791908690602401615b48565b60408051601f198184030181529181526020820180516001600160e01b03166001600160e01b031990941693909317909252600d805466ff0000000000001916600160301b17905590880151608089015191925060009161101f9163ffffffff169084613ba8565b600d805466ff00000000000019169055602089810151600090815260069091526040902054909150600160c01b90046001600160401b0316611062816001615d8e565b6020808b0151600090815260069091526040812080546001600160401b0393909316600160c01b026001600160c01b039093169290921790915560a08a015180516110af90600190615e0e565b815181106110bf576110bf615f15565b602091010151600d5460f89190911c60011491506000906110f0908a90600160581b900463ffffffff163a85613bf6565b905081156111f9576020808c01516000908152600690915260409020546001600160601b03808316600160601b90920416101561114057604051631e9acf1760e31b815260040160405180910390fd5b60208b81015160009081526006909152604090208054829190600c90611177908490600160601b90046001600160601b0316615e25565b82546101009290920a6001600160601b0381810219909316918316021790915589516000908152600e60209081526040808320546001600160a01b03168352600c9091528120805485945090926111d091859116615db9565b92506101000a8154816001600160601b0302191690836001600160601b031602179055506112e5565b6020808c01516000908152600690915260409020546001600160601b038083169116101561123a57604051631e9acf1760e31b815260040160405180910390fd5b6020808c0151600090815260069091526040812080548392906112679084906001600160601b0316615e25565b82546101009290920a6001600160601b0381810219909316918316021790915589516000908152600e60209081526040808320546001600160a01b03168352600b9091528120805485945090926112c091859116615db9565b92506101000a8154816001600160601b0302191690836001600160601b031602179055505b8a6020015188602001517f49580fdfd9497e1ed5c1b1cec0495087ae8e3f1267470ec2fb015db32e3d6aa78a604001518488604051611342939291909283526001600160601b039190911660208301521515604082015260600190565b60405180910390a3985050505050505050505b92915050565b600d54600160301b900460ff16156113865760405163769dd35360e11b815260040160405180910390fd5b61138f81613c46565b6113b757604051635428d44960e01b81526001600160a01b0382166004820152602401610c03565b6000806000806113c6866132d0565b945094505093509350336001600160a01b0316826001600160a01b0316146114305760405162461bcd60e51b815260206004820152601660248201527f4e6f7420737562736372697074696f6e206f776e6572000000000000000000006044820152606401610c03565b61143986611782565b156114865760405162461bcd60e51b815260206004820152601660248201527f50656e64696e67207265717565737420657869737473000000000000000000006044820152606401610c03565b60006040518060c0016040528061149b600190565b60ff168152602001888152602001846001600160a01b03168152602001838152602001866001600160601b03168152602001856001600160601b031681525090506000816040516020016114ef9190615a60565b604051602081830303815290604052905061150988613cb0565b505060405163ce3f471960e01b81526001600160a01b0388169063ce3f4719906001600160601b03881690611542908590600401615a4d565b6000604051808303818588803b15801561155b57600080fd5b505af115801561156f573d6000803e3d6000fd5b50506002546001600160a01b031615801593509150611598905057506001600160601b03861615155b156116775760025460405163a9059cbb60e01b81526001600160a01b0389811660048301526001600160601b03891660248301529091169063a9059cbb90604401602060405180830381600087803b1580156115f357600080fd5b505af1158015611607573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061162b919061559a565b6116775760405162461bcd60e51b815260206004820152601260248201527f696e73756666696369656e742066756e647300000000000000000000000000006044820152606401610c03565b600d805466ff0000000000001916600160301b17905560005b8351811015611725578381815181106116ab576116ab615f15565b6020908102919091010151604051638ea9811760e01b81526001600160a01b038a8116600483015290911690638ea9811790602401600060405180830381600087803b1580156116fa57600080fd5b505af115801561170e573d6000803e3d6000fd5b50505050808061171d90615e7d565b915050611690565b50600d805466ff00000000000019169055604080516001600160a01b0389168152602081018a90527fd63ca8cb945956747ee69bfdc3ea754c24a4caf7418db70e46052f7850be4187910160405180910390a15050505050505050565b6000818152600560209081526040808320815160608101835281546001600160a01b039081168252600183015416818501526002820180548451818702810187018652818152879693958601939092919083018282801561180c57602002820191906000526020600020905b81546001600160a01b031681526001909101906020018083116117ee575b505050505081525050905060005b8160400151518110156119795760005b600f5481101561196657600061192f600f838154811061184c5761184c615f15565b90600052602060002001548560400151858151811061186d5761186d615f15565b602002602001015188600460008960400151898151811061189057611890615f15565b6020908102919091018101516001600160a01b03908116835282820193909352604091820160009081208e82528252829020548251808301889052959093168583015260608501939093526001600160401b039091166080808501919091528151808503909101815260a08401825280519083012060c084019490945260e0808401859052815180850390910181526101009093019052815191012091565b50600081815260106020526040902054909150156119535750600195945050505050565b508061195e81615e7d565b91505061182a565b508061197181615e7d565b91505061181a565b5060009392505050565b600d54600160301b900460ff16156119ae5760405163769dd35360e11b815260040160405180910390fd5b336000908152600c60205260409020546001600160601b03808316911610156119ea57604051631e9acf1760e31b815260040160405180910390fd5b336000908152600c602052604081208054839290611a129084906001600160601b0316615e25565b92506101000a8154816001600160601b0302191690836001600160601b0316021790555080600a600c8282829054906101000a90046001600160601b0316611a5a9190615e25565b92506101000a8154816001600160601b0302191690836001600160601b031602179055506000826001600160a01b0316826001600160601b031660405160006040518083038185875af1925050503d8060008114611ad4576040519150601f19603f3d011682016040523d82523d6000602084013e611ad9565b606091505b5050905080611afb57604051630dcf35db60e41b815260040160405180910390fd5b505050565b611b08613703565b6002546001600160a01b031615611b3257604051631688c53760e11b815260040160405180910390fd5b600280546001600160a01b039384166001600160a01b03199182161790915560038054929093169116179055565b611b68613703565b611b7181613c46565b15611b9a5760405163ac8a27ef60e01b81526001600160a01b0382166004820152602401610c03565b601380546001810182556000919091527f66de8ffda797e3de9c05e8fc57b3bf0ec28a930d40b0d285d93c06501cf6a0900180546001600160a01b0319166001600160a01b0383169081179091556040519081527fb7cabbfc11e66731fc77de0444614282023bcbd41d16781c753a431d0af016259060200160405180910390a150565b600d54600160301b900460ff1615611c495760405163769dd35360e11b815260040160405180910390fd5b6002546001600160a01b0316611c725760405163c1f0c0a160e01b815260040160405180910390fd5b336000908152600b60205260409020546001600160601b0380831691161015611cae57604051631e9acf1760e31b815260040160405180910390fd5b336000908152600b602052604081208054839290611cd69084906001600160601b0316615e25565b92506101000a8154816001600160601b0302191690836001600160601b0316021790555080600a60008282829054906101000a90046001600160601b0316611d1e9190615e25565b82546101009290920a6001600160601b0381810219909316918316021790915560025460405163a9059cbb60e01b81526001600160a01b03868116600483015292851660248201529116915063a9059cbb90604401602060405180830381600087803b158015611d8d57600080fd5b505af1158015611da1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611dc5919061559a565b611de257604051631e9acf1760e31b815260040160405180910390fd5b5050565b611dee613703565b604080518082018252600091611e1d919084906002908390839080828437600092019190915250612e5d915050565b6000818152600e60205260409020549091506001600160a01b031615611e5957604051634a0b8fa760e01b815260048101829052602401610c03565b6000818152600e6020908152604080832080546001600160a01b0319166001600160a01b038816908117909155600f805460018101825594527f8d1108e10bcb7c27dddfc02ed9d693a074039d026cf4ea4240b40f7d581ac802909301849055518381527fe729ae16526293f74ade739043022254f1489f616295a25bf72dfb4511ed73b89101610d96565b6001546001600160a01b03163314611f3f5760405162461bcd60e51b815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e6572000000000000000000006044820152606401610c03565b60008054336001600160a01b0319808316821784556001805490911690556040516001600160a01b0390921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b600d54600090600160301b900460ff1615611fc45760405163769dd35360e11b815260040160405180910390fd5b6020808301356000908152600590915260409020546001600160a01b0316611fff57604051630fb532db60e11b815260040160405180910390fd5b3360009081526004602090815260408083208583013584529091529020546001600160401b031680612050576040516379bfd40160e01b815260208401356004820152336024820152604401610c03565b600d5461ffff16612067606085016040860161574b565b61ffff16108061208a575060c8612084606085016040860161574b565b61ffff16115b156120d05761209f606084016040850161574b565b600d5460405163539c34bb60e11b815261ffff92831660048201529116602482015260c86044820152606401610c03565b600d5462010000900463ffffffff166120ef608085016060860161584b565b63ffffffff16111561213f5761210b608084016060850161584b565b600d54604051637aebf00f60e11b815263ffffffff9283166004820152620100009091049091166024820152604401610c03565b6101f461215260a085016080860161584b565b63ffffffff1611156121985761216e60a084016080850161584b565b6040516311ce1afb60e21b815263ffffffff90911660048201526101f46024820152604401610c03565b60006121a5826001615d8e565b604080518635602080830182905233838501528089013560608401526001600160401b0385166080808501919091528451808503909101815260a0808501865281519183019190912060c085019390935260e0808501849052855180860390910181526101009094019094528251920191909120929350906000906122359061223090890189615c92565b613eff565b9050600061224282613f7c565b90508361224d613fed565b60208a013561226260808c0160608d0161584b565b61227260a08d0160808e0161584b565b338660405160200161228a9796959493929190615ba0565b604051602081830303815290604052805190602001206010600086815260200190815260200160002081905550336001600160a01b0316886020013589600001357feb0e3652e0f44f417695e6e90f2f42c99b65cd7169074c5a654b16b9748c3a4e87878d6040016020810190612301919061574b565b8e6060016020810190612314919061584b565b8f6080016020810190612327919061584b565b8960405161233a96959493929190615b61565b60405180910390a450503360009081526004602090815260408083208983013584529091529020805467ffffffffffffffff19166001600160401b039490941693909317909255925050505b919050565b600d54600090600160301b900460ff16156123b95760405163769dd35360e11b815260040160405180910390fd5b6000336123c7600143615e0e565b600754604051606093841b6bffffffffffffffffffffffff199081166020830152924060348201523090931b909116605483015260c01b6001600160c01b031916606882015260700160408051601f198184030181529190528051602090910120600780549192506001600160401b0390911690600061244683615e98565b91906101000a8154816001600160401b0302191690836001600160401b03160217905550506000806001600160401b0381111561248557612485615f2b565b6040519080825280602002602001820160405280156124ae578160200160208202803683370190505b506040805160608082018352600080835260208084018281528486018381528984526006835286842095518654925191516001600160601b039182166001600160c01b031990941693909317600160601b9190921602176001600160c01b0316600160c01b6001600160401b039092169190910217909355835191820184523382528183018181528285018681528883526005855294909120825181546001600160a01b03199081166001600160a01b03928316178355925160018301805490941691161790915592518051949550909361258f9260028501920190615138565b5061259f91506008905083614086565b5060405133815282907f1d3015d7ba850fa198dc7b1a3f5d42779313a681035f77c8c03764c61005518d9060200160405180910390a250905090565b600d54600160301b900460ff16156126065760405163769dd35360e11b815260040160405180910390fd5b6002546001600160a01b03163314612631576040516344b0e3c360e01b815260040160405180910390fd5b6020811461265257604051638129bbcd60e01b815260040160405180910390fd5b6000612660828401846155b7565b6000818152600560205260409020549091506001600160a01b031661269857604051630fb532db60e11b815260040160405180910390fd5b600081815260066020526040812080546001600160601b0316918691906126bf8385615db9565b92506101000a8154816001600160601b0302191690836001600160601b0316021790555084600a60008282829054906101000a90046001600160601b03166127079190615db9565b92506101000a8154816001600160601b0302191690836001600160601b03160217905550817f1ced9348ff549fceab2ac57cd3a9de38edaaab274b725ee82c23e8fc8c4eec7a82878461275a9190615d76565b604080519283526020830191909152015b60405180910390a2505050505050565b612783613703565b600a544790600160601b90046001600160601b0316818111156127c3576040516354ced18160e11b81526004810182905260248101839052604401610c03565b81811015611afb5760006127d78284615e0e565b90506000846001600160a01b03168260405160006040518083038185875af1925050503d8060008114612826576040519150601f19603f3d011682016040523d82523d6000602084013e61282b565b606091505b505090508061284d57604051630dcf35db60e41b815260040160405180910390fd5b604080516001600160a01b0387168152602081018490527f879c9ea2b9d5345b84ccd12610b032602808517cebdb795007f3dcb4df377317910160405180910390a15050505050565b61289e613703565b6000818152600560205260409020546001600160a01b03166128d357604051630fb532db60e11b815260040160405180910390fd5b600081815260056020526040902054610c0c9082906001600160a01b031661375f565b606060006129046008614092565b905080841061292657604051631390f2a160e01b815260040160405180910390fd5b60006129328486615d76565b905081811180612940575083155b61294a578061294c565b815b9050600061295a8683615e0e565b6001600160401b0381111561297157612971615f2b565b60405190808252806020026020018201604052801561299a578160200160208202803683370190505b50905060005b81518110156129ed576129be6129b68883615d76565b60089061409c565b8282815181106129d0576129d0615f15565b6020908102919091010152806129e581615e7d565b9150506129a0565b5095945050505050565b6129ff613703565b60c861ffff87161115612a395760405163539c34bb60e11b815261ffff871660048201819052602482015260c86044820152606401610c03565b60008213612a5d576040516321ea67b360e11b815260048101839052602401610c03565b6040805160a0808201835261ffff891680835263ffffffff89811660208086018290526000868801528a831660608088018290528b85166080988901819052600d805465ffffffffffff19168817620100008702176effffffffffffffffff000000000000191667010000000000000085026effffffff0000000000000000000000191617600160581b83021790558a51601280548d87015192891667ffffffffffffffff199091161764010000000092891692909202919091179081905560118d90558a519788528785019590955298860191909152840196909652938201879052838116928201929092529190921c90911660c08201527f777357bb93f63d088f18112d3dba38457aec633eb8f1341e1d418380ad328e789060e00160405180910390a1505050505050565b600d54600160301b900460ff1615612bb65760405163769dd35360e11b815260040160405180910390fd5b6000818152600560205260409020546001600160a01b0316612beb57604051630fb532db60e11b815260040160405180910390fd5b6000818152600560205260409020600101546001600160a01b03163314612c44576000818152600560205260409081902060010154905163d084e97560e01b81526001600160a01b039091166004820152602401610c03565b6000818152600560209081526040918290208054336001600160a01b0319808316821784556001909301805490931690925583516001600160a01b0390911680825292810191909152909183917fd4114ab6e9af9f597c52041f32d62dc57c5c4e4c0d4427006069635e216c938691015b60405180910390a25050565b60008281526005602052604090205482906001600160a01b031680612cf957604051630fb532db60e11b815260040160405180910390fd5b336001600160a01b03821614612d2d57604051636c51fda960e11b81526001600160a01b0382166004820152602401610c03565b600d54600160301b900460ff1615612d585760405163769dd35360e11b815260040160405180910390fd5b60008481526005602052604090206002015460641415612d8b576040516305a48e0f60e01b815260040160405180910390fd5b6001600160a01b03831660009081526004602090815260408083208784529091529020546001600160401b031615612dc257610e6b565b6001600160a01b03831660008181526004602090815260408083208884528252808320805467ffffffffffffffff19166001908117909155600583528184206002018054918201815584529282902090920180546001600160a01b03191684179055905191825285917f1e980d04aa7648e205713e5e8ea3808672ac163d10936d36f91b2c88ac1575e191015b60405180910390a250505050565b600081604051602001612e709190615a2c565b604051602081830303815290604052805190602001209050919050565b60008281526005602052604090205482906001600160a01b031680612ec557604051630fb532db60e11b815260040160405180910390fd5b336001600160a01b03821614612ef957604051636c51fda960e11b81526001600160a01b0382166004820152602401610c03565b600d54600160301b900460ff1615612f245760405163769dd35360e11b815260040160405180910390fd5b612f2d84611782565b15612f4b57604051631685ecdd60e31b815260040160405180910390fd5b6001600160a01b03831660009081526004602090815260408083208784529091529020546001600160401b0316612fa7576040516379bfd40160e01b8152600481018590526001600160a01b0384166024820152604401610c03565b60008481526005602090815260408083206002018054825181850281018501909352808352919290919083018282801561300a57602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311612fec575b505050505090506000600182516130219190615e0e565b905060005b825181101561312d57856001600160a01b031683828151811061304b5761304b615f15565b60200260200101516001600160a01b0316141561311b57600083838151811061307657613076615f15565b6020026020010151905080600560008a815260200190815260200160002060020183815481106130a8576130a8615f15565b600091825260208083209190910180546001600160a01b0319166001600160a01b0394909416939093179092558981526005909152604090206002018054806130f3576130f3615eff565b600082815260209020810160001990810180546001600160a01b03191690550190555061312d565b8061312581615e7d565b915050613026565b506001600160a01b03851660008181526004602090815260408083208a8452825291829020805467ffffffffffffffff19169055905191825287917f32158c6058347c1601b2d12bc696ac6901d8a9a9aa3ba10c27ab0a983e8425a7910161276b565b600f81815481106131a057600080fd5b600091825260209091200154905081565b60008281526005602052604090205482906001600160a01b0316806131e957604051630fb532db60e11b815260040160405180910390fd5b336001600160a01b0382161461321d57604051636c51fda960e11b81526001600160a01b0382166004820152602401610c03565b600d54600160301b900460ff16156132485760405163769dd35360e11b815260040160405180910390fd5b6000848152600560205260409020600101546001600160a01b03848116911614610e6b5760008481526005602090815260409182902060010180546001600160a01b0319166001600160a01b03871690811790915582513381529182015285917f21a4dad170a6bf476c31bbcf4a16628295b0e450672eec25d7c93308e05344a19101612e4f565b6000818152600560205260408120548190819081906060906001600160a01b031661330e57604051630fb532db60e11b815260040160405180910390fd5b60008681526006602090815260408083205460058352928190208054600290910180548351818602810186019094528084526001600160601b0380871696600160601b810490911695600160c01b9091046001600160401b0316946001600160a01b03909416939183918301828280156133b157602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311613393575b505050505090509450945094509450945091939590929450565b6133d3613703565b6002546001600160a01b03166133fc5760405163c1f0c0a160e01b815260040160405180910390fd5b6002546040516370a0823160e01b81523060048201526000916001600160a01b0316906370a082319060240160206040518083038186803b15801561344057600080fd5b505afa158015613454573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061347891906155d0565b600a549091506001600160601b0316818111156134b2576040516354ced18160e11b81526004810182905260248101839052604401610c03565b81811015611afb5760006134c68284615e0e565b60025460405163a9059cbb60e01b81526001600160a01b0387811660048301526024820184905292935091169063a9059cbb90604401602060405180830381600087803b15801561351657600080fd5b505af115801561352a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061354e919061559a565b61356b57604051631f01ff1360e21b815260040160405180910390fd5b604080516001600160a01b0386168152602081018390527f59bfc682b673f8cbf945f1e454df9334834abf7dfe7f92237ca29ecb9b436600910160405180910390a150505050565b600d54600160301b900460ff16156135de5760405163769dd35360e11b815260040160405180910390fd5b6000818152600560205260409020546001600160a01b031661361357604051630fb532db60e11b815260040160405180910390fd5b60008181526006602052604090208054600160601b90046001600160601b0316903490600c6136428385615db9565b92506101000a8154816001600160601b0302191690836001600160601b0316021790555034600a600c8282829054906101000a90046001600160601b031661368a9190615db9565b92506101000a8154816001600160601b0302191690836001600160601b03160217905550817f3f1ddc3ab1bdb39001ad76ca51a0e6f57ce6627c69f251d1de41622847721cde8234846136dd9190615d76565b60408051928352602083019190915201612cb5565b6136fa613703565b610c0c816140a8565b6000546001600160a01b0316331461375d5760405162461bcd60e51b815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e6572000000000000000000006044820152606401610c03565b565b60008061376b84613cb0565b60025491935091506001600160a01b03161580159061379257506001600160601b03821615155b156138425760025460405163a9059cbb60e01b81526001600160a01b0385811660048301526001600160601b03851660248301529091169063a9059cbb90604401602060405180830381600087803b1580156137ed57600080fd5b505af1158015613801573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613825919061559a565b61384257604051631e9acf1760e31b815260040160405180910390fd5b6000836001600160a01b0316826001600160601b031660405160006040518083038185875af1925050503d8060008114613898576040519150601f19603f3d011682016040523d82523d6000602084013e61389d565b606091505b50509050806138bf57604051630dcf35db60e41b815260040160405180910390fd5b604080516001600160a01b03861681526001600160601b038581166020830152841681830152905186917f8c74ce8b8cf87f5eb001275c8be27eb34ea2b62bfab6814fcc62192bb63e81c4919081900360600190a25050505050565b604080516060810182526000808252602082018190529181019190915260006139478460000151612e5d565b6000818152600e60205260409020549091506001600160a01b03168061398357604051631dfd6e1360e21b815260048101839052602401610c03565b60008286608001516040516020016139a5929190918252602082015260400190565b60408051601f19818403018152918152815160209283012060008181526010909352912054909150806139eb57604051631b44092560e11b815260040160405180910390fd5b85516020808801516040808a015160608b015160808c015160a08d01519351613a1a978a979096959101615bea565b604051602081830303815290604052805190602001208114613a4f5760405163354a450b60e21b815260040160405180910390fd5b6000613a5e8760000151614152565b905080613b36578651604051631d2827a760e31b81526001600160401b0390911660048201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063e9413d389060240160206040518083038186803b158015613ad057600080fd5b505afa158015613ae4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613b0891906155d0565b905080613b3657865160405163175dadad60e01b81526001600160401b039091166004820152602401610c03565b6000886080015182604051602001613b58929190918252602082015260400190565b6040516020818303038152906040528051906020012060001c90506000613b7f8a8361423c565b604080516060810182529889526020890196909652948701949094525093979650505050505050565b60005a611388811015613bba57600080fd5b611388810390508460408204820311613bd257600080fd5b50823b613bde57600080fd5b60008083516020850160008789f190505b9392505050565b60008115613c2457601254613c1d9086908690640100000000900463ffffffff16866142a7565b9050613c3e565b601254613c3b908690869063ffffffff1686614311565b90505b949350505050565b6000805b601354811015613ca757826001600160a01b031660138281548110613c7157613c71615f15565b6000918252602090912001546001600160a01b03161415613c955750600192915050565b80613c9f81615e7d565b915050613c4a565b50600092915050565b6000818152600560209081526040808320815160608101835281546001600160a01b03908116825260018301541681850152600282018054845181870281018701865281815287968796949594860193919290830182828015613d3c57602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311613d1e575b505050919092525050506000858152600660209081526040808320815160608101835290546001600160601b03808216808452600160601b8304909116948301859052600160c01b9091046001600160401b0316928201929092529096509094509192505b826040015151811015613e19576004600084604001518381518110613dc857613dc8615f15565b6020908102919091018101516001600160a01b0316825281810192909252604090810160009081208982529092529020805467ffffffffffffffff1916905580613e1181615e7d565b915050613da1565b50600085815260056020526040812080546001600160a01b03199081168255600182018054909116905590613e51600283018261519d565b5050600085815260066020526040812055613e6d6008866143ff565b50600a8054859190600090613e8c9084906001600160601b0316615e25565b92506101000a8154816001600160601b0302191690836001600160601b0316021790555082600a600c8282829054906101000a90046001600160601b0316613ed49190615e25565b92506101000a8154816001600160601b0302191690836001600160601b031602179055505050915091565b60408051602081019091526000815281613f285750604080516020810190915260008152611355565b63125fa26760e31b613f3a8385615e4d565b6001600160e01b03191614613f6257604051632923fee760e11b815260040160405180910390fd5b613f6f8260048186615d4c565b810190613bef91906155e9565b60607f92fd13387c7fe7befbc38d303d6468778fb9731bc4583f17d92989c6fcfdeaaa82604051602401613fb591511515815260200190565b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b03199093169290921790915292915050565b60004661a4b1811480614002575062066eed81145b1561407f5760646001600160a01b031663a3b1b31d6040518163ffffffff1660e01b815260040160206040518083038186803b15801561404157600080fd5b505afa158015614055573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061407991906155d0565b91505090565b4391505090565b6000613bef838361440b565b6000611355825490565b6000613bef838361445a565b6001600160a01b0381163314156141015760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c660000000000000000006044820152606401610c03565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b60004661a4b1811480614167575062066eed81145b1561422d57610100836001600160401b0316614181613fed565b61418b9190615e0e565b11806141a7575061419a613fed565b836001600160401b031610155b156141b55750600092915050565b6040516315a03d4160e11b81526001600160401b0384166004820152606490632b407a829060240160206040518083038186803b1580156141f557600080fd5b505afa158015614209573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613bef91906155d0565b50506001600160401b03164090565b60006142708360000151846020015185604001518660600151868860a001518960c001518a60e001518b6101000151614484565b60038360200151604051602001614288929190615b34565b60408051601f1981840301815291905280516020909101209392505050565b6000806142b26146af565b905060005a6142c18888615d76565b6142cb9190615e0e565b6142d59085615def565b905060006142ee63ffffffff871664e8d4a51000615def565b9050826142fb8284615d76565b6143059190615d76565b98975050505050505050565b60008061431c61470b565b905060008113614342576040516321ea67b360e11b815260048101829052602401610c03565b600061434c6146af565b9050600082825a61435d8b8b615d76565b6143679190615e0e565b6143719088615def565b61437b9190615d76565b61438d90670de0b6b3a7640000615def565b6143979190615ddb565b905060006143b063ffffffff881664e8d4a51000615def565b90506143c8816b033b2e3c9fd0803ce8000000615e0e565b8211156143e85760405163e80fa38160e01b815260040160405180910390fd5b6143f28183615d76565b9998505050505050505050565b6000613bef83836147da565b600081815260018301602052604081205461445257508154600181810184556000848152602080822090930184905584548482528286019093526040902091909155611355565b506000611355565b600082600001828154811061447157614471615f15565b9060005260206000200154905092915050565b61448d896148cd565b6144d95760405162461bcd60e51b815260206004820152601a60248201527f7075626c6963206b6579206973206e6f74206f6e2063757276650000000000006044820152606401610c03565b6144e2886148cd565b61452e5760405162461bcd60e51b815260206004820152601560248201527f67616d6d61206973206e6f74206f6e20637572766500000000000000000000006044820152606401610c03565b614537836148cd565b6145835760405162461bcd60e51b815260206004820152601d60248201527f6347616d6d615769746e657373206973206e6f74206f6e2063757276650000006044820152606401610c03565b61458c826148cd565b6145d85760405162461bcd60e51b815260206004820152601c60248201527f73486173685769746e657373206973206e6f74206f6e206375727665000000006044820152606401610c03565b6145e4878a88876149a6565b6146305760405162461bcd60e51b815260206004820152601960248201527f6164647228632a706b2b732a6729213d5f755769746e657373000000000000006044820152606401610c03565b600061463c8a87614ac9565b9050600061464f898b878b868989614b2d565b90506000614660838d8d8a86614c4d565b9050808a146146a15760405162461bcd60e51b815260206004820152600d60248201526c34b73b30b634b210383937b7b360991b6044820152606401610c03565b505050505050505050505050565b60004661a4b18114806146c4575062066eed81145b1561470357606c6001600160a01b031663c6f7de0e6040518163ffffffff1660e01b815260040160206040518083038186803b15801561404157600080fd5b600091505090565b600d5460035460408051633fabe5a360e21b81529051600093670100000000000000900463ffffffff169283151592859283926001600160a01b03169163feaf968c9160048083019260a0929190829003018186803b15801561476d57600080fd5b505afa158015614781573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906147a59190615866565b5094509092508491505080156147c957506147c08242615e0e565b8463ffffffff16105b15613c3e5750601154949350505050565b600081815260018301602052604081205480156148c35760006147fe600183615e0e565b855490915060009061481290600190615e0e565b905081811461487757600086600001828154811061483257614832615f15565b906000526020600020015490508087600001848154811061485557614855615f15565b6000918252602080832090910192909255918252600188019052604090208390555b855486908061488857614888615eff565b600190038181906000526020600020016000905590558560010160008681526020019081526020016000206000905560019350505050611355565b6000915050611355565b80516000906401000003d019116149265760405162461bcd60e51b815260206004820152601260248201527f696e76616c696420782d6f7264696e61746500000000000000000000000000006044820152606401610c03565b60208201516401000003d0191161497f5760405162461bcd60e51b815260206004820152601260248201527f696e76616c696420792d6f7264696e61746500000000000000000000000000006044820152606401610c03565b60208201516401000003d01990800961499f8360005b6020020151614c8d565b1492915050565b60006001600160a01b0382166149ec5760405162461bcd60e51b815260206004820152600b60248201526a626164207769746e65737360a81b6044820152606401610c03565b602084015160009060011615614a0357601c614a06565b601b5b9050600070014551231950b75fc4402da1732fc9bebe1985876000602002015109865170014551231950b75fc4402da1732fc9bebe19918203925060009190890987516040805160008082526020820180845287905260ff88169282019290925260608101929092526080820183905291925060019060a0016020604051602081039080840390855afa158015614aa1573d6000803e3d6000fd5b5050604051601f1901516001600160a01b039081169088161495505050505050949350505050565b614ad16151bb565b614afe60018484604051602001614aea93929190615a0b565b604051602081830303815290604052614cb1565b90505b614b0a816148cd565b611355578051604080516020810192909252614b269101614aea565b9050614b01565b614b356151bb565b825186516401000003d0199081900691061415614b945760405162461bcd60e51b815260206004820152601e60248201527f706f696e747320696e2073756d206d7573742062652064697374696e637400006044820152606401610c03565b614b9f878988614cff565b614beb5760405162461bcd60e51b815260206004820152601660248201527f4669727374206d756c20636865636b206661696c6564000000000000000000006044820152606401610c03565b614bf6848685614cff565b614c425760405162461bcd60e51b815260206004820152601760248201527f5365636f6e64206d756c20636865636b206661696c65640000000000000000006044820152606401610c03565b614305868484614e27565b600060028686868587604051602001614c6b969594939291906159ac565b60408051601f1981840301815291905280516020909101209695505050505050565b6000806401000003d01980848509840990506401000003d019600782089392505050565b614cb96151bb565b614cc282614eee565b8152614cd7614cd2826000614995565b614f29565b602082018190526002900660011415612386576020810180516401000003d019039052919050565b600082614d3c5760405162461bcd60e51b815260206004820152600b60248201526a3d32b9379039b1b0b630b960a91b6044820152606401610c03565b83516020850151600090614d5290600290615ebf565b15614d5e57601c614d61565b601b5b9050600070014551231950b75fc4402da1732fc9bebe198387096040805160008082526020820180845281905260ff86169282019290925260608101869052608081018390529192509060019060a0016020604051602081039080840390855afa158015614dd3573d6000803e3d6000fd5b505050602060405103519050600086604051602001614df2919061599a565b60408051601f1981840301815291905280516020909101206001600160a01b0392831692169190911498975050505050505050565b614e2f6151bb565b835160208086015185519186015160009384938493614e5093909190614f49565b919450925090506401000003d019858209600114614eb05760405162461bcd60e51b815260206004820152601960248201527f696e765a206d75737420626520696e7665727365206f66207a000000000000006044820152606401610c03565b60405180604001604052806401000003d01980614ecf57614ecf615ee9565b87860981526020016401000003d0198785099052979650505050505050565b805160208201205b6401000003d019811061238657604080516020808201939093528151808203840181529082019091528051910120614ef6565b6000611355826002614f426401000003d0196001615d76565b901c615029565b60008080600180826401000003d019896401000003d019038808905060006401000003d0198b6401000003d019038a0890506000614f89838385856150cb565b9098509050614f9a88828e886150ef565b9098509050614fab88828c876150ef565b90985090506000614fbe8d878b856150ef565b9098509050614fcf888286866150cb565b9098509050614fe088828e896150ef565b9098509050818114615015576401000003d019818a0998506401000003d01982890997506401000003d0198183099650615019565b8196505b5050505050509450945094915050565b6000806150346151d9565b6020808252818101819052604082015260608101859052608081018490526401000003d01960a08201526150666151f7565b60208160c0846005600019fa9250826150c15760405162461bcd60e51b815260206004820152601260248201527f6269674d6f64457870206661696c7572652100000000000000000000000000006044820152606401610c03565b5195945050505050565b6000806401000003d0198487096401000003d0198487099097909650945050505050565b600080806401000003d019878509905060006401000003d01987876401000003d019030990506401000003d0198183086401000003d01986890990999098509650505050505050565b82805482825590600052602060002090810192821561518d579160200282015b8281111561518d57825182546001600160a01b0319166001600160a01b03909116178255602090920191600190910190615158565b50615199929150615215565b5090565b5080546000825590600052602060002090810190610c0c9190615215565b60405180604001604052806002906020820280368337509192915050565b6040518060c001604052806006906020820280368337509192915050565b60405180602001604052806001906020820280368337509192915050565b5b808211156151995760008155600101615216565b803561238681615f41565b806040810183101561135557600080fd5b600082601f83011261525757600080fd5b61525f615cdf565b80838560408601111561527157600080fd5b60005b6002811015615293578135845260209384019390910190600101615274565b509095945050505050565b600082601f8301126152af57600080fd5b81356001600160401b03808211156152c9576152c9615f2b565b604051601f8301601f19908116603f011681019082821181831017156152f1576152f1615f2b565b8160405283815286602085880101111561530a57600080fd5b836020870160208301376000602085830101528094505050505092915050565b600060c0828403121561533c57600080fd5b615344615d07565b905081356001600160401b03808216821461535e57600080fd5b81835260208401356020840152615377604085016153dd565b6040840152615388606085016153dd565b60608401526153996080850161522a565b608084015260a08401359150808211156153b257600080fd5b506153bf8482850161529e565b60a08301525092915050565b803561ffff8116811461238657600080fd5b803563ffffffff8116811461238657600080fd5b805169ffffffffffffffffffff8116811461238657600080fd5b80356001600160601b038116811461238657600080fd5b60006020828403121561543457600080fd5b8135613bef81615f41565b6000806040838503121561545257600080fd5b823561545d81615f41565b915061546b6020840161540b565b90509250929050565b6000806040838503121561548757600080fd5b823561549281615f41565b915060208301356154a281615f41565b809150509250929050565b600080606083850312156154c057600080fd5b82356154cb81615f41565b915061546b8460208501615235565b600080600080606085870312156154f057600080fd5b84356154fb81615f41565b93506020850135925060408501356001600160401b038082111561551e57600080fd5b818701915087601f83011261553257600080fd5b81358181111561554157600080fd5b88602082850101111561555357600080fd5b95989497505060200194505050565b60006040828403121561557457600080fd5b613bef8383615235565b60006040828403121561559057600080fd5b613bef8383615246565b6000602082840312156155ac57600080fd5b8151613bef81615f56565b6000602082840312156155c957600080fd5b5035919050565b6000602082840312156155e257600080fd5b5051919050565b6000602082840312156155fb57600080fd5b604051602081018181106001600160401b038211171561561d5761561d615f2b565b604052823561562b81615f56565b81529392505050565b6000808284036101c081121561564957600080fd5b6101a08082121561565957600080fd5b615661615d29565b915061566d8686615246565b825261567c8660408701615246565b60208301526080850135604083015260a0850135606083015260c085013560808301526156ab60e0860161522a565b60a08301526101006156bf87828801615246565b60c08401526156d2876101408801615246565b60e0840152610180860135908301529092508301356001600160401b038111156156fb57600080fd5b6157078582860161532a565b9150509250929050565b60006020828403121561572357600080fd5b81356001600160401b0381111561573957600080fd5b820160c08185031215613bef57600080fd5b60006020828403121561575d57600080fd5b613bef826153cb565b60008060008060008086880360e081121561578057600080fd5b615789886153cb565b9650615797602089016153dd565b95506157a5604089016153dd565b94506157b3606089016153dd565b9350608088013592506040609f19820112156157ce57600080fd5b506157d7615cdf565b6157e360a089016153dd565b81526157f160c089016153dd565b6020820152809150509295509295509295565b6000806040838503121561581757600080fd5b8235915060208301356154a281615f41565b6000806040838503121561583c57600080fd5b50508035926020909101359150565b60006020828403121561585d57600080fd5b613bef826153dd565b600080600080600060a0868803121561587e57600080fd5b615887866153f1565b94506020860151935060408601519250606086015191506158aa608087016153f1565b90509295509295909350565b600081518084526020808501945080840160005b838110156158ef5781516001600160a01b0316875295820195908201906001016158ca565b509495945050505050565b8060005b6002811015610e6b5781518452602093840193909101906001016158fe565b600081518084526020808501945080840160005b838110156158ef57815187529582019590820190600101615931565b6000815180845260005b8181101561597357602081850181015186830182015201615957565b81811115615985576000602083870101525b50601f01601f19169290920160200192915050565b6159a481836158fa565b604001919050565b8681526159bc60208201876158fa565b6159c960608201866158fa565b6159d660a08201856158fa565b6159e360e08201846158fa565b60609190911b6bffffffffffffffffffffffff19166101208201526101340195945050505050565b838152615a1b60208201846158fa565b606081019190915260800192915050565b6040810161135582846158fa565b602081526000613bef602083018461591d565b602081526000613bef602083018461594d565b6020815260ff8251166020820152602082015160408201526001600160a01b0360408301511660608201526000606083015160c06080840152615aa660e08401826158b6565b905060808401516001600160601b0380821660a08601528060a08701511660c086015250508091505092915050565b60006060820161ffff86168352602063ffffffff86168185015260606040850152818551808452608086019150828701935060005b81811015615b2657845183529383019391830191600101615b0a565b509098975050505050505050565b82815260608101613bef60208301846158fa565b828152604060208201526000613c3e604083018461591d565b86815285602082015261ffff85166040820152600063ffffffff808616606084015280851660808401525060c060a083015261430560c083018461594d565b878152866020820152856040820152600063ffffffff80871660608401528086166080840152506001600160a01b03841660a083015260e060c08301526143f260e083018461594d565b8781526001600160401b0387166020820152856040820152600063ffffffff80871660608401528086166080840152506001600160a01b03841660a083015260e060c08301526143f260e083018461594d565b60006001600160601b0380881683528087166020840152506001600160401b03851660408301526001600160a01b038416606083015260a06080830152615c8760a08301846158b6565b979650505050505050565b6000808335601e19843603018112615ca957600080fd5b8301803591506001600160401b03821115615cc357600080fd5b602001915036819003821315615cd857600080fd5b9250929050565b604080519081016001600160401b0381118282101715615d0157615d01615f2b565b60405290565b60405160c081016001600160401b0381118282101715615d0157615d01615f2b565b60405161012081016001600160401b0381118282101715615d0157615d01615f2b565b60008085851115615d5c57600080fd5b83861115615d6957600080fd5b5050820193919092039150565b60008219821115615d8957615d89615ed3565b500190565b60006001600160401b03808316818516808303821115615db057615db0615ed3565b01949350505050565b60006001600160601b03808316818516808303821115615db057615db0615ed3565b600082615dea57615dea615ee9565b500490565b6000816000190483118215151615615e0957615e09615ed3565b500290565b600082821015615e2057615e20615ed3565b500390565b60006001600160601b0383811690831681811015615e4557615e45615ed3565b039392505050565b6001600160e01b03198135818116916004851015615e755780818660040360031b1b83161692505b505092915050565b6000600019821415615e9157615e91615ed3565b5060010190565b60006001600160401b0380831681811415615eb557615eb5615ed3565b6001019392505050565b600082615ece57615ece615ee9565b500690565b634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052601260045260246000fd5b634e487b7160e01b600052603160045260246000fd5b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052604160045260246000fd5b6001600160a01b0381168114610c0c57600080fd5b8015158114610c0c57600080fdfea164736f6c6343000806000a", } var VRFCoordinatorV2PlusABI = VRFCoordinatorV2PlusMetaData.ABI 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 a6c491ac6b2..d158a94937f 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 @@ -6,7 +6,7 @@ authorized_receiver: ../../contracts/solc/v0.7/AuthorizedReceiver.abi ../../cont automation_consumer_benchmark: ../../contracts/solc/v0.8.16/AutomationConsumerBenchmark.abi ../../contracts/solc/v0.8.16/AutomationConsumerBenchmark.bin f52c76f1aaed4be541d82d97189d70f5aa027fc9838037dd7a7d21910c8c488e automation_forwarder_logic: ../../contracts/solc/v0.8.16/AutomationForwarderLogic.abi ../../contracts/solc/v0.8.16/AutomationForwarderLogic.bin 15ae0c367297955fdab4b552dbb10e1f2be80a8fde0efec4a4d398693e9d72b5 automation_registrar_wrapper2_1: ../../contracts/solc/v0.8.16/AutomationRegistrar2_1.abi ../../contracts/solc/v0.8.16/AutomationRegistrar2_1.bin eb06d853aab39d3196c593b03e555851cbe8386e0fe54a74c2479f62d14b3c42 -automation_utils_2_1: ../../contracts/solc/v0.8.16/AutomationUtils2_1.abi ../../contracts/solc/v0.8.16/AutomationUtils2_1.bin 0b3006a2a1588916d22bf1ae5429bd3bce24a58904588d5ed3fe1026d64616cf +automation_utils_2_1: ../../contracts/solc/v0.8.16/AutomationUtils2_1.abi ../../contracts/solc/v0.8.16/AutomationUtils2_1.bin f7e675941621528e03fab1487e38a2d9ecef94694035fb51c1bc16561f3d2cea batch_blockhash_store: ../../contracts/solc/v0.8.6/BatchBlockhashStore.abi ../../contracts/solc/v0.8.6/BatchBlockhashStore.bin c5ab26709a01050402615659403f32d5cd1b85f3ad6bb6bfe021692f4233cf19 batch_vrf_coordinator_v2: ../../contracts/solc/v0.8.6/BatchVRFCoordinatorV2.abi ../../contracts/solc/v0.8.6/BatchVRFCoordinatorV2.bin d0a54963260d8c1f1bbd984b758285e6027cfb5a7e42701bcb562ab123219332 batch_vrf_coordinator_v2plus: ../../contracts/solc/v0.8.6/BatchVRFCoordinatorV2Plus.abi ../../contracts/solc/v0.8.6/BatchVRFCoordinatorV2Plus.bin 7bb76ae241cf1b37b41920830b836cb99f1ad33efd7435ca2398ff6cd2fe5d48 @@ -36,7 +36,7 @@ keeper_registry_wrapper1_1_mock: ../../contracts/solc/v0.7/KeeperRegistry1_1Mock keeper_registry_wrapper1_2: ../../contracts/solc/v0.8.6/KeeperRegistry1_2.abi ../../contracts/solc/v0.8.6/KeeperRegistry1_2.bin c08f903e7ecbdf89bbfea32c6dd334d3bf908ac809ebf63545890798a5f7a4a7 keeper_registry_wrapper1_3: ../../contracts/solc/v0.8.6/KeeperRegistry1_3.abi ../../contracts/solc/v0.8.6/KeeperRegistry1_3.bin 5e1414eacbc1880b7349a4f253b7eca176f7f6300ef3cd834c493ce795a17e25 keeper_registry_wrapper2_0: ../../contracts/solc/v0.8.6/KeeperRegistry2_0.abi ../../contracts/solc/v0.8.6/KeeperRegistry2_0.bin c32dea7d5ef66b7c58ddc84ddf69aa44df1b3ae8601fbc271c95be4ff5853056 -keeper_registry_wrapper_2_1: ../../contracts/solc/v0.8.16/KeeperRegistry2_1.abi ../../contracts/solc/v0.8.16/KeeperRegistry2_1.bin 6406f37de79d3d2efa86fb961e1462b62a5a2fff4aeb408bbdb4bc7272d91638 +keeper_registry_wrapper_2_1: ../../contracts/solc/v0.8.16/KeeperRegistry2_1.abi ../../contracts/solc/v0.8.16/KeeperRegistry2_1.bin 604e4a0cd980c713929b523b999462a3aa0ed06f96ff563a4c8566cf59c8445b keepers_vrf_consumer: ../../contracts/solc/v0.8.6/KeepersVRFConsumer.abi ../../contracts/solc/v0.8.6/KeepersVRFConsumer.bin fa75572e689c9e84705c63e8dbe1b7b8aa1a8fe82d66356c4873d024bb9166e8 log_emitter: ../../contracts/solc/v0.8.19/LogEmitter.abi ../../contracts/solc/v0.8.19/LogEmitter.bin 244ba13730c036de0b02beef4e3d9c9a96946ce353c27f366baecc7f5be5a6fd log_triggered_feed_lookup_wrapper: ../../contracts/solc/v0.8.16/LogTriggeredStreamsLookup.abi ../../contracts/solc/v0.8.16/LogTriggeredStreamsLookup.bin b3c01ce82842c6be4aceba218c78c1e4958803eab3abe5b0cdbe6fb0464c4a5a @@ -59,15 +59,15 @@ solidity_vrf_v08_verifier_wrapper: ../../contracts/solc/v0.8.6/VRFTestHelper.abi solidity_vrf_verifier_wrapper: ../../contracts/solc/v0.6/VRFTestHelper.abi ../../contracts/solc/v0.6/VRFTestHelper.bin 44c2b67d8d2990ab580453deb29d63508c6147a3dc49908a1db563bef06e6474 solidity_vrf_wrapper: ../../contracts/solc/v0.6/VRF.abi ../../contracts/solc/v0.6/VRF.bin 04ede5b83c06ba5b76ef99c081c72928007d8a7aaefcf21449a46a07cbd4bfc2 streams_lookup_compatible_interface: ../../contracts/solc/v0.8.16/StreamsLookupCompatibleInterface.abi ../../contracts/solc/v0.8.16/StreamsLookupCompatibleInterface.bin feb92cc666df21ea04ab9d7a588a513847b01b2f66fc167d06ab28ef2b17e015 -streams_lookup_upkeep_wrapper: ../../contracts/solc/v0.8.16/StreamsLookupUpkeep.abi ../../contracts/solc/v0.8.16/StreamsLookupUpkeep.bin 4999afb752411696ec59210609b6deef45f519b18bd5e1450688062b3f7d0951 +streams_lookup_upkeep_wrapper: ../../contracts/solc/v0.8.16/StreamsLookupUpkeep.abi ../../contracts/solc/v0.8.16/StreamsLookupUpkeep.bin a2c5a0ee6c85104609259ecdb09440f4eb115259f4283b2509e41e9c57aca265 test_api_consumer_wrapper: ../../contracts/solc/v0.6/TestAPIConsumer.abi ../../contracts/solc/v0.6/TestAPIConsumer.bin ed10893cb18894c18e275302329c955f14ea2de37ee044f84aa1e067ac5ea71e trusted_blockhash_store: ../../contracts/solc/v0.8.6/TrustedBlockhashStore.abi ../../contracts/solc/v0.8.6/TrustedBlockhashStore.bin a85d2899892aa9fd73fc99852ccba52c3983375113580673e6c5d655bfa79909 type_and_version_interface_wrapper: ../../contracts/solc/v0.8.6/TypeAndVersionInterface.abi ../../contracts/solc/v0.8.6/TypeAndVersionInterface.bin bc9c3a6e73e3ebd5b58754df0deeb3b33f4bb404d5709bb904aed51d32f4b45e upkeep_counter_wrapper: ../../contracts/solc/v0.7/UpkeepCounter.abi ../../contracts/solc/v0.7/UpkeepCounter.bin 901961ebf18906febc1c350f02da85c7ea1c2a68da70cfd94efa27c837a48663 upkeep_perform_counter_restrictive_wrapper: ../../contracts/solc/v0.7/UpkeepPerformCounterRestrictive.abi ../../contracts/solc/v0.7/UpkeepPerformCounterRestrictive.bin 8975a058fba528e16d8414dc6f13946d17a145fcbc66cf25a32449b6fe1ce878 upkeep_transcoder: ../../contracts/solc/v0.8.6/UpkeepTranscoder.abi ../../contracts/solc/v0.8.6/UpkeepTranscoder.bin 336c92a981597be26508455f81a908a0784a817b129a59686c5b2c4afcba730a -verifiable_load_log_trigger_upkeep_wrapper: ../../contracts/solc/v0.8.16/VerifiableLoadLogTriggerUpkeep.abi ../../contracts/solc/v0.8.16/VerifiableLoadLogTriggerUpkeep.bin 9d6f38552015d190c32671d785339716803b3b97223ea388e7a699d7f707494f -verifiable_load_streams_lookup_upkeep_wrapper: ../../contracts/solc/v0.8.16/VerifiableLoadStreamsLookupUpkeep.abi ../../contracts/solc/v0.8.16/VerifiableLoadStreamsLookupUpkeep.bin 4c02260ab1ab687536e13f417c048ee387c56c64d22a1b35ccd9bbc56f13ce50 +verifiable_load_log_trigger_upkeep_wrapper: ../../contracts/solc/v0.8.16/VerifiableLoadLogTriggerUpkeep.abi ../../contracts/solc/v0.8.16/VerifiableLoadLogTriggerUpkeep.bin 13f2238ad1ea1dfde87ea48d1d16a4939dc2c8ede399034c072b07deee9e642e +verifiable_load_streams_lookup_upkeep_wrapper: ../../contracts/solc/v0.8.16/VerifiableLoadStreamsLookupUpkeep.abi ../../contracts/solc/v0.8.16/VerifiableLoadStreamsLookupUpkeep.bin c626fb01272895f2a87ddd0f038c99bf46e9bedd4abd8dc102fe89ff3cb87a9a verifiable_load_upkeep_wrapper: ../../contracts/solc/v0.8.16/VerifiableLoadUpkeep.abi ../../contracts/solc/v0.8.16/VerifiableLoadUpkeep.bin a3e02c43756ea91e7ce4b81e48c11648f1d12f6663c236780147e41dfa36ebee vrf_consumer_v2: ../../contracts/solc/v0.8.6/VRFConsumerV2.abi ../../contracts/solc/v0.8.6/VRFConsumerV2.bin 9ef258bf8e9f8d880fd229ceb145593d91e24fc89366baa0bf19169c5787d15f vrf_consumer_v2_plus_upgradeable_example: ../../contracts/solc/v0.8.6/VRFConsumerV2PlusUpgradeableExample.abi ../../contracts/solc/v0.8.6/VRFConsumerV2PlusUpgradeableExample.bin 3155c611e4d6882e9324b6e975033b31356776ea8b031ca63d63da37589d583b @@ -75,7 +75,7 @@ vrf_consumer_v2_upgradeable_example: ../../contracts/solc/v0.8.6/VRFConsumerV2Up vrf_coordinator_mock: ../../contracts/solc/v0.8.6/VRFCoordinatorMock.abi ../../contracts/solc/v0.8.6/VRFCoordinatorMock.bin 5c495cf8df1f46d8736b9150cdf174cce358cb8352f60f0d5bb9581e23920501 vrf_coordinator_v2: ../../contracts/solc/v0.8.6/VRFCoordinatorV2.abi ../../contracts/solc/v0.8.6/VRFCoordinatorV2.bin 75c87cf1624a401ac6303df9c8e04896aa8a53849e8b0c3d7340a9d089ef6d4b vrf_coordinator_v2_plus_v2_example: ../../contracts/solc/v0.8.6/VRFCoordinatorV2Plus_V2Example.abi ../../contracts/solc/v0.8.6/VRFCoordinatorV2Plus_V2Example.bin 50d881ecf2551c0e56b84cb932f068b703b38b00c73eb05d4e4b80754ecf6b6d -vrf_coordinator_v2plus: ../../contracts/solc/v0.8.6/VRFCoordinatorV2Plus.abi ../../contracts/solc/v0.8.6/VRFCoordinatorV2Plus.bin bcd16361198eea25b9ca2fb41f019d0ff02f4e7b05289608c37f2e4c9440754d +vrf_coordinator_v2plus: ../../contracts/solc/v0.8.6/VRFCoordinatorV2Plus.abi ../../contracts/solc/v0.8.6/VRFCoordinatorV2Plus.bin f80932e5292602d0b3adbde425f9c0774926f786c12ad020463e4f8e025426d3 vrf_external_sub_owner_example: ../../contracts/solc/v0.8.6/VRFExternalSubOwnerExample.abi ../../contracts/solc/v0.8.6/VRFExternalSubOwnerExample.bin 14f888eb313930b50233a6f01ea31eba0206b7f41a41f6311670da8bb8a26963 vrf_load_test_external_sub_owner: ../../contracts/solc/v0.8.6/VRFLoadTestExternalSubOwner.abi ../../contracts/solc/v0.8.6/VRFLoadTestExternalSubOwner.bin 2097faa70265e420036cc8a3efb1f1e0836ad2d7323b295b9a26a125dbbe6c7d vrf_load_test_ownerless_consumer: ../../contracts/solc/v0.8.6/VRFLoadTestOwnerlessConsumer.abi ../../contracts/solc/v0.8.6/VRFLoadTestOwnerlessConsumer.bin 74f914843cbc70b9c3079c3e1c709382ce415225e8bb40113e7ac018bfcb0f5c diff --git a/core/gethwrappers/llo-feeds/generated/fee_manager/fee_manager.go b/core/gethwrappers/llo-feeds/generated/fee_manager/fee_manager.go index 75fcba1ce41..d8fdd50e6ed 100644 --- a/core/gethwrappers/llo-feeds/generated/fee_manager/fee_manager.go +++ b/core/gethwrappers/llo-feeds/generated/fee_manager/fee_manager.go @@ -50,8 +50,8 @@ type IRewardManagerFeePayment struct { } var FeeManagerMetaData = &bind.MetaData{ - ABI: "[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_linkAddress\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_nativeAddress\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_proxyAddress\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_rewardManagerAddress\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"ExpiredReport\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidAddress\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidDeposit\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidDiscount\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidQuote\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidSurcharge\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"Unauthorized\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ZeroDeficit\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"components\":[{\"internalType\":\"bytes32\",\"name\":\"poolId\",\"type\":\"bytes32\"},{\"internalType\":\"uint192\",\"name\":\"amount\",\"type\":\"uint192\"}],\"indexed\":false,\"internalType\":\"structIRewardManager.FeePayment[]\",\"name\":\"rewards\",\"type\":\"tuple[]\"}],\"name\":\"InsufficientLink\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"configDigest\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"linkQuantity\",\"type\":\"uint256\"}],\"name\":\"LinkDeficitCleared\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"newSurcharge\",\"type\":\"uint64\"}],\"name\":\"NativeSurchargeUpdated\",\"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\":\"address\",\"name\":\"subscriber\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"feedId\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"discount\",\"type\":\"uint64\"}],\"name\":\"SubscriberDiscountUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"adminAddress\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"assetAddress\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint192\",\"name\":\"quantity\",\"type\":\"uint192\"}],\"name\":\"Withdraw\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"acceptOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"subscriber\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"report\",\"type\":\"bytes\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"quoteAddress\",\"type\":\"address\"}],\"internalType\":\"structIFeeManager.Quote\",\"name\":\"quote\",\"type\":\"tuple\"}],\"name\":\"getFeeAndReward\",\"outputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"assetAddress\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"internalType\":\"structCommon.Asset\",\"name\":\"\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"assetAddress\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"internalType\":\"structCommon.Asset\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"linkAvailableForPayment\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"configDigest\",\"type\":\"bytes32\"}],\"name\":\"payLinkDeficit\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"payload\",\"type\":\"bytes\"},{\"internalType\":\"address\",\"name\":\"subscriber\",\"type\":\"address\"}],\"name\":\"processFee\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes[]\",\"name\":\"payloads\",\"type\":\"bytes[]\"},{\"internalType\":\"address\",\"name\":\"subscriber\",\"type\":\"address\"}],\"name\":\"processFeeBulk\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"name\":\"s_linkDeficit\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_nativeSurcharge\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"s_subscriberDiscounts\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"configDigest\",\"type\":\"bytes32\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"addr\",\"type\":\"address\"},{\"internalType\":\"uint64\",\"name\":\"weight\",\"type\":\"uint64\"}],\"internalType\":\"structCommon.AddressAndWeight[]\",\"name\":\"rewardRecipientAndWeights\",\"type\":\"tuple[]\"}],\"name\":\"setFeeRecipients\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"surcharge\",\"type\":\"uint64\"}],\"name\":\"setNativeSurcharge\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes4\",\"name\":\"interfaceId\",\"type\":\"bytes4\"}],\"name\":\"supportsInterface\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"typeAndVersion\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"subscriber\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"feedId\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"uint64\",\"name\":\"discount\",\"type\":\"uint64\"}],\"name\":\"updateSubscriberDiscount\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"assetAddress\",\"type\":\"address\"},{\"internalType\":\"uint192\",\"name\":\"quantity\",\"type\":\"uint192\"}],\"name\":\"withdraw\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", - Bin: "0x6101006040523480156200001257600080fd5b50604051620033c1380380620033c1833981016040819052620000359162000288565b33806000816200008c5760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b0384811691909117909155811615620000bf57620000bf81620001c0565b5050506001600160a01b0384161580620000e057506001600160a01b038316155b80620000f357506001600160a01b038216155b806200010657506001600160a01b038116155b15620001255760405163e6c4247b60e01b815260040160405180910390fd5b6001600160a01b03848116608081905284821660a05283821660c05290821660e081905260405163095ea7b360e01b81526004810191909152600019602482015263095ea7b3906044016020604051808303816000875af11580156200018f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620001b59190620002e5565b505050505062000310565b336001600160a01b038216036200021a5760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c66000000000000000000604482015260640162000083565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b80516001600160a01b03811681146200028357600080fd5b919050565b600080600080608085870312156200029f57600080fd5b620002aa856200026b565b9350620002ba602086016200026b565b9250620002ca604086016200026b565b9150620002da606086016200026b565b905092959194509250565b600060208284031215620002f857600080fd5b815180151581146200030957600080fd5b9392505050565b60805160a05160c05160e051612feb620003d6600039600081816111250152818161146e01528181611b770152611dd201526000818161059f015281816111e501526113b4015260008181610a2101528181610a7401528181610d2b01528181610e3701528181611a9d0152611b4601526000818161073301528181610a4601528181610acf01528181610c1901528181610c8801528181610cc701528181610de001528181610f770152818161130a015281816118460152611c380152612feb6000f3fe60806040526004361061010e5760003560e01c806387d6d843116100a5578063d09dc33911610074578063f1387e1611610059578063f1387e1614610345578063f2fde38b14610358578063f65df9621461037857600080fd5b8063d09dc33914610310578063e389d9a41461032557600080fd5b806387d6d8431461024f5780638da5cb5b1461028d578063c541cbde146102c2578063ce7817d1146102f057600080fd5b806332f5f746116100e157806332f5f746146101f157806340d7f78e14610207578063505380941461021a57806379ba50971461023a57600080fd5b8063013f542b1461011357806301ffc9a7146101535780631791dc5e14610183578063181f5a77146101a5575b600080fd5b34801561011f57600080fd5b5061014061012e3660046123ce565b60036020526000908152604090205481565b6040519081526020015b60405180910390f35b34801561015f57600080fd5b5061017361016e3660046123e7565b610398565b604051901515815260200161014a565b34801561018f57600080fd5b506101a361019e366004612471565b610431565b005b3480156101b157600080fd5b50604080518082018252601081527f4665654d616e6167657220302e302e31000000000000000000000000000000006020820152905161014a91906124ce565b3480156101fd57600080fd5b5061014060045481565b6101a361021536600461251f565b610587565b34801561022657600080fd5b506101a36102353660046125c2565b6107e4565b34801561024657600080fd5b506101a361087e565b34801561025b57600080fd5b5061014061026a3660046125dd565b600260209081526000938452604080852082529284528284209052825290205481565b34801561029957600080fd5b5060005460405173ffffffffffffffffffffffffffffffffffffffff909116815260200161014a565b3480156102ce57600080fd5b506102e26102dd366004612749565b610980565b60405161014a9291906127ea565b3480156102fc57600080fd5b506101a361030b36600461283e565b610d8a565b34801561031c57600080fd5b50610140610f46565b34801561033157600080fd5b506101a36103403660046123ce565b610ffc565b6101a361035336600461288f565b6111cd565b34801561036457600080fd5b506101a36103733660046128f1565b611388565b34801561038457600080fd5b506101a361039336600461290e565b61139c565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167ff1387e1600000000000000000000000000000000000000000000000000000000148061042b57507fffffffff0000000000000000000000000000000000000000000000000000000082167f40d7f78e00000000000000000000000000000000000000000000000000000000145b92915050565b6104396114d5565b73ffffffffffffffffffffffffffffffffffffffff82166104ba576000805460405173ffffffffffffffffffffffffffffffffffffffff9091169177ffffffffffffffffffffffffffffffffffffffffffffffff841680156108fc02929091818181858888f193505050501580156104b5573d6000803e3d6000fd5b505050565b6105146104dc60005473ffffffffffffffffffffffffffffffffffffffff1690565b73ffffffffffffffffffffffffffffffffffffffff84169077ffffffffffffffffffffffffffffffffffffffffffffffff8416611558565b6040805133815273ffffffffffffffffffffffffffffffffffffffff8416602082015277ffffffffffffffffffffffffffffffffffffffffffffffff83168183015290517f72608e45b52a95a12c2ac7f15ff53f92fc9572c9d84b6e6b5d7f0f7826cf32719181900360600190a15b5050565b3373ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016148015906105e5575060005473ffffffffffffffffffffffffffffffffffffffff163314155b1561061c576040517f82b4290000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008267ffffffffffffffff81111561063757610637612614565b60405190808252806020026020018201604052801561067057816020015b61065d612349565b8152602001906001900390816106555790505b5090506000806000805b868110156107ad576000806106b28a8a8581811061069a5761069a61298d565b90506020028101906106ac91906129bc565b8a61162c565b91509150816020015160001461079a5760405180606001604052808b8b868181106106df576106df61298d565b90506020028101906106f191906129bc565b6106fa91612a28565b815260208101849052604001829052878561071481612a93565b9650815181106107265761072661298d565b60200260200101819052507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16826000015173ffffffffffffffffffffffffffffffffffffffff16036107935785600101955061079a565b8460010194505b5050806107a690612a93565b905061067a565b50821515806107bb57508115155b156107d1576107cc85858585611761565b6107db565b6107db8534611e54565b50505050505050565b6107ec6114d5565b670de0b6b3a764000067ffffffffffffffff82161115610838576040517f05e8ac2900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b67ffffffffffffffff811660048190556040519081527f08f7c0d17932ddb8523bc06754d42ff19ebc77d76a8b9bfde02c28ab1ed3d6399060200160405180910390a150565b60015473ffffffffffffffffffffffffffffffffffffffff163314610904576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e65720000000000000000000060448201526064015b60405180910390fd5b60008054337fffffffffffffffffffffffff00000000000000000000000000000000000000008083168217845560018054909116905560405173ffffffffffffffffffffffffffffffffffffffff90921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b604080518082019091526000808252602082015260408051808201909152600080825260208201526040805180820190915260008082526020820152604080518082019091526000808252602082015260006109db87612acb565b90507fffff000000000000000000000000000000000000000000000000000000000000808216908101610a7257505073ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000811683527f00000000000000000000000000000000000000000000000000000000000000001681529092509050610d82565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16876000015173ffffffffffffffffffffffffffffffffffffffff1614158015610b2257507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16876000015173ffffffffffffffffffffffffffffffffffffffff1614155b15610b59576040517ff861803000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008060008a806020019051810190610b729190612b24565b77ffffffffffffffffffffffffffffffffffffffffffffffff92831698509116955063ffffffff1693505050428210159050610bda576040517fb6c405f500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff808d16600090815260026020908152604080832089845282528083208e51851684529091529020547f00000000000000000000000000000000000000000000000000000000000000009091168752610c6a610c5282670de0b6b3a7640000612b96565b610c5c9086612ba9565b670de0b6b3a7640000611e9d565b60208801528a5173ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000008116911603610cf85773ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016885260208088015190890152610d75565b600454600090610d1490610c5290670de0b6b3a7640000612be6565b73ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168a529050610d6e610d6483670de0b6b3a7640000612b96565b610c5c9083612ba9565b60208a0152505b5095975093955050505050505b935093915050565b610d926114d5565b670de0b6b3a764000067ffffffffffffffff82161115610dde576040517f997ea36000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1614158015610e8657507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1614155b15610ebd576040517fe6c4247b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff848116600081815260026020908152604080832088845282528083209487168084529482529182902067ffffffffffffffff86169081905582519485529084015285927f5eba5a8afa39780f0f99b6cbeb95f3da6a7040ca00abd46bdc91a0a060134139910160405180910390a350505050565b6040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201526000907f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16906370a0823190602401602060405180830381865afa158015610fd3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ff79190612bf9565b905090565b6110046114d5565b6000818152600360205260408120549081900361104d576040517f03aad31200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000828152600360205260408082208290558051600180825281830190925290816020015b604080518082019091526000808252602082015281526020019060019003908161107257905050905060405180604001604052808481526020018377ffffffffffffffffffffffffffffffffffffffffffffffff16815250816000815181106110dd576110dd61298d565b60209081029190910101526040517fb0d9fa1900000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000169063b0d9fa199061115c9084903090600401612c72565b600060405180830381600087803b15801561117657600080fd5b505af115801561118a573d6000803e3d6000fd5b50505050827f843f0b103e50b42b08f9d30f12f961845a6d02623730872e24644899c0dd9895836040516111c091815260200190565b60405180910390a2505050565b3373ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000161480159061122b575060005473ffffffffffffffffffffffffffffffffffffffff163314155b15611262576040517f82b4290000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008061127085858561162c565b9150915081602001516000036112915761128a8334611e54565b5050505050565b604080516001808252818301909252600091816020015b6112b0612349565b8152602001906001900390816112a85750506040805160608101909152909150806112db8789612a28565b815260200184815260200183815250816000815181106112fd576112fd61298d565b60200260200101819052507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16836000015173ffffffffffffffffffffffffffffffffffffffff16036113725761136d848260016000611761565b611380565b611380848260006001611761565b505050505050565b6113906114d5565b61139981611ed5565b50565b3373ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016148015906113fa575060005473ffffffffffffffffffffffffffffffffffffffff163314155b15611431576040517f82b4290000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040517f14060f2300000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016906314060f23906114a790869086908690600401612caa565b600060405180830381600087803b1580156114c157600080fd5b505af11580156107db573d6000803e3d6000fd5b60005473ffffffffffffffffffffffffffffffffffffffff163314611556576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e65720000000000000000000060448201526064016108fb565b565b60405173ffffffffffffffffffffffffffffffffffffffff83166024820152604481018290526104b59084907fa9059cbb00000000000000000000000000000000000000000000000000000000906064015b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff0000000000000000000000000000000000000000000000000000000090931692909217909152611fca565b604080518082019091526000808252602082015260408051808201909152600080825260208201523073ffffffffffffffffffffffffffffffffffffffff8416036116a3576040517fe6c4247b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60006116b185870187612d98565b9150506000816116c090612acb565b6040805160208101909152600081529091507e010000000000000000000000000000000000000000000000000000000000007fffff000000000000000000000000000000000000000000000000000000000000831614611747576000611728888a018a612e5c565b95505050505050808060200190518101906117439190612f24565b9150505b611752868483610980565b94509450505050935093915050565b60008267ffffffffffffffff81111561177c5761177c612614565b6040519080825280602002602001820160405280156117c157816020015b604080518082019091526000808252602082015281526020019060019003908161179a5790505b50905060008267ffffffffffffffff8111156117df576117df612614565b60405190808252806020026020018201604052801561182457816020015b60408051808201909152600080825260208201528152602001906001900390816117fd5790505b509050600080808080611837888a612be6565b905060005b81811015611a58577f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168b828151811061188d5761188d61298d565b6020026020010151602001516000015173ffffffffffffffffffffffffffffffffffffffff16036119535760405180604001604052808c83815181106118d5576118d561298d565b60200260200101516000015181526020018c83815181106118f8576118f861298d565b6020026020010151604001516020015177ffffffffffffffffffffffffffffffffffffffffffffffff1681525088858061193190612a93565b9650815181106119435761194361298d565b6020026020010181905250611a48565b60405180604001604052808c83815181106119705761197061298d565b60200260200101516000015181526020018c83815181106119935761199361298d565b6020026020010151604001516020015177ffffffffffffffffffffffffffffffffffffffffffffffff168152508784806119cc90612a93565b9550815181106119de576119de61298d565b60200260200101819052508a81815181106119fb576119fb61298d565b6020026020010151602001516020015186611a169190612be6565b95508a8181518110611a2a57611a2a61298d565b6020026020010151604001516020015185611a459190612be6565b94505b611a5181612a93565b905061183c565b5060003415611b265734861115611a9b576040517fb2e532de00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663d0e30db0876040518263ffffffff1660e01b81526004016000604051808303818588803b158015611b0357600080fd5b505af1158015611b17573d6000803e3d6000fd5b50505050508534039050611b6e565b8515611b6e57611b6e73ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168d30896120d6565b875115611c03577f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663b0d9fa19898e6040518363ffffffff1660e01b8152600401611bd0929190612c72565b600060405180830381600087803b158015611bea57600080fd5b505af1158015611bfe573d6000803e3d6000fd5b505050505b865115611e3c576040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16906370a0823190602401602060405180830381865afa158015611c94573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611cb89190612bf9565b851115611d955760005b8751811015611d5857878181518110611cdd57611cdd61298d565b60200260200101516020015177ffffffffffffffffffffffffffffffffffffffffffffffff16600360008a8481518110611d1957611d1961298d565b60200260200101516000015181526020019081526020016000206000828254611d429190612be6565b90915550611d51905081612a93565b9050611cc2565b507ff52e5907b69d97c33392936c12d78b494463b78c5b72df50b4c497eee5720b6787604051611d889190612f52565b60405180910390a1611e3c565b6040517fb0d9fa1900000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000169063b0d9fa1990611e09908a903090600401612c72565b600060405180830381600087803b158015611e2357600080fd5b505af1158015611e37573d6000803e3d6000fd5b505050505b611e468c82611e54565b505050505050505050505050565b80156105835760405173ffffffffffffffffffffffffffffffffffffffff83169082156108fc029083906000818181858888f193505050501580156104b5573d6000803e3d6000fd5b60008215611ecb5781611eb1600185612b96565b611ebb9190612f65565b611ec6906001612be6565b611ece565b60005b9392505050565b3373ffffffffffffffffffffffffffffffffffffffff821603611f54576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c6600000000000000000060448201526064016108fb565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b600061202c826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff1661213a9092919063ffffffff16565b8051909150156104b5578080602001905181019061204a9190612fa0565b6104b5576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f7420737563636565640000000000000000000000000000000000000000000060648201526084016108fb565b60405173ffffffffffffffffffffffffffffffffffffffff808516602483015283166044820152606481018290526121349085907f23b872dd00000000000000000000000000000000000000000000000000000000906084016115aa565b50505050565b60606121498484600085612151565b949350505050565b6060824710156121e3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f60448201527f722063616c6c000000000000000000000000000000000000000000000000000060648201526084016108fb565b6000808673ffffffffffffffffffffffffffffffffffffffff16858760405161220c9190612fc2565b60006040518083038185875af1925050503d8060008114612249576040519150601f19603f3d011682016040523d82523d6000602084013e61224e565b606091505b509150915061225f8783838761226a565b979650505050505050565b606083156123005782516000036122f95773ffffffffffffffffffffffffffffffffffffffff85163b6122f9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064016108fb565b5081612149565b61214983838151156123155781518083602001fd5b806040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016108fb91906124ce565b6040518060600160405280600080191681526020016123916040518060400160405280600073ffffffffffffffffffffffffffffffffffffffff168152602001600081525090565b81526020016123c96040518060400160405280600073ffffffffffffffffffffffffffffffffffffffff168152602001600081525090565b905290565b6000602082840312156123e057600080fd5b5035919050565b6000602082840312156123f957600080fd5b81357fffffffff0000000000000000000000000000000000000000000000000000000081168114611ece57600080fd5b73ffffffffffffffffffffffffffffffffffffffff8116811461139957600080fd5b77ffffffffffffffffffffffffffffffffffffffffffffffff8116811461139957600080fd5b6000806040838503121561248457600080fd5b823561248f81612429565b9150602083013561249f8161244b565b809150509250929050565b60005b838110156124c55781810151838201526020016124ad565b50506000910152565b60208152600082518060208401526124ed8160408501602087016124aa565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169190910160400192915050565b60008060006040848603121561253457600080fd5b833567ffffffffffffffff8082111561254c57600080fd5b818601915086601f83011261256057600080fd5b81358181111561256f57600080fd5b8760208260051b850101111561258457600080fd5b6020928301955093505084013561259a81612429565b809150509250925092565b803567ffffffffffffffff811681146125bd57600080fd5b919050565b6000602082840312156125d457600080fd5b611ece826125a5565b6000806000606084860312156125f257600080fd5b83356125fd81612429565b925060208401359150604084013561259a81612429565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6040516020810167ffffffffffffffff8111828210171561266657612666612614565b60405290565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff811182821017156126b3576126b3612614565b604052919050565b600082601f8301126126cc57600080fd5b813567ffffffffffffffff8111156126e6576126e6612614565b61271760207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8401160161266c565b81815284602083860101111561272c57600080fd5b816020850160208301376000918101602001919091529392505050565b6000806000838503606081121561275f57600080fd5b843561276a81612429565b9350602085013567ffffffffffffffff81111561278657600080fd5b612792878288016126bb565b93505060207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc0820112156127c557600080fd5b506127ce612643565b60408501356127dc81612429565b815292959194509192509050565b825173ffffffffffffffffffffffffffffffffffffffff1681526020808401519082015260808101825173ffffffffffffffffffffffffffffffffffffffff16604083015260208301516060830152611ece565b6000806000806080858703121561285457600080fd5b843561285f81612429565b935060208501359250604085013561287681612429565b9150612884606086016125a5565b905092959194509250565b6000806000604084860312156128a457600080fd5b833567ffffffffffffffff808211156128bc57600080fd5b818601915086601f8301126128d057600080fd5b8135818111156128df57600080fd5b87602082850101111561258457600080fd5b60006020828403121561290357600080fd5b8135611ece81612429565b60008060006040848603121561292357600080fd5b83359250602084013567ffffffffffffffff8082111561294257600080fd5b818601915086601f83011261295657600080fd5b81358181111561296557600080fd5b8760208260061b850101111561297a57600080fd5b6020830194508093505050509250925092565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe18436030181126129f157600080fd5b83018035915067ffffffffffffffff821115612a0c57600080fd5b602001915036819003821315612a2157600080fd5b9250929050565b8035602083101561042b577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff602084900360031b1b1692915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203612ac457612ac4612a64565b5060010190565b80516020808301519190811015612b0a577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8160200360031b1b821691505b50919050565b805163ffffffff811681146125bd57600080fd5b60008060008060008060c08789031215612b3d57600080fd5b86519550612b4d60208801612b10565b9450612b5b60408801612b10565b93506060870151612b6b8161244b565b6080880151909350612b7c8161244b565b9150612b8a60a08801612b10565b90509295509295509295565b8181038181111561042b5761042b612a64565b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0483118215151615612be157612be1612a64565b500290565b8082018082111561042b5761042b612a64565b600060208284031215612c0b57600080fd5b5051919050565b600081518084526020808501945080840160005b83811015612c675781518051885283015177ffffffffffffffffffffffffffffffffffffffffffffffff168388015260409096019590820190600101612c26565b509495945050505050565b604081526000612c856040830185612c12565b905073ffffffffffffffffffffffffffffffffffffffff831660208301529392505050565b8381526040602080830182905282820184905260009190859060608501845b87811015612d1d578335612cdc81612429565b73ffffffffffffffffffffffffffffffffffffffff16825267ffffffffffffffff612d088585016125a5565b16828401529284019290840190600101612cc9565b5098975050505050505050565b600082601f830112612d3b57600080fd5b6040516060810181811067ffffffffffffffff82111715612d5e57612d5e612614565b604052806060840185811115612d7357600080fd5b845b81811015612d8d578035835260209283019201612d75565b509195945050505050565b60008060808385031215612dab57600080fd5b612db58484612d2a565b9150606083013567ffffffffffffffff811115612dd157600080fd5b612ddd858286016126bb565b9150509250929050565b600082601f830112612df857600080fd5b8135602067ffffffffffffffff821115612e1457612e14612614565b8160051b612e2382820161266c565b9283528481018201928281019087851115612e3d57600080fd5b83870192505b8483101561225f57823582529183019190830190612e43565b6000806000806000806101008789031215612e7657600080fd5b612e808888612d2a565b9550606087013567ffffffffffffffff80821115612e9d57600080fd5b612ea98a838b016126bb565b96506080890135915080821115612ebf57600080fd5b612ecb8a838b01612de7565b955060a0890135915080821115612ee157600080fd5b612eed8a838b01612de7565b945060c0890135935060e0890135915080821115612f0a57600080fd5b50612f1789828a016126bb565b9150509295509295509295565b600060208284031215612f3657600080fd5b612f3e612643565b8251612f4981612429565b81529392505050565b602081526000611ece6020830184612c12565b600082612f9b577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500490565b600060208284031215612fb257600080fd5b81518015158114611ece57600080fd5b60008251612fd48184602087016124aa565b919091019291505056fea164736f6c6343000810000a", + ABI: "[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_linkAddress\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_nativeAddress\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_proxyAddress\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_rewardManagerAddress\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"ExpiredReport\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidAddress\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidDeposit\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidDiscount\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidQuote\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidReceivingAddress\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidSurcharge\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"Unauthorized\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ZeroDeficit\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"configDigest\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"subscriber\",\"type\":\"address\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"assetAddress\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"indexed\":false,\"internalType\":\"structCommon.Asset\",\"name\":\"fee\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"assetAddress\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"indexed\":false,\"internalType\":\"structCommon.Asset\",\"name\":\"reward\",\"type\":\"tuple\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"appliedDiscount\",\"type\":\"uint256\"}],\"name\":\"DiscountApplied\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"components\":[{\"internalType\":\"bytes32\",\"name\":\"poolId\",\"type\":\"bytes32\"},{\"internalType\":\"uint192\",\"name\":\"amount\",\"type\":\"uint192\"}],\"indexed\":false,\"internalType\":\"structIRewardManager.FeePayment[]\",\"name\":\"rewards\",\"type\":\"tuple[]\"}],\"name\":\"InsufficientLink\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"configDigest\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"linkQuantity\",\"type\":\"uint256\"}],\"name\":\"LinkDeficitCleared\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"newSurcharge\",\"type\":\"uint64\"}],\"name\":\"NativeSurchargeUpdated\",\"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\":\"address\",\"name\":\"subscriber\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"feedId\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"discount\",\"type\":\"uint64\"}],\"name\":\"SubscriberDiscountUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"adminAddress\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"assetAddress\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint192\",\"name\":\"quantity\",\"type\":\"uint192\"}],\"name\":\"Withdraw\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"acceptOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"subscriber\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"report\",\"type\":\"bytes\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"quoteAddress\",\"type\":\"address\"}],\"internalType\":\"structIFeeManager.Quote\",\"name\":\"quote\",\"type\":\"tuple\"}],\"name\":\"getFeeAndReward\",\"outputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"assetAddress\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"internalType\":\"structCommon.Asset\",\"name\":\"\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"assetAddress\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"internalType\":\"structCommon.Asset\",\"name\":\"\",\"type\":\"tuple\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"linkAvailableForPayment\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"configDigest\",\"type\":\"bytes32\"}],\"name\":\"payLinkDeficit\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"payload\",\"type\":\"bytes\"},{\"internalType\":\"address\",\"name\":\"subscriber\",\"type\":\"address\"}],\"name\":\"processFee\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes[]\",\"name\":\"payloads\",\"type\":\"bytes[]\"},{\"internalType\":\"address\",\"name\":\"subscriber\",\"type\":\"address\"}],\"name\":\"processFeeBulk\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"name\":\"s_linkDeficit\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_nativeSurcharge\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"s_subscriberDiscounts\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"configDigest\",\"type\":\"bytes32\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"addr\",\"type\":\"address\"},{\"internalType\":\"uint64\",\"name\":\"weight\",\"type\":\"uint64\"}],\"internalType\":\"structCommon.AddressAndWeight[]\",\"name\":\"rewardRecipientAndWeights\",\"type\":\"tuple[]\"}],\"name\":\"setFeeRecipients\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"surcharge\",\"type\":\"uint64\"}],\"name\":\"setNativeSurcharge\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes4\",\"name\":\"interfaceId\",\"type\":\"bytes4\"}],\"name\":\"supportsInterface\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"typeAndVersion\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"subscriber\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"feedId\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"uint64\",\"name\":\"discount\",\"type\":\"uint64\"}],\"name\":\"updateSubscriberDiscount\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"assetAddress\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"uint192\",\"name\":\"quantity\",\"type\":\"uint192\"}],\"name\":\"withdraw\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", + Bin: "0x6101006040523480156200001257600080fd5b50604051620034d8380380620034d8833981016040819052620000359162000288565b33806000816200008c5760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b0384811691909117909155811615620000bf57620000bf81620001c0565b5050506001600160a01b0384161580620000e057506001600160a01b038316155b80620000f357506001600160a01b038216155b806200010657506001600160a01b038116155b15620001255760405163e6c4247b60e01b815260040160405180910390fd5b6001600160a01b03848116608081905284821660a05283821660c05290821660e081905260405163095ea7b360e01b81526004810191909152600019602482015263095ea7b3906044016020604051808303816000875af11580156200018f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620001b59190620002e5565b505050505062000310565b336001600160a01b038216036200021a5760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c66000000000000000000604482015260640162000083565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b80516001600160a01b03811681146200028357600080fd5b919050565b600080600080608085870312156200029f57600080fd5b620002aa856200026b565b9350620002ba602086016200026b565b9250620002ca604086016200026b565b9150620002da606086016200026b565b905092959194509250565b600060208284031215620002f857600080fd5b815180151581146200030957600080fd5b9392505050565b60805160a05160c05160e051613102620003d660003960008181611185015281816114a601528181611ce20152611f3001526000818161061a0152818161124501526113ec015260008181610a7a01528181610ad101528181610d8801528181610e9701528181611c080152611cb101526000818161079301528181610a9f01528181610b2c01528181610c7601528181610ce501528181610d2401528181610e4001528181610fd70152818161134f015281816118830152611da301526131026000f3fe60806040526004361061010e5760003560e01c806387d6d843116100a5578063d09dc33911610074578063f1387e1611610059578063f1387e1614610382578063f2fde38b14610395578063f65df962146103b557600080fd5b8063d09dc3391461034d578063e389d9a41461036257600080fd5b806387d6d8431461024f5780638da5cb5b1461028d578063c541cbde146102c2578063ce7817d11461032d57600080fd5b806332f5f746116100e157806332f5f746146101f157806340d7f78e14610207578063505380941461021a57806379ba50971461023a57600080fd5b8063013f542b1461011357806301ffc9a714610153578063181f5a77146101835780631d4d84a2146101cf575b600080fd5b34801561011f57600080fd5b5061014061012e366004612532565b60036020526000908152604090205481565b6040519081526020015b60405180910390f35b34801561015f57600080fd5b5061017361016e36600461254b565b6103d5565b604051901515815260200161014a565b34801561018f57600080fd5b50604080518082018252601081527f4665654d616e6167657220312e302e30000000000000000000000000000000006020820152905161014a91906125b1565b3480156101db57600080fd5b506101ef6101ea36600461264a565b61046e565b005b3480156101fd57600080fd5b5061014060045481565b6101ef610215366004612695565b610602565b34801561022657600080fd5b506101ef61023536600461272d565b610845565b34801561024657600080fd5b506101ef6108df565b34801561025b57600080fd5b5061014061026a366004612748565b600260209081526000938452604080852082529284528284209052825290205481565b34801561029957600080fd5b5060005460405173ffffffffffffffffffffffffffffffffffffffff909116815260200161014a565b3480156102ce57600080fd5b506102e26102dd3660046128b4565b6109e1565b60408051845173ffffffffffffffffffffffffffffffffffffffff9081168252602095860151868301528451169181019190915292909101516060830152608082015260a00161014a565b34801561033957600080fd5b506101ef610348366004612955565b610dea565b34801561035957600080fd5b50610140610fa6565b34801561036e57600080fd5b506101ef61037d366004612532565b61105c565b6101ef6103903660046129a6565b61122d565b3480156103a157600080fd5b506101ef6103b0366004612a08565b6113c0565b3480156103c157600080fd5b506101ef6103d0366004612a25565b6113d4565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167ff1387e1600000000000000000000000000000000000000000000000000000000148061046857507fffffffff0000000000000000000000000000000000000000000000000000000082167f40d7f78e00000000000000000000000000000000000000000000000000000000145b92915050565b61047661150d565b73ffffffffffffffffffffffffffffffffffffffff831661054b5760008273ffffffffffffffffffffffffffffffffffffffff168277ffffffffffffffffffffffffffffffffffffffffffffffff1660405160006040518083038185875af1925050503d8060008114610505576040519150601f19603f3d011682016040523d82523d6000602084013e61050a565b606091505b5050905080610545576040517fef2af20100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b50505050565b61058673ffffffffffffffffffffffffffffffffffffffff84168377ffffffffffffffffffffffffffffffffffffffffffffffff8416611590565b6040805133815273ffffffffffffffffffffffffffffffffffffffff848116602083015285168183015277ffffffffffffffffffffffffffffffffffffffffffffffff8316606082015290517f7ff78a71698bdb18dcca96f52ab25e0a1b146fb6a49adf8e6845299e49021f299181900360800190a15b505050565b3373ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001614610671576040517f82b4290000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008267ffffffffffffffff81111561068c5761068c61277f565b6040519080825280602002602001820160405280156106c557816020015b6106b26124a5565b8152602001906001900390816106aa5790505b5090506000806000805b8681101561080e5760008060006107098b8b868181106106f1576106f1612aa4565b90506020028101906107039190612ad3565b8b611664565b92509250925082602001516000146107fa5760405180608001604052808c8c8781811061073857610738612aa4565b905060200281019061074a9190612ad3565b61075391612b3f565b81526020018481526020018381526020018281525088868061077490612baa565b97508151811061078657610786612aa4565b60200260200101819052507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16836000015173ffffffffffffffffffffffffffffffffffffffff16036107f3578660010196506107fa565b8560010195505b5050508061080790612baa565b90506106cf565b508215158061081c57508115155b156108325761082d8585858561179e565b61083c565b61083c8534611fb2565b50505050505050565b61084d61150d565b670de0b6b3a764000067ffffffffffffffff82161115610899576040517f05e8ac2900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b67ffffffffffffffff811660048190556040519081527f08f7c0d17932ddb8523bc06754d42ff19ebc77d76a8b9bfde02c28ab1ed3d6399060200160405180910390a150565b60015473ffffffffffffffffffffffffffffffffffffffff163314610965576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e65720000000000000000000060448201526064015b60405180910390fd5b60008054337fffffffffffffffffffffffff00000000000000000000000000000000000000008083168217845560018054909116905560405173ffffffffffffffffffffffffffffffffffffffff90921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b6040805180820182526000808252602080830182905283518085018552828152808201839052845180860186528381528083018490528551808701909652838652918501839052929382610a3488612be2565b90507fffff000000000000000000000000000000000000000000000000000000000000808216908101610acf57505073ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000811683527f0000000000000000000000000000000000000000000000000000000000000000168152909350915060009050610de1565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16886000015173ffffffffffffffffffffffffffffffffffffffff1614158015610b7f57507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16886000015173ffffffffffffffffffffffffffffffffffffffff1614155b15610bb6576040517ff861803000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008060008b806020019051810190610bcf9190612c3b565b77ffffffffffffffffffffffffffffffffffffffffffffffff92831698509116955063ffffffff1693505050428210159050610c37576040517fb6c405f500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff808e16600090815260026020908152604080832089845282528083208f51851684529091529020547f00000000000000000000000000000000000000000000000000000000000000009091168752610cc7610caf82670de0b6b3a7640000612cad565b610cb99086612cc0565b670de0b6b3a7640000611fff565b60208801528b5173ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000008116911603610d555773ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016885260208088015190890152610dd2565b600454600090610d7190610caf90670de0b6b3a7640000612cfd565b73ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168a529050610dcb610dc183670de0b6b3a7640000612cad565b610cb99083612cc0565b60208a0152505b96995094975094955050505050505b93509350939050565b610df261150d565b670de0b6b3a764000067ffffffffffffffff82161115610e3e576040517f997ea36000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1614158015610ee657507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1614155b15610f1d576040517fe6c4247b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff848116600081815260026020908152604080832088845282528083209487168084529482529182902067ffffffffffffffff86169081905582519485529084015285927f5eba5a8afa39780f0f99b6cbeb95f3da6a7040ca00abd46bdc91a0a060134139910160405180910390a350505050565b6040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201526000907f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16906370a0823190602401602060405180830381865afa158015611033573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110579190612d10565b905090565b61106461150d565b600081815260036020526040812054908190036110ad576040517f03aad31200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000828152600360205260408082208290558051600180825281830190925290816020015b60408051808201909152600080825260208201528152602001906001900390816110d257905050905060405180604001604052808481526020018377ffffffffffffffffffffffffffffffffffffffffffffffff168152508160008151811061113d5761113d612aa4565b60209081029190910101526040517fb0d9fa1900000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000169063b0d9fa19906111bc9084903090600401612d89565b600060405180830381600087803b1580156111d657600080fd5b505af11580156111ea573d6000803e3d6000fd5b50505050827f843f0b103e50b42b08f9d30f12f961845a6d02623730872e24644899c0dd98958360405161122091815260200190565b60405180910390a2505050565b3373ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000161461129c576040517f82b4290000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008060006112ac868686611664565b92509250925082602001516000036112d0576112c88434611fb2565b505050505050565b604080516001808252818301909252600091816020015b6112ef6124a5565b8152602001906001900390816112e757505060408051608081019091529091508061131a888a612b3f565b8152602001858152602001848152602001838152508160008151811061134257611342612aa4565b60200260200101819052507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16846000015173ffffffffffffffffffffffffffffffffffffffff16036113b25761082d85826001600061179e565b61083c85826000600161179e565b6113c861150d565b6113d181612037565b50565b3373ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001614801590611432575060005473ffffffffffffffffffffffffffffffffffffffff163314155b15611469576040517f82b4290000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040517f14060f2300000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016906314060f23906114df90869086908690600401612dc1565b600060405180830381600087803b1580156114f957600080fd5b505af115801561083c573d6000803e3d6000fd5b60005473ffffffffffffffffffffffffffffffffffffffff16331461158e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e657200000000000000000000604482015260640161095c565b565b60405173ffffffffffffffffffffffffffffffffffffffff83166024820152604481018290526105fd9084907fa9059cbb00000000000000000000000000000000000000000000000000000000906064015b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff000000000000000000000000000000000000000000000000000000009093169290921790915261212c565b6040805180820190915260008082526020820152604080518082019091526000808252602082015260003073ffffffffffffffffffffffffffffffffffffffff8516036116dd576040517fe6c4247b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60006116eb86880188612eaf565b9150506000816116fa90612be2565b6040805160208101909152600081529091507e010000000000000000000000000000000000000000000000000000000000007fffff000000000000000000000000000000000000000000000000000000000000831614611781576000611762898b018b612f73565b955050505050508080602001905181019061177d919061303b565b9150505b61178c8784836109e1565b95509550955050505093509350939050565b60008267ffffffffffffffff8111156117b9576117b961277f565b6040519080825280602002602001820160405280156117fe57816020015b60408051808201909152600080825260208201528152602001906001900390816117d75790505b50905060008267ffffffffffffffff81111561181c5761181c61277f565b60405190808252806020026020018201604052801561186157816020015b604080518082019091526000808252602082015281526020019060019003908161183a5790505b509050600080808080611874888a612cfd565b905060005b81811015611bc3577f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168b82815181106118ca576118ca612aa4565b6020026020010151602001516000015173ffffffffffffffffffffffffffffffffffffffff16036119905760405180604001604052808c838151811061191257611912612aa4565b60200260200101516000015181526020018c838151811061193557611935612aa4565b6020026020010151604001516020015177ffffffffffffffffffffffffffffffffffffffffffffffff1681525088858061196e90612baa565b96508151811061198057611980612aa4565b6020026020010181905250611a85565b60405180604001604052808c83815181106119ad576119ad612aa4565b60200260200101516000015181526020018c83815181106119d0576119d0612aa4565b6020026020010151604001516020015177ffffffffffffffffffffffffffffffffffffffffffffffff16815250878480611a0990612baa565b955081518110611a1b57611a1b612aa4565b60200260200101819052508a8181518110611a3857611a38612aa4565b6020026020010151602001516020015186611a539190612cfd565b95508a8181518110611a6757611a67612aa4565b6020026020010151604001516020015185611a829190612cfd565b94505b8a8181518110611a9757611a97612aa4565b602002602001015160600151600014611bb3578b73ffffffffffffffffffffffffffffffffffffffff168b8281518110611ad357611ad3612aa4565b6020026020010151600001517f88b15eb682210089cddf967648e2cb2a4535aeadc8f8f36050922e33c04e71258d8481518110611b1257611b12612aa4565b6020026020010151602001518e8581518110611b3057611b30612aa4565b6020026020010151604001518f8681518110611b4e57611b4e612aa4565b602002602001015160600151604051611baa93929190835173ffffffffffffffffffffffffffffffffffffffff908116825260209485015185830152835116604082015291909201516060820152608081019190915260a00190565b60405180910390a35b611bbc81612baa565b9050611879565b5060003415611c915734861115611c06576040517fb2e532de00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663d0e30db0876040518263ffffffff1660e01b81526004016000604051808303818588803b158015611c6e57600080fd5b505af1158015611c82573d6000803e3d6000fd5b50505050508534039050611cd9565b8515611cd957611cd973ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168d3089612238565b875115611d6e577f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663b0d9fa19898e6040518363ffffffff1660e01b8152600401611d3b929190612d89565b600060405180830381600087803b158015611d5557600080fd5b505af1158015611d69573d6000803e3d6000fd5b505050505b865115611f9a576040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16906370a0823190602401602060405180830381865afa158015611dff573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e239190612d10565b851115611ef35760005b8751811015611eb657878181518110611e4857611e48612aa4565b60200260200101516020015177ffffffffffffffffffffffffffffffffffffffffffffffff16600360008a8481518110611e8457611e84612aa4565b60209081029190910181015151825281019190915260400160002080549091019055611eaf81612baa565b9050611e2d565b507ff52e5907b69d97c33392936c12d78b494463b78c5b72df50b4c497eee5720b6787604051611ee69190613069565b60405180910390a1611f9a565b6040517fb0d9fa1900000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000169063b0d9fa1990611f67908a903090600401612d89565b600060405180830381600087803b158015611f8157600080fd5b505af1158015611f95573d6000803e3d6000fd5b505050505b611fa48c82611fb2565b505050505050505050505050565b8015611ffb5760405173ffffffffffffffffffffffffffffffffffffffff83169082156108fc029083906000818181858888f193505050501580156105fd573d6000803e3d6000fd5b5050565b6000821561202d5781612013600185612cad565b61201d919061307c565b612028906001612cfd565b612030565b60005b9392505050565b3373ffffffffffffffffffffffffffffffffffffffff8216036120b6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c66000000000000000000604482015260640161095c565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b600061218e826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff166122969092919063ffffffff16565b8051909150156105fd57808060200190518101906121ac91906130b7565b6105fd576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f74207375636365656400000000000000000000000000000000000000000000606482015260840161095c565b60405173ffffffffffffffffffffffffffffffffffffffff808516602483015283166044820152606481018290526105459085907f23b872dd00000000000000000000000000000000000000000000000000000000906084016115e2565b60606122a584846000856122ad565b949350505050565b60608247101561233f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f60448201527f722063616c6c0000000000000000000000000000000000000000000000000000606482015260840161095c565b6000808673ffffffffffffffffffffffffffffffffffffffff16858760405161236891906130d9565b60006040518083038185875af1925050503d80600081146123a5576040519150601f19603f3d011682016040523d82523d6000602084013e6123aa565b606091505b50915091506123bb878383876123c6565b979650505050505050565b6060831561245c5782516000036124555773ffffffffffffffffffffffffffffffffffffffff85163b612455576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604482015260640161095c565b50816122a5565b6122a583838151156124715781518083602001fd5b806040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161095c91906125b1565b6040518060800160405280600080191681526020016124ed6040518060400160405280600073ffffffffffffffffffffffffffffffffffffffff168152602001600081525090565b81526020016125256040518060400160405280600073ffffffffffffffffffffffffffffffffffffffff168152602001600081525090565b8152602001600081525090565b60006020828403121561254457600080fd5b5035919050565b60006020828403121561255d57600080fd5b81357fffffffff000000000000000000000000000000000000000000000000000000008116811461203057600080fd5b60005b838110156125a8578181015183820152602001612590565b50506000910152565b60208152600082518060208401526125d081604085016020870161258d565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169190910160400192915050565b73ffffffffffffffffffffffffffffffffffffffff811681146113d157600080fd5b77ffffffffffffffffffffffffffffffffffffffffffffffff811681146113d157600080fd5b60008060006060848603121561265f57600080fd5b833561266a81612602565b9250602084013561267a81612602565b9150604084013561268a81612624565b809150509250925092565b6000806000604084860312156126aa57600080fd5b833567ffffffffffffffff808211156126c257600080fd5b818601915086601f8301126126d657600080fd5b8135818111156126e557600080fd5b8760208260051b85010111156126fa57600080fd5b6020928301955093505084013561268a81612602565b803567ffffffffffffffff8116811461272857600080fd5b919050565b60006020828403121561273f57600080fd5b61203082612710565b60008060006060848603121561275d57600080fd5b833561276881612602565b925060208401359150604084013561268a81612602565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6040516020810167ffffffffffffffff811182821017156127d1576127d161277f565b60405290565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff8111828210171561281e5761281e61277f565b604052919050565b600082601f83011261283757600080fd5b813567ffffffffffffffff8111156128515761285161277f565b61288260207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f840116016127d7565b81815284602083860101111561289757600080fd5b816020850160208301376000918101602001919091529392505050565b600080600083850360608112156128ca57600080fd5b84356128d581612602565b9350602085013567ffffffffffffffff8111156128f157600080fd5b6128fd87828801612826565b93505060207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc08201121561293057600080fd5b506129396127ae565b604085013561294781612602565b815292959194509192509050565b6000806000806080858703121561296b57600080fd5b843561297681612602565b935060208501359250604085013561298d81612602565b915061299b60608601612710565b905092959194509250565b6000806000604084860312156129bb57600080fd5b833567ffffffffffffffff808211156129d357600080fd5b818601915086601f8301126129e757600080fd5b8135818111156129f657600080fd5b8760208285010111156126fa57600080fd5b600060208284031215612a1a57600080fd5b813561203081612602565b600080600060408486031215612a3a57600080fd5b83359250602084013567ffffffffffffffff80821115612a5957600080fd5b818601915086601f830112612a6d57600080fd5b813581811115612a7c57600080fd5b8760208260061b8501011115612a9157600080fd5b6020830194508093505050509250925092565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112612b0857600080fd5b83018035915067ffffffffffffffff821115612b2357600080fd5b602001915036819003821315612b3857600080fd5b9250929050565b80356020831015610468577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff602084900360031b1b1692915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203612bdb57612bdb612b7b565b5060010190565b80516020808301519190811015612c21577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8160200360031b1b821691505b50919050565b805163ffffffff8116811461272857600080fd5b60008060008060008060c08789031215612c5457600080fd5b86519550612c6460208801612c27565b9450612c7260408801612c27565b93506060870151612c8281612624565b6080880151909350612c9381612624565b9150612ca160a08801612c27565b90509295509295509295565b8181038181111561046857610468612b7b565b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0483118215151615612cf857612cf8612b7b565b500290565b8082018082111561046857610468612b7b565b600060208284031215612d2257600080fd5b5051919050565b600081518084526020808501945080840160005b83811015612d7e5781518051885283015177ffffffffffffffffffffffffffffffffffffffffffffffff168388015260409096019590820190600101612d3d565b509495945050505050565b604081526000612d9c6040830185612d29565b905073ffffffffffffffffffffffffffffffffffffffff831660208301529392505050565b8381526040602080830182905282820184905260009190859060608501845b87811015612e34578335612df381612602565b73ffffffffffffffffffffffffffffffffffffffff16825267ffffffffffffffff612e1f858501612710565b16828401529284019290840190600101612de0565b5098975050505050505050565b600082601f830112612e5257600080fd5b6040516060810181811067ffffffffffffffff82111715612e7557612e7561277f565b604052806060840185811115612e8a57600080fd5b845b81811015612ea4578035835260209283019201612e8c565b509195945050505050565b60008060808385031215612ec257600080fd5b612ecc8484612e41565b9150606083013567ffffffffffffffff811115612ee857600080fd5b612ef485828601612826565b9150509250929050565b600082601f830112612f0f57600080fd5b8135602067ffffffffffffffff821115612f2b57612f2b61277f565b8160051b612f3a8282016127d7565b9283528481018201928281019087851115612f5457600080fd5b83870192505b848310156123bb57823582529183019190830190612f5a565b6000806000806000806101008789031215612f8d57600080fd5b612f978888612e41565b9550606087013567ffffffffffffffff80821115612fb457600080fd5b612fc08a838b01612826565b96506080890135915080821115612fd657600080fd5b612fe28a838b01612efe565b955060a0890135915080821115612ff857600080fd5b6130048a838b01612efe565b945060c0890135935060e089013591508082111561302157600080fd5b5061302e89828a01612826565b9150509295509295509295565b60006020828403121561304d57600080fd5b6130556127ae565b825161306081612602565b81529392505050565b6020815260006120306020830184612d29565b6000826130b2577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500490565b6000602082840312156130c957600080fd5b8151801515811461203057600080fd5b600082516130eb81846020870161258d565b919091019291505056fea164736f6c6343000810000a", } var FeeManagerABI = FeeManagerMetaData.ABI @@ -190,26 +190,27 @@ func (_FeeManager *FeeManagerTransactorRaw) Transact(opts *bind.TransactOpts, me return _FeeManager.Contract.contract.Transact(opts, method, params...) } -func (_FeeManager *FeeManagerCaller) GetFeeAndReward(opts *bind.CallOpts, subscriber common.Address, report []byte, quote IFeeManagerQuote) (CommonAsset, CommonAsset, error) { +func (_FeeManager *FeeManagerCaller) GetFeeAndReward(opts *bind.CallOpts, subscriber common.Address, report []byte, quote IFeeManagerQuote) (CommonAsset, CommonAsset, *big.Int, error) { var out []interface{} err := _FeeManager.contract.Call(opts, &out, "getFeeAndReward", subscriber, report, quote) if err != nil { - return *new(CommonAsset), *new(CommonAsset), err + return *new(CommonAsset), *new(CommonAsset), *new(*big.Int), err } out0 := *abi.ConvertType(out[0], new(CommonAsset)).(*CommonAsset) out1 := *abi.ConvertType(out[1], new(CommonAsset)).(*CommonAsset) + out2 := *abi.ConvertType(out[2], new(*big.Int)).(**big.Int) - return out0, out1, err + return out0, out1, out2, err } -func (_FeeManager *FeeManagerSession) GetFeeAndReward(subscriber common.Address, report []byte, quote IFeeManagerQuote) (CommonAsset, CommonAsset, error) { +func (_FeeManager *FeeManagerSession) GetFeeAndReward(subscriber common.Address, report []byte, quote IFeeManagerQuote) (CommonAsset, CommonAsset, *big.Int, error) { return _FeeManager.Contract.GetFeeAndReward(&_FeeManager.CallOpts, subscriber, report, quote) } -func (_FeeManager *FeeManagerCallerSession) GetFeeAndReward(subscriber common.Address, report []byte, quote IFeeManagerQuote) (CommonAsset, CommonAsset, error) { +func (_FeeManager *FeeManagerCallerSession) GetFeeAndReward(subscriber common.Address, report []byte, quote IFeeManagerQuote) (CommonAsset, CommonAsset, *big.Int, error) { return _FeeManager.Contract.GetFeeAndReward(&_FeeManager.CallOpts, subscriber, report, quote) } @@ -463,16 +464,155 @@ func (_FeeManager *FeeManagerTransactorSession) UpdateSubscriberDiscount(subscri return _FeeManager.Contract.UpdateSubscriberDiscount(&_FeeManager.TransactOpts, subscriber, feedId, token, discount) } -func (_FeeManager *FeeManagerTransactor) Withdraw(opts *bind.TransactOpts, assetAddress common.Address, quantity *big.Int) (*types.Transaction, error) { - return _FeeManager.contract.Transact(opts, "withdraw", assetAddress, quantity) +func (_FeeManager *FeeManagerTransactor) Withdraw(opts *bind.TransactOpts, assetAddress common.Address, recipient common.Address, quantity *big.Int) (*types.Transaction, error) { + return _FeeManager.contract.Transact(opts, "withdraw", assetAddress, recipient, quantity) } -func (_FeeManager *FeeManagerSession) Withdraw(assetAddress common.Address, quantity *big.Int) (*types.Transaction, error) { - return _FeeManager.Contract.Withdraw(&_FeeManager.TransactOpts, assetAddress, quantity) +func (_FeeManager *FeeManagerSession) Withdraw(assetAddress common.Address, recipient common.Address, quantity *big.Int) (*types.Transaction, error) { + return _FeeManager.Contract.Withdraw(&_FeeManager.TransactOpts, assetAddress, recipient, quantity) } -func (_FeeManager *FeeManagerTransactorSession) Withdraw(assetAddress common.Address, quantity *big.Int) (*types.Transaction, error) { - return _FeeManager.Contract.Withdraw(&_FeeManager.TransactOpts, assetAddress, quantity) +func (_FeeManager *FeeManagerTransactorSession) Withdraw(assetAddress common.Address, recipient common.Address, quantity *big.Int) (*types.Transaction, error) { + return _FeeManager.Contract.Withdraw(&_FeeManager.TransactOpts, assetAddress, recipient, quantity) +} + +type FeeManagerDiscountAppliedIterator struct { + Event *FeeManagerDiscountApplied + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *FeeManagerDiscountAppliedIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(FeeManagerDiscountApplied) + 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(FeeManagerDiscountApplied) + 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 *FeeManagerDiscountAppliedIterator) Error() error { + return it.fail +} + +func (it *FeeManagerDiscountAppliedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type FeeManagerDiscountApplied struct { + ConfigDigest [32]byte + Subscriber common.Address + Fee CommonAsset + Reward CommonAsset + AppliedDiscount *big.Int + Raw types.Log +} + +func (_FeeManager *FeeManagerFilterer) FilterDiscountApplied(opts *bind.FilterOpts, configDigest [][32]byte, subscriber []common.Address) (*FeeManagerDiscountAppliedIterator, error) { + + var configDigestRule []interface{} + for _, configDigestItem := range configDigest { + configDigestRule = append(configDigestRule, configDigestItem) + } + var subscriberRule []interface{} + for _, subscriberItem := range subscriber { + subscriberRule = append(subscriberRule, subscriberItem) + } + + logs, sub, err := _FeeManager.contract.FilterLogs(opts, "DiscountApplied", configDigestRule, subscriberRule) + if err != nil { + return nil, err + } + return &FeeManagerDiscountAppliedIterator{contract: _FeeManager.contract, event: "DiscountApplied", logs: logs, sub: sub}, nil +} + +func (_FeeManager *FeeManagerFilterer) WatchDiscountApplied(opts *bind.WatchOpts, sink chan<- *FeeManagerDiscountApplied, configDigest [][32]byte, subscriber []common.Address) (event.Subscription, error) { + + var configDigestRule []interface{} + for _, configDigestItem := range configDigest { + configDigestRule = append(configDigestRule, configDigestItem) + } + var subscriberRule []interface{} + for _, subscriberItem := range subscriber { + subscriberRule = append(subscriberRule, subscriberItem) + } + + logs, sub, err := _FeeManager.contract.WatchLogs(opts, "DiscountApplied", configDigestRule, subscriberRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(FeeManagerDiscountApplied) + if err := _FeeManager.contract.UnpackLog(event, "DiscountApplied", 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 (_FeeManager *FeeManagerFilterer) ParseDiscountApplied(log types.Log) (*FeeManagerDiscountApplied, error) { + event := new(FeeManagerDiscountApplied) + if err := _FeeManager.contract.UnpackLog(event, "DiscountApplied", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil } type FeeManagerInsufficientLinkIterator struct { @@ -1309,6 +1449,7 @@ func (it *FeeManagerWithdrawIterator) Close() error { type FeeManagerWithdraw struct { AdminAddress common.Address + Recipient common.Address AssetAddress common.Address Quantity *big.Int Raw types.Log @@ -1368,6 +1509,8 @@ func (_FeeManager *FeeManagerFilterer) ParseWithdraw(log types.Log) (*FeeManager func (_FeeManager *FeeManager) ParseLog(log types.Log) (generated.AbigenLog, error) { switch log.Topics[0] { + case _FeeManager.abi.Events["DiscountApplied"].ID: + return _FeeManager.ParseDiscountApplied(log) case _FeeManager.abi.Events["InsufficientLink"].ID: return _FeeManager.ParseInsufficientLink(log) case _FeeManager.abi.Events["LinkDeficitCleared"].ID: @@ -1388,6 +1531,10 @@ func (_FeeManager *FeeManager) ParseLog(log types.Log) (generated.AbigenLog, err } } +func (FeeManagerDiscountApplied) Topic() common.Hash { + return common.HexToHash("0x88b15eb682210089cddf967648e2cb2a4535aeadc8f8f36050922e33c04e7125") +} + func (FeeManagerInsufficientLink) Topic() common.Hash { return common.HexToHash("0xf52e5907b69d97c33392936c12d78b494463b78c5b72df50b4c497eee5720b67") } @@ -1413,7 +1560,7 @@ func (FeeManagerSubscriberDiscountUpdated) Topic() common.Hash { } func (FeeManagerWithdraw) Topic() common.Hash { - return common.HexToHash("0x72608e45b52a95a12c2ac7f15ff53f92fc9572c9d84b6e6b5d7f0f7826cf3271") + return common.HexToHash("0x7ff78a71698bdb18dcca96f52ab25e0a1b146fb6a49adf8e6845299e49021f29") } func (_FeeManager *FeeManager) Address() common.Address { @@ -1421,7 +1568,7 @@ func (_FeeManager *FeeManager) Address() common.Address { } type FeeManagerInterface interface { - GetFeeAndReward(opts *bind.CallOpts, subscriber common.Address, report []byte, quote IFeeManagerQuote) (CommonAsset, CommonAsset, error) + GetFeeAndReward(opts *bind.CallOpts, subscriber common.Address, report []byte, quote IFeeManagerQuote) (CommonAsset, CommonAsset, *big.Int, error) LinkAvailableForPayment(opts *bind.CallOpts) (*big.Int, error) @@ -1453,7 +1600,13 @@ type FeeManagerInterface interface { UpdateSubscriberDiscount(opts *bind.TransactOpts, subscriber common.Address, feedId [32]byte, token common.Address, discount uint64) (*types.Transaction, error) - Withdraw(opts *bind.TransactOpts, assetAddress common.Address, quantity *big.Int) (*types.Transaction, error) + Withdraw(opts *bind.TransactOpts, assetAddress common.Address, recipient common.Address, quantity *big.Int) (*types.Transaction, error) + + FilterDiscountApplied(opts *bind.FilterOpts, configDigest [][32]byte, subscriber []common.Address) (*FeeManagerDiscountAppliedIterator, error) + + WatchDiscountApplied(opts *bind.WatchOpts, sink chan<- *FeeManagerDiscountApplied, configDigest [][32]byte, subscriber []common.Address) (event.Subscription, error) + + ParseDiscountApplied(log types.Log) (*FeeManagerDiscountApplied, error) FilterInsufficientLink(opts *bind.FilterOpts) (*FeeManagerInsufficientLinkIterator, error) diff --git a/core/gethwrappers/llo-feeds/generated/reward_manager/reward_manager.go b/core/gethwrappers/llo-feeds/generated/reward_manager/reward_manager.go index ed4c621842c..236eeaa5c1a 100644 --- a/core/gethwrappers/llo-feeds/generated/reward_manager/reward_manager.go +++ b/core/gethwrappers/llo-feeds/generated/reward_manager/reward_manager.go @@ -41,8 +41,8 @@ type IRewardManagerFeePayment struct { } var RewardManagerMetaData = &bind.MetaData{ - ABI: "[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"linkAddress\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"InvalidAddress\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidPoolId\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidWeights\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"Unauthorized\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"newFeeManagerAddress\",\"type\":\"address\"}],\"name\":\"FeeManagerUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"components\":[{\"internalType\":\"bytes32\",\"name\":\"poolId\",\"type\":\"bytes32\"},{\"internalType\":\"uint192\",\"name\":\"amount\",\"type\":\"uint192\"}],\"indexed\":false,\"internalType\":\"structIRewardManager.FeePayment[]\",\"name\":\"payments\",\"type\":\"tuple[]\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"payee\",\"type\":\"address\"}],\"name\":\"FeePaid\",\"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\":\"poolId\",\"type\":\"bytes32\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"addr\",\"type\":\"address\"},{\"internalType\":\"uint64\",\"name\":\"weight\",\"type\":\"uint64\"}],\"indexed\":false,\"internalType\":\"structCommon.AddressAndWeight[]\",\"name\":\"newRewardRecipients\",\"type\":\"tuple[]\"}],\"name\":\"RewardRecipientsUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"poolId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint192\",\"name\":\"quantity\",\"type\":\"uint192\"}],\"name\":\"RewardsClaimed\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"acceptOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32[]\",\"name\":\"poolIds\",\"type\":\"bytes32[]\"}],\"name\":\"claimRewards\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"}],\"name\":\"getAvailableRewardPoolIds\",\"outputs\":[{\"internalType\":\"bytes32[]\",\"name\":\"\",\"type\":\"bytes32[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"bytes32\",\"name\":\"poolId\",\"type\":\"bytes32\"},{\"internalType\":\"uint192\",\"name\":\"amount\",\"type\":\"uint192\"}],\"internalType\":\"structIRewardManager.FeePayment[]\",\"name\":\"payments\",\"type\":\"tuple[]\"},{\"internalType\":\"address\",\"name\":\"payee\",\"type\":\"address\"}],\"name\":\"onFeePaid\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"poolId\",\"type\":\"bytes32\"},{\"internalType\":\"address[]\",\"name\":\"recipients\",\"type\":\"address[]\"}],\"name\":\"payRecipients\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_feeManagerAddress\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"s_registeredPoolIds\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"s_rewardRecipientWeights\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"name\":\"s_rewardRecipientWeightsSet\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"name\":\"s_totalRewardRecipientFees\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"s_totalRewardRecipientFeesLastClaimedAmounts\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newFeeManagerAddress\",\"type\":\"address\"}],\"name\":\"setFeeManager\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"poolId\",\"type\":\"bytes32\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"addr\",\"type\":\"address\"},{\"internalType\":\"uint64\",\"name\":\"weight\",\"type\":\"uint64\"}],\"internalType\":\"structCommon.AddressAndWeight[]\",\"name\":\"rewardRecipientAndWeights\",\"type\":\"tuple[]\"}],\"name\":\"setRewardRecipients\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes4\",\"name\":\"interfaceId\",\"type\":\"bytes4\"}],\"name\":\"supportsInterface\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"typeAndVersion\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"poolId\",\"type\":\"bytes32\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"addr\",\"type\":\"address\"},{\"internalType\":\"uint64\",\"name\":\"weight\",\"type\":\"uint64\"}],\"internalType\":\"structCommon.AddressAndWeight[]\",\"name\":\"newRewardRecipients\",\"type\":\"tuple[]\"}],\"name\":\"updateRewardRecipients\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", - Bin: "0x60a06040523480156200001157600080fd5b5060405162002080380380620020808339810160408190526200003491620001a6565b33806000816200008b5760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b0384811691909117909155811615620000be57620000be81620000fb565b5050506001600160a01b038116620000e95760405163e6c4247b60e01b815260040160405180910390fd5b6001600160a01b0316608052620001d8565b336001600160a01b03821603620001555760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c66000000000000000000604482015260640162000082565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b600060208284031215620001b957600080fd5b81516001600160a01b0381168114620001d157600080fd5b9392505050565b608051611e85620001fb60003960008181610ca70152610ee20152611e856000f3fe608060405234801561001057600080fd5b50600436106101365760003560e01c806359256201116100b25780638ac85a5c11610081578063b0d9fa1911610066578063b0d9fa1914610377578063cd5f72921461038a578063f2fde38b1461039d57600080fd5b80638ac85a5c1461032e5780638da5cb5b1461035957600080fd5b806359256201146102b857806360122608146102db5780636992922f1461030657806379ba50971461032657600080fd5b8063276e766011610109578063472d35b9116100ee578063472d35b91461027f5780634944832f146102925780634d322084146102a557600080fd5b8063276e76601461020c57806339ee81e11461025157600080fd5b806301ffc9a71461013b5780630f3c34d1146101a557806314060f23146101ba578063181f5a77146101cd575b600080fd5b6101906101493660046117aa565b7fffffffff00000000000000000000000000000000000000000000000000000000167fb0d9fa19000000000000000000000000000000000000000000000000000000001490565b60405190151581526020015b60405180910390f35b6101b86101b336600461186a565b6103b0565b005b6101b86101c836600461195c565b6103be565b604080518082018252601381527f5265776172644d616e6167657220302e302e31000000000000000000000000006020820152905161019c91906119cc565b60075461022c9073ffffffffffffffffffffffffffffffffffffffff1681565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200161019c565b61027161025f366004611a1d565b60026020526000908152604090205481565b60405190815260200161019c565b6101b861028d366004611a5f565b610574565b6101b86102a036600461195c565b610642565b6101b86102b3366004611a81565b6107c4565b6101906102c6366004611a1d565b60056020526000908152604090205460ff1681565b6102716102e9366004611b00565b600360209081526000928352604080842090915290825290205481565b610319610314366004611a5f565b610903565b60405161019c9190611b2c565b6101b8610a34565b61027161033c366004611b00565b600460209081526000928352604080842090915290825290205481565b60005473ffffffffffffffffffffffffffffffffffffffff1661022c565b6101b8610385366004611b70565b610b36565b610271610398366004611a1d565b610d10565b6101b86103ab366004611a5f565b610d31565b6103ba3382610d45565b5050565b60005473ffffffffffffffffffffffffffffffffffffffff1633148015906103fe575060075473ffffffffffffffffffffffffffffffffffffffff163314155b15610435576040517f82b4290000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000819003610470576040517fe6c4247b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008381526005602052604090205460ff16156104b9576040517f0afa7ee800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6006805460018181019092557ff652222313e28459528d920b65115c16c04f3efc82aaedc97be59f3f377c0d3f01849055600084815260056020526040902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169091179055610535838383670de0b6b3a7640000610f12565b827f8f668d6090683f98b3373a8b83d214da45737f7486cb7de554cc07b54e61cfe68383604051610567929190611bdc565b60405180910390a2505050565b61057c611123565b73ffffffffffffffffffffffffffffffffffffffff81166105c9576040517fe6c4247b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600780547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040519081527fe45f5e140399b0a7e12971ab020724b828fbed8ac408c420884dc7d1bbe506b49060200160405180910390a150565b61064a611123565b60408051600180825281830190925260009160208083019080368337019050509050838160008151811061068057610680611c51565b6020026020010181815250506000805b838110156107765760008585838181106106ac576106ac611c51565b6106c29260206040909202019081019150611a5f565b600088815260046020908152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915281205491925081900361072e576040517fe6c4247b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61075f87878581811061074357610743611c51565b6107599260206040909202019081019150611a5f565b86610d45565b5092909201915061076f81611caf565b9050610690565b5061078385858584610f12565b847f8f668d6090683f98b3373a8b83d214da45737f7486cb7de554cc07b54e61cfe685856040516107b5929190611bdc565b60405180910390a25050505050565b826107e460005473ffffffffffffffffffffffffffffffffffffffff1690565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161415801561083657506000818152600460209081526040808320338452909152902054155b1561086d576040517f82b4290000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040805160018082528183019092526000916020808301908036833701905050905084816000815181106108a3576108a3611c51565b60200260200101818152505060005b838110156108fb576108ea8585838181106108cf576108cf611c51565b90506020020160208101906108e49190611a5f565b83610d45565b506108f481611caf565b90506108b2565b505050505050565b60065460609060008167ffffffffffffffff811115610924576109246117ec565b60405190808252806020026020018201604052801561094d578160200160208202803683370190505b5090506000805b83811015610a2a5760006006828154811061097157610971611c51565b600091825260208083209091015480835260048252604080842073ffffffffffffffffffffffffffffffffffffffff8c16855290925291205490915015610a19576000818152600260209081526040808320546003835281842073ffffffffffffffffffffffffffffffffffffffff8c168552909252909120548114610a175781858580600101965081518110610a0a57610a0a611c51565b6020026020010181815250505b505b50610a2381611caf565b9050610954565b5090949350505050565b60015473ffffffffffffffffffffffffffffffffffffffff163314610aba576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e65720000000000000000000060448201526064015b60405180910390fd5b60008054337fffffffffffffffffffffffff00000000000000000000000000000000000000008083168217845560018054909116905560405173ffffffffffffffffffffffffffffffffffffffff90921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b60005473ffffffffffffffffffffffffffffffffffffffff163314801590610b76575060075473ffffffffffffffffffffffffffffffffffffffff163314155b15610bad576040517f82b4290000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000805b83811015610c8c57848482818110610bcb57610bcb611c51565b9050604002016020016020810190610be39190611d0f565b77ffffffffffffffffffffffffffffffffffffffffffffffff1660026000878785818110610c1357610c13611c51565b6040908102929092013583525060208201929092520160002080549091019055848482818110610c4557610c45611c51565b9050604002016020016020810190610c5d9190611d0f565b77ffffffffffffffffffffffffffffffffffffffffffffffff168201915080610c8590611caf565b9050610bb1565b50610ccf73ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168330846111a6565b7fa1cc025ea76bacce5d740ee4bc331899375dc2c5f2ab33933aaacbd9ba001b66848484604051610d0293929190611d2a565b60405180910390a150505050565b60068181548110610d2057600080fd5b600091825260209091200154905081565b610d39611123565b610d4281611288565b50565b60008060005b8351811015610ec1576000848281518110610d6857610d68611c51565b6020026020010151905060006002600083815260200190815260200160002054905080600003610d99575050610eb1565b600082815260036020908152604080832073ffffffffffffffffffffffffffffffffffffffff8b16808552908352818420548685526004845282852091855292528220549083039190670de0b6b3a764000090830204905080600003610e025750505050610eb1565b600084815260036020908152604080832073ffffffffffffffffffffffffffffffffffffffff8d168085529252909120849055885196820196899087908110610e4d57610e4d611c51565b60200260200101517f989969655bc1d593922527fe85d71347bb8e12fa423cc71f362dd8ef7cb10ef283604051610ea4919077ffffffffffffffffffffffffffffffffffffffffffffffff91909116815260200190565b60405180910390a3505050505b610eba81611caf565b9050610d4b565b508015610f0957610f0973ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016858361137d565b90505b92915050565b610f6d8383808060200260200160405190810160405280939291908181526020016000905b82821015610f6357610f5460408302860136819003810190611db1565b81526020019060010190610f37565b50505050506113d8565b15610fa4576040517fe6c4247b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000805b838110156110e2576000858583818110610fc457610fc4611c51565b9050604002016020016020810190610fdc9190611e0c565b67ffffffffffffffff1690506000868684818110610ffc57610ffc611c51565b6110129260206040909202019081019150611a5f565b905073ffffffffffffffffffffffffffffffffffffffff8116611061576040517fe6c4247b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8160000361109b576040517f84677ce800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600088815260046020908152604080832073ffffffffffffffffffffffffffffffffffffffff90941683529290522081905591909101906110db81611caf565b9050610fa8565b5081811461111c576040517f84677ce800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5050505050565b60005473ffffffffffffffffffffffffffffffffffffffff1633146111a4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e6572000000000000000000006044820152606401610ab1565b565b60405173ffffffffffffffffffffffffffffffffffffffff808516602483015283166044820152606481018290526112829085907f23b872dd00000000000000000000000000000000000000000000000000000000906084015b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff000000000000000000000000000000000000000000000000000000009093169290921790915261148f565b50505050565b3373ffffffffffffffffffffffffffffffffffffffff821603611307576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c660000000000000000006044820152606401610ab1565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b60405173ffffffffffffffffffffffffffffffffffffffff83166024820152604481018290526113d39084907fa9059cbb0000000000000000000000000000000000000000000000000000000090606401611200565b505050565b6000805b82518110156114865760006113f2826001611e27565b90505b835181101561147d5783818151811061141057611410611c51565b60200260200101516000015173ffffffffffffffffffffffffffffffffffffffff1684838151811061144457611444611c51565b60200260200101516000015173ffffffffffffffffffffffffffffffffffffffff1603611475575060019392505050565b6001016113f5565b506001016113dc565b50600092915050565b60006114f1826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff1661159b9092919063ffffffff16565b8051909150156113d3578080602001905181019061150f9190611e3a565b6113d3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f742073756363656564000000000000000000000000000000000000000000006064820152608401610ab1565b60606115aa84846000856115b2565b949350505050565b606082471015611644576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f60448201527f722063616c6c00000000000000000000000000000000000000000000000000006064820152608401610ab1565b6000808673ffffffffffffffffffffffffffffffffffffffff16858760405161166d9190611e5c565b60006040518083038185875af1925050503d80600081146116aa576040519150601f19603f3d011682016040523d82523d6000602084013e6116af565b606091505b50915091506116c0878383876116cb565b979650505050505050565b6060831561176157825160000361175a5773ffffffffffffffffffffffffffffffffffffffff85163b61175a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610ab1565b50816115aa565b6115aa83838151156117765781518083602001fd5b806040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610ab191906119cc565b6000602082840312156117bc57600080fd5b81357fffffffff0000000000000000000000000000000000000000000000000000000081168114610f0957600080fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715611862576118626117ec565b604052919050565b6000602080838503121561187d57600080fd5b823567ffffffffffffffff8082111561189557600080fd5b818501915085601f8301126118a957600080fd5b8135818111156118bb576118bb6117ec565b8060051b91506118cc84830161181b565b81815291830184019184810190888411156118e657600080fd5b938501935b83851015611904578435825293850193908501906118eb565b98975050505050505050565b60008083601f84011261192257600080fd5b50813567ffffffffffffffff81111561193a57600080fd5b6020830191508360208260061b850101111561195557600080fd5b9250929050565b60008060006040848603121561197157600080fd5b83359250602084013567ffffffffffffffff81111561198f57600080fd5b61199b86828701611910565b9497909650939450505050565b60005b838110156119c35781810151838201526020016119ab565b50506000910152565b60208152600082518060208401526119eb8160408501602087016119a8565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169190910160400192915050565b600060208284031215611a2f57600080fd5b5035919050565b803573ffffffffffffffffffffffffffffffffffffffff81168114611a5a57600080fd5b919050565b600060208284031215611a7157600080fd5b611a7a82611a36565b9392505050565b600080600060408486031215611a9657600080fd5b83359250602084013567ffffffffffffffff80821115611ab557600080fd5b818601915086601f830112611ac957600080fd5b813581811115611ad857600080fd5b8760208260051b8501011115611aed57600080fd5b6020830194508093505050509250925092565b60008060408385031215611b1357600080fd5b82359150611b2360208401611a36565b90509250929050565b6020808252825182820181905260009190848201906040850190845b81811015611b6457835183529284019291840191600101611b48565b50909695505050505050565b600080600060408486031215611b8557600080fd5b833567ffffffffffffffff811115611b9c57600080fd5b611ba886828701611910565b9094509250611bbb905060208501611a36565b90509250925092565b803567ffffffffffffffff81168114611a5a57600080fd5b6020808252818101839052600090604080840186845b87811015611c445773ffffffffffffffffffffffffffffffffffffffff611c1883611a36565b16835267ffffffffffffffff611c2f868401611bc4565b16838601529183019190830190600101611bf2565b5090979650505050505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203611ce057611ce0611c80565b5060010190565b803577ffffffffffffffffffffffffffffffffffffffffffffffff81168114611a5a57600080fd5b600060208284031215611d2157600080fd5b611a7a82611ce7565b60408082528181018490526000908560608401835b87811015611d865782358252602077ffffffffffffffffffffffffffffffffffffffffffffffff611d71828601611ce7565b16908301529183019190830190600101611d3f565b5080935050505073ffffffffffffffffffffffffffffffffffffffff83166020830152949350505050565b600060408284031215611dc357600080fd5b6040516040810181811067ffffffffffffffff82111715611de657611de66117ec565b604052611df283611a36565b8152611e0060208401611bc4565b60208201529392505050565b600060208284031215611e1e57600080fd5b611a7a82611bc4565b80820180821115610f0c57610f0c611c80565b600060208284031215611e4c57600080fd5b81518015158114610f0957600080fd5b60008251611e6e8184602087016119a8565b919091019291505056fea164736f6c6343000810000a", + ABI: "[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"linkAddress\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"InvalidAddress\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidPoolId\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidPoolLength\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidWeights\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"Unauthorized\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"newFeeManagerAddress\",\"type\":\"address\"}],\"name\":\"FeeManagerUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"components\":[{\"internalType\":\"bytes32\",\"name\":\"poolId\",\"type\":\"bytes32\"},{\"internalType\":\"uint192\",\"name\":\"amount\",\"type\":\"uint192\"}],\"indexed\":false,\"internalType\":\"structIRewardManager.FeePayment[]\",\"name\":\"payments\",\"type\":\"tuple[]\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"payer\",\"type\":\"address\"}],\"name\":\"FeePaid\",\"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\":\"poolId\",\"type\":\"bytes32\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"addr\",\"type\":\"address\"},{\"internalType\":\"uint64\",\"name\":\"weight\",\"type\":\"uint64\"}],\"indexed\":false,\"internalType\":\"structCommon.AddressAndWeight[]\",\"name\":\"newRewardRecipients\",\"type\":\"tuple[]\"}],\"name\":\"RewardRecipientsUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"poolId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint192\",\"name\":\"quantity\",\"type\":\"uint192\"}],\"name\":\"RewardsClaimed\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"acceptOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32[]\",\"name\":\"poolIds\",\"type\":\"bytes32[]\"}],\"name\":\"claimRewards\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"startIndex\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"endIndex\",\"type\":\"uint256\"}],\"name\":\"getAvailableRewardPoolIds\",\"outputs\":[{\"internalType\":\"bytes32[]\",\"name\":\"\",\"type\":\"bytes32[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"bytes32\",\"name\":\"poolId\",\"type\":\"bytes32\"},{\"internalType\":\"uint192\",\"name\":\"amount\",\"type\":\"uint192\"}],\"internalType\":\"structIRewardManager.FeePayment[]\",\"name\":\"payments\",\"type\":\"tuple[]\"},{\"internalType\":\"address\",\"name\":\"payer\",\"type\":\"address\"}],\"name\":\"onFeePaid\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"poolId\",\"type\":\"bytes32\"},{\"internalType\":\"address[]\",\"name\":\"recipients\",\"type\":\"address[]\"}],\"name\":\"payRecipients\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_feeManagerAddress\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"s_registeredPoolIds\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"s_rewardRecipientWeights\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"name\":\"s_rewardRecipientWeightsSet\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"name\":\"s_totalRewardRecipientFees\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"s_totalRewardRecipientFeesLastClaimedAmounts\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newFeeManagerAddress\",\"type\":\"address\"}],\"name\":\"setFeeManager\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"poolId\",\"type\":\"bytes32\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"addr\",\"type\":\"address\"},{\"internalType\":\"uint64\",\"name\":\"weight\",\"type\":\"uint64\"}],\"internalType\":\"structCommon.AddressAndWeight[]\",\"name\":\"rewardRecipientAndWeights\",\"type\":\"tuple[]\"}],\"name\":\"setRewardRecipients\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes4\",\"name\":\"interfaceId\",\"type\":\"bytes4\"}],\"name\":\"supportsInterface\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"typeAndVersion\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"poolId\",\"type\":\"bytes32\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"addr\",\"type\":\"address\"},{\"internalType\":\"uint64\",\"name\":\"weight\",\"type\":\"uint64\"}],\"internalType\":\"structCommon.AddressAndWeight[]\",\"name\":\"newRewardRecipients\",\"type\":\"tuple[]\"}],\"name\":\"updateRewardRecipients\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", + Bin: "0x60a06040523480156200001157600080fd5b50604051620020ec380380620020ec8339810160408190526200003491620001a6565b33806000816200008b5760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b0384811691909117909155811615620000be57620000be81620000fb565b5050506001600160a01b038116620000e95760405163e6c4247b60e01b815260040160405180910390fd5b6001600160a01b0316608052620001d8565b336001600160a01b03821603620001555760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c66000000000000000000604482015260640162000082565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b600060208284031215620001b957600080fd5b81516001600160a01b0381168114620001d157600080fd5b9392505050565b608051611ef1620001fb60003960008181610cda0152610f150152611ef16000f3fe608060405234801561001057600080fd5b50600436106101365760003560e01c80634d322084116100b25780638ac85a5c11610081578063b0d9fa1911610066578063b0d9fa1914610377578063cd5f72921461038a578063f2fde38b1461039d57600080fd5b80638ac85a5c1461032e5780638da5cb5b1461035957600080fd5b80634d322084146102c557806359256201146102d857806360122608146102fb57806379ba50971461032657600080fd5b8063276e76601161010957806347226475116100ee578063472264751461027f578063472d35b91461029f5780634944832f146102b257600080fd5b8063276e76601461020c57806339ee81e11461025157600080fd5b806301ffc9a71461013b5780630f3c34d1146101a557806314060f23146101ba578063181f5a77146101cd575b600080fd5b6101906101493660046117dd565b7fffffffff00000000000000000000000000000000000000000000000000000000167fb0d9fa19000000000000000000000000000000000000000000000000000000001490565b60405190151581526020015b60405180910390f35b6101b86101b336600461189d565b6103b0565b005b6101b86101c836600461198f565b6103be565b604080518082018252601381527f5265776172644d616e6167657220312e302e30000000000000000000000000006020820152905161019c91906119ff565b60075461022c9073ffffffffffffffffffffffffffffffffffffffff1681565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200161019c565b61027161025f366004611a50565b60026020526000908152604090205481565b60405190815260200161019c565b61029261028d366004611a92565b610574565b60405161019c9190611ac5565b6101b86102ad366004611b09565b6106fe565b6101b86102c036600461198f565b6107cc565b6101b86102d3366004611b2b565b61094e565b6101906102e6366004611a50565b60056020526000908152604090205460ff1681565b610271610309366004611baa565b600360209081526000928352604080842090915290825290205481565b6101b8610a8d565b61027161033c366004611baa565b600460209081526000928352604080842090915290825290205481565b60005473ffffffffffffffffffffffffffffffffffffffff1661022c565b6101b8610385366004611bd6565b610b8f565b610271610398366004611a50565b610d43565b6101b86103ab366004611b09565b610d64565b6103ba3382610d78565b5050565b60005473ffffffffffffffffffffffffffffffffffffffff1633148015906103fe575060075473ffffffffffffffffffffffffffffffffffffffff163314155b15610435576040517f82b4290000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000819003610470576040517fe6c4247b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008381526005602052604090205460ff16156104b9576040517f0afa7ee800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6006805460018181019092557ff652222313e28459528d920b65115c16c04f3efc82aaedc97be59f3f377c0d3f01849055600084815260056020526040902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169091179055610535838383670de0b6b3a7640000610f45565b827f8f668d6090683f98b3373a8b83d214da45737f7486cb7de554cc07b54e61cfe68383604051610567929190611c42565b60405180910390a2505050565b6006546060906000818411610589578361058b565b815b9050808511156105c7576040517fa22caccc00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60006105d38683611cd9565b67ffffffffffffffff8111156105eb576105eb61181f565b604051908082528060200260200182016040528015610614578160200160208202803683370190505b5090506000865b838110156106f15760006006828154811061063857610638611cec565b600091825260208083209091015480835260048252604080842073ffffffffffffffffffffffffffffffffffffffff8f168552909252912054909150156106e0576000818152600260209081526040808320546003835281842073ffffffffffffffffffffffffffffffffffffffff8f1685529092529091205481146106de57818585806001019650815181106106d1576106d1611cec565b6020026020010181815250505b505b506106ea81611d1b565b905061061b565b5090979650505050505050565b610706611156565b73ffffffffffffffffffffffffffffffffffffffff8116610753576040517fe6c4247b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600780547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040519081527fe45f5e140399b0a7e12971ab020724b828fbed8ac408c420884dc7d1bbe506b49060200160405180910390a150565b6107d4611156565b60408051600180825281830190925260009160208083019080368337019050509050838160008151811061080a5761080a611cec565b6020026020010181815250506000805b8381101561090057600085858381811061083657610836611cec565b61084c9260206040909202019081019150611b09565b600088815260046020908152604080832073ffffffffffffffffffffffffffffffffffffffff851684529091528120549192508190036108b8576040517fe6c4247b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6108e98787858181106108cd576108cd611cec565b6108e39260206040909202019081019150611b09565b86610d78565b509290920191506108f981611d1b565b905061081a565b5061090d85858584610f45565b847f8f668d6090683f98b3373a8b83d214da45737f7486cb7de554cc07b54e61cfe6858560405161093f929190611c42565b60405180910390a25050505050565b8261096e60005473ffffffffffffffffffffffffffffffffffffffff1690565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16141580156109c057506000818152600460209081526040808320338452909152902054155b156109f7576040517f82b4290000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b604080516001808252818301909252600091602080830190803683370190505090508481600081518110610a2d57610a2d611cec565b60200260200101818152505060005b83811015610a8557610a74858583818110610a5957610a59611cec565b9050602002016020810190610a6e9190611b09565b83610d78565b50610a7e81611d1b565b9050610a3c565b505050505050565b60015473ffffffffffffffffffffffffffffffffffffffff163314610b13576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e65720000000000000000000060448201526064015b60405180910390fd5b60008054337fffffffffffffffffffffffff00000000000000000000000000000000000000008083168217845560018054909116905560405173ffffffffffffffffffffffffffffffffffffffff90921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b60075473ffffffffffffffffffffffffffffffffffffffff163314610be0576040517f82b4290000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000805b83811015610cbf57848482818110610bfe57610bfe611cec565b9050604002016020016020810190610c169190611d7b565b77ffffffffffffffffffffffffffffffffffffffffffffffff1660026000878785818110610c4657610c46611cec565b6040908102929092013583525060208201929092520160002080549091019055848482818110610c7857610c78611cec565b9050604002016020016020810190610c909190611d7b565b77ffffffffffffffffffffffffffffffffffffffffffffffff168201915080610cb890611d1b565b9050610be4565b50610d0273ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168330846111d9565b7fa1cc025ea76bacce5d740ee4bc331899375dc2c5f2ab33933aaacbd9ba001b66848484604051610d3593929190611d96565b60405180910390a150505050565b60068181548110610d5357600080fd5b600091825260209091200154905081565b610d6c611156565b610d75816112bb565b50565b60008060005b8351811015610ef4576000848281518110610d9b57610d9b611cec565b6020026020010151905060006002600083815260200190815260200160002054905080600003610dcc575050610ee4565b600082815260036020908152604080832073ffffffffffffffffffffffffffffffffffffffff8b16808552908352818420548685526004845282852091855292528220549083039190670de0b6b3a764000090830204905080600003610e355750505050610ee4565b600084815260036020908152604080832073ffffffffffffffffffffffffffffffffffffffff8d168085529252909120849055885196820196899087908110610e8057610e80611cec565b60200260200101517f989969655bc1d593922527fe85d71347bb8e12fa423cc71f362dd8ef7cb10ef283604051610ed7919077ffffffffffffffffffffffffffffffffffffffffffffffff91909116815260200190565b60405180910390a3505050505b610eed81611d1b565b9050610d7e565b508015610f3c57610f3c73ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001685836113b0565b90505b92915050565b610fa08383808060200260200160405190810160405280939291908181526020016000905b82821015610f9657610f8760408302860136819003810190611e1d565b81526020019060010190610f6a565b505050505061140b565b15610fd7576040517fe6c4247b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000805b83811015611115576000858583818110610ff757610ff7611cec565b905060400201602001602081019061100f9190611e78565b67ffffffffffffffff169050600086868481811061102f5761102f611cec565b6110459260206040909202019081019150611b09565b905073ffffffffffffffffffffffffffffffffffffffff8116611094576040517fe6c4247b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b816000036110ce576040517f84677ce800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600088815260046020908152604080832073ffffffffffffffffffffffffffffffffffffffff909416835292905220819055919091019061110e81611d1b565b9050610fdb565b5081811461114f576040517f84677ce800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5050505050565b60005473ffffffffffffffffffffffffffffffffffffffff1633146111d7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e6572000000000000000000006044820152606401610b0a565b565b60405173ffffffffffffffffffffffffffffffffffffffff808516602483015283166044820152606481018290526112b59085907f23b872dd00000000000000000000000000000000000000000000000000000000906084015b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff00000000000000000000000000000000000000000000000000000000909316929092179091526114c2565b50505050565b3373ffffffffffffffffffffffffffffffffffffffff82160361133a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c660000000000000000006044820152606401610b0a565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b60405173ffffffffffffffffffffffffffffffffffffffff83166024820152604481018290526114069084907fa9059cbb0000000000000000000000000000000000000000000000000000000090606401611233565b505050565b6000805b82518110156114b9576000611425826001611e93565b90505b83518110156114b05783818151811061144357611443611cec565b60200260200101516000015173ffffffffffffffffffffffffffffffffffffffff1684838151811061147757611477611cec565b60200260200101516000015173ffffffffffffffffffffffffffffffffffffffff16036114a8575060019392505050565b600101611428565b5060010161140f565b50600092915050565b6000611524826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff166115ce9092919063ffffffff16565b80519091501561140657808060200190518101906115429190611ea6565b611406576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f742073756363656564000000000000000000000000000000000000000000006064820152608401610b0a565b60606115dd84846000856115e5565b949350505050565b606082471015611677576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f60448201527f722063616c6c00000000000000000000000000000000000000000000000000006064820152608401610b0a565b6000808673ffffffffffffffffffffffffffffffffffffffff1685876040516116a09190611ec8565b60006040518083038185875af1925050503d80600081146116dd576040519150601f19603f3d011682016040523d82523d6000602084013e6116e2565b606091505b50915091506116f3878383876116fe565b979650505050505050565b6060831561179457825160000361178d5773ffffffffffffffffffffffffffffffffffffffff85163b61178d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610b0a565b50816115dd565b6115dd83838151156117a95781518083602001fd5b806040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610b0a91906119ff565b6000602082840312156117ef57600080fd5b81357fffffffff0000000000000000000000000000000000000000000000000000000081168114610f3c57600080fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff811182821017156118955761189561181f565b604052919050565b600060208083850312156118b057600080fd5b823567ffffffffffffffff808211156118c857600080fd5b818501915085601f8301126118dc57600080fd5b8135818111156118ee576118ee61181f565b8060051b91506118ff84830161184e565b818152918301840191848101908884111561191957600080fd5b938501935b838510156119375784358252938501939085019061191e565b98975050505050505050565b60008083601f84011261195557600080fd5b50813567ffffffffffffffff81111561196d57600080fd5b6020830191508360208260061b850101111561198857600080fd5b9250929050565b6000806000604084860312156119a457600080fd5b83359250602084013567ffffffffffffffff8111156119c257600080fd5b6119ce86828701611943565b9497909650939450505050565b60005b838110156119f65781810151838201526020016119de565b50506000910152565b6020815260008251806020840152611a1e8160408501602087016119db565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169190910160400192915050565b600060208284031215611a6257600080fd5b5035919050565b803573ffffffffffffffffffffffffffffffffffffffff81168114611a8d57600080fd5b919050565b600080600060608486031215611aa757600080fd5b611ab084611a69565b95602085013595506040909401359392505050565b6020808252825182820181905260009190848201906040850190845b81811015611afd57835183529284019291840191600101611ae1565b50909695505050505050565b600060208284031215611b1b57600080fd5b611b2482611a69565b9392505050565b600080600060408486031215611b4057600080fd5b83359250602084013567ffffffffffffffff80821115611b5f57600080fd5b818601915086601f830112611b7357600080fd5b813581811115611b8257600080fd5b8760208260051b8501011115611b9757600080fd5b6020830194508093505050509250925092565b60008060408385031215611bbd57600080fd5b82359150611bcd60208401611a69565b90509250929050565b600080600060408486031215611beb57600080fd5b833567ffffffffffffffff811115611c0257600080fd5b611c0e86828701611943565b9094509250611c21905060208501611a69565b90509250925092565b803567ffffffffffffffff81168114611a8d57600080fd5b6020808252818101839052600090604080840186845b878110156106f15773ffffffffffffffffffffffffffffffffffffffff611c7e83611a69565b16835267ffffffffffffffff611c95868401611c2a565b16838601529183019190830190600101611c58565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b81810381811115610f3f57610f3f611caa565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203611d4c57611d4c611caa565b5060010190565b803577ffffffffffffffffffffffffffffffffffffffffffffffff81168114611a8d57600080fd5b600060208284031215611d8d57600080fd5b611b2482611d53565b60408082528181018490526000908560608401835b87811015611df25782358252602077ffffffffffffffffffffffffffffffffffffffffffffffff611ddd828601611d53565b16908301529183019190830190600101611dab565b5080935050505073ffffffffffffffffffffffffffffffffffffffff83166020830152949350505050565b600060408284031215611e2f57600080fd5b6040516040810181811067ffffffffffffffff82111715611e5257611e5261181f565b604052611e5e83611a69565b8152611e6c60208401611c2a565b60208201529392505050565b600060208284031215611e8a57600080fd5b611b2482611c2a565b80820180821115610f3f57610f3f611caa565b600060208284031215611eb857600080fd5b81518015158114610f3c57600080fd5b60008251611eda8184602087016119db565b919091019291505056fea164736f6c6343000810000a", } var RewardManagerABI = RewardManagerMetaData.ABI @@ -181,9 +181,9 @@ func (_RewardManager *RewardManagerTransactorRaw) Transact(opts *bind.TransactOp return _RewardManager.Contract.contract.Transact(opts, method, params...) } -func (_RewardManager *RewardManagerCaller) GetAvailableRewardPoolIds(opts *bind.CallOpts, recipient common.Address) ([][32]byte, error) { +func (_RewardManager *RewardManagerCaller) GetAvailableRewardPoolIds(opts *bind.CallOpts, recipient common.Address, startIndex *big.Int, endIndex *big.Int) ([][32]byte, error) { var out []interface{} - err := _RewardManager.contract.Call(opts, &out, "getAvailableRewardPoolIds", recipient) + err := _RewardManager.contract.Call(opts, &out, "getAvailableRewardPoolIds", recipient, startIndex, endIndex) if err != nil { return *new([][32]byte), err @@ -195,12 +195,12 @@ func (_RewardManager *RewardManagerCaller) GetAvailableRewardPoolIds(opts *bind. } -func (_RewardManager *RewardManagerSession) GetAvailableRewardPoolIds(recipient common.Address) ([][32]byte, error) { - return _RewardManager.Contract.GetAvailableRewardPoolIds(&_RewardManager.CallOpts, recipient) +func (_RewardManager *RewardManagerSession) GetAvailableRewardPoolIds(recipient common.Address, startIndex *big.Int, endIndex *big.Int) ([][32]byte, error) { + return _RewardManager.Contract.GetAvailableRewardPoolIds(&_RewardManager.CallOpts, recipient, startIndex, endIndex) } -func (_RewardManager *RewardManagerCallerSession) GetAvailableRewardPoolIds(recipient common.Address) ([][32]byte, error) { - return _RewardManager.Contract.GetAvailableRewardPoolIds(&_RewardManager.CallOpts, recipient) +func (_RewardManager *RewardManagerCallerSession) GetAvailableRewardPoolIds(recipient common.Address, startIndex *big.Int, endIndex *big.Int) ([][32]byte, error) { + return _RewardManager.Contract.GetAvailableRewardPoolIds(&_RewardManager.CallOpts, recipient, startIndex, endIndex) } func (_RewardManager *RewardManagerCaller) Owner(opts *bind.CallOpts) (common.Address, error) { @@ -425,16 +425,16 @@ func (_RewardManager *RewardManagerTransactorSession) ClaimRewards(poolIds [][32 return _RewardManager.Contract.ClaimRewards(&_RewardManager.TransactOpts, poolIds) } -func (_RewardManager *RewardManagerTransactor) OnFeePaid(opts *bind.TransactOpts, payments []IRewardManagerFeePayment, payee common.Address) (*types.Transaction, error) { - return _RewardManager.contract.Transact(opts, "onFeePaid", payments, payee) +func (_RewardManager *RewardManagerTransactor) OnFeePaid(opts *bind.TransactOpts, payments []IRewardManagerFeePayment, payer common.Address) (*types.Transaction, error) { + return _RewardManager.contract.Transact(opts, "onFeePaid", payments, payer) } -func (_RewardManager *RewardManagerSession) OnFeePaid(payments []IRewardManagerFeePayment, payee common.Address) (*types.Transaction, error) { - return _RewardManager.Contract.OnFeePaid(&_RewardManager.TransactOpts, payments, payee) +func (_RewardManager *RewardManagerSession) OnFeePaid(payments []IRewardManagerFeePayment, payer common.Address) (*types.Transaction, error) { + return _RewardManager.Contract.OnFeePaid(&_RewardManager.TransactOpts, payments, payer) } -func (_RewardManager *RewardManagerTransactorSession) OnFeePaid(payments []IRewardManagerFeePayment, payee common.Address) (*types.Transaction, error) { - return _RewardManager.Contract.OnFeePaid(&_RewardManager.TransactOpts, payments, payee) +func (_RewardManager *RewardManagerTransactorSession) OnFeePaid(payments []IRewardManagerFeePayment, payer common.Address) (*types.Transaction, error) { + return _RewardManager.Contract.OnFeePaid(&_RewardManager.TransactOpts, payments, payer) } func (_RewardManager *RewardManagerTransactor) PayRecipients(opts *bind.TransactOpts, poolId [32]byte, recipients []common.Address) (*types.Transaction, error) { @@ -676,7 +676,7 @@ func (it *RewardManagerFeePaidIterator) Close() error { type RewardManagerFeePaid struct { Payments []IRewardManagerFeePayment - Payee common.Address + Payer common.Address Raw types.Log } @@ -1318,7 +1318,7 @@ func (_RewardManager *RewardManager) Address() common.Address { } type RewardManagerInterface interface { - GetAvailableRewardPoolIds(opts *bind.CallOpts, recipient common.Address) ([][32]byte, error) + GetAvailableRewardPoolIds(opts *bind.CallOpts, recipient common.Address, startIndex *big.Int, endIndex *big.Int) ([][32]byte, error) Owner(opts *bind.CallOpts) (common.Address, error) @@ -1342,7 +1342,7 @@ type RewardManagerInterface interface { ClaimRewards(opts *bind.TransactOpts, poolIds [][32]byte) (*types.Transaction, error) - OnFeePaid(opts *bind.TransactOpts, payments []IRewardManagerFeePayment, payee common.Address) (*types.Transaction, error) + OnFeePaid(opts *bind.TransactOpts, payments []IRewardManagerFeePayment, payer common.Address) (*types.Transaction, error) PayRecipients(opts *bind.TransactOpts, poolId [32]byte, recipients []common.Address) (*types.Transaction, error) diff --git a/core/gethwrappers/llo-feeds/generated/verifier_proxy/verifier_proxy.go b/core/gethwrappers/llo-feeds/generated/verifier_proxy/verifier_proxy.go index 77e76dfd70b..12e5e28948e 100644 --- a/core/gethwrappers/llo-feeds/generated/verifier_proxy/verifier_proxy.go +++ b/core/gethwrappers/llo-feeds/generated/verifier_proxy/verifier_proxy.go @@ -36,8 +36,8 @@ type CommonAddressAndWeight struct { } var VerifierProxyMetaData = &bind.MetaData{ - ABI: "[{\"inputs\":[{\"internalType\":\"contractAccessControllerInterface\",\"name\":\"accessController\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"AccessForbidden\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"BadVerification\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"configDigest\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"verifier\",\"type\":\"address\"}],\"name\":\"ConfigDigestAlreadySet\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"verifier\",\"type\":\"address\"}],\"name\":\"VerifierAlreadyInitialized\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"VerifierInvalid\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"configDigest\",\"type\":\"bytes32\"}],\"name\":\"VerifierNotFound\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ZeroAddress\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"oldAccessController\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"newAccessController\",\"type\":\"address\"}],\"name\":\"AccessControllerSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"oldFeeManager\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"newFeeManager\",\"type\":\"address\"}],\"name\":\"FeeManagerSet\",\"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\":\"verifierAddress\",\"type\":\"address\"}],\"name\":\"VerifierInitialized\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"oldConfigDigest\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"newConfigDigest\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"verifierAddress\",\"type\":\"address\"}],\"name\":\"VerifierSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"configDigest\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"verifierAddress\",\"type\":\"address\"}],\"name\":\"VerifierUnset\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"acceptOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"configDigest\",\"type\":\"bytes32\"}],\"name\":\"getVerifier\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"verifierAddress\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"verifierAddress\",\"type\":\"address\"}],\"name\":\"initializeVerifier\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_accessController\",\"outputs\":[{\"internalType\":\"contractAccessControllerInterface\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_feeManager\",\"outputs\":[{\"internalType\":\"contractIVerifierFeeManager\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"contractAccessControllerInterface\",\"name\":\"accessController\",\"type\":\"address\"}],\"name\":\"setAccessController\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"contractIVerifierFeeManager\",\"name\":\"feeManager\",\"type\":\"address\"}],\"name\":\"setFeeManager\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"currentConfigDigest\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"newConfigDigest\",\"type\":\"bytes32\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"addr\",\"type\":\"address\"},{\"internalType\":\"uint64\",\"name\":\"weight\",\"type\":\"uint64\"}],\"internalType\":\"structCommon.AddressAndWeight[]\",\"name\":\"addressesAndWeights\",\"type\":\"tuple[]\"}],\"name\":\"setVerifier\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"typeAndVersion\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"configDigest\",\"type\":\"bytes32\"}],\"name\":\"unsetVerifier\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"payload\",\"type\":\"bytes\"}],\"name\":\"verify\",\"outputs\":[{\"internalType\":\"bytes\",\"name\":\"verifiedReport\",\"type\":\"bytes\"}],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes[]\",\"name\":\"payloads\",\"type\":\"bytes[]\"}],\"name\":\"verifyBulk\",\"outputs\":[{\"internalType\":\"bytes[]\",\"name\":\"verifiedReports\",\"type\":\"bytes[]\"}],\"stateMutability\":\"payable\",\"type\":\"function\"}]", - Bin: "0x60806040523480156200001157600080fd5b5060405162001ac538038062001ac5833981016040819052620000349162000193565b33806000816200008b5760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b0384811691909117909155811615620000be57620000be81620000e8565b5050600480546001600160a01b0319166001600160a01b03939093169290921790915550620001c5565b336001600160a01b03821603620001425760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c66000000000000000000604482015260640162000082565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b600060208284031215620001a657600080fd5b81516001600160a01b0381168114620001be57600080fd5b9392505050565b6118f080620001d56000396000f3fe6080604052600436106100dd5760003560e01c80638da5cb5b1161007f578063b011b24711610059578063b011b2471461028e578063eeb7b248146102ae578063f08391d8146102f1578063f2fde38b1461031157600080fd5b80638da5cb5b146102235780638e760afe1461024e57806394ba28461461026157600080fd5b80636e914094116100bb5780636e914094146101ae57806379ba5097146101ce57806383490cd7146101e35780638c2a4d531461020357600080fd5b8063181f5a77146100e257806338416b5b1461013a578063472d35b91461018c575b600080fd5b3480156100ee57600080fd5b5060408051808201909152601381527f566572696669657250726f787920312e312e300000000000000000000000000060208201525b6040516101319190611216565b60405180910390f35b34801561014657600080fd5b506005546101679073ffffffffffffffffffffffffffffffffffffffff1681565b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610131565b34801561019857600080fd5b506101ac6101a7366004611252565b610331565b005b3480156101ba57600080fd5b506101ac6101c936600461126f565b61040d565b3480156101da57600080fd5b506101ac6104fe565b6101f66101f1366004611288565b6105fb565b60405161013191906112fd565b34801561020f57600080fd5b506101ac61021e366004611252565b610859565b34801561022f57600080fd5b5060005473ffffffffffffffffffffffffffffffffffffffff16610167565b61012461025c36600461137d565b610a8a565b34801561026d57600080fd5b506004546101679073ffffffffffffffffffffffffffffffffffffffff1681565b34801561029a57600080fd5b506101ac6102a93660046113dd565b610c3e565b3480156102ba57600080fd5b506101676102c936600461126f565b60009081526003602052604090205473ffffffffffffffffffffffffffffffffffffffff1690565b3480156102fd57600080fd5b506101ac61030c366004611252565b610e64565b34801561031d57600080fd5b506101ac61032c366004611252565b610eeb565b610339610eff565b73ffffffffffffffffffffffffffffffffffffffff8116610386576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6005805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff000000000000000000000000000000000000000083168117909355604080519190921680825260208201939093527f04628abcaa6b1674651352125cb94b65b289145bc2bc4d67720bb7d966372f0391015b60405180910390a15050565b610415610eff565b60008181526003602052604090205473ffffffffffffffffffffffffffffffffffffffff1680610479576040517fb151802b000000000000000000000000000000000000000000000000000000008152600481018390526024015b60405180910390fd5b6000828152600360205260409081902080547fffffffffffffffffffffffff0000000000000000000000000000000000000000169055517f11dc15c4b8ac2b183166cc8427e5385a5ece8308217a4217338c6a7614845c4c90610401908490849091825273ffffffffffffffffffffffffffffffffffffffff16602082015260400190565b60015473ffffffffffffffffffffffffffffffffffffffff16331461057f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e6572000000000000000000006044820152606401610470565b60008054337fffffffffffffffffffffffff00000000000000000000000000000000000000008083168217845560018054909116905560405173ffffffffffffffffffffffffffffffffffffffff90921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b60045460609073ffffffffffffffffffffffffffffffffffffffff1680158015906106bb57506040517f6b14daf800000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff821690636b14daf89061067890339060009036906004016114a9565b602060405180830381865afa158015610695573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106b991906114d9565b155b156106f2576040517fef67f5d800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60055473ffffffffffffffffffffffffffffffffffffffff16801561079c576040517f40d7f78e00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8216906340d7f78e903490610769908990899033906004016114fb565b6000604051808303818588803b15801561078257600080fd5b505af1158015610796573d6000803e3d6000fd5b50505050505b8367ffffffffffffffff8111156107b5576107b56115f0565b6040519080825280602002602001820160405280156107e857816020015b60608152602001906001900390816107d35790505b50925060005b848110156108505761082286868381811061080b5761080b61161f565b905060200281019061081d919061164e565b610f82565b8482815181106108345761083461161f565b602002602001018190525080610849906116ba565b90506107ee565b50505092915050565b610861610eff565b8073ffffffffffffffffffffffffffffffffffffffff81166108af576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040517f01ffc9a70000000000000000000000000000000000000000000000000000000081527f3d3ac1b500000000000000000000000000000000000000000000000000000000600482015273ffffffffffffffffffffffffffffffffffffffff8216906301ffc9a790602401602060405180830381865afa158015610939573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061095d91906114d9565b610993576040517f75b0527a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff821660009081526002602052604090205460ff1615610a0b576040517f4e01ccfd00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff83166004820152602401610470565b73ffffffffffffffffffffffffffffffffffffffff821660008181526002602090815260409182902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016600117905590519182527f1f2cd7c97f4d801b5efe26cc409617c1fd6c5ef786e79aacb90af40923e4e8e99101610401565b60045460609073ffffffffffffffffffffffffffffffffffffffff168015801590610b4a57506040517f6b14daf800000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff821690636b14daf890610b0790339060009036906004016114a9565b602060405180830381865afa158015610b24573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b4891906114d9565b155b15610b81576040517fef67f5d800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60055473ffffffffffffffffffffffffffffffffffffffff168015610c2b576040517ff1387e1600000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff82169063f1387e16903490610bf890899089903390600401611719565b6000604051808303818588803b158015610c1157600080fd5b505af1158015610c25573d6000803e3d6000fd5b50505050505b610c358585610f82565b95945050505050565b600083815260036020526040902054839073ffffffffffffffffffffffffffffffffffffffff168015610cbc576040517f375d1fe60000000000000000000000000000000000000000000000000000000081526004810183905273ffffffffffffffffffffffffffffffffffffffff82166024820152604401610470565b3360009081526002602052604090205460ff16610d05576040517fef67f5d800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600085815260036020526040902080547fffffffffffffffffffffffff000000000000000000000000000000000000000016331790558215610e1d5760055473ffffffffffffffffffffffffffffffffffffffff16610d90576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6005546040517ff65df96200000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff9091169063f65df96290610dea90889088908890600401611753565b600060405180830381600087803b158015610e0457600080fd5b505af1158015610e18573d6000803e3d6000fd5b505050505b6040805187815260208101879052338183015290517fbeb513e532542a562ac35699e7cd9ae7d198dcd3eee15bada6c857d28ceaddcf9181900360600190a1505050505050565b610e6c610eff565b6004805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff000000000000000000000000000000000000000083168117909355604080519190921680825260208201939093527f953e92b1a6442e9c3242531154a3f6f6eb00b4e9c719ba8118fa6235e4ce89b69101610401565b610ef3610eff565b610efc816110b3565b50565b60005473ffffffffffffffffffffffffffffffffffffffff163314610f80576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e6572000000000000000000006044820152606401610470565b565b60606000610f9083856117dc565b60008181526003602052604090205490915073ffffffffffffffffffffffffffffffffffffffff1680610ff2576040517fb151802b00000000000000000000000000000000000000000000000000000000815260048101839052602401610470565b6040517f3d3ac1b500000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff821690633d3ac1b59061104890889088903390600401611719565b6000604051808303816000875af1158015611067573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201604052610c359190810190611818565b92915050565b3373ffffffffffffffffffffffffffffffffffffffff821603611132576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c660000000000000000006044820152606401610470565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b60005b838110156111c35781810151838201526020016111ab565b50506000910152565b600081518084526111e48160208601602086016111a8565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b60208152600061122960208301846111cc565b9392505050565b73ffffffffffffffffffffffffffffffffffffffff81168114610efc57600080fd5b60006020828403121561126457600080fd5b813561122981611230565b60006020828403121561128157600080fd5b5035919050565b6000806020838503121561129b57600080fd5b823567ffffffffffffffff808211156112b357600080fd5b818501915085601f8301126112c757600080fd5b8135818111156112d657600080fd5b8660208260051b85010111156112eb57600080fd5b60209290920196919550909350505050565b6000602080830181845280855180835260408601915060408160051b870101925083870160005b82811015611370577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc088860301845261135e8583516111cc565b94509285019290850190600101611324565b5092979650505050505050565b6000806020838503121561139057600080fd5b823567ffffffffffffffff808211156113a857600080fd5b818501915085601f8301126113bc57600080fd5b8135818111156113cb57600080fd5b8660208285010111156112eb57600080fd5b600080600080606085870312156113f357600080fd5b8435935060208501359250604085013567ffffffffffffffff8082111561141957600080fd5b818701915087601f83011261142d57600080fd5b81358181111561143c57600080fd5b8860208260061b850101111561145157600080fd5b95989497505060200194505050565b8183528181602085013750600060208284010152600060207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f840116840101905092915050565b73ffffffffffffffffffffffffffffffffffffffff84168152604060208201526000610c35604083018486611460565b6000602082840312156114eb57600080fd5b8151801515811461122957600080fd5b6040808252810183905260006060600585901b8301810190830186835b878110156115c7577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa086850301835281357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe18a360301811261157957600080fd5b8901602081810191359067ffffffffffffffff82111561159857600080fd5b8136038313156115a757600080fd5b6115b2878385611460565b96509485019493909301925050600101611518565b50505073ffffffffffffffffffffffffffffffffffffffff841660208401529050949350505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe184360301811261168357600080fd5b83018035915067ffffffffffffffff82111561169e57600080fd5b6020019150368190038213156116b357600080fd5b9250929050565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203611712577f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b5060010190565b60408152600061172d604083018587611460565b905073ffffffffffffffffffffffffffffffffffffffff83166020830152949350505050565b838152604060208083018290528282018490526000919085906060850184805b888110156117cd57843561178681611230565b73ffffffffffffffffffffffffffffffffffffffff1683528484013567ffffffffffffffff81168082146117b8578384fd5b84860152509385019391850191600101611773565b50909998505050505050505050565b803560208310156110ad577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff602084900360031b1b1692915050565b60006020828403121561182a57600080fd5b815167ffffffffffffffff8082111561184257600080fd5b818401915084601f83011261185657600080fd5b815181811115611868576118686115f0565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f011681019083821181831017156118ae576118ae6115f0565b816040528281528760208487010111156118c757600080fd5b6118d88360208301602088016111a8565b97965050505050505056fea164736f6c6343000810000a", + ABI: "[{\"inputs\":[{\"internalType\":\"contractAccessControllerInterface\",\"name\":\"accessController\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"AccessForbidden\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"BadVerification\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"configDigest\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"verifier\",\"type\":\"address\"}],\"name\":\"ConfigDigestAlreadySet\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"FeeManagerInvalid\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"verifier\",\"type\":\"address\"}],\"name\":\"VerifierAlreadyInitialized\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"VerifierInvalid\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"configDigest\",\"type\":\"bytes32\"}],\"name\":\"VerifierNotFound\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ZeroAddress\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"oldAccessController\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"newAccessController\",\"type\":\"address\"}],\"name\":\"AccessControllerSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"oldFeeManager\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"newFeeManager\",\"type\":\"address\"}],\"name\":\"FeeManagerSet\",\"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\":\"verifierAddress\",\"type\":\"address\"}],\"name\":\"VerifierInitialized\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"oldConfigDigest\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"newConfigDigest\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"verifierAddress\",\"type\":\"address\"}],\"name\":\"VerifierSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"configDigest\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"verifierAddress\",\"type\":\"address\"}],\"name\":\"VerifierUnset\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"acceptOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"configDigest\",\"type\":\"bytes32\"}],\"name\":\"getVerifier\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"verifierAddress\",\"type\":\"address\"}],\"name\":\"initializeVerifier\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_accessController\",\"outputs\":[{\"internalType\":\"contractAccessControllerInterface\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_feeManager\",\"outputs\":[{\"internalType\":\"contractIVerifierFeeManager\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"contractAccessControllerInterface\",\"name\":\"accessController\",\"type\":\"address\"}],\"name\":\"setAccessController\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"contractIVerifierFeeManager\",\"name\":\"feeManager\",\"type\":\"address\"}],\"name\":\"setFeeManager\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"currentConfigDigest\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"newConfigDigest\",\"type\":\"bytes32\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"addr\",\"type\":\"address\"},{\"internalType\":\"uint64\",\"name\":\"weight\",\"type\":\"uint64\"}],\"internalType\":\"structCommon.AddressAndWeight[]\",\"name\":\"addressesAndWeights\",\"type\":\"tuple[]\"}],\"name\":\"setVerifier\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"typeAndVersion\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"configDigest\",\"type\":\"bytes32\"}],\"name\":\"unsetVerifier\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"payload\",\"type\":\"bytes\"}],\"name\":\"verify\",\"outputs\":[{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes[]\",\"name\":\"payloads\",\"type\":\"bytes[]\"}],\"name\":\"verifyBulk\",\"outputs\":[{\"internalType\":\"bytes[]\",\"name\":\"verifiedReports\",\"type\":\"bytes[]\"}],\"stateMutability\":\"payable\",\"type\":\"function\"}]", + Bin: "0x60806040523480156200001157600080fd5b5060405162001c6138038062001c61833981016040819052620000349162000193565b33806000816200008b5760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b0384811691909117909155811615620000be57620000be81620000e8565b5050600480546001600160a01b0319166001600160a01b03939093169290921790915550620001c5565b336001600160a01b03821603620001425760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c66000000000000000000604482015260640162000082565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b600060208284031215620001a657600080fd5b81516001600160a01b0381168114620001be57600080fd5b9392505050565b611a8c80620001d56000396000f3fe6080604052600436106100dd5760003560e01c80638da5cb5b1161007f578063b011b24711610059578063b011b2471461028e578063eeb7b248146102ae578063f08391d8146102f1578063f2fde38b1461031157600080fd5b80638da5cb5b146102235780638e760afe1461024e57806394ba28461461026157600080fd5b80636e914094116100bb5780636e914094146101ae57806379ba5097146101ce57806383490cd7146101e35780638c2a4d531461020357600080fd5b8063181f5a77146100e257806338416b5b1461013a578063472d35b91461018c575b600080fd5b3480156100ee57600080fd5b5060408051808201909152601381527f566572696669657250726f787920312e312e300000000000000000000000000060208201525b60405161013191906113b2565b60405180910390f35b34801561014657600080fd5b506005546101679073ffffffffffffffffffffffffffffffffffffffff1681565b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610131565b34801561019857600080fd5b506101ac6101a73660046113ee565b610331565b005b3480156101ba57600080fd5b506101ac6101c936600461140b565b6105a9565b3480156101da57600080fd5b506101ac61069a565b6101f66101f1366004611424565b610797565b6040516101319190611499565b34801561020f57600080fd5b506101ac61021e3660046113ee565b6109f5565b34801561022f57600080fd5b5060005473ffffffffffffffffffffffffffffffffffffffff16610167565b61012461025c366004611519565b610c26565b34801561026d57600080fd5b506004546101679073ffffffffffffffffffffffffffffffffffffffff1681565b34801561029a57600080fd5b506101ac6102a9366004611579565b610dda565b3480156102ba57600080fd5b506101676102c936600461140b565b60009081526003602052604090205473ffffffffffffffffffffffffffffffffffffffff1690565b3480156102fd57600080fd5b506101ac61030c3660046113ee565b611000565b34801561031d57600080fd5b506101ac61032c3660046113ee565b611087565b61033961109b565b73ffffffffffffffffffffffffffffffffffffffff8116610386576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040517f01ffc9a70000000000000000000000000000000000000000000000000000000081527ff1387e1600000000000000000000000000000000000000000000000000000000600482015273ffffffffffffffffffffffffffffffffffffffff8216906301ffc9a790602401602060405180830381865afa158015610410573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061043491906115fc565b15806104eb57506040517f01ffc9a70000000000000000000000000000000000000000000000000000000081527f40d7f78e00000000000000000000000000000000000000000000000000000000600482015273ffffffffffffffffffffffffffffffffffffffff8216906301ffc9a790602401602060405180830381865afa1580156104c5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104e991906115fc565b155b15610522576040517f8238941900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6005805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff000000000000000000000000000000000000000083168117909355604080519190921680825260208201939093527f04628abcaa6b1674651352125cb94b65b289145bc2bc4d67720bb7d966372f0391015b60405180910390a15050565b6105b161109b565b60008181526003602052604090205473ffffffffffffffffffffffffffffffffffffffff1680610615576040517fb151802b000000000000000000000000000000000000000000000000000000008152600481018390526024015b60405180910390fd5b6000828152600360205260409081902080547fffffffffffffffffffffffff0000000000000000000000000000000000000000169055517f11dc15c4b8ac2b183166cc8427e5385a5ece8308217a4217338c6a7614845c4c9061059d908490849091825273ffffffffffffffffffffffffffffffffffffffff16602082015260400190565b60015473ffffffffffffffffffffffffffffffffffffffff16331461071b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e657200000000000000000000604482015260640161060c565b60008054337fffffffffffffffffffffffff00000000000000000000000000000000000000008083168217845560018054909116905560405173ffffffffffffffffffffffffffffffffffffffff90921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b60045460609073ffffffffffffffffffffffffffffffffffffffff16801580159061085757506040517f6b14daf800000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff821690636b14daf8906108149033906000903690600401611667565b602060405180830381865afa158015610831573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061085591906115fc565b155b1561088e576040517fef67f5d800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60055473ffffffffffffffffffffffffffffffffffffffff168015610938576040517f40d7f78e00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8216906340d7f78e90349061090590899089903390600401611697565b6000604051808303818588803b15801561091e57600080fd5b505af1158015610932573d6000803e3d6000fd5b50505050505b8367ffffffffffffffff8111156109515761095161178c565b60405190808252806020026020018201604052801561098457816020015b606081526020019060019003908161096f5790505b50925060005b848110156109ec576109be8686838181106109a7576109a76117bb565b90506020028101906109b991906117ea565b61111e565b8482815181106109d0576109d06117bb565b6020026020010181905250806109e590611856565b905061098a565b50505092915050565b6109fd61109b565b8073ffffffffffffffffffffffffffffffffffffffff8116610a4b576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040517f01ffc9a70000000000000000000000000000000000000000000000000000000081527f3d3ac1b500000000000000000000000000000000000000000000000000000000600482015273ffffffffffffffffffffffffffffffffffffffff8216906301ffc9a790602401602060405180830381865afa158015610ad5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610af991906115fc565b610b2f576040517f75b0527a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff821660009081526002602052604090205460ff1615610ba7576040517f4e01ccfd00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8316600482015260240161060c565b73ffffffffffffffffffffffffffffffffffffffff821660008181526002602090815260409182902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016600117905590519182527f1f2cd7c97f4d801b5efe26cc409617c1fd6c5ef786e79aacb90af40923e4e8e9910161059d565b60045460609073ffffffffffffffffffffffffffffffffffffffff168015801590610ce657506040517f6b14daf800000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff821690636b14daf890610ca39033906000903690600401611667565b602060405180830381865afa158015610cc0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ce491906115fc565b155b15610d1d576040517fef67f5d800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60055473ffffffffffffffffffffffffffffffffffffffff168015610dc7576040517ff1387e1600000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff82169063f1387e16903490610d94908990899033906004016118b5565b6000604051808303818588803b158015610dad57600080fd5b505af1158015610dc1573d6000803e3d6000fd5b50505050505b610dd1858561111e565b95945050505050565b600083815260036020526040902054839073ffffffffffffffffffffffffffffffffffffffff168015610e58576040517f375d1fe60000000000000000000000000000000000000000000000000000000081526004810183905273ffffffffffffffffffffffffffffffffffffffff8216602482015260440161060c565b3360009081526002602052604090205460ff16610ea1576040517fef67f5d800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600085815260036020526040902080547fffffffffffffffffffffffff000000000000000000000000000000000000000016331790558215610fb95760055473ffffffffffffffffffffffffffffffffffffffff16610f2c576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6005546040517ff65df96200000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff9091169063f65df96290610f86908890889088906004016118ef565b600060405180830381600087803b158015610fa057600080fd5b505af1158015610fb4573d6000803e3d6000fd5b505050505b6040805187815260208101879052338183015290517fbeb513e532542a562ac35699e7cd9ae7d198dcd3eee15bada6c857d28ceaddcf9181900360600190a1505050505050565b61100861109b565b6004805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff000000000000000000000000000000000000000083168117909355604080519190921680825260208201939093527f953e92b1a6442e9c3242531154a3f6f6eb00b4e9c719ba8118fa6235e4ce89b6910161059d565b61108f61109b565b6110988161124f565b50565b60005473ffffffffffffffffffffffffffffffffffffffff16331461111c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e657200000000000000000000604482015260640161060c565b565b6060600061112c8385611978565b60008181526003602052604090205490915073ffffffffffffffffffffffffffffffffffffffff168061118e576040517fb151802b0000000000000000000000000000000000000000000000000000000081526004810183905260240161060c565b6040517f3d3ac1b500000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff821690633d3ac1b5906111e4908890889033906004016118b5565b6000604051808303816000875af1158015611203573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201604052610dd191908101906119b4565b92915050565b3373ffffffffffffffffffffffffffffffffffffffff8216036112ce576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c66000000000000000000604482015260640161060c565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b60005b8381101561135f578181015183820152602001611347565b50506000910152565b60008151808452611380816020860160208601611344565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b6020815260006113c56020830184611368565b9392505050565b73ffffffffffffffffffffffffffffffffffffffff8116811461109857600080fd5b60006020828403121561140057600080fd5b81356113c5816113cc565b60006020828403121561141d57600080fd5b5035919050565b6000806020838503121561143757600080fd5b823567ffffffffffffffff8082111561144f57600080fd5b818501915085601f83011261146357600080fd5b81358181111561147257600080fd5b8660208260051b850101111561148757600080fd5b60209290920196919550909350505050565b6000602080830181845280855180835260408601915060408160051b870101925083870160005b8281101561150c577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc08886030184526114fa858351611368565b945092850192908501906001016114c0565b5092979650505050505050565b6000806020838503121561152c57600080fd5b823567ffffffffffffffff8082111561154457600080fd5b818501915085601f83011261155857600080fd5b81358181111561156757600080fd5b86602082850101111561148757600080fd5b6000806000806060858703121561158f57600080fd5b8435935060208501359250604085013567ffffffffffffffff808211156115b557600080fd5b818701915087601f8301126115c957600080fd5b8135818111156115d857600080fd5b8860208260061b85010111156115ed57600080fd5b95989497505060200194505050565b60006020828403121561160e57600080fd5b815180151581146113c557600080fd5b8183528181602085013750600060208284010152600060207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f840116840101905092915050565b73ffffffffffffffffffffffffffffffffffffffff84168152604060208201526000610dd160408301848661161e565b6040808252810183905260006060600585901b8301810190830186835b87811015611763577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa086850301835281357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe18a360301811261171557600080fd5b8901602081810191359067ffffffffffffffff82111561173457600080fd5b81360383131561174357600080fd5b61174e87838561161e565b965094850194939093019250506001016116b4565b50505073ffffffffffffffffffffffffffffffffffffffff841660208401529050949350505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe184360301811261181f57600080fd5b83018035915067ffffffffffffffff82111561183a57600080fd5b60200191503681900382131561184f57600080fd5b9250929050565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82036118ae577f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b5060010190565b6040815260006118c960408301858761161e565b905073ffffffffffffffffffffffffffffffffffffffff83166020830152949350505050565b838152604060208083018290528282018490526000919085906060850184805b88811015611969578435611922816113cc565b73ffffffffffffffffffffffffffffffffffffffff1683528484013567ffffffffffffffff8116808214611954578384fd5b8486015250938501939185019160010161190f565b50909998505050505050505050565b80356020831015611249577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff602084900360031b1b1692915050565b6000602082840312156119c657600080fd5b815167ffffffffffffffff808211156119de57600080fd5b818401915084601f8301126119f257600080fd5b815181811115611a0457611a0461178c565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f01168101908382118183101715611a4a57611a4a61178c565b81604052828152876020848701011115611a6357600080fd5b611a74836020830160208801611344565b97965050505050505056fea164736f6c6343000810000a", } var VerifierProxyABI = VerifierProxyMetaData.ABI 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 7e7819a6cab..997207960b4 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,9 +1,9 @@ GETH_VERSION: 1.12.0 errored_verifier: ../../../contracts/solc/v0.8.16/ErroredVerifier.abi ../../../contracts/solc/v0.8.16/ErroredVerifier.bin 510d18a58bfda646be35e46491baf73041eb333a349615465b20e2b5b41c5f73 exposed_verifier: ../../../contracts/solc/v0.8.16/ExposedVerifier.abi ../../../contracts/solc/v0.8.16/ExposedVerifier.bin 6932cea8f2738e874d3ec9e1a4231d2421704030c071d9e15dd2f7f08482c246 -fee_manager: ../../../contracts/solc/v0.8.16/FeeManager.abi ../../../contracts/solc/v0.8.16/FeeManager.bin bdae30fb942324e29ea99513fe1aadb705152bf5ac3dd411e8f31d24d99b7bc8 +fee_manager: ../../../contracts/solc/v0.8.16/FeeManager.abi ../../../contracts/solc/v0.8.16/FeeManager.bin 2c22cbfb24374f645eef8a368f30d1821e350501742118eebd0fa3e8bcbc4d29 llo_feeds: ../../../contracts/solc/v0.8.16/FeeManager.abi ../../../contracts/solc/v0.8.16/FeeManager.bin cb71e018f67e49d7bc0e194c822204dfd59f79ff42e4fc8fd8ab63f3acd71361 llo_feeds_test: ../../../contracts/solc/v0.8.16/ExposedVerifier.abi ../../../contracts/solc/v0.8.16/ExposedVerifier.bin 6932cea8f2738e874d3ec9e1a4231d2421704030c071d9e15dd2f7f08482c246 -reward_manager: ../../../contracts/solc/v0.8.16/RewardManager.abi ../../../contracts/solc/v0.8.16/RewardManager.bin 87ff86cc1e15b9f291b6cdc8e1cc2d884f49d0555a03e1ab3da5bbfeaa0273fd +reward_manager: ../../../contracts/solc/v0.8.16/RewardManager.abi ../../../contracts/solc/v0.8.16/RewardManager.bin 8b163eb0537180accfa69beea298890f1605c8d9f776689ea26802eefda46457 verifier: ../../../contracts/solc/v0.8.16/Verifier.abi ../../../contracts/solc/v0.8.16/Verifier.bin 135206eccb805c267392c398df385aa51b22db4d4c59fa1f31f0e5b0a607c812 -verifier_proxy: ../../../contracts/solc/v0.8.16/VerifierProxy.abi ../../../contracts/solc/v0.8.16/VerifierProxy.bin ffe46f650ac7e8389102596339fb060d5ca5b695efc462cae031dc1f102d2571 +verifier_proxy: ../../../contracts/solc/v0.8.16/VerifierProxy.abi ../../../contracts/solc/v0.8.16/VerifierProxy.bin 92ad0416e999e9d55e4f00a8b7df616bb69ae27ce52994a6061598e95364d2cc diff --git a/core/internal/testutils/evmtest/evmtest.go b/core/internal/testutils/evmtest/evmtest.go index 43502ea35ec..4532e79ac07 100644 --- a/core/internal/testutils/evmtest/evmtest.go +++ b/core/internal/testutils/evmtest/evmtest.go @@ -34,6 +34,7 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/keystore" "github.com/smartcontractkit/chainlink/v2/core/services/pg" + "github.com/smartcontractkit/chainlink/v2/core/services/relay" evmrelay "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm" "github.com/smartcontractkit/chainlink/v2/core/services/srvctest" "github.com/smartcontractkit/chainlink/v2/core/utils" @@ -150,9 +151,9 @@ func (mo *TestConfigs) PutChains(cs ...evmtoml.EVMConfig) { defer mo.mu.Unlock() chains: for i := range cs { - id := cs[i].ChainID.String() + id := cs[i].ChainID for j, c2 := range mo.EVMConfigs { - if c2.ChainID.String() == id { + if c2.ChainID == id { mo.EVMConfigs[j] = &cs[i] // replace continue chains } @@ -161,7 +162,7 @@ chains: } } -func (mo *TestConfigs) Chains(offset int, limit int, ids ...string) (cs []types.ChainStatus, count int, err error) { +func (mo *TestConfigs) Chains(ids ...relay.ChainID) (cs []types.ChainStatus, count int, err error) { mo.mu.RLock() defer mo.mu.RUnlock() if len(ids) == 0 { @@ -200,19 +201,19 @@ func (mo *TestConfigs) Chains(offset int, limit int, ids ...string) (cs []types. } // Nodes implements evmtypes.Configs -func (mo *TestConfigs) Nodes(chainID utils.Big) (nodes []evmtypes.Node, err error) { +func (mo *TestConfigs) Nodes(id relay.ChainID) (nodes []evmtypes.Node, err error) { mo.mu.RLock() defer mo.mu.RUnlock() for i := range mo.EVMConfigs { c := mo.EVMConfigs[i] - if chainID.Cmp(c.ChainID) == 0 { + if id == c.ChainID.String() { for _, n := range c.Nodes { nodes = append(nodes, legacyNode(n, c.ChainID)) } } } - err = fmt.Errorf("no nodes: chain %s: %w", chainID.String(), chains.ErrNotFound) + err = fmt.Errorf("no nodes: chain %s: %w", id, chains.ErrNotFound) return } diff --git a/core/scripts/chaincli/command/keeper/launch.go b/core/scripts/chaincli/command/keeper/launch.go index 7e4c79f70d2..e918095edb4 100644 --- a/core/scripts/chaincli/command/keeper/launch.go +++ b/core/scripts/chaincli/command/keeper/launch.go @@ -47,7 +47,7 @@ var launchAndTestCmd = &cobra.Command{ func init() { launchAndTestCmd.Flags().BoolP("withdraw", "w", true, "Specify if funds should be withdrawn and upkeeps should be canceled") - launchAndTestCmd.Flags().BoolP("bootstrap", "b", true, "Specify if launching bootstrap node is required. Default listen ports(5688, 8000) are used, if you need to use custom ports, please use bootstrap command") + launchAndTestCmd.Flags().BoolP("bootstrap", "b", false, "Specify if launching bootstrap node is required. Default listen ports(5688, 8000) are used, if you need to use custom ports, please use bootstrap command") launchAndTestCmd.Flags().BoolP("export-logs", "l", false, "Specify if container logs should be exported to ./") launchAndTestCmd.Flags().BoolP("force", "f", false, "Specify if existing containers should be forcefully removed ./") } diff --git a/core/scripts/chaincli/handler/keeper_deployer.go b/core/scripts/chaincli/handler/keeper_deployer.go index 089b176695c..eae8c68d332 100644 --- a/core/scripts/chaincli/handler/keeper_deployer.go +++ b/core/scripts/chaincli/handler/keeper_deployer.go @@ -14,6 +14,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" ocr2config "github.com/smartcontractkit/libocr/offchainreporting2plus/confighelper" + ocr3confighelper "github.com/smartcontractkit/libocr/offchainreporting2plus/ocr3confighelper" ocr2types "github.com/smartcontractkit/libocr/offchainreporting2plus/types" "github.com/umbracle/ethgo/abi" @@ -297,11 +298,13 @@ func (d *v21KeeperDeployer) SetKeepers(opts *bind.TransactOpts, cls []cmd.HTTPCl panic(err) } - signerOnchainPublicKeys, transmitterAccounts, f, _, offchainConfigVersion, offchainConfig, err := ocr2config.ContractSetConfigArgsForTests( + signerOnchainPublicKeys, transmitterAccounts, f, _, offchainConfigVersion, offchainConfig, err := ocr3confighelper.ContractSetConfigArgsForTests( 5*time.Second, // deltaProgress time.Duration, 10*time.Second, // deltaResend time.Duration, + 400*time.Millisecond, // deltaInitial time.Duration, 2500*time.Millisecond, // deltaRound time.Duration, 40*time.Millisecond, // deltaGrace time.Duration, + 300*time.Millisecond, // deltaCertifiedCommitRequest time.Duration, 30*time.Second, // deltaStage time.Duration, 50, // rMax uint8, S, // s []int, @@ -309,7 +312,6 @@ func (d *v21KeeperDeployer) SetKeepers(opts *bind.TransactOpts, cls []cmd.HTTPCl offC, // reportingPluginConfig []byte, 20*time.Millisecond, // maxDurationQuery time.Duration, 1600*time.Millisecond, // maxDurationObservation time.Duration, - 800*time.Millisecond, // maxDurationReport time.Duration, 20*time.Millisecond, // maxDurationShouldAcceptFinalizedReport time.Duration, 20*time.Millisecond, // maxDurationShouldTransmitAcceptedReport time.Duration, 1, // f int, diff --git a/core/scripts/chaincli/handler/keeper_launch.go b/core/scripts/chaincli/handler/keeper_launch.go index fb975b48369..83ee6a77129 100644 --- a/core/scripts/chaincli/handler/keeper_launch.go +++ b/core/scripts/chaincli/handler/keeper_launch.go @@ -347,6 +347,7 @@ name = "ocr2-automation" forwardingAllowed = false schemaVersion = 1 contractID = "%s" +contractConfigTrackerPollInterval = "15s" ocrKeyBundleID = "%s" transmitterID = "%s" p2pv2Bootstrappers = [ @@ -358,6 +359,8 @@ chainID = %d [pluginConfig] maxServiceWorkers = 100 +cacheEvictionInterval = "1s" +contractVersion = "%s" mercuryCredentialName = "%s"` // createOCR2KeeperJob creates an ocr2keeper job in the chainlink node by the given address @@ -367,6 +370,12 @@ func (k *Keeper) createOCR2KeeperJob(client cmd.HTTPClient, contractAddr, nodeAd return fmt.Errorf("failed to get node OCR2 key bundle ID: %s", err) } + // Correctly assign contract version in OCR job spec. + var contractVersion string = "v2.0" + if k.cfg.RegistryVersion == keeper.RegistryVersion_2_1 { + contractVersion = "v2.1" + } + request, err := json.Marshal(web.CreateJobRequest{ TOML: fmt.Sprintf(ocr2keeperJobTemplate, contractAddr, // contractID @@ -374,6 +383,7 @@ func (k *Keeper) createOCR2KeeperJob(client cmd.HTTPClient, contractAddr, nodeAd 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 ), }) diff --git a/core/scripts/chaincli/handler/keeper_verifiable_load.go b/core/scripts/chaincli/handler/keeper_verifiable_load.go index ad704393877..429a7620079 100644 --- a/core/scripts/chaincli/handler/keeper_verifiable_load.go +++ b/core/scripts/chaincli/handler/keeper_verifiable_load.go @@ -37,7 +37,7 @@ type upkeepInfo struct { } type verifiableLoad interface { - GetActiveUpkeepIDs(opts *bind.CallOpts, startIndex *big.Int, maxCount *big.Int) ([]*big.Int, error) + GetAllActiveUpkeepIDsOnRegistry(opts *bind.CallOpts, startIndex *big.Int, maxCount *big.Int) ([]*big.Int, error) Counters(opts *bind.CallOpts, upkeepId *big.Int) (*big.Int, error) GetBucketedDelays(opts *bind.CallOpts, upkeepId *big.Int, bucket uint16) ([]*big.Int, error) Buckets(opts *bind.CallOpts, arg0 *big.Int) (uint16, error) @@ -79,7 +79,7 @@ func (k *Keeper) GetVerifiableLoadStats(ctx context.Context) { } // get all active upkeep IDs on this verifiable load contract - upkeepIds, err := v.GetActiveUpkeepIDs(opts, big.NewInt(0), big.NewInt(0)) + upkeepIds, err := v.GetAllActiveUpkeepIDsOnRegistry(opts, big.NewInt(0), big.NewInt(0)) if err != nil { log.Fatalf("failed to get active upkeep IDs from %s: %v", k.cfg.VerifiableLoadContractAddress, err) } diff --git a/core/scripts/functions/src/generate_jobspecs_cmd.go b/core/scripts/functions/src/generate_jobspecs_cmd.go index 332e2bdc0cb..4f35dac51bd 100644 --- a/core/scripts/functions/src/generate_jobspecs_cmd.go +++ b/core/scripts/functions/src/generate_jobspecs_cmd.go @@ -31,6 +31,8 @@ func (g *generateJobSpecs) Run(args []string) { donID := fs.String("donid", "", "don id string") routerAddress := fs.String("contract", "", "router contract address") truncateHostname := fs.Bool("truncateboothostname", false, "truncate host name to first segment (needed for staging DONs)") + gatewayID := fs.String("gatewayid", "", "gateway id string") + gatewayURL := fs.String("gatewayurl", "", "gateway url string") err := fs.Parse(args) if err != nil || nodesFile == nil || *nodesFile == "" || routerAddress == nil || *routerAddress == "" { fs.Usage() @@ -45,7 +47,7 @@ func (g *generateJobSpecs) Run(args []string) { helpers.PanicErr(err) bootHost := nodes[0].url.Host - lines = replacePlaceholders(lines, *donID, *chainID, *p2pPort, *routerAddress, bootHost, &bootstrapNode, &bootstrapNode, *truncateHostname) + lines = replacePlaceholders(lines, *donID, *chainID, *p2pPort, *routerAddress, bootHost, &bootstrapNode, &bootstrapNode, *truncateHostname, *gatewayID, *gatewayURL) outputPath := filepath.Join(artefactsDir, bootHost+".toml") err = writeLines(lines, outputPath) helpers.PanicErr(err) @@ -54,7 +56,7 @@ func (g *generateJobSpecs) Run(args []string) { lines, err = readLines(filepath.Join(templatesDir, oracleSpecTemplate)) helpers.PanicErr(err) for i := 1; i < len(nodes); i++ { - oracleLines := replacePlaceholders(lines, *donID, *chainID, *p2pPort, *routerAddress, bootHost, &bootstrapNode, &nca[i], *truncateHostname) + oracleLines := replacePlaceholders(lines, *donID, *chainID, *p2pPort, *routerAddress, bootHost, &bootstrapNode, &nca[i], *truncateHostname, *gatewayID, *gatewayURL) outputPath := filepath.Join(artefactsDir, nodes[i].url.Host+".toml") err = writeLines(oracleLines, outputPath) helpers.PanicErr(err) @@ -62,7 +64,7 @@ func (g *generateJobSpecs) Run(args []string) { } } -func replacePlaceholders(lines []string, donID string, chainID, p2pPort int64, routerAddress, bootHost string, boot *NodeKeys, node *NodeKeys, truncateHostname bool) (output []string) { +func replacePlaceholders(lines []string, donID string, chainID, p2pPort int64, routerAddress, bootHost string, boot *NodeKeys, node *NodeKeys, truncateHostname bool, gatewayID string, gatewayURL string) (output []string) { chainIDStr := strconv.FormatInt(chainID, 10) if truncateHostname { bootHost = bootHost[:strings.IndexByte(bootHost, '.')] @@ -77,6 +79,8 @@ func replacePlaceholders(lines []string, donID string, chainID, p2pPort int64, r l = strings.Replace(l, "{{p2p_bootstrapper}}", bootstrapper, 1) l = strings.Replace(l, "{{timestamp}}", ts, 1) l = strings.Replace(l, "{{don_id}}", donID, 1) + l = strings.Replace(l, "{{gateway_id}}", gatewayID, 1) + l = strings.Replace(l, "{{gateway_url}}", gatewayURL, 1) output = append(output, l) } return diff --git a/core/scripts/functions/templates/oracle.toml b/core/scripts/functions/templates/oracle.toml index 092965ca7a5..208637b50fc 100644 --- a/core/scripts/functions/templates/oracle.toml +++ b/core/scripts/functions/templates/oracle.toml @@ -67,4 +67,8 @@ maxSecretsSizesList = [10_240, 20_480, 51_200, 102_400, 307_200, 512_000, 1_048_ NodeAddress = "{{node_eth_address}}" [pluginConfig.gatewayConnectorConfig.WsClientConfig] - HandshakeTimeoutMillis = 1_000 \ No newline at end of file + HandshakeTimeoutMillis = 1_000 + + [[pluginConfig.gatewayConnectorConfig.Gateways]] + Id = "{{gateway_id}}" + URL = "{{gateway_url}}" \ No newline at end of file diff --git a/core/scripts/go.mod b/core/scripts/go.mod index d9f2cc7c9c3..cfdcdf648e1 100644 --- a/core/scripts/go.mod +++ b/core/scripts/go.mod @@ -19,7 +19,7 @@ require ( github.com/shopspring/decimal v1.3.1 github.com/smartcontractkit/chainlink/v2 v2.0.0-00010101000000-000000000000 github.com/smartcontractkit/libocr v0.0.0-20230816220705-665e93233ae5 - github.com/smartcontractkit/ocr2keepers v0.7.19 + github.com/smartcontractkit/ocr2keepers v0.7.23 github.com/smartcontractkit/ocr2vrf v0.0.0-20230804151440-2f1eb1e20687 github.com/smartcontractkit/sqlx v1.3.5-0.20210805004948-4be295aacbeb github.com/spf13/cobra v1.6.1 @@ -98,6 +98,7 @@ require ( github.com/docker/go-units v0.5.0 // indirect 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/fatih/color v1.15.0 // indirect github.com/flynn/noise v0.0.0-20180327030543-2492fe189ae6 // indirect github.com/fsnotify/fsnotify v1.6.0 // indirect @@ -298,11 +299,11 @@ require ( 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.20230831132059-42af68994512 // indirect - github.com/smartcontractkit/chainlink-relay v0.1.7-0.20230901143551-bf6bd84d6938 // indirect + github.com/smartcontractkit/chainlink-relay v0.1.7-0.20230908162043-e2f9fcf758d8 // indirect github.com/smartcontractkit/chainlink-solana v1.0.3-0.20230831134610-680240b97aca // indirect github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20230901115736-bbabe542a918 // indirect - github.com/smartcontractkit/tdh2/go/ocr2/decryptionplugin v0.0.0-20230829114801-14bf715f805e // indirect - github.com/smartcontractkit/tdh2/go/tdh2 v0.0.0-20230829114801-14bf715f805e // 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 github.com/spacemonkeygo/spacelog v0.0.0-20180420211403-2296661a0572 // indirect github.com/spaolacci/murmur3 v1.1.0 // indirect diff --git a/core/scripts/go.sum b/core/scripts/go.sum index 26a31aafde8..8ef1604eecb 100644 --- a/core/scripts/go.sum +++ b/core/scripts/go.sum @@ -320,6 +320,8 @@ github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.m github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/envoyproxy/protoc-gen-validate v1.0.2 h1:QkIBuU5k+x7/QXPvPPnWXWlCdaBFApVqftFV6k087DA= +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/go-ethereum v1.12.0 h1:bdnhLPtqETd4m3mS8BGMNvBTf36bO5bx/hxE2zljOa0= github.com/ethereum/go-ethereum v1.12.0/go.mod h1:/oo2X/dZLJjf2mJ6YT9wcWxa4nNJDBKDBU6sFIpx1Gs= @@ -1375,8 +1377,8 @@ github.com/smartcontractkit/caigo v0.0.0-20230621050857-b29a4ca8c704 h1:T3lFWumv github.com/smartcontractkit/caigo v0.0.0-20230621050857-b29a4ca8c704/go.mod h1:2QuJdEouTWjh5BDy5o/vgGXQtR4Gz8yH1IYB5eT7u4M= github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20230831132059-42af68994512 h1:DojChlaudA1HAxwQPKmt/EDf36OUeFJ0LJBYClauMyU= github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20230831132059-42af68994512/go.mod h1:xMwqRdj5vqYhCJXgKVqvyAwdcqM6ZAEhnwEQ4Khsop8= -github.com/smartcontractkit/chainlink-relay v0.1.7-0.20230901143551-bf6bd84d6938 h1:LnxS4RoDcUS4+zXoY/gaV4BB6u90DgW3LtyFCoCpJzY= -github.com/smartcontractkit/chainlink-relay v0.1.7-0.20230901143551-bf6bd84d6938/go.mod h1:gWclxGW7rLkbjXn7FGizYlyKhp/boekto4MEYGyiMG4= +github.com/smartcontractkit/chainlink-relay v0.1.7-0.20230908162043-e2f9fcf758d8 h1:JRXkI/eE1S0E3VatXVc24vD5e8Zu+YwSV6uSvOh23xU= +github.com/smartcontractkit/chainlink-relay v0.1.7-0.20230908162043-e2f9fcf758d8/go.mod h1:gWclxGW7rLkbjXn7FGizYlyKhp/boekto4MEYGyiMG4= github.com/smartcontractkit/chainlink-solana v1.0.3-0.20230831134610-680240b97aca h1:x7M0m512gtXw5Z4B1WJPZ52VgshoIv+IvHqQ8hsH4AE= github.com/smartcontractkit/chainlink-solana v1.0.3-0.20230831134610-680240b97aca/go.mod h1:RIUJXn7EVp24TL2p4FW79dYjyno23x5mjt1nKN+5WEk= github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20230901115736-bbabe542a918 h1:ByVauKFXphRlSNG47lNuxZ9aicu+r8AoNp933VRPpCw= @@ -1387,16 +1389,16 @@ github.com/smartcontractkit/grpc-proxy v0.0.0-20230731113816-f1be6620749f h1:hgJ github.com/smartcontractkit/grpc-proxy v0.0.0-20230731113816-f1be6620749f/go.mod h1:MvMXoufZAtqExNexqi4cjrNYE9MefKddKylxjS+//n0= github.com/smartcontractkit/libocr v0.0.0-20230816220705-665e93233ae5 h1:rzbqGoScs9VHGnyCKF7AoQEuUfwJnzcKmGIfaczeanA= github.com/smartcontractkit/libocr v0.0.0-20230816220705-665e93233ae5/go.mod h1:2lyRkw/qLQgUWlrWWmq5nj0y90rWeO6Y+v+fCakRgb0= -github.com/smartcontractkit/ocr2keepers v0.7.19 h1:w9CMs1V8pmxdRX6ME98goIRPMuN9DOkfMmZHeDPDQXY= -github.com/smartcontractkit/ocr2keepers v0.7.19/go.mod h1:AjcIEKeNnU7NRlvnuMCTjBIQ1kpW0YHhlFdeDa/3hs0= +github.com/smartcontractkit/ocr2keepers v0.7.23 h1:hvMCHm9zTOKGELc40n+JLGmbiW1tkFnHW17qAtoVews= +github.com/smartcontractkit/ocr2keepers v0.7.23/go.mod h1:AjcIEKeNnU7NRlvnuMCTjBIQ1kpW0YHhlFdeDa/3hs0= github.com/smartcontractkit/ocr2vrf v0.0.0-20230804151440-2f1eb1e20687 h1:NwC3SOc25noBTe1KUQjt45fyTIuInhoE2UfgcHAdihM= github.com/smartcontractkit/ocr2vrf v0.0.0-20230804151440-2f1eb1e20687/go.mod h1:YYZq52t4wcHoMQeITksYsorD+tZcOyuVU5+lvot3VFM= github.com/smartcontractkit/sqlx v1.3.5-0.20210805004948-4be295aacbeb h1:OMaBUb4X9IFPLbGbCHsMU+kw/BPCrewaVwWGIBc0I4A= github.com/smartcontractkit/sqlx v1.3.5-0.20210805004948-4be295aacbeb/go.mod h1:HNUu4cJekUdsJbwRBCiOybtkPJEfGRELQPe2tkoDEyk= -github.com/smartcontractkit/tdh2/go/ocr2/decryptionplugin v0.0.0-20230829114801-14bf715f805e h1:faa7bAs8xCVsnJoNmAtV18la0wqBoaWSWFqNdjkPdAw= -github.com/smartcontractkit/tdh2/go/ocr2/decryptionplugin v0.0.0-20230829114801-14bf715f805e/go.mod h1:q6f4fe39oZPdsh1i57WznEZgxd8siidMaSFq3wdPmVg= -github.com/smartcontractkit/tdh2/go/tdh2 v0.0.0-20230829114801-14bf715f805e h1:JMCSFOQIYOh7zUYi9C3UQG9Lz5ECNejTURBN+Khhwz4= -github.com/smartcontractkit/tdh2/go/tdh2 v0.0.0-20230829114801-14bf715f805e/go.mod h1:G5Sd/yzHWf26rQ+X0nG9E0buKPqRGPMJAfk2gwCzOOw= +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/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= diff --git a/core/services/chainlink/config_mercury.go b/core/services/chainlink/config_mercury.go index 93d88c689b8..1a20dd069d8 100644 --- a/core/services/chainlink/config_mercury.go +++ b/core/services/chainlink/config_mercury.go @@ -11,11 +11,15 @@ type mercuryConfig struct { func (m *mercuryConfig) Credentials(credName string) *models.MercuryCredentials { if mc, ok := m.s.Credentials[credName]; ok { - return &models.MercuryCredentials{ + c := &models.MercuryCredentials{ URL: mc.URL.URL().String(), - Username: string(*mc.Username), Password: string(*mc.Password), + Username: string(*mc.Username), + } + if mc.LegacyURL != nil && mc.LegacyURL.URL() != nil { + c.LegacyURL = mc.LegacyURL.URL().String() } + return c } return nil } diff --git a/core/services/chainlink/mocks/relayer_chain_interoperators.go b/core/services/chainlink/mocks/relayer_chain_interoperators.go index f25ced6c3ca..c0eb699a492 100644 --- a/core/services/chainlink/mocks/relayer_chain_interoperators.go +++ b/core/services/chainlink/mocks/relayer_chain_interoperators.go @@ -10,7 +10,7 @@ import ( cosmos "github.com/smartcontractkit/chainlink/v2/core/chains/cosmos" evm "github.com/smartcontractkit/chainlink/v2/core/chains/evm" - + // Manually edited. mockery generates the wrong dependency. edited to use `loop` rather than `loop/internal` // seems to caused by incorrect alias resolution of the relayer dep internal "github.com/smartcontractkit/chainlink-relay/pkg/loop" @@ -160,11 +160,11 @@ func (_m *RelayerChainInteroperators) List(filter chainlink.FilterFn) chainlink. return r0 } -// NodeStatuses provides a mock function with given fields: ctx, offset, limit, chainIDs -func (_m *RelayerChainInteroperators) NodeStatuses(ctx context.Context, offset int, limit int, chainIDs ...string) ([]types.NodeStatus, int, error) { - _va := make([]interface{}, len(chainIDs)) - for _i := range chainIDs { - _va[_i] = chainIDs[_i] +// NodeStatuses provides a mock function with given fields: ctx, offset, limit, relayIDs +func (_m *RelayerChainInteroperators) NodeStatuses(ctx context.Context, offset int, limit int, relayIDs ...relay.ID) ([]types.NodeStatus, int, error) { + _va := make([]interface{}, len(relayIDs)) + for _i := range relayIDs { + _va[_i] = relayIDs[_i] } var _ca []interface{} _ca = append(_ca, ctx, offset, limit) @@ -174,25 +174,25 @@ func (_m *RelayerChainInteroperators) NodeStatuses(ctx context.Context, offset i var r0 []types.NodeStatus var r1 int var r2 error - if rf, ok := ret.Get(0).(func(context.Context, int, int, ...string) ([]types.NodeStatus, int, error)); ok { - return rf(ctx, offset, limit, chainIDs...) + if rf, ok := ret.Get(0).(func(context.Context, int, int, ...relay.ID) ([]types.NodeStatus, int, error)); ok { + return rf(ctx, offset, limit, relayIDs...) } - if rf, ok := ret.Get(0).(func(context.Context, int, int, ...string) []types.NodeStatus); ok { - r0 = rf(ctx, offset, limit, chainIDs...) + if rf, ok := ret.Get(0).(func(context.Context, int, int, ...relay.ID) []types.NodeStatus); ok { + r0 = rf(ctx, offset, limit, relayIDs...) } else { if ret.Get(0) != nil { r0 = ret.Get(0).([]types.NodeStatus) } } - if rf, ok := ret.Get(1).(func(context.Context, int, int, ...string) int); ok { - r1 = rf(ctx, offset, limit, chainIDs...) + if rf, ok := ret.Get(1).(func(context.Context, int, int, ...relay.ID) int); ok { + r1 = rf(ctx, offset, limit, relayIDs...) } else { r1 = ret.Get(1).(int) } - if rf, ok := ret.Get(2).(func(context.Context, int, int, ...string) error); ok { - r2 = rf(ctx, offset, limit, chainIDs...) + if rf, ok := ret.Get(2).(func(context.Context, int, int, ...relay.ID) error); ok { + r2 = rf(ctx, offset, limit, relayIDs...) } else { r2 = ret.Error(2) } diff --git a/core/services/chainlink/relayer_chain_interoperators.go b/core/services/chainlink/relayer_chain_interoperators.go index 65859338b6c..823d3f88c98 100644 --- a/core/services/chainlink/relayer_chain_interoperators.go +++ b/core/services/chainlink/relayer_chain_interoperators.go @@ -53,17 +53,21 @@ type LegacyChainer interface { LegacyCosmosChains() cosmos.LegacyChainContainer } -// Similar to [chains.ChainStatuser] but keyed by relay identifier instead of string -// TODO BCF-2441 remove this comment when chains.ChainStatus is no longer keyed. type ChainStatuser interface { ChainStatus(ctx context.Context, id relay.ID) (types.ChainStatus, error) ChainStatuses(ctx context.Context, offset, limit int) ([]types.ChainStatus, int, error) } +// NodesStatuser is an interface for node configuration and state. +// TODO BCF-2440, BCF-2511 may need Node(ctx,name) to get a node status by name +type NodesStatuser interface { + NodeStatuses(ctx context.Context, offset, limit int, relayIDs ...relay.ID) (nodes []types.NodeStatus, count int, err error) +} + // ChainsNodesStatuser report statuses about chains and nodes type ChainsNodesStatuser interface { ChainStatuser - chains.NodesStatuser + NodesStatuser } var _ RelayerChainInteroperators = &CoreRelayerChainInteroperators{} @@ -112,7 +116,7 @@ func InitEVM(ctx context.Context, factory RelayerFactory, config EVMFactoryConfi // adapter is a service op.srvs = append(op.srvs, a) op.loopRelayers[id] = a - legacyMap[id.ChainID.String()] = a.Chain() + legacyMap[id.ChainID] = a.Chain() if a.Default() { defaultChain = a.Chain() } @@ -139,7 +143,7 @@ func InitCosmos(ctx context.Context, factory RelayerFactory, config CosmosFactor for id, a := range adapters { op.srvs = append(op.srvs, a) op.loopRelayers[id] = a - legacyMap[id.ChainID.String()] = a.Chain() + legacyMap[id.ChainID] = a.Chain() } op.legacyChains.CosmosChains = cosmos.NewLegacyChains(legacyMap) @@ -215,14 +219,11 @@ func (rs *CoreRelayerChainInteroperators) ChainStatus(ctx context.Context, id re if err != nil { return types.ChainStatus{}, fmt.Errorf("%w: error getting chain status: %w", chains.ErrNotFound, err) } - // this call is weird because the [loop.Relayer] interface still requires id - // but in this context the `relayer` should only have only id - // moreover, the `relayer` here is pinned to one chain we need to pass the chain id - return lr.ChainStatus(ctx, id.ChainID.String()) + + return lr.GetChainStatus(ctx) } func (rs *CoreRelayerChainInteroperators) ChainStatuses(ctx context.Context, offset, limit int) ([]types.ChainStatus, int, error) { - // chain statuses are not dynamic; the call would be better named as ChainConfig or such. var ( stats []types.ChainStatus @@ -240,8 +241,7 @@ func (rs *CoreRelayerChainInteroperators) ChainStatuses(ctx context.Context, off }) for _, rid := range relayerIds { lr := rs.loopRelayers[rid] - // the relayer is chain specific; use the chain id and not the relayer id - stat, err := lr.ChainStatus(ctx, rid.ChainID.String()) + stat, err := lr.GetChainStatus(ctx) if err != nil { totalErr = errors.Join(totalErr, err) continue @@ -275,51 +275,46 @@ func (rs *CoreRelayerChainInteroperators) Node(ctx context.Context, name string) } // ids must be a string representation of relay.Identifier -// ids are a filter; if none are specificied, all are returned. -// TODO: BCF-2440/1 this signature can be changed to id relay.Identifier which is a much better API -func (rs *CoreRelayerChainInteroperators) NodeStatuses(ctx context.Context, offset, limit int, relayerIDs ...string) (nodes []types.NodeStatus, count int, err error) { +// ids are a filter; if none are specified, all are returned. +func (rs *CoreRelayerChainInteroperators) NodeStatuses(ctx context.Context, offset, limit int, relayerIDs ...relay.ID) (nodes []types.NodeStatus, count int, err error) { var ( totalErr error result []types.NodeStatus ) if len(relayerIDs) == 0 { - for rid, lr := range rs.loopRelayers { - stats, _, err := lr.NodeStatuses(ctx, offset, limit, rid.ChainID.String()) + for _, lr := range rs.loopRelayers { + stats, _, total, err := lr.ListNodeStatuses(ctx, int32(limit), "") if err != nil { totalErr = errors.Join(totalErr, err) continue } result = append(result, stats...) + count += total } } else { - for _, idStr := range relayerIDs { - rid := new(relay.ID) - err := rid.UnmarshalString(idStr) - if err != nil { - totalErr = errors.Join(totalErr, err) - continue - } - lr, exist := rs.loopRelayers[*rid] + for _, rid := range relayerIDs { + lr, exist := rs.loopRelayers[rid] if !exist { totalErr = errors.Join(totalErr, fmt.Errorf("relayer %s does not exist", rid.Name())) continue } - nodeStats, _, err := lr.NodeStatuses(ctx, offset, limit, rid.ChainID.String()) + nodeStats, _, total, err := lr.ListNodeStatuses(ctx, int32(limit), "") if err != nil { totalErr = errors.Join(totalErr, err) continue } result = append(result, nodeStats...) + count += total } } if totalErr != nil { return nil, 0, totalErr } if len(result) > limit && limit > 0 { - return result[offset : offset+limit], limit, nil + return result[offset : offset+limit], count, nil } - return result[offset:], len(result[offset:]), nil + return result[offset:], count, nil } type FilterFn func(id relay.ID) bool diff --git a/core/services/chainlink/relayer_chain_interoperators_test.go b/core/services/chainlink/relayer_chain_interoperators_test.go index 29dffd1df19..5a6e3cbcfb3 100644 --- a/core/services/chainlink/relayer_chain_interoperators_test.go +++ b/core/services/chainlink/relayer_chain_interoperators_test.go @@ -412,19 +412,19 @@ func TestCoreRelayerChainInteroperators(t *testing.T) { assert.NoError(t, err) stat, err := cr.ChainStatus(testctx, wantId) assert.NoError(t, err) - assert.Equal(t, wantId.ChainID.String(), stat.ID) + assert.Equal(t, wantId.ChainID, stat.ID) // check legacy chains for evm and cosmos if wantId.Network == relay.EVM { - c, err := cr.LegacyEVMChains().Get(wantId.ChainID.String()) + c, err := cr.LegacyEVMChains().Get(wantId.ChainID) assert.NoError(t, err) assert.NotNil(t, c) - assert.Equal(t, wantId.ChainID.String(), c.ID().String()) + assert.Equal(t, wantId.ChainID, c.ID().String()) } if wantId.Network == relay.Cosmos { - c, err := cr.LegacyCosmosChains().Get(wantId.ChainID.String()) + c, err := cr.LegacyCosmosChains().Get(wantId.ChainID) assert.NoError(t, err) assert.NotNil(t, c) - assert.Equal(t, wantId.ChainID.String(), c.ID()) + assert.Equal(t, wantId.ChainID, c.ID()) } } } diff --git a/core/services/chainlink/relayer_factory.go b/core/services/chainlink/relayer_factory.go index 4ff70a585ac..0a0d653f5fc 100644 --- a/core/services/chainlink/relayer_factory.go +++ b/core/services/chainlink/relayer_factory.go @@ -58,11 +58,11 @@ func (r *RelayerFactory) NewEVM(ctx context.Context, config EVMFactoryConfig) (m legacyChains := evmrelay.NewLegacyChainsFromRelayerExtenders(evmRelayExtenders) for _, ext := range evmRelayExtenders.Slice() { relayID := relay.ID{Network: relay.EVM, ChainID: relay.ChainID(ext.Chain().ID().String())} - chain, err := legacyChains.Get(relayID.ChainID.String()) + chain, err := legacyChains.Get(relayID.ChainID) if err != nil { return nil, err } - relayer := evmrelay.NewLoopRelayAdapter(evmrelay.NewRelayer(ccOpts.DB, chain, r.QConfig, ccOpts.Logger, config.CSAETHKeystore, ccOpts.EventBroadcaster), ext) + relayer := evmrelay.NewLoopRelayServerAdapter(evmrelay.NewRelayer(ccOpts.DB, chain, r.QConfig, ccOpts.Logger, config.CSAETHKeystore, ccOpts.EventBroadcaster), ext) relayers[relayID] = relayer } @@ -98,10 +98,6 @@ func (r *RelayerFactory) NewSolana(ks keystore.Solana, chainCfgs solana.SolanaCo continue } - // all the lower level APIs expect a config slice. create a single valued set per id - // TODO BCF-2605: clean this up - singleChainCfg := solana.SolanaConfigs{chainCfg} - if cmdName := env.SolanaPluginCmd.Get(); cmdName != "" { // setup the solana relayer to be a LOOP @@ -128,14 +124,13 @@ func (r *RelayerFactory) NewSolana(ks keystore.Solana, chainCfgs solana.SolanaCo opts := solana.ChainOpts{ Logger: solLggr, KeyStore: signer, - Configs: solana.NewConfigs(singleChainCfg), } - relayExt, err := solana.NewRelayExtender(chainCfg, opts) + chain, err := solana.NewChain(chainCfg, opts) if err != nil { return nil, err } - solanaRelayers[relayId] = relay.NewRelayerAdapter(pkgsolana.NewRelayer(solLggr, relayExt), relayExt) + solanaRelayers[relayId] = relay.NewRelayerServerAdapter(pkgsolana.NewRelayer(solLggr, chain), chain) } } return solanaRelayers, nil @@ -172,10 +167,6 @@ func (r *RelayerFactory) NewStarkNet(ks keystore.StarkNet, chainCfgs starknet.St continue } - // all the lower level APIs expect a config slice. create a single valued set per id - // TODO BCF-2605: clean this up - singleChainCfg := starknet.StarknetConfigs{chainCfg} - if cmdName := env.StarknetPluginCmd.Get(); cmdName != "" { // setup the starknet relayer to be a LOOP cfgTOML, err := toml.Marshal(struct { @@ -200,15 +191,14 @@ func (r *RelayerFactory) NewStarkNet(ks keystore.StarkNet, chainCfgs starknet.St opts := starknet.ChainOpts{ Logger: starkLggr, KeyStore: loopKs, - Configs: starknet.NewConfigs(singleChainCfg), } - relayExt, err := starknet.NewRelayExtender(chainCfg, opts) + chain, err := starknet.NewChain(chainCfg, opts) if err != nil { return nil, err } - starknetRelayers[relayId] = relay.NewRelayerAdapter(pkgstarknet.NewRelayer(starkLggr, relayExt), relayExt) + starknetRelayers[relayId] = relay.NewRelayerServerAdapter(pkgstarknet.NewRelayer(starkLggr, chain), chain) } } return starknetRelayers, nil @@ -235,19 +225,18 @@ func (r *RelayerFactory) NewCosmos(ctx context.Context, config CosmosFactoryConf opts := cosmos.ChainOpts{ QueryConfig: r.QConfig, - Logger: lggr.Named(relayId.ChainID.String()), + Logger: lggr.Named(relayId.ChainID), DB: r.DB, KeyStore: loopKs, EventBroadcaster: config.EventBroadcaster, } - opts.Configs = cosmos.NewConfigs(cosmos.CosmosConfigs{chainCfg}) - relayExt, err := cosmos.NewRelayExtender(chainCfg, opts) + chain, err := cosmos.NewChain(chainCfg, opts) if err != nil { return nil, fmt.Errorf("failed to load Cosmos chain %q: %w", relayId, err) } - relayers[relayId] = cosmos.NewLoopRelayerChain(pkgcosmos.NewRelayer(lggr, relayExt), relayExt) + relayers[relayId] = cosmos.NewLoopRelayerChain(pkgcosmos.NewRelayer(lggr, chain), chain) } return relayers, nil diff --git a/core/services/chainlink/testdata/secrets-full-redacted.toml b/core/services/chainlink/testdata/secrets-full-redacted.toml index c0c97b76e57..d2bf45e0bc2 100644 --- a/core/services/chainlink/testdata/secrets-full-redacted.toml +++ b/core/services/chainlink/testdata/secrets-full-redacted.toml @@ -28,3 +28,9 @@ Password = 'xxxxx' URL = 'xxxxx' Username = 'xxxxx' Password = 'xxxxx' + +[Mercury.Credentials.cred3] +LegacyURL = 'xxxxx' +URL = 'xxxxx' +Username = 'xxxxx' +Password = 'xxxxx' diff --git a/core/services/chainlink/testdata/secrets-full.toml b/core/services/chainlink/testdata/secrets-full.toml index 3773a798f7e..7dd8b38a834 100644 --- a/core/services/chainlink/testdata/secrets-full.toml +++ b/core/services/chainlink/testdata/secrets-full.toml @@ -25,3 +25,9 @@ Password = "password1" URL = "https://chain2.link" Username = "username2" Password = "password2" + +[Mercury.Credentials.cred3] +LegacyURL = "https://chain2.old.link" +URL = "https://chain2.link" +Username = "username2" +Password = "password2" diff --git a/core/services/functions/listener.go b/core/services/functions/listener.go index f7c94437654..e0bf5b79b03 100644 --- a/core/services/functions/listener.go +++ b/core/services/functions/listener.go @@ -728,6 +728,7 @@ func (l *FunctionsListener) getSecrets(ctx context.Context, eaClient ExternalAda decryptedSecretsBytes, err := l.decryptor.Decrypt(decryptCtx, requestID[:], secrets) if err != nil { + l.logger.Debugw("threshold decryption of secrets failed", "requestID", requestIDStr, "err", err) return "", errors.New("threshold decryption of secrets failed"), nil } return string(decryptedSecretsBytes), nil, nil diff --git a/core/services/job/job_orm_test.go b/core/services/job/job_orm_test.go index 1f5dba452fe..4fb8b767903 100644 --- a/core/services/job/job_orm_test.go +++ b/core/services/job/job_orm_test.go @@ -15,6 +15,7 @@ import ( "github.com/stretchr/testify/require" "gopkg.in/guregu/null.v4" + "github.com/smartcontractkit/chainlink-relay/pkg/types" "github.com/smartcontractkit/chainlink/v2/core/services/relay" "github.com/smartcontractkit/chainlink/v2/core/assets" @@ -911,7 +912,7 @@ func TestORM_ValidateKeyStoreMatch(t *testing.T) { }) t.Run("test Mercury ETH key validation", func(t *testing.T) { - jb.OCR2OracleSpec.PluginType = job.Mercury + jb.OCR2OracleSpec.PluginType = types.Mercury err = job.ValidateKeyStoreMatch(jb.OCR2OracleSpec, keyStore, "bad key") require.EqualError(t, err, "no CSA key matching: \"bad key\"") diff --git a/core/services/job/models.go b/core/services/job/models.go index d70afde12c2..03015aa1a7b 100644 --- a/core/services/job/models.go +++ b/core/services/job/models.go @@ -14,8 +14,10 @@ import ( "github.com/pkg/errors" "gopkg.in/guregu/null.v4" + "github.com/smartcontractkit/chainlink-relay/pkg/types" "github.com/smartcontractkit/chainlink/v2/core/assets" "github.com/smartcontractkit/chainlink/v2/core/bridges" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/config/toml" clnull "github.com/smartcontractkit/chainlink/v2/core/null" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/ethkey" "github.com/smartcontractkit/chainlink/v2/core/services/pipeline" @@ -310,28 +312,7 @@ func (r JSONConfig) MercuryCredentialName() (string, error) { return name, nil } -var ForwardersSupportedPlugins = []OCR2PluginType{Median, DKG, OCR2VRF, OCR2Keeper, OCR2Functions} - -// OCR2PluginType defines supported OCR2 plugin types. -type OCR2PluginType string - -const ( - // Median refers to the median.Median type - Median OCR2PluginType = "median" - - DKG OCR2PluginType = "dkg" - - OCR2VRF OCR2PluginType = "ocr2vrf" - - // Keeper was rebranded to automation. For now the plugin type required in job spec points - // to the new name (automation) but in code we refer it to keepers - // TODO: sc-55296 to rename ocr2keeper to ocr2automation in code - OCR2Keeper OCR2PluginType = "ocr2automation" - - OCR2Functions OCR2PluginType = "functions" - - Mercury OCR2PluginType = "mercury" -) +var ForwardersSupportedPlugins = []types.OCR2PluginType{types.Median, types.DKG, types.OCR2VRF, types.OCR2Keeper, types.Functions} // OCR2OracleSpec defines the job spec for OCR2 jobs. // Relay config is chain specific config for a relay (chain adapter). @@ -341,21 +322,32 @@ type OCR2OracleSpec struct { FeedID *common.Hash `toml:"feedID"` Relay relay.Network `toml:"relay"` // TODO BCF-2442 implement ChainID as top level parameter rathe than buried in RelayConfig. - ChainID string `toml:"chainID"` - RelayConfig JSONConfig `toml:"relayConfig"` - P2PV2Bootstrappers pq.StringArray `toml:"p2pv2Bootstrappers"` - OCRKeyBundleID null.String `toml:"ocrKeyBundleID"` - MonitoringEndpoint null.String `toml:"monitoringEndpoint"` - TransmitterID null.String `toml:"transmitterID"` - BlockchainTimeout models.Interval `toml:"blockchainTimeout"` - ContractConfigTrackerPollInterval models.Interval `toml:"contractConfigTrackerPollInterval"` - ContractConfigConfirmations uint16 `toml:"contractConfigConfirmations"` - PluginConfig JSONConfig `toml:"pluginConfig"` - PluginType OCR2PluginType `toml:"pluginType"` - CreatedAt time.Time `toml:"-"` - UpdatedAt time.Time `toml:"-"` - CaptureEATelemetry bool `toml:"captureEATelemetry"` - CaptureAutomationCustomTelemetry bool `toml:"captureAutomationCustomTelemetry"` + ChainID string `toml:"chainID"` + RelayConfig JSONConfig `toml:"relayConfig"` + P2PV2Bootstrappers pq.StringArray `toml:"p2pv2Bootstrappers"` + OCRKeyBundleID null.String `toml:"ocrKeyBundleID"` + MonitoringEndpoint null.String `toml:"monitoringEndpoint"` + TransmitterID null.String `toml:"transmitterID"` + BlockchainTimeout models.Interval `toml:"blockchainTimeout"` + ContractConfigTrackerPollInterval models.Interval `toml:"contractConfigTrackerPollInterval"` + ContractConfigConfirmations uint16 `toml:"contractConfigConfirmations"` + PluginConfig JSONConfig `toml:"pluginConfig"` + PluginType types.OCR2PluginType `toml:"pluginType"` + CreatedAt time.Time `toml:"-"` + UpdatedAt time.Time `toml:"-"` + CaptureEATelemetry bool `toml:"captureEATelemetry"` + CaptureAutomationCustomTelemetry bool `toml:"captureAutomationCustomTelemetry"` +} + +func validateRelayID(id relay.ID) error { + // only the EVM has specific requirements + if id.Network == relay.EVM { + _, err := toml.ChainIDInt64(id.ChainID) + if err != nil { + return fmt.Errorf("invalid EVM chain id %s: %w", id.ChainID, err) + } + } + return nil } func (s *OCR2OracleSpec) RelayID() (relay.ID, error) { @@ -363,7 +355,12 @@ func (s *OCR2OracleSpec) RelayID() (relay.ID, error) { if err != nil { return relay.ID{}, err } - return relay.NewID(s.Relay, cid) + rid := relay.NewID(s.Relay, cid) + err = validateRelayID(rid) + if err != nil { + return relay.ID{}, err + } + return rid, nil } func (s *OCR2OracleSpec) getChainID() (relay.ChainID, error) { diff --git a/core/services/job/orm.go b/core/services/job/orm.go index 277b03b24dd..d53452fa3bc 100644 --- a/core/services/job/orm.go +++ b/core/services/job/orm.go @@ -19,6 +19,8 @@ import ( "github.com/smartcontractkit/sqlx" + "github.com/smartcontractkit/chainlink-relay/pkg/types" + "github.com/smartcontractkit/chainlink/v2/core/bridges" "github.com/smartcontractkit/chainlink/v2/core/chains" "github.com/smartcontractkit/chainlink/v2/core/chains/evm" @@ -268,7 +270,7 @@ func (o *orm) CreateJob(jb *Job, qopts ...pg.QOpt) error { return errors.Errorf("forwarding is not currently supported for %s jobs", jb.OCR2OracleSpec.PluginType) } - if jb.OCR2OracleSpec.PluginType == Mercury { + if jb.OCR2OracleSpec.PluginType == types.Mercury { if jb.OCR2OracleSpec.FeedID == nil { return errors.New("feed ID is required for mercury plugin type") } @@ -278,7 +280,7 @@ func (o *orm) CreateJob(jb *Job, qopts ...pg.QOpt) error { } } - if jb.OCR2OracleSpec.PluginType == Median { + if jb.OCR2OracleSpec.PluginType == types.Median { var cfg medianconfig.PluginConfig err = json.Unmarshal(jb.OCR2OracleSpec.PluginConfig.Bytes(), &cfg) if err != nil { @@ -456,7 +458,7 @@ func (o *orm) CreateJob(jb *Job, qopts ...pg.QOpt) error { // ValidateKeyStoreMatch confirms that the key has a valid match in the keystore func ValidateKeyStoreMatch(spec *OCR2OracleSpec, keyStore keystore.Master, key string) error { - if spec.PluginType == Mercury { + if spec.PluginType == types.Mercury { _, err := keyStore.CSA().Get(key) if err != nil { return errors.Errorf("no CSA key matching: %q", key) diff --git a/core/services/job/spawner_test.go b/core/services/job/spawner_test.go index f35aa50ba4d..efa252e4c4d 100644 --- a/core/services/job/spawner_test.go +++ b/core/services/job/spawner_test.go @@ -67,7 +67,7 @@ type relayGetter struct { } func (g *relayGetter) Get(id relay.ID) (loop.Relayer, error) { - return evmrelayer.NewLoopRelayAdapter(g.r, g.e), nil + return evmrelayer.NewLoopRelayServerAdapter(g.r, g.e), nil } func TestSpawner_CreateJobDeleteJob(t *testing.T) { diff --git a/core/services/ocr2/delegate.go b/core/services/ocr2/delegate.go index 2a8fea38efe..2d1ff41ac12 100644 --- a/core/services/ocr2/delegate.go +++ b/core/services/ocr2/delegate.go @@ -265,7 +265,7 @@ func (d *Delegate) cleanupEVM(jb job.Job, q pg.Queryer, relayID relay.ID) error // an inconsistent state. This assumes UnregisterFilter will return nil if the filter wasn't found // at all (no rows deleted). spec := jb.OCR2OracleSpec - chain, err := d.legacyChains.Get(relayID.ChainID.String()) + chain, err := d.legacyChains.Get(relayID.ChainID) if err != nil { d.lggr.Error("cleanupEVM: failed to chain get chain %s", "err", relayID.ChainID, err) return nil @@ -274,12 +274,12 @@ func (d *Delegate) cleanupEVM(jb job.Job, q pg.Queryer, relayID relay.ID) error var filters []string switch spec.PluginType { - case job.OCR2VRF: + case types.OCR2VRF: filters, err = ocr2coordinator.FilterNamesFromSpec(spec) if err != nil { d.lggr.Errorw("failed to derive ocr2vrf filter names from spec", "err", err, "spec", spec) } - case job.OCR2Keeper: + case types.OCR2Keeper: filters, err = ocr2keeper.FilterNamesFromSpec20(spec) if err != nil { d.lggr.Errorw("failed to derive ocr2keeper filter names from spec", "err", err, "spec", spec) @@ -345,7 +345,7 @@ func (d *Delegate) ServicesForSpec(jb job.Job, qopts ...pg.QOpt) ([]job.ServiceC if rid.Network == relay.EVM { lggr = logger.Sugared(lggr.With("evmChainID", rid.ChainID)) - chain, err2 := d.legacyChains.Get(rid.ChainID.String()) + chain, err2 := d.legacyChains.Get(rid.ChainID) if err2 != nil { return nil, fmt.Errorf("ServicesForSpec: could not get EVM chain %s: %w", rid.ChainID, err2) } @@ -405,22 +405,22 @@ func (d *Delegate) ServicesForSpec(jb job.Job, qopts ...pg.QOpt) ([]job.ServiceC ctx := lggrCtx.ContextWithValues(context.Background()) switch spec.PluginType { - case job.Mercury: + case types.Mercury: return d.newServicesMercury(ctx, lggr, jb, runResults, bootstrapPeers, kb, ocrDB, lc, ocrLogger) - case job.Median: + case types.Median: return d.newServicesMedian(ctx, lggr, jb, runResults, bootstrapPeers, kb, ocrDB, lc, ocrLogger) - case job.DKG: + case types.DKG: return d.newServicesDKG(lggr, jb, bootstrapPeers, kb, ocrDB, lc, ocrLogger) - case job.OCR2VRF: + case types.OCR2VRF: return d.newServicesOCR2VRF(lggr, jb, runResults, bootstrapPeers, kb, ocrDB, lc) - case job.OCR2Keeper: + case types.OCR2Keeper: return d.newServicesOCR2Keepers(lggr, jb, runResults, bootstrapPeers, kb, ocrDB, lc, ocrLogger) - case job.OCR2Functions: + case types.Functions: const ( _ int32 = iota thresholdPluginId @@ -437,7 +437,7 @@ func (d *Delegate) ServicesForSpec(jb job.Job, qopts ...pg.QOpt) ([]job.ServiceC func GetEVMEffectiveTransmitterID(jb *job.Job, chain evm.Chain, lggr logger.SugaredLogger) (string, error) { spec := jb.OCR2OracleSpec - if spec.PluginType == job.Mercury { + if spec.PluginType == types.Mercury { return spec.TransmitterID.String, nil } @@ -448,7 +448,7 @@ func GetEVMEffectiveTransmitterID(jb *job.Job, chain evm.Chain, lggr logger.Suga if err != nil { return "", err } - if len(sendingKeys) > 1 && spec.PluginType != job.OCR2VRF { + if len(sendingKeys) > 1 && spec.PluginType != types.OCR2VRF { return "", errors.New("only ocr2 vrf should have more than 1 sending key") } spec.TransmitterID = null.StringFrom(sendingKeys[0]) @@ -509,18 +509,19 @@ func (d *Delegate) newServicesMercury( if err != nil { return nil, fmt.Errorf("failed to get relay %s is it enabled?: %w", spec.Relay, err) } - chain, err := d.legacyChains.Get(rid.ChainID.String()) + chain, err := d.legacyChains.Get(rid.ChainID) if err != nil { return nil, fmt.Errorf("mercury services: failed to get chain %s: %w", rid.ChainID, err) } - mercuryProvider, err2 := relayer.NewMercuryProvider(ctx, + provider, err2 := relayer.NewPluginProvider(ctx, types.RelayArgs{ ExternalJobID: jb.ExternalJobID, JobID: spec.ID, ContractID: spec.ContractID, New: d.isNewlyCreatedJob, RelayConfig: spec.RelayConfig.Bytes(), + ProviderType: string(spec.PluginType), }, types.PluginArgs{ TransmitterID: transmitterID, PluginConfig: spec.PluginConfig.Bytes(), @@ -529,6 +530,11 @@ func (d *Delegate) newServicesMercury( return nil, err2 } + mercuryProvider, ok := provider.(types.MercuryProvider) + if !ok { + return nil, errors.New("could not coerce PluginProvider to MercuryProvider") + } + oracleArgsNoPlugin := libocr2.MercuryOracleArgs{ BinaryNetworkEndpointFactory: d.peerWrapper.Peer2, V2Bootstrappers: bootstrapPeers, @@ -618,7 +624,7 @@ func (d *Delegate) newServicesDKG( return nil, fmt.Errorf("DKG services: expected EVM relayer got %s", rid.Network) } - chain, err2 := d.legacyChains.Get(rid.ChainID.String()) + chain, err2 := d.legacyChains.Get(rid.ChainID) if err2 != nil { return nil, fmt.Errorf("DKG services: failed to get chain %s: %w", rid.ChainID, err2) } @@ -686,7 +692,7 @@ func (d *Delegate) newServicesOCR2VRF( if rid.Network != relay.EVM { return nil, fmt.Errorf("VRF services: expected EVM relayer got %s", rid.Network) } - chain, err2 := d.legacyChains.Get(rid.ChainID.String()) + chain, err2 := d.legacyChains.Get(rid.ChainID) if err2 != nil { return nil, fmt.Errorf("VRF services: failed to get chain (%s): %w", rid.ChainID, err2) } @@ -912,7 +918,7 @@ func (d *Delegate) newServicesOCR2Keepers21( return nil, fmt.Errorf("keeper2 services: expected EVM relayer got %s", rid.Network) } - chain, err2 := d.legacyChains.Get(rid.ChainID.String()) + chain, err2 := d.legacyChains.Get(rid.ChainID) if err2 != nil { return nil, fmt.Errorf("keeper2 services: failed to get chain %s: %w", rid.ChainID, err2) } @@ -1025,7 +1031,7 @@ func (d *Delegate) newServicesOCR2Keepers20( if rid.Network != relay.EVM { return nil, fmt.Errorf("keepers2.0 services: expected EVM relayer got %s", rid.Network) } - chain, err2 := d.legacyChains.Get(rid.ChainID.String()) + chain, err2 := d.legacyChains.Get(rid.ChainID) if err2 != nil { return nil, fmt.Errorf("keepers2.0 services: failed to get chain (%s): %w", rid.ChainID, err2) } @@ -1160,7 +1166,7 @@ func (d *Delegate) newServicesOCR2Functions( if rid.Network != relay.EVM { return nil, fmt.Errorf("functions services: expected EVM relayer got %s", rid.Network) } - chain, err := d.legacyChains.Get(rid.ChainID.String()) + chain, err := d.legacyChains.Get(rid.ChainID) if err != nil { return nil, fmt.Errorf("functions services: failed to get chain %s: %w", rid.ChainID, err) } diff --git a/core/services/ocr2/delegate_test.go b/core/services/ocr2/delegate_test.go index e78af2e19b4..97c9faa44d4 100644 --- a/core/services/ocr2/delegate_test.go +++ b/core/services/ocr2/delegate_test.go @@ -8,6 +8,7 @@ import ( "github.com/stretchr/testify/require" "gopkg.in/guregu/null.v4" + "github.com/smartcontractkit/chainlink-relay/pkg/types" evmcfg "github.com/smartcontractkit/chainlink/v2/core/chains/evm/config/toml" txmmocks "github.com/smartcontractkit/chainlink/v2/core/chains/evm/txmgr/mocks" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" @@ -49,7 +50,7 @@ func TestGetEVMEffectiveTransmitterID(t *testing.T) { type testCase struct { name string - pluginType job.OCR2PluginType + pluginType types.OCR2PluginType transmitterID null.String sendingKeys []any expectedError bool @@ -75,7 +76,7 @@ func TestGetEVMEffectiveTransmitterID(t *testing.T) { testCases := []testCase{ { name: "mercury plugin should just return transmitterID", - pluginType: job.Mercury, + pluginType: types.Mercury, transmitterID: null.StringFrom("Mercury transmitterID"), expectedTransmitterID: "Mercury transmitterID", }, @@ -91,7 +92,7 @@ func TestGetEVMEffectiveTransmitterID(t *testing.T) { }, { name: "when transmitterID is not defined and plugin is ocr2vrf, it should allow>1 sendingKeys and set transmitterID to the first one", - pluginType: job.OCR2VRF, + pluginType: types.OCR2VRF, sendingKeys: []any{"0x7e57000000000000000000000000000000000000", "0x7e57000000000000000000000000000000000001", "0x7e57000000000000000000000000000000000002"}, expectedTransmitterID: "0x7e57000000000000000000000000000000000000", }, @@ -109,7 +110,7 @@ func TestGetEVMEffectiveTransmitterID(t *testing.T) { }, { name: "when forwarders are enabled and when transmitterID is not defined, it should use first sendingKey to retrieve forwarder address", - pluginType: job.OCR2VRF, + pluginType: types.OCR2VRF, forwardingEnabled: true, sendingKeys: []any{"0x7e57000000000000000000000000000000000001", "0x7e57000000000000000000000000000000000002"}, getForwarderForEOAArg: common.HexToAddress("0x7e57000000000000000000000000000000000001"), @@ -117,7 +118,7 @@ func TestGetEVMEffectiveTransmitterID(t *testing.T) { }, { name: "when forwarders are enabled but forwarder address fails to be retrieved and when transmitterID is not defined, it should default to using first sendingKey", - pluginType: job.OCR2VRF, + pluginType: types.OCR2VRF, forwardingEnabled: true, sendingKeys: []any{"0x7e57000000000000000000000000000000000001", "0x7e57000000000000000000000000000000000002"}, getForwarderForEOAArg: common.HexToAddress("0x7e57000000000000000000000000000000000001"), diff --git a/core/services/ocr2/models/models.go b/core/services/ocr2/models/models.go index 970c0aa7e0a..4d3b8bf532c 100644 --- a/core/services/ocr2/models/models.go +++ b/core/services/ocr2/models/models.go @@ -1,11 +1,8 @@ package models type MercuryCredentials struct { - URL string - Username string - Password string -} - -func (mc *MercuryCredentials) Validate() bool { - return mc.URL != "" && mc.Username != "" && mc.Password != "" + LegacyURL string + URL string + Username string + Password string } diff --git a/core/services/ocr2/plugins/functions/integration_tests/v1/internal/testutils.go b/core/services/ocr2/plugins/functions/integration_tests/v1/internal/testutils.go index bedfdc92d19..c376213ed13 100644 --- a/core/services/ocr2/plugins/functions/integration_tests/v1/internal/testutils.go +++ b/core/services/ocr2/plugins/functions/integration_tests/v1/internal/testutils.go @@ -192,11 +192,13 @@ func StartNewChainWithContracts(t *testing.T, nClients int) (*bind.TransactOpts, var handleOracleFulfillmentSelector [4]byte copy(handleOracleFulfillmentSelector[:], handleOracleFulfillmentSelectorSlice[:4]) functionsRouterConfig := functions_router.FunctionsRouterConfig{ - MaxConsumersPerSubscription: uint16(100), - AdminFee: big.NewInt(0), - HandleOracleFulfillmentSelector: handleOracleFulfillmentSelector, - MaxCallbackGasLimits: []uint32{300_000, 500_000, 1_000_000}, - GasForCallExactCheck: 5000, + MaxConsumersPerSubscription: uint16(100), + AdminFee: big.NewInt(0), + HandleOracleFulfillmentSelector: handleOracleFulfillmentSelector, + MaxCallbackGasLimits: []uint32{300_000, 500_000, 1_000_000}, + GasForCallExactCheck: 5000, + SubscriptionDepositMinimumRequests: 10, + SubscriptionDepositJuels: big.NewInt(9 * 1e18), // 9 LINK } routerAddress, _, routerContract, err := functions_router.DeployFunctionsRouter(owner, b, linkAddr, functionsRouterConfig) require.NoError(t, err) @@ -214,7 +216,6 @@ func StartNewChainWithContracts(t *testing.T, nClients int) (*bind.TransactOpts, // Deploy Coordinator contract (matches updateConfig() in FunctionsBilling.sol) coordinatorConfig := functions_coordinator.FunctionsBillingConfig{ - MaxCallbackGasLimit: uint32(450_000), FeedStalenessSeconds: uint32(86_400), GasOverheadBeforeCallback: uint32(325_000), GasOverheadAfterCallback: uint32(50_000), diff --git a/core/services/ocr2/plugins/median/services.go b/core/services/ocr2/plugins/median/services.go index 8ff97c2cc56..e435ee747f5 100644 --- a/core/services/ocr2/plugins/median/services.go +++ b/core/services/ocr2/plugins/median/services.go @@ -3,6 +3,7 @@ package median import ( "context" "encoding/json" + "errors" "fmt" "time" @@ -67,12 +68,13 @@ func NewMedianServices(ctx context.Context, } spec := jb.OCR2OracleSpec - provider, err := relayer.NewMedianProvider(ctx, types.RelayArgs{ + provider, err := relayer.NewPluginProvider(ctx, types.RelayArgs{ ExternalJobID: jb.ExternalJobID, JobID: spec.ID, ContractID: spec.ContractID, New: isNewlyCreatedJob, RelayConfig: spec.RelayConfig.Bytes(), + ProviderType: string(spec.PluginType), }, types.PluginArgs{ TransmitterID: spec.TransmitterID.String, PluginConfig: spec.PluginConfig.Bytes(), @@ -80,6 +82,12 @@ func NewMedianServices(ctx context.Context, if err != nil { return } + + medianProvider, ok := provider.(types.MedianProvider) + if !ok { + return nil, errors.New("could not coerce PluginProvider to MedianProvider") + } + srvs = append(srvs, provider) argsNoPlugin.ContractTransmitter = provider.ContractTransmitter() argsNoPlugin.ContractConfigTracker = provider.ContractConfigTracker() @@ -113,11 +121,11 @@ func NewMedianServices(ctx context.Context, abort() return } - median := loop.NewMedianService(lggr, telem, cmdFn, provider, dataSource, juelsPerFeeCoinSource, errorLog) + median := loop.NewMedianService(lggr, telem, cmdFn, medianProvider, dataSource, juelsPerFeeCoinSource, errorLog) argsNoPlugin.ReportingPluginFactory = median srvs = append(srvs, median) } else { - argsNoPlugin.ReportingPluginFactory, err = NewPlugin(lggr).NewMedianFactory(ctx, provider, dataSource, juelsPerFeeCoinSource, errorLog) + argsNoPlugin.ReportingPluginFactory, err = NewPlugin(lggr).NewMedianFactory(ctx, medianProvider, dataSource, juelsPerFeeCoinSource, errorLog) if err != nil { err = fmt.Errorf("failed to create median factory: %w", err) abort() diff --git a/core/services/ocr2/plugins/mercury/helpers_test.go b/core/services/ocr2/plugins/mercury/helpers_test.go index e93f161916a..ddb521ff9ca 100644 --- a/core/services/ocr2/plugins/mercury/helpers_test.go +++ b/core/services/ocr2/plugins/mercury/helpers_test.go @@ -22,7 +22,14 @@ import ( "go.uber.org/zap/zaptest/observer" "github.com/smartcontractkit/libocr/commontypes" + "github.com/smartcontractkit/libocr/offchainreporting2/chains/evmutil" + ocrtypes "github.com/smartcontractkit/libocr/offchainreporting2plus/types" + "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" + "github.com/smartcontractkit/chainlink/v2/core/internal/cltest/heavyweight" + "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" + "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/keystest" + "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/chaintype" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/csakey" @@ -30,17 +37,10 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/p2pkey" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/validate" "github.com/smartcontractkit/chainlink/v2/core/services/ocrbootstrap" + "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/mercury" "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/mercury/wsrpc/pb" - "github.com/smartcontractkit/chainlink/v2/core/utils" - - relaymercury "github.com/smartcontractkit/chainlink-relay/pkg/reportingplugins/mercury" - - "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" - "github.com/smartcontractkit/chainlink/v2/core/internal/cltest/heavyweight" - "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" - "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/keystest" - "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/store/models" + "github.com/smartcontractkit/chainlink/v2/core/utils" ) var _ pb.MercuryServer = &mercuryServer{} @@ -51,13 +51,14 @@ type request struct { } type mercuryServer struct { - privKey ed25519.PrivateKey - reqsCh chan request - t *testing.T + privKey ed25519.PrivateKey + reqsCh chan request + t *testing.T + buildReport func() []byte } -func NewMercuryServer(t *testing.T, privKey ed25519.PrivateKey, reqsCh chan request) *mercuryServer { - return &mercuryServer{privKey, reqsCh, t} +func NewMercuryServer(t *testing.T, privKey ed25519.PrivateKey, reqsCh chan request, buildReport func() []byte) *mercuryServer { + return &mercuryServer{privKey, reqsCh, t, buildReport} } func (s *mercuryServer) Transmit(ctx context.Context, req *pb.TransmitRequest) (*pb.TransmitResponse, error) { @@ -85,9 +86,12 @@ func (s *mercuryServer) LatestReport(ctx context.Context, lrr *pb.LatestReportRe out.Report = new(pb.Report) out.Report.FeedId = lrr.FeedId - price := big.NewInt(123456789) - encodedPrice, _ := relaymercury.EncodeValueInt192(price) - out.Report.Price = encodedPrice + report := s.buildReport() + payload, err := mercury.PayloadTypes.Pack(evmutil.RawReportContext(ocrtypes.ReportContext{}), report, [][32]byte{}, [][32]byte{}, [32]byte{}) + if err != nil { + panic(err) + } + out.Report.Payload = payload return out, nil } diff --git a/core/services/ocr2/plugins/mercury/integration_test.go b/core/services/ocr2/plugins/mercury/integration_test.go index b75855b8db5..be82e21a6fb 100644 --- a/core/services/ocr2/plugins/mercury/integration_test.go +++ b/core/services/ocr2/plugins/mercury/integration_test.go @@ -34,6 +34,9 @@ import ( "go.uber.org/zap/zaptest/observer" relaymercury "github.com/smartcontractkit/chainlink-relay/pkg/reportingplugins/mercury" + relaycodecv1 "github.com/smartcontractkit/chainlink-relay/pkg/reportingplugins/mercury/v1" + relaycodecv2 "github.com/smartcontractkit/chainlink-relay/pkg/reportingplugins/mercury/v2" + relaycodecv3 "github.com/smartcontractkit/chainlink-relay/pkg/reportingplugins/mercury/v3" "github.com/smartcontractkit/chainlink/v2/core/assets" "github.com/smartcontractkit/chainlink/v2/core/bridges" @@ -149,7 +152,13 @@ func TestIntegration_MercuryV1(t *testing.T) { reqs := make(chan request) serverKey := csakey.MustNewV2XXXTestingOnly(big.NewInt(-1)) serverPubKey := serverKey.PublicKey - srv := NewMercuryServer(t, ed25519.PrivateKey(serverKey.Raw()), reqs) + srv := NewMercuryServer(t, ed25519.PrivateKey(serverKey.Raw()), reqs, func() []byte { + report, err := (&reportcodecv1.ReportCodec{}).BuildReport(relaycodecv1.ReportFields{BenchmarkPrice: big.NewInt(234567), Bid: big.NewInt(1), Ask: big.NewInt(1), CurrentBlockHash: make([]byte, 32)}) + if err != nil { + panic(err) + } + return report + }) clientCSAKeys := make([]csakey.KeyV2, n+1) clientPubKeys := make([]ed25519.PublicKey, n+1) for i := 0; i < n+1; i++ { @@ -494,7 +503,13 @@ func TestIntegration_MercuryV2(t *testing.T) { reqs := make(chan request) serverKey := csakey.MustNewV2XXXTestingOnly(big.NewInt(-1)) serverPubKey := serverKey.PublicKey - srv := NewMercuryServer(t, ed25519.PrivateKey(serverKey.Raw()), reqs) + srv := NewMercuryServer(t, ed25519.PrivateKey(serverKey.Raw()), reqs, func() []byte { + report, err := (&reportcodecv2.ReportCodec{}).BuildReport(relaycodecv2.ReportFields{BenchmarkPrice: big.NewInt(234567), LinkFee: big.NewInt(1), NativeFee: big.NewInt(1)}) + if err != nil { + panic(err) + } + return report + }) clientCSAKeys := make([]csakey.KeyV2, n+1) clientPubKeys := make([]ed25519.PublicKey, n+1) for i := 0; i < n+1; i++ { @@ -686,7 +701,7 @@ func TestIntegration_MercuryV2(t *testing.T) { continue // already saw all oracles for this feed } - expectedFee := relaymercury.CalculateFee(big.NewInt(123456789), rawReportingPluginConfig.BaseUSDFeeCents) + expectedFee := relaymercury.CalculateFee(big.NewInt(234567), rawReportingPluginConfig.BaseUSDFeeCents) expectedExpiresAt := reportElems["observationsTimestamp"].(uint32) + rawReportingPluginConfig.ExpirationWindow assert.GreaterOrEqual(t, int(reportElems["observationsTimestamp"].(uint32)), int(testStartTimeStamp)) @@ -766,7 +781,13 @@ func TestIntegration_MercuryV3(t *testing.T) { reqs := make(chan request) serverKey := csakey.MustNewV2XXXTestingOnly(big.NewInt(-1)) serverPubKey := serverKey.PublicKey - srv := NewMercuryServer(t, ed25519.PrivateKey(serverKey.Raw()), reqs) + srv := NewMercuryServer(t, ed25519.PrivateKey(serverKey.Raw()), reqs, func() []byte { + report, err := (&reportcodecv3.ReportCodec{}).BuildReport(relaycodecv3.ReportFields{BenchmarkPrice: big.NewInt(234567), Bid: big.NewInt(1), Ask: big.NewInt(1), LinkFee: big.NewInt(1), NativeFee: big.NewInt(1)}) + if err != nil { + panic(err) + } + return report + }) clientCSAKeys := make([]csakey.KeyV2, n+1) clientPubKeys := make([]ed25519.PublicKey, n+1) for i := 0; i < n+1; i++ { @@ -962,7 +983,7 @@ func TestIntegration_MercuryV3(t *testing.T) { continue // already saw all oracles for this feed } - expectedFee := relaymercury.CalculateFee(big.NewInt(123456789), rawReportingPluginConfig.BaseUSDFeeCents) + expectedFee := relaymercury.CalculateFee(big.NewInt(234567), rawReportingPluginConfig.BaseUSDFeeCents) expectedExpiresAt := reportElems["observationsTimestamp"].(uint32) + rawReportingPluginConfig.ExpirationWindow assert.GreaterOrEqual(t, int(reportElems["observationsTimestamp"].(uint32)), int(testStartTimeStamp)) diff --git a/core/services/ocr2/plugins/mercury/plugin.go b/core/services/ocr2/plugins/mercury/plugin.go index 64336548a1e..05e7e968f8b 100644 --- a/core/services/ocr2/plugins/mercury/plugin.go +++ b/core/services/ocr2/plugins/mercury/plugin.go @@ -67,7 +67,7 @@ func NewServices( runResults, chEnhancedTelem, chainHeadTracker, - ocr2Provider.ContractTransmitter(), + ocr2Provider.MercuryServerFetcher(), pluginConfig.InitialBlockNumber.Ptr(), feedID, ) @@ -87,7 +87,7 @@ func NewServices( lggr, runResults, chEnhancedTelem, - ocr2Provider.ContractTransmitter(), + ocr2Provider.MercuryServerFetcher(), *pluginConfig.LinkFeedID, *pluginConfig.NativeFeedID, ) @@ -107,7 +107,7 @@ func NewServices( lggr, runResults, chEnhancedTelem, - ocr2Provider.ContractTransmitter(), + ocr2Provider.MercuryServerFetcher(), *pluginConfig.LinkFeedID, *pluginConfig.NativeFeedID, ) diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/block_subscriber.go b/core/services/ocr2/plugins/ocr2keeper/evm21/block_subscriber.go index 9a7d9c5dcc7..87b46c9785b 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm21/block_subscriber.go +++ b/core/services/ocr2/plugins/ocr2keeper/evm21/block_subscriber.go @@ -29,11 +29,15 @@ const ( blockHistorySize = int64(256) ) +var ( + BlockSubscriberServiceName = "BlockSubscriber" +) + type BlockSubscriber struct { - sync utils.StartStopOnce + utils.StartStopOnce + threadCtrl utils.ThreadControl + mu sync.RWMutex - ctx context.Context - cancel context.CancelFunc hb httypes.HeadBroadcaster lp logpoller.LogPoller headC chan *evmtypes.Head @@ -53,6 +57,7 @@ var _ ocr2keepers.BlockSubscriber = &BlockSubscriber{} func NewBlockSubscriber(hb httypes.HeadBroadcaster, lp logpoller.LogPoller, lggr logger.Logger) *BlockSubscriber { return &BlockSubscriber{ + threadCtrl: utils.NewThreadControl(), hb: hb, lp: lp, headC: make(chan *evmtypes.Head, channelSize), @@ -81,8 +86,8 @@ func (bs *BlockSubscriber) getBlockRange(ctx context.Context) ([]uint64, error) return blocks, nil } -func (bs *BlockSubscriber) initializeBlocks(blocks []uint64) error { - logpollerBlocks, err := bs.lp.GetBlocksRange(bs.ctx, blocks, pg.WithParentCtx(bs.ctx)) +func (bs *BlockSubscriber) initializeBlocks(ctx context.Context, blocks []uint64) error { + logpollerBlocks, err := bs.lp.GetBlocksRange(ctx, blocks) if err != nil { return err } @@ -127,67 +132,61 @@ func (bs *BlockSubscriber) cleanup() { bs.lggr.Infof("lastClearedBlock is set to %d", bs.lastClearedBlock) } -func (bs *BlockSubscriber) Start(_ context.Context) error { - bs.lggr.Info("block subscriber started.") - return bs.sync.StartOnce("BlockSubscriber", func() error { - bs.mu.Lock() - defer bs.mu.Unlock() - bs.ctx, bs.cancel = context.WithCancel(context.Background()) - // initialize the blocks map with the recent blockSize blocks - blocks, err := bs.getBlockRange(bs.ctx) - if err != nil { - bs.lggr.Errorf("failed to get block range", err) - } - err = bs.initializeBlocks(blocks) - if err != nil { - bs.lggr.Errorf("failed to get log poller blocks", err) - } - - _, bs.unsubscribe = bs.hb.Subscribe(&headWrapper{headC: bs.headC, lggr: bs.lggr}) +func (bs *BlockSubscriber) initialize(ctx context.Context) { + bs.mu.Lock() + defer bs.mu.Unlock() + // initialize the blocks map with the recent blockSize blocks + blocks, err := bs.getBlockRange(ctx) + if err != nil { + bs.lggr.Errorf("failed to get block range", err) + } + err = bs.initializeBlocks(ctx, blocks) + if err != nil { + bs.lggr.Errorf("failed to get log poller blocks", err) + } + _, bs.unsubscribe = bs.hb.Subscribe(&headWrapper{headC: bs.headC, lggr: bs.lggr}) +} +func (bs *BlockSubscriber) Start(ctx context.Context) error { + return bs.StartOnce(BlockSubscriberServiceName, func() error { + bs.lggr.Info("block subscriber started.") + bs.initialize(ctx) // poll from head broadcaster channel and push to subscribers - { - go func(ctx context.Context) { - for { - select { - case h := <-bs.headC: - if h != nil { - bs.processHead(h) - } - case <-ctx.Done(): - return + bs.threadCtrl.Go(func(ctx context.Context) { + for { + select { + case h := <-bs.headC: + if h != nil { + bs.processHead(h) } + case <-ctx.Done(): + return } - }(bs.ctx) - } - - // clean up block maps - { - go func(ctx context.Context) { - ticker := time.NewTicker(cleanUpInterval) - for { - select { - case <-ticker.C: - bs.cleanup() - case <-ctx.Done(): - ticker.Stop() - return - } + } + }) + // cleanup old blocks + bs.threadCtrl.Go(func(ctx context.Context) { + ticker := time.NewTicker(cleanUpInterval) + defer ticker.Stop() + + for { + select { + case <-ticker.C: + bs.cleanup() + case <-ctx.Done(): + return } - }(bs.ctx) - } + } + }) return nil }) } func (bs *BlockSubscriber) Close() error { - bs.lggr.Info("stop block subscriber") - return bs.sync.StopOnce("BlockSubscriber", func() error { - bs.mu.Lock() - defer bs.mu.Unlock() - - bs.cancel() + return bs.StopOnce(BlockSubscriberServiceName, func() error { + bs.lggr.Info("stop block subscriber") + bs.threadCtrl.Close() bs.unsubscribe() return nil }) diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/block_subscriber_test.go b/core/services/ocr2/plugins/ocr2keeper/evm21/block_subscriber_test.go index 19dfa7d9281..23fcf3f6695 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm21/block_subscriber_test.go +++ b/core/services/ocr2/plugins/ocr2keeper/evm21/block_subscriber_test.go @@ -158,7 +158,7 @@ func TestBlockSubscriber_InitializeBlocks(t *testing.T) { bs := NewBlockSubscriber(hb, lp, lggr) bs.blockHistorySize = historySize bs.blockSize = blockSize - err := bs.initializeBlocks(tc.Blocks) + err := bs.initializeBlocks(testutils.Context(t), tc.Blocks) if tc.Error != nil { assert.Equal(t, tc.Error.Error(), err.Error()) diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/core/payload_test.go b/core/services/ocr2/plugins/ocr2keeper/evm21/core/payload_test.go index f7b245ffce0..1ca280c0d2d 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm21/core/payload_test.go +++ b/core/services/ocr2/plugins/ocr2keeper/evm21/core/payload_test.go @@ -40,11 +40,12 @@ func TestWorkID(t *testing.T) { BlockNumber: 123, BlockHash: common.HexToHash("0xabcdef"), LogTriggerExtension: &ocr2keepers.LogTriggerExtension{ - Index: 1, - TxHash: common.HexToHash("0x12345"), + Index: 1, + TxHash: common.HexToHash("0x12345"), + BlockHash: common.HexToHash("0xabcdef"), }, }, - expected: "db0e245ff4e7551d6c862d9a0eb5466624e1439ad1db262a7a3d6137d892d0a3", + expected: "aaa208331dfafff7a681e3358d082a2e78633dd05c8fb2817c391888cadb2912", }, { name: "happy path example from an actual tx", @@ -53,11 +54,12 @@ func TestWorkID(t *testing.T) { BlockNumber: 39344455, BlockHash: common.HexToHash("0xb41258d18cd44ebf7a0d70de011f2bc4a67c9b68e8b6dada864045d8543bb020"), LogTriggerExtension: &ocr2keepers.LogTriggerExtension{ - Index: 41, - TxHash: common.HexToHash("0x44079b1b33aff337dbf17b9e12c5724ecab979c50c8201a9814a488ff3e22384"), + Index: 41, + TxHash: common.HexToHash("0x44079b1b33aff337dbf17b9e12c5724ecab979c50c8201a9814a488ff3e22384"), + BlockHash: common.HexToHash("0xb41258d18cd44ebf7a0d70de011f2bc4a67c9b68e8b6dada864045d8543bb020"), }, }, - expected: "cdb4cfd9b4855b28d243d099c41b832da6b2d99dda3e7d09b900899afd09328f", + expected: "ef1b6acac8aa3682a8a08f666a13cfa165f7e811a16ea9fa0817f437fc4d110d", }, { name: "empty upkeepID", @@ -124,7 +126,7 @@ func TestNewUpkeepPayload(t *testing.T) { }, }, check: []byte("check-data-111"), - workID: "d2fc1c0d626b480a4180f30b89142ae727c85e0b4dc0a82645bcef8062ff932a", + workID: "d8e7c8907a0b60b637ce71ff4f757edf076e270d52c51f6e4d46a3b0696e0a39", }, } diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/core/trigger.go b/core/services/ocr2/plugins/ocr2keeper/evm21/core/trigger.go index 9999aefbd25..79273479596 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm21/core/trigger.go +++ b/core/services/ocr2/plugins/ocr2keeper/evm21/core/trigger.go @@ -16,7 +16,7 @@ type triggerWrapper = automation_utils_2_1.KeeperRegistryBase21LogTrigger var ErrABINotParsable = fmt.Errorf("error parsing abi") -// according to the upkeep type of the given id. +// PackTrigger packs the trigger data according to the upkeep type of the given id. it will remove the first 4 bytes of function selector. func PackTrigger(id *big.Int, trig triggerWrapper) ([]byte, error) { var trigger []byte var err error @@ -41,10 +41,11 @@ func PackTrigger(id *big.Int, trig triggerWrapper) ([]byte, error) { trigger, err = utilsABI.Pack("_conditionalTrigger", &trig) case ocr2keepers.LogTrigger: logTrig := automation_utils_2_1.KeeperRegistryBase21LogTrigger{ - BlockNum: trig.BlockNum, - BlockHash: trig.BlockHash, - LogIndex: trig.LogIndex, - TxHash: trig.TxHash, + BlockNum: trig.BlockNum, + BlockHash: trig.BlockHash, + LogBlockHash: trig.LogBlockHash, + LogIndex: trig.LogIndex, + TxHash: trig.TxHash, } trigger, err = utilsABI.Pack("_logTrigger", &logTrig) default: @@ -98,6 +99,7 @@ func UnpackTrigger(id *big.Int, raw []byte) (triggerWrapper, error) { } copy(triggerW.BlockHash[:], converted.BlockHash[:]) copy(triggerW.TxHash[:], converted.TxHash[:]) + copy(triggerW.LogBlockHash[:], converted.LogBlockHash[:]) return triggerW, nil default: return triggerWrapper{}, fmt.Errorf("unknown trigger type: %d", upkeepType) diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/core/trigger_test.go b/core/services/ocr2/plugins/ocr2keeper/evm21/core/trigger_test.go index 5fa5ae5c910..0233e40679d 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm21/core/trigger_test.go +++ b/core/services/ocr2/plugins/ocr2keeper/evm21/core/trigger_test.go @@ -23,13 +23,14 @@ func TestPackUnpackTrigger(t *testing.T) { "happy flow log trigger", append([]byte{1}, common.LeftPadBytes([]byte{1}, 15)...), triggerWrapper{ - BlockNum: 1, - BlockHash: common.HexToHash("0x01111111"), - LogIndex: 1, - TxHash: common.HexToHash("0x01111111"), + BlockNum: 1, + BlockHash: common.HexToHash("0x01111111"), + LogIndex: 1, + TxHash: common.HexToHash("0x01111111"), + LogBlockHash: common.HexToHash("0x01111abc"), }, func() []byte { - b, _ := hexutil.Decode("0x0000000000000000000000000000000000000000000000000000000001111111000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000001111111") + b, _ := hexutil.Decode("0x0000000000000000000000000000000000000000000000000000000001111abc0000000000000000000000000000000000000000000000000000000001111111000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000001111111") return b }(), nil, diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/core/utils.go b/core/services/ocr2/plugins/ocr2keeper/evm21/core/utils.go index 25003055a3b..6a31b938fc6 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm21/core/utils.go +++ b/core/services/ocr2/plugins/ocr2keeper/evm21/core/utils.go @@ -19,14 +19,14 @@ func GetTxBlock(ctx context.Context, client client.Client, txHash common.Hash) ( if strings.Contains(err.Error(), "not yet been implemented") { // workaround for simulated chains // Exploratory: fix this properly (e.g. in the simulated backend) - receipt, err1 := client.TransactionReceipt(ctx, txHash) + r, err1 := client.TransactionReceipt(ctx, txHash) if err1 != nil { return nil, common.Hash{}, err1 } - if receipt.Status != 1 { + if r.Status != 1 { return nil, common.Hash{}, nil } - return receipt.BlockNumber, receipt.BlockHash, nil + return r.BlockNumber, r.BlockHash, nil } return nil, common.Hash{}, err } diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/encoding/encoder.go b/core/services/ocr2/plugins/ocr2keeper/evm21/encoding/encoder.go index 62a359a7231..239de099c01 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm21/encoding/encoder.go +++ b/core/services/ocr2/plugins/ocr2keeper/evm21/encoding/encoder.go @@ -68,6 +68,7 @@ func (e reportEncoder) Encode(results ...ocr2keepers.CheckResult) ([]byte, error case ocr2keepers.LogTrigger: triggerW.TxHash = result.Trigger.LogTriggerExtension.TxHash triggerW.LogIndex = result.Trigger.LogTriggerExtension.Index + triggerW.LogBlockHash = result.Trigger.LogTriggerExtension.BlockHash default: // no special handling here for conditional triggers } @@ -86,7 +87,7 @@ func (e reportEncoder) Encode(results ...ocr2keepers.CheckResult) ([]byte, error return e.packer.PackReport(report) } -// Extract the plugin will call this function to accept/transmit reports +// Extract extracts a slice of reported upkeeps (upkeep id, trigger, and work id) from raw bytes. the plugin will call this function to accept/transmit reports. func (e reportEncoder) Extract(raw []byte) ([]ocr2keepers.ReportedUpkeep, error) { report, err := e.packer.UnpackReport(raw) if err != nil { @@ -110,6 +111,7 @@ func (e reportEncoder) Extract(raw []byte) ([]ocr2keepers.ReportedUpkeep, error) trigger.LogTriggerExtension = &ocr2keepers.LogTriggerExtension{} trigger.LogTriggerExtension.TxHash = triggerW.TxHash trigger.LogTriggerExtension.Index = triggerW.LogIndex + trigger.LogTriggerExtension.BlockHash = triggerW.LogBlockHash default: } workID := core.UpkeepWorkID(*id, trigger) diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/encoding/encoder_test.go b/core/services/ocr2/plugins/ocr2keeper/evm21/encoding/encoder_test.go index a7fe7f536b1..36435a93bab 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm21/encoding/encoder_test.go +++ b/core/services/ocr2/plugins/ocr2keeper/evm21/encoding/encoder_test.go @@ -37,7 +37,7 @@ func TestReportEncoder_EncodeExtract(t *testing.T) { []ocr2keepers.CheckResult{ newResult(1, 1, core.GenUpkeepID(ocr2keepers.LogTrigger, "123"), 1, 1), }, - 704, + 736, 1, 1, nil, @@ -49,7 +49,7 @@ func TestReportEncoder_EncodeExtract(t *testing.T) { newResult(1, 1, core.GenUpkeepID(ocr2keepers.ConditionTrigger, "20"), 1, 1), newResult(1, 1, core.GenUpkeepID(ocr2keepers.ConditionTrigger, "30"), 1, 1), }, - 1280, + 1312, 3, 3, nil, @@ -61,7 +61,7 @@ func TestReportEncoder_EncodeExtract(t *testing.T) { newResult(1, 1, core.GenUpkeepID(ocr2keepers.ConditionTrigger, "20"), 1, 1), newResult(1, 1, core.GenUpkeepID(ocr2keepers.LogTrigger, "10"), 1, 1), }, - 1280, + 1312, 1000, 2000, nil, @@ -110,8 +110,9 @@ func newResult(block int64, checkBlock ocr2keepers.BlockNumber, id ocr2keepers.U if tp == ocr2keepers.LogTrigger { trig.LogTriggerExtension = &ocr2keepers.LogTriggerExtension{ - Index: 1, - TxHash: common.HexToHash("0x1234567890123456789012345678901234567890123456789012345678901234"), + Index: 1, + TxHash: common.HexToHash("0x1234567890123456789012345678901234567890123456789012345678901234"), + BlockHash: common.HexToHash("0xaaaaaaaa90123456789012345678901234567890123456789012345678901234"), } } diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/encoding/interface.go b/core/services/ocr2/plugins/ocr2keeper/evm21/encoding/interface.go index 4b559e9104e..ee7074faf08 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm21/encoding/interface.go +++ b/core/services/ocr2/plugins/ocr2keeper/evm21/encoding/interface.go @@ -30,6 +30,7 @@ const ( UpkeepFailureReasonTxHashNoLongerExists UpkeepFailureReason = 33 UpkeepFailureReasonInvalidRevertDataInput UpkeepFailureReason = 34 UpkeepFailureReasonSimulationFailed UpkeepFailureReason = 35 + UpkeepFailureReasonTxHashReorged UpkeepFailureReason = 36 // pipeline execution error NoPipelineError PipelineExecutionState = 0 @@ -41,6 +42,7 @@ const ( MercuryUnmarshalError PipelineExecutionState = 6 InvalidMercuryRequest PipelineExecutionState = 7 InvalidMercuryResponse PipelineExecutionState = 8 // this will only happen if Mercury server sends bad responses + UpkeepNotAuthorized PipelineExecutionState = 9 ) type UpkeepInfo = iregistry21.KeeperRegistryBase21UpkeepInfo @@ -49,7 +51,6 @@ type Packer interface { UnpackCheckResult(payload ocr2keepers.UpkeepPayload, raw string) (ocr2keepers.CheckResult, error) UnpackCheckCallbackResult(callbackResp []byte) (PipelineExecutionState, bool, []byte, uint8, *big.Int, error) UnpackPerformResult(raw string) (PipelineExecutionState, bool, error) - UnpackUpkeepInfo(id *big.Int, raw string) (UpkeepInfo, error) UnpackLogTriggerConfig(raw []byte) (automation_utils_2_1.LogTriggerConfig, error) PackReport(report automation_utils_2_1.KeeperRegistryBase21Report) ([]byte, error) UnpackReport(raw []byte) (automation_utils_2_1.KeeperRegistryBase21Report, error) diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/encoding/packer.go b/core/services/ocr2/plugins/ocr2keeper/evm21/encoding/packer.go index c710b31291f..45d5736cb72 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm21/encoding/packer.go +++ b/core/services/ocr2/plugins/ocr2keeper/evm21/encoding/packer.go @@ -94,22 +94,6 @@ func (p *abiPacker) UnpackPerformResult(raw string) (PipelineExecutionState, boo return NoPipelineError, *abi.ConvertType(out[0], new(bool)).(*bool), nil } -func (p *abiPacker) UnpackUpkeepInfo(id *big.Int, raw string) (UpkeepInfo, error) { - b, err := hexutil.Decode(raw) - if err != nil { - return UpkeepInfo{}, err - } - - out, err := p.abi.Methods["getUpkeep"].Outputs.UnpackValues(b) - if err != nil { - return UpkeepInfo{}, fmt.Errorf("%w: unpack getUpkeep return: %s", err, raw) - } - - info := *abi.ConvertType(out[0], new(UpkeepInfo)).(*UpkeepInfo) - - return info, nil -} - // UnpackLogTriggerConfig unpacks the log trigger config from the given raw data func (p *abiPacker) UnpackLogTriggerConfig(raw []byte) (automation_utils_2_1.LogTriggerConfig, error) { var cfg automation_utils_2_1.LogTriggerConfig diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/block_time.go b/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/block_time.go index 3af93f873c1..9fc35dd84be 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/block_time.go +++ b/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/block_time.go @@ -11,7 +11,7 @@ import ( ) var ( - defaultSampleSize = int64(200) + defaultSampleSize = int64(10000) defaultBlockTime = time.Second * 1 ) @@ -34,39 +34,28 @@ func (r *blockTimeResolver) BlockTime(ctx context.Context, blockSampleSize int64 if err != nil { return 0, fmt.Errorf("failed to get latest block from poller: %w", err) } - if latest < blockSampleSize { + if latest <= blockSampleSize { return defaultBlockTime, nil } - blockTimes, err := r.getSampleTimestamps(ctx, blockSampleSize, latest) + start, end := latest-blockSampleSize, latest + startTime, endTime, err := r.getSampleTimestamps(ctx, uint64(start), uint64(end)) if err != nil { return 0, err } - var sumDiff time.Duration - for i := range blockTimes { - if i != int(blockSampleSize-1) { - sumDiff += blockTimes[i].Sub(blockTimes[i+1]) - } - } - - return sumDiff / time.Duration(blockSampleSize-1), nil + return endTime.Sub(startTime) / time.Duration(blockSampleSize), nil } -func (r *blockTimeResolver) getSampleTimestamps(ctx context.Context, blockSampleSize, latest int64) ([]time.Time, error) { - blockSample := make([]uint64, blockSampleSize) - for i := range blockSample { - blockSample[i] = uint64(latest - blockSampleSize + int64(i)) - } - blocks, err := r.poller.GetBlocksRange(ctx, blockSample) +func (r *blockTimeResolver) getSampleTimestamps(ctx context.Context, start, end uint64) (time.Time, time.Time, error) { + blocks, err := r.poller.GetBlocksRange(ctx, []uint64{start, end}) if err != nil { - return nil, fmt.Errorf("failed to get block range from poller: %w", err) + return time.Time{}, time.Time{}, fmt.Errorf("failed to get block range from poller: %w", err) } sort.Slice(blocks, func(i, j int) bool { - return blocks[i].BlockNumber > blocks[j].BlockNumber + return blocks[i].BlockNumber < blocks[j].BlockNumber }) - blockTimes := make([]time.Time, blockSampleSize) - for i, b := range blocks { - blockTimes[i] = b.BlockTimestamp + if len(blocks) < 2 { + return time.Time{}, time.Time{}, fmt.Errorf("failed to fetch blocks %d, %d from log poller", start, end) } - return blockTimes, nil + return blocks[0].BlockTimestamp, blocks[1].BlockTimestamp, nil } diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/block_time_test.go b/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/block_time_test.go index 55437ff6721..0ad9990e185 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/block_time_test.go +++ b/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/block_time_test.go @@ -52,10 +52,8 @@ func TestBlockTimeResolver_BlockTime(t *testing.T) { 20, nil, []logpoller.LogPollerBlock{ - {BlockTimestamp: now.Add(-time.Second * (2 * 4)), BlockNumber: 1}, - {BlockTimestamp: now.Add(-time.Second * (2 * 3)), BlockNumber: 2}, - {BlockTimestamp: now.Add(-time.Second * (2 * 2)), BlockNumber: 3}, - {BlockTimestamp: now.Add(-time.Second * 2), BlockNumber: 4}, + {BlockTimestamp: now.Add(-time.Second * (2 * 4)), BlockNumber: 16}, + {BlockTimestamp: now, BlockNumber: 20}, }, nil, 2 * time.Second, diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/buffer.go b/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/buffer.go index ad0ae5e1024..b06a3ca809f 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/buffer.go +++ b/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/buffer.go @@ -1,26 +1,45 @@ package logprovider import ( + "encoding/hex" "math/big" "sort" "sync" "sync/atomic" + "github.com/smartcontractkit/ocr2keepers/pkg/v3/random" + ocr2keepers "github.com/smartcontractkit/ocr2keepers/pkg/v3/types" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller" "github.com/smartcontractkit/chainlink/v2/core/logger" ) var ( - // allowedLogsPerBlock is the maximum number of logs allowed per upkeep in a block. - allowedLogsPerBlock = 128 - // bufferMaxBlockSize is the maximum number of blocks in the buffer. - bufferMaxBlockSize = 1024 + // 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 ) // fetchedLog holds the log and the ID of the upkeep type fetchedLog struct { upkeepID *big.Int log logpoller.Log + // cachedLogID is the cached log identifier, used for sorting. + // It is calculated lazily, and cached for performance. + cachedLogID string +} + +func (l *fetchedLog) getLogID() string { + if len(l.cachedLogID) == 0 { + ext := ocr2keepers.LogTriggerExtension{ + Index: uint32(l.log.LogIndex), + } + copy(ext.TxHash[:], l.log.TxHash[:]) + copy(ext.BlockHash[:], l.log.BlockHash[:]) + l.cachedLogID = hex.EncodeToString(ext.LogIdentifier()) + } + return l.cachedLogID } // fetchedBlock holds the logs fetched for a block @@ -33,9 +52,46 @@ type fetchedBlock struct { visited []fetchedLog } +func (b *fetchedBlock) Append(lggr logger.Logger, fl fetchedLog, maxBlockLogs, maxUpkeepLogs int) (fetchedLog, bool) { + has, upkeepLogs := b.has(fl.upkeepID, fl.log) + if has { + // Skipping known logs + return fetchedLog{}, false + } + // lggr.Debugw("Adding log", "i", i, "blockBlock", currentBlock.blockNumber, "logBlock", log.BlockNumber, "id", id) + b.logs = append(b.logs, fl) + + // drop logs if we reached limits. + if upkeepLogs+1 > maxUpkeepLogs { + // in case we have logs overflow for a particular upkeep, we drop a log of that upkeep, + // based on shared, random (per block) order of the logs in the block. + b.Sort() + var dropped fetchedLog + currentLogs := make([]fetchedLog, 0, len(b.logs)-1) + for _, l := range b.logs { + if dropped.upkeepID == nil && l.upkeepID.Cmp(fl.upkeepID) == 0 { + dropped = l + continue + } + currentLogs = append(currentLogs, l) + } + b.logs = currentLogs + return dropped, true + } else if len(b.logs)+len(b.visited) > maxBlockLogs { + // in case we have logs overflow in the buffer level, we drop a log based on + // shared, random (per block) order of the logs in the block. + b.Sort() + dropped := b.logs[0] + b.logs = b.logs[1:] + return dropped, true + } + + return fetchedLog{}, true +} + // Has returns true if the block has the log, // and the number of logs for that upkeep in the block. -func (b fetchedBlock) Has(id *big.Int, log logpoller.Log) (bool, int) { +func (b fetchedBlock) has(id *big.Int, log logpoller.Log) (bool, int) { allLogs := append(b.logs, b.visited...) upkeepLogs := 0 for _, l := range allLogs { @@ -43,7 +99,7 @@ func (b fetchedBlock) Has(id *big.Int, log logpoller.Log) (bool, int) { continue } upkeepLogs++ - if l.log.BlockNumber == log.BlockNumber && l.log.TxHash == log.TxHash && l.log.LogIndex == log.LogIndex { + if l.log.BlockHash == log.BlockHash && l.log.TxHash == log.TxHash && l.log.LogIndex == log.LogIndex { return true, upkeepLogs } } @@ -62,6 +118,22 @@ func (b fetchedBlock) Clone() fetchedBlock { } } +// Sort by log identifiers, shuffled using a pseduorandom souce that is shared across all nodes +// for a given block. +func (b *fetchedBlock) Sort() { + randSeed := random.GetRandomKeySource(nil, uint64(b.blockNumber)) + + shuffledLogIDs := make(map[string]string, len(b.logs)) + for _, log := range b.logs { + logID := log.getLogID() + shuffledLogIDs[logID] = random.ShuffleString(logID, randSeed) + } + + sort.SliceStable(b.logs, func(i, j int) bool { + return shuffledLogIDs[b.logs[i].getLogID()] < shuffledLogIDs[b.logs[j].getLogID()] + }) +} + // logEventBuffer is a circular/ring buffer of fetched logs. // Each entry in the buffer represents a block, // and holds the logs fetched for that block. @@ -97,6 +169,7 @@ func (b *logEventBuffer) bufferSize() int { } // 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 { b.lock.Lock() defer b.lock.Unlock() @@ -107,7 +180,8 @@ func (b *logEventBuffer) enqueue(id *big.Int, logs ...logpoller.Log) int { maxUpkeepLogs := int(b.maxUpkeepLogsPerBlock) latestBlock := b.latestBlockSeen() - added := 0 + added, dropped := 0, 0 + for _, log := range logs { if log.BlockNumber == 0 { // invalid log @@ -125,23 +199,20 @@ func (b *logEventBuffer) enqueue(id *big.Int, logs ...logpoller.Log) int { lggr.Debugw("Skipping log from old block", "currentBlock", currentBlock.blockNumber, "newBlock", log.BlockNumber) continue } - if len(currentBlock.logs)+1 > maxBlockLogs { - lggr.Debugw("Reached max logs number per block, dropping log", "blockNumber", log.BlockNumber, - "blockHash", log.BlockHash, "txHash", log.TxHash, "logIndex", log.LogIndex) + droppedLog, ok := currentBlock.Append(lggr, fetchedLog{upkeepID: id, log: log}, maxBlockLogs, maxUpkeepLogs) + if !ok { + // Skipping known logs continue } - if has, upkeepLogs := currentBlock.Has(id, log); has { - // Skipping existing log - continue - } else if upkeepLogs+1 > maxUpkeepLogs { - lggr.Debugw("Reached max logs number per upkeep, dropping log", "blockNumber", log.BlockNumber, - "blockHash", log.BlockHash, "txHash", log.TxHash, "logIndex", log.LogIndex) - continue + if droppedLog.upkeepID != nil { + dropped++ + lggr.Debugw("Reached log buffer limits, dropping log", "blockNumber", droppedLog.log.BlockNumber, + "blockHash", droppedLog.log.BlockHash, "txHash", droppedLog.log.TxHash, "logIndex", droppedLog.log.LogIndex, + "upkeepID", droppedLog.upkeepID.String()) } - // lggr.Debugw("Adding log", "i", i, "blockBlock", currentBlock.blockNumber, "logBlock", log.BlockNumber, "id", id) - currentBlock.logs = append(currentBlock.logs, fetchedLog{upkeepID: id, log: log}) - b.blocks[i] = currentBlock added++ + b.blocks[i] = currentBlock + if log.BlockNumber > latestBlock { latestBlock = log.BlockNumber } @@ -151,10 +222,10 @@ func (b *logEventBuffer) enqueue(id *big.Int, logs ...logpoller.Log) int { atomic.StoreInt64(&b.latestBlock, latestBlock) } if added > 0 { - lggr.Debugw("Added logs to buffer", "addedLogs", added, "latestBlock", latestBlock) + lggr.Debugw("Added logs to buffer", "addedLogs", added, "dropped", dropped, "latestBlock", latestBlock) } - return added + return added - dropped } // peek returns the logs in range [latestBlock-blocks, latestBlock] @@ -196,7 +267,7 @@ func (b *logEventBuffer) peekRange(start, end int64) []fetchedLog { } // dequeueRange returns the logs between start and end inclusive. -func (b *logEventBuffer) dequeueRange(start, end int64, upkeepLimit int) []fetchedLog { +func (b *logEventBuffer) dequeueRange(start, end int64, upkeepLimit, totalLimit int) []fetchedLog { b.lock.Lock() defer b.lock.Unlock() @@ -214,20 +285,33 @@ func (b *logEventBuffer) dequeueRange(start, end int64, upkeepLimit int) []fetch }) logsCount := map[string]int{} + totalCount := 0 var results []fetchedLog for _, block := range fetchedBlocks { - // double checking that we don't have any gaps in the range if block.blockNumber < start || block.blockNumber > end { + // double checking that we don't have any gaps in the range continue } + if totalCount >= totalLimit { + // reached total limit, no need to process more blocks + break + } + // Sort the logs in random order that is shared across all nodes. + // This ensures that nodes across the network will process the same logs. + block.Sort() var remainingLogs, blockResults []fetchedLog for _, log := range block.logs { + if totalCount >= totalLimit { + remainingLogs = append(remainingLogs, log) + continue + } if logsCount[log.upkeepID.String()] >= upkeepLimit { remainingLogs = append(remainingLogs, log) continue } - logsCount[log.upkeepID.String()]++ blockResults = append(blockResults, log) + logsCount[log.upkeepID.String()]++ + totalCount++ } if len(blockResults) == 0 { continue diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/buffer_test.go b/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/buffer_test.go index 18eecb748a5..5c8908f9be7 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/buffer_test.go +++ b/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/buffer_test.go @@ -1,15 +1,18 @@ package logprovider import ( + "encoding/hex" "fmt" "math/big" "testing" "github.com/ethereum/go-ethereum/common" + ocr2keepers "github.com/smartcontractkit/ocr2keepers/pkg/v3/types" "github.com/stretchr/testify/require" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller" "github.com/smartcontractkit/chainlink/v2/core/logger" + "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evm21/core" ) func TestLogEventBuffer_GetBlocksInRange(t *testing.T) { @@ -236,7 +239,7 @@ func TestLogEventBuffer_EnqueueDequeue(t *testing.T) { results := buf.peekRange(int64(1), int64(2)) require.Equal(t, 2, len(results)) verifyBlockNumbers(t, results, 1, 2) - removed := buf.dequeueRange(int64(1), int64(2), 2) + removed := buf.dequeueRange(int64(1), int64(2), 2, 10) require.Equal(t, 2, len(removed)) results = buf.peekRange(int64(1), int64(2)) require.Equal(t, 0, len(results)) @@ -256,7 +259,7 @@ func TestLogEventBuffer_EnqueueDequeue(t *testing.T) { results := buf.peek(8) require.Equal(t, 4, len(results)) verifyBlockNumbers(t, results, 1, 2, 3, 3) - removed := buf.dequeueRange(1, 3, 5) + removed := buf.dequeueRange(1, 3, 5, 5) require.Equal(t, 4, len(removed)) buf.lock.Lock() require.Equal(t, 0, len(buf.blocks[0].logs)) @@ -313,10 +316,18 @@ func TestLogEventBuffer_EnqueueDequeue(t *testing.T) { logpoller.Log{BlockNumber: 5, TxHash: common.HexToHash("0x5"), LogIndex: 0}, ), 5) - logs := buf.dequeueRange(1, 5, 2) + logs := buf.dequeueRange(1, 5, 2, 10) require.Equal(t, 2, len(logs)) require.Equal(t, int64(5), logs[0].log.BlockNumber) require.Equal(t, int64(4), logs[1].log.BlockNumber) + + require.Equal(t, buf.enqueue(big.NewInt(1), + logpoller.Log{BlockNumber: 4, TxHash: common.HexToHash("0x4"), LogIndex: 1}, + logpoller.Log{BlockNumber: 5, TxHash: common.HexToHash("0x5"), LogIndex: 1}, + ), 2) + + logs = buf.dequeueRange(1, 5, 3, 2) + require.Equal(t, 2, len(logs)) }) t.Run("dequeue doesn't return same logs again", func(t *testing.T) { @@ -327,19 +338,508 @@ func TestLogEventBuffer_EnqueueDequeue(t *testing.T) { logpoller.Log{BlockNumber: 3, TxHash: common.HexToHash("0x3"), LogIndex: 0}, ), 3) - logs := buf.dequeueRange(3, 3, 2) + logs := buf.dequeueRange(3, 3, 2, 10) fmt.Println(logs) require.Equal(t, 1, len(logs)) - logs = buf.dequeueRange(3, 3, 2) + logs = buf.dequeueRange(3, 3, 2, 10) fmt.Println(logs) require.Equal(t, 0, len(logs)) }) } +func TestLogEventBuffer_FetchedBlock_Append(t *testing.T) { + type appendArgs struct { + fl fetchedLog + maxBlockLogs, maxUpkeepLogs int + added, dropped bool + } + + tests := []struct { + name string + blockNumber int64 + logs []fetchedLog + visited []fetchedLog + toAdd []appendArgs + expected []fetchedLog + added bool + }{ + { + name: "empty block", + blockNumber: 1, + logs: []fetchedLog{}, + visited: []fetchedLog{}, + toAdd: []appendArgs{ + { + fl: fetchedLog{ + log: logpoller.Log{ + BlockNumber: 1, + TxHash: common.HexToHash("0x1"), + LogIndex: 0, + }, + upkeepID: core.GenUpkeepID(ocr2keepers.LogTrigger, "111").BigInt(), + }, + maxBlockLogs: 10, + maxUpkeepLogs: 2, + added: true, + }, + }, + expected: []fetchedLog{ + { + log: logpoller.Log{ + BlockNumber: 1, + TxHash: common.HexToHash("0x1"), + LogIndex: 0, + }, + upkeepID: core.GenUpkeepID(ocr2keepers.LogTrigger, "111").BigInt(), + }, + }, + }, + { + name: "existing log", + blockNumber: 1, + logs: []fetchedLog{ + { + log: logpoller.Log{ + BlockNumber: 1, + TxHash: common.HexToHash("0x1"), + LogIndex: 0, + }, + upkeepID: core.GenUpkeepID(ocr2keepers.LogTrigger, "111").BigInt(), + }, + }, + visited: []fetchedLog{}, + toAdd: []appendArgs{ + { + fl: fetchedLog{ + log: logpoller.Log{ + BlockNumber: 1, + TxHash: common.HexToHash("0x1"), + LogIndex: 0, + }, + upkeepID: core.GenUpkeepID(ocr2keepers.LogTrigger, "111").BigInt(), + }, + maxBlockLogs: 10, + maxUpkeepLogs: 2, + added: false, + }, + }, + expected: []fetchedLog{ + { + log: logpoller.Log{ + BlockNumber: 1, + TxHash: common.HexToHash("0x1"), + LogIndex: 0, + }, + upkeepID: core.GenUpkeepID(ocr2keepers.LogTrigger, "111").BigInt(), + }, + }, + }, + { + name: "visited log", + blockNumber: 1, + logs: []fetchedLog{}, + visited: []fetchedLog{ + { + log: logpoller.Log{ + BlockNumber: 1, + TxHash: common.HexToHash("0x1"), + LogIndex: 0, + }, + upkeepID: core.GenUpkeepID(ocr2keepers.LogTrigger, "111").BigInt(), + }, + }, + toAdd: []appendArgs{ + { + fl: fetchedLog{ + log: logpoller.Log{ + BlockNumber: 1, + TxHash: common.HexToHash("0x1"), + LogIndex: 0, + }, + upkeepID: core.GenUpkeepID(ocr2keepers.LogTrigger, "111").BigInt(), + }, + maxBlockLogs: 10, + maxUpkeepLogs: 2, + added: false, + }, + }, + expected: []fetchedLog{}, + }, + { + name: "upkeep log limits", + blockNumber: 1, + logs: []fetchedLog{}, + visited: []fetchedLog{}, + toAdd: []appendArgs{ + { + fl: fetchedLog{ + log: logpoller.Log{ + BlockNumber: 1, + TxHash: common.HexToHash("0x1"), + LogIndex: 0, + }, + upkeepID: core.GenUpkeepID(ocr2keepers.LogTrigger, "111").BigInt(), + }, + maxBlockLogs: 10, + maxUpkeepLogs: 2, + added: true, + }, + { + fl: fetchedLog{ + log: logpoller.Log{ + BlockNumber: 1, + TxHash: common.HexToHash("0x1"), + LogIndex: 1, + }, + upkeepID: core.GenUpkeepID(ocr2keepers.LogTrigger, "111").BigInt(), + }, + maxBlockLogs: 10, + maxUpkeepLogs: 2, + added: true, + }, + { + fl: fetchedLog{ + log: logpoller.Log{ + BlockNumber: 1, + TxHash: common.HexToHash("0x1"), + LogIndex: 2, + }, + upkeepID: core.GenUpkeepID(ocr2keepers.LogTrigger, "111").BigInt(), + }, + maxBlockLogs: 10, + maxUpkeepLogs: 2, + added: true, + dropped: true, + }, + }, + expected: []fetchedLog{ + { + log: logpoller.Log{ + BlockNumber: 1, + TxHash: common.HexToHash("0x1"), + LogIndex: 1, + }, + upkeepID: core.GenUpkeepID(ocr2keepers.LogTrigger, "111").BigInt(), + }, + { + log: logpoller.Log{ + BlockNumber: 1, + TxHash: common.HexToHash("0x1"), + LogIndex: 2, + }, + upkeepID: core.GenUpkeepID(ocr2keepers.LogTrigger, "111").BigInt(), + }, + }, + }, + { + name: "block log limits", + blockNumber: 1, + logs: []fetchedLog{}, + visited: []fetchedLog{}, + toAdd: []appendArgs{ + { + fl: fetchedLog{ + log: logpoller.Log{ + BlockNumber: 1, + TxHash: common.HexToHash("0x1"), + LogIndex: 0, + }, + upkeepID: core.GenUpkeepID(ocr2keepers.LogTrigger, "111").BigInt(), + }, + maxBlockLogs: 2, + maxUpkeepLogs: 4, + added: true, + }, + { + fl: fetchedLog{ + log: logpoller.Log{ + BlockNumber: 1, + TxHash: common.HexToHash("0x1"), + LogIndex: 1, + }, + upkeepID: core.GenUpkeepID(ocr2keepers.LogTrigger, "111").BigInt(), + }, + maxBlockLogs: 2, + maxUpkeepLogs: 4, + added: true, + }, + { + fl: fetchedLog{ + log: logpoller.Log{ + BlockNumber: 1, + TxHash: common.HexToHash("0x1"), + LogIndex: 2, + }, + upkeepID: core.GenUpkeepID(ocr2keepers.LogTrigger, "111").BigInt(), + }, + maxBlockLogs: 2, + maxUpkeepLogs: 4, + added: true, + dropped: true, + }, + }, + expected: []fetchedLog{ + { + log: logpoller.Log{ + BlockNumber: 1, + TxHash: common.HexToHash("0x1"), + LogIndex: 1, + }, + upkeepID: core.GenUpkeepID(ocr2keepers.LogTrigger, "111").BigInt(), + }, + { + log: logpoller.Log{ + BlockNumber: 1, + TxHash: common.HexToHash("0x1"), + LogIndex: 2, + }, + upkeepID: core.GenUpkeepID(ocr2keepers.LogTrigger, "111").BigInt(), + }, + }, + }, + } + + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + lggr := logger.TestLogger(t) + b := fetchedBlock{ + blockNumber: tc.blockNumber, + logs: make([]fetchedLog, len(tc.logs)), + visited: make([]fetchedLog, len(tc.visited)), + } + copy(b.logs, tc.logs) + copy(b.visited, tc.visited) + + for _, args := range tc.toAdd { + dropped, added := b.Append(lggr, args.fl, args.maxBlockLogs, args.maxUpkeepLogs) + require.Equal(t, args.added, added) + if args.dropped { + require.NotNil(t, dropped.upkeepID) + } else { + require.Nil(t, dropped.upkeepID) + } + } + // clear cached logIDs + for i := range b.logs { + b.logs[i].cachedLogID = "" + } + require.Equal(t, tc.expected, b.logs) + }) + } +} +func TestLogEventBuffer_FetchedBlock_Sort(t *testing.T) { + tests := []struct { + name string + blockNumber int64 + logs []fetchedLog + beforeSort []string + afterSort []string + iterations int + }{ + { + name: "no logs", + blockNumber: 10, + logs: []fetchedLog{}, + beforeSort: []string{}, + afterSort: []string{}, + }, + { + name: "single log", + blockNumber: 1, + logs: []fetchedLog{ + { + log: logpoller.Log{ + BlockHash: common.HexToHash("0x111"), + BlockNumber: 1, + TxHash: common.HexToHash("0x1"), + LogIndex: 0, + }, + }, + }, + beforeSort: []string{ + "0000000000000000000000000000000000000000000000000000000000000111000000000000000000000000000000000000000000000000000000000000000100000000", + }, + afterSort: []string{ + "0000000000000000000000000000000000000000000000000000000000000111000000000000000000000000000000000000000000000000000000000000000100000000", + }, + }, + { + name: "multiple logs with 10 iterations", + blockNumber: 1, + logs: []fetchedLog{ + { + log: logpoller.Log{ + BlockNumber: 1, + BlockHash: common.HexToHash("0xa25ebae1099f3fbae2525ebae279f3ae25e"), + TxHash: common.HexToHash("0xb711bd1103927611ee41152aa8ae27f3330"), + LogIndex: 0, + }, + upkeepID: core.GenUpkeepID(ocr2keepers.LogTrigger, "111").BigInt(), + }, + { + log: logpoller.Log{ + BlockNumber: 1, + BlockHash: common.HexToHash("0xa25ebae1099f3fbae2525ebae279f3ae25e"), + TxHash: common.HexToHash("0xa651bd1109922111ee411525ebae27f3fb6"), + LogIndex: 0, + }, + upkeepID: core.GenUpkeepID(ocr2keepers.LogTrigger, "222").BigInt(), + }, + { + log: logpoller.Log{ + BlockNumber: 1, + BlockHash: common.HexToHash("0xa25ebae1099f3fbae2525ebae279f3ae25e"), + TxHash: common.HexToHash("0xa651bd1109922111ee411525ebae27f3fb6"), + LogIndex: 4, + }, + upkeepID: core.GenUpkeepID(ocr2keepers.LogTrigger, "111").BigInt(), + }, + { + log: logpoller.Log{ + BlockNumber: 1, + BlockHash: common.HexToHash("0xa25ebae1099f3fbae2525ebae279f3ae25e"), + TxHash: common.HexToHash("0xa651bd1109922111ee411525ebae27f3fb6"), + LogIndex: 3, + }, + upkeepID: core.GenUpkeepID(ocr2keepers.LogTrigger, "222").BigInt(), + }, + { + log: logpoller.Log{ + BlockNumber: 1, + BlockHash: common.HexToHash("0xa25ebae1099f3fbae2525ebae279f3ae25e"), + TxHash: common.HexToHash("0xa651bd1109922111ee411525ebae27f3fb6"), + LogIndex: 2, + }, + upkeepID: core.GenUpkeepID(ocr2keepers.LogTrigger, "111").BigInt(), + }, + { + log: logpoller.Log{ + BlockNumber: 1, + BlockHash: common.HexToHash("0xa25ebae1099f3fbae2525ebae279f3ae25e"), + TxHash: common.HexToHash("0xa651bd1109922111ee411525ebae27f3fb6"), + LogIndex: 5, + }, + upkeepID: core.GenUpkeepID(ocr2keepers.LogTrigger, "111").BigInt(), + }, + { + log: logpoller.Log{ + BlockNumber: 1, + BlockHash: common.HexToHash("0xa25ebae1099f3fbae2525ebae279f3ae25e"), + TxHash: common.HexToHash("0xa651bd1109922111ee411525ebae27f3fb6"), + LogIndex: 3, + }, + upkeepID: core.GenUpkeepID(ocr2keepers.LogTrigger, "111").BigInt(), + }, + { + log: logpoller.Log{ + BlockNumber: 1, + BlockHash: common.HexToHash("0xa25ebae1099f3fbae2525ebae279f3ae25e"), + TxHash: common.HexToHash("0xa651bd1109922111ee411525ebae27f3fb6"), + LogIndex: 1, + }, + upkeepID: core.GenUpkeepID(ocr2keepers.LogTrigger, "111").BigInt(), + }, + }, + beforeSort: []string{ + "00000000000000000000000000000a25ebae1099f3fbae2525ebae279f3ae25e00000000000000000000000000000b711bd1103927611ee41152aa8ae27f333000000000", + "00000000000000000000000000000a25ebae1099f3fbae2525ebae279f3ae25e00000000000000000000000000000a651bd1109922111ee411525ebae27f3fb600000000", + "00000000000000000000000000000a25ebae1099f3fbae2525ebae279f3ae25e00000000000000000000000000000a651bd1109922111ee411525ebae27f3fb600000004", + "00000000000000000000000000000a25ebae1099f3fbae2525ebae279f3ae25e00000000000000000000000000000a651bd1109922111ee411525ebae27f3fb600000003", + "00000000000000000000000000000a25ebae1099f3fbae2525ebae279f3ae25e00000000000000000000000000000a651bd1109922111ee411525ebae27f3fb600000002", + "00000000000000000000000000000a25ebae1099f3fbae2525ebae279f3ae25e00000000000000000000000000000a651bd1109922111ee411525ebae27f3fb600000005", + "00000000000000000000000000000a25ebae1099f3fbae2525ebae279f3ae25e00000000000000000000000000000a651bd1109922111ee411525ebae27f3fb600000003", + "00000000000000000000000000000a25ebae1099f3fbae2525ebae279f3ae25e00000000000000000000000000000a651bd1109922111ee411525ebae27f3fb600000001", + }, + afterSort: []string{ + "00000000000000000000000000000a25ebae1099f3fbae2525ebae279f3ae25e00000000000000000000000000000b711bd1103927611ee41152aa8ae27f333000000000", + "00000000000000000000000000000a25ebae1099f3fbae2525ebae279f3ae25e00000000000000000000000000000a651bd1109922111ee411525ebae27f3fb600000000", + "00000000000000000000000000000a25ebae1099f3fbae2525ebae279f3ae25e00000000000000000000000000000a651bd1109922111ee411525ebae27f3fb600000001", + "00000000000000000000000000000a25ebae1099f3fbae2525ebae279f3ae25e00000000000000000000000000000a651bd1109922111ee411525ebae27f3fb600000002", + "00000000000000000000000000000a25ebae1099f3fbae2525ebae279f3ae25e00000000000000000000000000000a651bd1109922111ee411525ebae27f3fb600000003", + "00000000000000000000000000000a25ebae1099f3fbae2525ebae279f3ae25e00000000000000000000000000000a651bd1109922111ee411525ebae27f3fb600000003", + "00000000000000000000000000000a25ebae1099f3fbae2525ebae279f3ae25e00000000000000000000000000000a651bd1109922111ee411525ebae27f3fb600000004", + "00000000000000000000000000000a25ebae1099f3fbae2525ebae279f3ae25e00000000000000000000000000000a651bd1109922111ee411525ebae27f3fb600000005", + }, + iterations: 10, + }, + } + + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + b := fetchedBlock{ + blockNumber: tc.blockNumber, + logs: make([]fetchedLog, len(tc.logs)), + } + if tc.iterations == 0 { + tc.iterations = 1 + } + // performing the same multiple times should yield the same result + // default is one iteration + for i := 0; i < tc.iterations; i++ { + copy(b.logs, tc.logs) + logIDs := getLogIds(b) + require.Equal(t, len(tc.beforeSort), len(logIDs)) + require.Equal(t, tc.beforeSort, logIDs) + b.Sort() + logIDsAfterSort := getLogIds(b) + require.Equal(t, len(tc.afterSort), len(logIDsAfterSort)) + require.Equal(t, tc.afterSort, logIDsAfterSort) + } + }) + } +} + +func TestLogEventBuffer_FetchedBlock_Clone(t *testing.T) { + b1 := fetchedBlock{ + blockNumber: 1, + logs: []fetchedLog{ + { + log: logpoller.Log{ + BlockNumber: 1, + TxHash: common.HexToHash("0x1"), + LogIndex: 0, + }, + upkeepID: core.GenUpkeepID(ocr2keepers.LogTrigger, "111").BigInt(), + }, + { + log: logpoller.Log{ + BlockNumber: 1, + TxHash: common.HexToHash("0x1"), + LogIndex: 2, + }, + upkeepID: core.GenUpkeepID(ocr2keepers.LogTrigger, "111").BigInt(), + }, + }, + } + + b2 := b1.Clone() + require.Equal(t, b1.blockNumber, b2.blockNumber) + require.Equal(t, len(b1.logs), len(b2.logs)) + require.Equal(t, b1.logs[0].log.BlockNumber, b2.logs[0].log.BlockNumber) + + b1.blockNumber = 2 + b1.logs[0].log.BlockNumber = 2 + require.NotEqual(t, b1.blockNumber, b2.blockNumber) + require.NotEqual(t, b1.logs[0].log.BlockNumber, b2.logs[0].log.BlockNumber) +} + func verifyBlockNumbers(t *testing.T, logs []fetchedLog, bns ...int64) { require.Equal(t, len(bns), len(logs), "expected length mismatch") for i, log := range logs { require.Equal(t, bns[i], log.log.BlockNumber, "wrong block number") } } + +func getLogIds(b fetchedBlock) []string { + logIDs := make([]string, len(b.logs)) + for i, l := range b.logs { + ext := ocr2keepers.LogTriggerExtension{ + TxHash: l.log.TxHash, + Index: uint32(l.log.LogIndex), + BlockHash: l.log.BlockHash, + } + logIDs[i] = hex.EncodeToString(ext.LogIdentifier()) + } + return logIDs +} diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/factory.go b/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/factory.go index 0db15da0f32..4b3fa8cb404 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/factory.go +++ b/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/factory.go @@ -36,6 +36,8 @@ type LogTriggersOptions struct { BlockRateLimit rate.Limit // blockLimitBurst is the burst upper limit on the range of blocks the we fetch logs for. BlockLimitBurst int + // Finality depth is the number of blocks to wait before considering a block final. + FinalityDepth int64 } func NewOptions(finalityDepth int64) LogTriggersOptions { @@ -49,8 +51,8 @@ func NewOptions(finalityDepth int64) LogTriggersOptions { func (o *LogTriggersOptions) Defaults(finalityDepth int64) { if o.LookbackBlocks == 0 { lookbackBlocks := int64(200) - if lookbackBlocks < int64(finalityDepth) { - lookbackBlocks = int64(finalityDepth) + if lookbackBlocks < finalityDepth { + lookbackBlocks = finalityDepth } o.LookbackBlocks = lookbackBlocks } @@ -63,4 +65,7 @@ func (o *LogTriggersOptions) Defaults(finalityDepth int64) { if o.BlockRateLimit == 0 { o.BlockRateLimit = rate.Every(o.ReadInterval) } + if o.FinalityDepth == 0 { + o.FinalityDepth = finalityDepth + } } diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/filter.go b/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/filter.go index db1cb43d2c3..44780cbc4b1 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/filter.go +++ b/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/filter.go @@ -46,6 +46,7 @@ func (f upkeepFilter) Clone() upkeepFilter { } } +// Select returns a slice of logs which match the upkeep filter. func (f upkeepFilter) Select(logs ...logpoller.Log) []logpoller.Log { var selected []logpoller.Log for _, log := range logs { @@ -56,6 +57,7 @@ func (f upkeepFilter) Select(logs ...logpoller.Log) []logpoller.Log { return selected } +// match returns a bool indicating if the log's topics data matches selector and indexed topics in upkeep filter. func (f upkeepFilter) match(log logpoller.Log) bool { filters := f.topics[1:] selector := f.selector @@ -65,7 +67,7 @@ func (f upkeepFilter) match(log logpoller.Log) bool { return true } - for i, f := range filters { + for i, filter := range filters { // bitwise AND the selector with the index to check // if the filter is needed mask := uint8(1 << uint8(i)) @@ -76,7 +78,7 @@ func (f upkeepFilter) match(log logpoller.Log) bool { // log doesn't have enough topics return false } - if !bytes.Equal(f.Bytes(), log.Topics[i+1]) { + if !bytes.Equal(filter.Bytes(), log.Topics[i+1]) { return false } } diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/integration_test.go b/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/integration_test.go index 30994543eb6..b5f229f6015 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/integration_test.go +++ b/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/integration_test.go @@ -478,10 +478,10 @@ func TestIntegration_LogRecoverer_Backfill(t *testing.T) { } lp, ethClient, utilsABI := setupDependencies(t, db, backend) filterStore := logprovider.NewUpkeepFilterStore() - origDefaultRecoveryInterval := logprovider.DefaultRecoveryInterval - logprovider.DefaultRecoveryInterval = time.Millisecond * 200 + origDefaultRecoveryInterval := logprovider.RecoveryInterval + logprovider.RecoveryInterval = time.Millisecond * 200 defer func() { - logprovider.DefaultRecoveryInterval = origDefaultRecoveryInterval + logprovider.RecoveryInterval = origDefaultRecoveryInterval }() provider, recoverer := setup(logger.TestLogger(t), lp, nil, utilsABI, &mockUpkeepStateStore{}, filterStore, opts) logProvider := provider.(logprovider.LogEventProviderTest) diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/log_packer.go b/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/log_packer.go index c4e8d7e0da2..49bc9b19d4f 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/log_packer.go +++ b/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/log_packer.go @@ -22,13 +22,13 @@ func NewLogEventsPacker(utilsABI abi.ABI) *logEventsPacker { } func (p *logEventsPacker) PackLogData(log logpoller.Log) ([]byte, error) { - topics := [][32]byte{} + var topics [][32]byte for _, topic := range log.GetTopics() { topics = append(topics, topic) } b, err := p.abi.Pack("_log", &automation_utils_2_1.Log{ Index: big.NewInt(log.LogIndex), - TxIndex: big.NewInt(0), // TODO: Add this to the logpoller + TxIndex: big.NewInt(0), // Exploratory: Add this to the logpoller and pass correct value TxHash: log.TxHash, BlockNumber: big.NewInt(log.BlockNumber), BlockHash: log.BlockHash, diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/provider.go b/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/provider.go index 8fbbb1e0a9d..b62fb370847 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/provider.go +++ b/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/provider.go @@ -22,14 +22,19 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evm21/core" "github.com/smartcontractkit/chainlink/v2/core/services/pg" + "github.com/smartcontractkit/chainlink/v2/core/utils" ) var ( + LogProviderServiceName = "LogEventProvider" + ErrHeadNotAvailable = fmt.Errorf("head not available") ErrBlockLimitExceeded = fmt.Errorf("block limit exceeded") // AllowedLogsPerUpkeep is the maximum number of logs allowed per upkeep every single call. AllowedLogsPerUpkeep = 5 + // MaxPayloads is the maximum number of payloads to return per call. + MaxPayloads = 100 readJobQueueSize = 64 readLogsTimeout = 10 * time.Second @@ -76,9 +81,10 @@ var _ LogEventProviderTest = &logEventProvider{} // logEventProvider manages log filters for upkeeps and enables to read the log events. type logEventProvider struct { - lggr logger.Logger + utils.StartStopOnce + threadCtrl utils.ThreadControl - cancel context.CancelFunc + lggr logger.Logger poller logpoller.LogPoller @@ -97,9 +103,10 @@ type logEventProvider struct { func NewLogProvider(lggr logger.Logger, poller logpoller.LogPoller, packer LogDataPacker, filterStore UpkeepFilterStore, opts LogTriggersOptions) *logEventProvider { return &logEventProvider{ - packer: packer, + threadCtrl: utils.NewThreadControl(), lggr: lggr.Named("KeepersRegistry.LogEventProvider"), - buffer: newLogEventBuffer(lggr, int(opts.LookbackBlocks), bufferMaxBlockSize, allowedLogsPerBlock), + packer: packer, + buffer: newLogEventBuffer(lggr, int(opts.LookbackBlocks), maxLogsPerBlock, maxLogsPerUpkeepInBlock), poller: poller, opts: opts, filterStore: filterStore, @@ -107,33 +114,22 @@ func NewLogProvider(lggr logger.Logger, poller logpoller.LogPoller, packer LogDa } func (p *logEventProvider) Start(context.Context) error { - ctx, cancel := context.WithCancel(context.Background()) + return p.StartOnce(LogProviderServiceName, func() error { - p.lock.Lock() - if p.cancel != nil { - p.lock.Unlock() - cancel() // Cancel the created context - return errors.New("already started") - } - p.cancel = cancel - p.lock.Unlock() + readQ := make(chan []*big.Int, readJobQueueSize) - readQ := make(chan []*big.Int, readJobQueueSize) + p.lggr.Infow("starting log event provider", "readInterval", p.opts.ReadInterval, "readMaxBatchSize", readMaxBatchSize, "readers", readerThreads) - p.lggr.Infow("starting log event provider", "readInterval", p.opts.ReadInterval, "readMaxBatchSize", readMaxBatchSize, "readers", readerThreads) + for i := 0; i < readerThreads; i++ { + p.threadCtrl.Go(func(ctx context.Context) { + p.startReader(ctx, readQ) + }) + } - { // start readers - go func(ctx context.Context) { - for i := 0; i < readerThreads; i++ { - go p.startReader(ctx, readQ) - } - }(ctx) - } + p.threadCtrl.Go(func(ctx context.Context) { + lggr := p.lggr.With("where", "scheduler") - { // start scheduler - lggr := p.lggr.With("where", "scheduler") - go func(ctx context.Context) { - err := p.scheduleReadJobs(ctx, func(ids []*big.Int) { + p.scheduleReadJobs(ctx, func(ids []*big.Int) { select { case readQ <- ids: case <-ctx.Done(): @@ -141,31 +137,21 @@ func (p *logEventProvider) Start(context.Context) error { lggr.Warnw("readQ is full, dropping ids", "ids", ids) } }) - if err != nil { - lggr.Warnw("stopped scheduling read jobs with error", "err", err) - } - lggr.Debug("stopped scheduling read jobs") - }(ctx) - } + }) - return nil + return nil + }) } func (p *logEventProvider) Close() error { - p.lock.Lock() - defer p.lock.Unlock() - - if cancel := p.cancel; cancel != nil { - p.cancel = nil - cancel() - } else { - return errors.New("already stopped") - } - return nil + return p.StopOnce(LogProviderServiceName, func() error { + p.threadCtrl.Close() + return nil + }) } -func (p *logEventProvider) Name() string { - return p.lggr.Name() +func (p *logEventProvider) HealthReport() map[string]error { + return map[string]error{LogProviderServiceName: p.Healthy()} } func (p *logEventProvider) GetLatestPayloads(ctx context.Context) ([]ocr2keepers.UpkeepPayload, error) { @@ -177,7 +163,7 @@ func (p *logEventProvider) GetLatestPayloads(ctx context.Context) ([]ocr2keepers if start <= 0 { start = 1 } - logs := p.buffer.dequeueRange(start, latest, AllowedLogsPerUpkeep) + logs := p.buffer.dequeueRange(start, latest, AllowedLogsPerUpkeep, MaxPayloads) // p.lggr.Debugw("got latest logs from buffer", "latest", latest, "diff", diff, "logs", len(logs)) @@ -231,7 +217,7 @@ func (p *logEventProvider) CurrentPartitionIdx() uint64 { } // scheduleReadJobs starts a scheduler that pushed ids to readQ for reading logs in the background. -func (p *logEventProvider) scheduleReadJobs(pctx context.Context, execute func([]*big.Int)) error { +func (p *logEventProvider) scheduleReadJobs(pctx context.Context, execute func([]*big.Int)) { ctx, cancel := context.WithCancel(pctx) defer cancel() @@ -259,7 +245,7 @@ func (p *logEventProvider) scheduleReadJobs(pctx context.Context, execute func([ partitionIdx++ atomic.StoreUint64(&p.currentPartitionIdx, partitionIdx) case <-ctx.Done(): - return ctx.Err() + return } } } @@ -318,7 +304,10 @@ func (p *logEventProvider) updateFiltersLastPoll(entries []upkeepFilter) { p.filterStore.UpdateFilters(func(orig, f upkeepFilter) upkeepFilter { if f.lastPollBlock > orig.lastPollBlock { orig.lastPollBlock = f.lastPollBlock - p.lggr.Debugw("Updated lastPollBlock", "lastPollBlock", f.lastPollBlock, "upkeepID", f.upkeepID) + if f.lastPollBlock%10 == 0 { + // print log occasionally to avoid spamming logs + p.lggr.Debugw("Updated lastPollBlock", "lastPollBlock", f.lastPollBlock, "upkeepID", f.upkeepID) + } } return orig }, entries...) diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/provider_life_cycle.go b/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/provider_life_cycle.go index 8a21637241a..ab816adb1b3 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/provider_life_cycle.go +++ b/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/provider_life_cycle.go @@ -18,8 +18,7 @@ import ( var ( // LogRetention is the amount of time to retain logs for. LogRetention = 24 * time.Hour - // When adding a filter in log poller, backfill is done for this number of blocks - // from latest + // LogBackfillBuffer is the number of blocks from the latest block for which backfill is done when adding a filter in log poller LogBackfillBuffer = 100 ) @@ -83,11 +82,6 @@ func (p *logEventProvider) RegisterFilter(ctx context.Context, opts FilterOption p.lggr.Debugf("filter for upkeep with id %s already registered with the same config", upkeepID.String()) return nil } - // removing filter so we can recreate it with updated values - err := p.poller.UnregisterFilter(p.filterName(currentFilter.upkeepID)) - if err != nil { - return fmt.Errorf("failed to unregister upkeep filter %s for update: %w", upkeepID.String(), err) - } filter = *currentFilter } else { // new filter filter = upkeepFilter{ @@ -115,28 +109,47 @@ func (p *logEventProvider) register(ctx context.Context, lpFilter logpoller.Filt if err != nil { return fmt.Errorf("failed to get latest block while registering filter: %w", err) } + lggr := p.lggr.With("upkeepID", ufilter.upkeepID.String()) + logPollerHasFilter := p.poller.HasFilter(lpFilter.Name) + filterStoreHasFilter := p.filterStore.Has(ufilter.upkeepID) + if filterStoreHasFilter { + // removing filter in case of an update so we can recreate it with updated values + lggr.Debugw("Upserting upkeep filter") + err := p.poller.UnregisterFilter(lpFilter.Name) + if err != nil { + return fmt.Errorf("failed to upsert (unregister) upkeep filter %s: %w", ufilter.upkeepID.String(), err) + } + } if err := p.poller.RegisterFilter(lpFilter); err != nil { return err } p.filterStore.AddActiveUpkeeps(ufilter) + if logPollerHasFilter { + // already registered in DB before, no need to backfill + return nil + } backfillBlock := latest - int64(LogBackfillBuffer) if backfillBlock < 1 { // New chain, backfill from start backfillBlock = 1 } - // TODO: Optimise to do backfill from ufilter.configUpdateBlock only for new filters - // if it is not too old + if int64(ufilter.configUpdateBlock) > backfillBlock { + // backfill from config update block in case it is not too old + backfillBlock = int64(ufilter.configUpdateBlock) + } + // NOTE: replys are planned to be done as part of RegisterFilter within logpoller + lggr.Debugw("Backfilling logs for new upkeep filter", "backfillBlock", backfillBlock) p.poller.ReplayAsync(backfillBlock) return nil } func (p *logEventProvider) UnregisterFilter(upkeepID *big.Int) error { - err := p.poller.UnregisterFilter(p.filterName(upkeepID)) - if err != nil { - // TODO: mark as removed in filter store, so we'll - // automatically retry on next refresh - return fmt.Errorf("failed to unregister upkeep filter %s: %w", upkeepID.String(), err) + // Filter might have been unregistered already, only try to unregister if it exists + if p.poller.HasFilter(p.filterName(upkeepID)) { + if err := p.poller.UnregisterFilter(p.filterName(upkeepID)); err != nil { + return fmt.Errorf("failed to unregister upkeep filter %s: %w", upkeepID.String(), err) + } } p.filterStore.RemoveActiveUpkeeps(upkeepFilter{ upkeepID: upkeepID, diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/provider_life_cycle_test.go b/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/provider_life_cycle_test.go index c42e1c3bac3..4b1ff06f316 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/provider_life_cycle_test.go +++ b/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/provider_life_cycle_test.go @@ -23,6 +23,8 @@ func TestLogEventProvider_LifeCycle(t *testing.T) { errored bool upkeepID *big.Int upkeepCfg LogTriggerConfig + hasFilter bool + replyed bool cfgUpdateBlock uint64 mockPoller bool unregister bool @@ -35,6 +37,8 @@ func TestLogEventProvider_LifeCycle(t *testing.T) { ContractAddress: common.BytesToAddress(common.LeftPadBytes([]byte{1, 2, 3, 4}, 20)), Topic0: common.BytesToHash(common.LeftPadBytes([]byte{1, 2, 3, 4}, 32)), }, + false, + true, uint64(1), true, false, @@ -44,6 +48,8 @@ func TestLogEventProvider_LifeCycle(t *testing.T) { true, big.NewInt(111), LogTriggerConfig{}, + false, + false, uint64(0), false, false, @@ -56,18 +62,22 @@ func TestLogEventProvider_LifeCycle(t *testing.T) { ContractAddress: common.BytesToAddress(common.LeftPadBytes([]byte{}, 20)), Topic0: common.BytesToHash(common.LeftPadBytes([]byte{}, 32)), }, + false, + false, uint64(2), false, false, }, { - "existing config", + "existing config with old block", true, big.NewInt(111), LogTriggerConfig{ ContractAddress: common.BytesToAddress(common.LeftPadBytes([]byte{1, 2, 3, 4}, 20)), Topic0: common.BytesToHash(common.LeftPadBytes([]byte{1, 2, 3, 4}, 32)), }, + true, + false, uint64(0), true, false, @@ -80,23 +90,41 @@ func TestLogEventProvider_LifeCycle(t *testing.T) { ContractAddress: common.BytesToAddress(common.LeftPadBytes([]byte{1, 2, 3, 4}, 20)), Topic0: common.BytesToHash(common.LeftPadBytes([]byte{1, 2, 3, 4}, 32)), }, + true, + false, uint64(2), true, true, }, } - mp := new(mocks.LogPoller) - mp.On("RegisterFilter", mock.Anything).Return(nil) - mp.On("UnregisterFilter", mock.Anything).Return(nil) - mp.On("LatestBlock", mock.Anything).Return(int64(0), nil) - mp.On("ReplayAsync", mock.Anything).Return(nil) - p := NewLogProvider(logger.TestLogger(t), mp, &mockedPacker{}, NewUpkeepFilterStore(), NewOptions(200)) + p := NewLogProvider(logger.TestLogger(t), nil, &mockedPacker{}, NewUpkeepFilterStore(), NewOptions(200)) for _, tc := range tests { t.Run(tc.name, func(t *testing.T) { ctx, cancel := context.WithCancel(context.Background()) defer cancel() + + if tc.mockPoller { + lp := new(mocks.LogPoller) + lp.On("RegisterFilter", mock.Anything).Return(nil) + lp.On("UnregisterFilter", mock.Anything).Return(nil) + lp.On("LatestBlock", mock.Anything).Return(int64(0), nil) + hasFitlerTimes := 1 + if tc.unregister { + hasFitlerTimes = 2 + } + lp.On("HasFilter", p.filterName(tc.upkeepID)).Return(tc.hasFilter).Times(hasFitlerTimes) + if tc.replyed { + lp.On("ReplayAsync", mock.Anything).Return(nil).Times(1) + } else { + lp.On("ReplayAsync", mock.Anything).Return(nil).Times(0) + } + p.lock.Lock() + p.poller = lp + p.lock.Unlock() + } + err := p.RegisterFilter(ctx, FilterOptions{ UpkeepID: tc.upkeepID, TriggerConfig: tc.upkeepCfg, @@ -120,6 +148,7 @@ func TestEventLogProvider_RefreshActiveUpkeeps(t *testing.T) { mp := new(mocks.LogPoller) mp.On("RegisterFilter", mock.Anything).Return(nil) mp.On("UnregisterFilter", mock.Anything).Return(nil) + mp.On("HasFilter", mock.Anything).Return(false) mp.On("LatestBlock", mock.Anything).Return(int64(0), nil) mp.On("ReplayAsync", mock.Anything).Return(nil) @@ -146,6 +175,7 @@ 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) newIds, err = p.RefreshActiveUpkeeps( core.GenUpkeepID(ocr2keepers.LogTrigger, "2222").BigInt(), core.GenUpkeepID(ocr2keepers.LogTrigger, "1234").BigInt(), diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/provider_test.go b/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/provider_test.go index 159e229a2ff..db22886cbb7 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/provider_test.go +++ b/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/provider_test.go @@ -193,7 +193,7 @@ func TestLogEventProvider_ScheduleReadJobs(t *testing.T) { reads := make(chan []*big.Int, 100) go func(ctx context.Context) { - _ = p.scheduleReadJobs(ctx, func(ids []*big.Int) { + p.scheduleReadJobs(ctx, func(ids []*big.Int) { select { case reads <- ids: default: @@ -246,6 +246,7 @@ func TestLogEventProvider_ReadLogs(t *testing.T) { mp.On("RegisterFilter", mock.Anything).Return(nil) mp.On("ReplayAsync", mock.Anything).Return() + mp.On("HasFilter", mock.Anything).Return(false) mp.On("UnregisterFilter", mock.Anything, mock.Anything).Return(nil) mp.On("LatestBlock", mock.Anything).Return(int64(1), nil) mp.On("LogsWithSigs", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return([]logpoller.Log{ diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/recoverer.go b/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/recoverer.go index 7a7dbbe46be..c5b06701737 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/recoverer.go +++ b/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/recoverer.go @@ -6,6 +6,7 @@ import ( "errors" "fmt" "io" + "math" "math/big" "sort" "sync" @@ -13,6 +14,7 @@ import ( "time" "github.com/ethereum/go-ethereum/common" + "github.com/smartcontractkit/ocr2keepers/pkg/v3/random" ocr2keepers "github.com/smartcontractkit/ocr2keepers/pkg/v3/types" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" @@ -24,13 +26,23 @@ import ( ) var ( - DefaultRecoveryInterval = 5 * time.Second - RecoveryCacheTTL = 10*time.Minute - time.Second - GCInterval = RecoveryCacheTTL - - recoveryBatchSize = 10 + LogRecovererServiceName = "LogRecoverer" + + // RecoveryInterval is the interval at which the recovery scanning processing is triggered + RecoveryInterval = 5 * time.Second + // RecoveryCacheTTL is the time to live for the recovery cache + RecoveryCacheTTL = 10 * time.Minute + // GCInterval is the interval at which the recovery cache is cleaned up + GCInterval = RecoveryCacheTTL - time.Second + // MaxProposals is the maximum number of proposals that can be returned by GetRecoveryProposals + MaxProposals = 20 + // recoveryBatchSize is the number of filters to recover in a single batch + recoveryBatchSize = 10 + // recoveryLogsBuffer is the number of blocks to be used as a safety buffer when reading logs recoveryLogsBuffer = int64(200) recoveryLogsBurst = int64(500) + // blockTimeUpdateCadence is the cadence at which the chain's blocktime is re-calculated + blockTimeUpdateCadence = 10 * time.Minute ) type LogRecoverer interface { @@ -47,9 +59,10 @@ type visitedRecord struct { } type logRecoverer struct { - lggr logger.Logger + utils.StartStopOnce + threadCtrl utils.ThreadControl - cancel context.CancelFunc + lggr logger.Logger lookbackBlocks *atomic.Int64 blockTime *atomic.Int64 @@ -60,30 +73,38 @@ type logRecoverer struct { pending []ocr2keepers.UpkeepPayload visited map[string]visitedRecord - filterStore UpkeepFilterStore - states core.UpkeepStateReader - packer LogDataPacker - poller logpoller.LogPoller - client client.Client + filterStore UpkeepFilterStore + states core.UpkeepStateReader + packer LogDataPacker + poller logpoller.LogPoller + client client.Client + blockTimeResolver *blockTimeResolver + + finalityDepth int64 } var _ LogRecoverer = &logRecoverer{} func NewLogRecoverer(lggr logger.Logger, poller logpoller.LogPoller, client client.Client, stateStore core.UpkeepStateReader, packer LogDataPacker, filterStore UpkeepFilterStore, opts LogTriggersOptions) *logRecoverer { rec := &logRecoverer{ - lggr: lggr.Named("LogRecoverer"), + lggr: lggr.Named(LogRecovererServiceName), + + threadCtrl: utils.NewThreadControl(), blockTime: &atomic.Int64{}, lookbackBlocks: &atomic.Int64{}, interval: opts.ReadInterval * 5, - pending: make([]ocr2keepers.UpkeepPayload, 0), - visited: make(map[string]visitedRecord), - poller: poller, - filterStore: filterStore, - states: stateStore, - packer: packer, - client: client, + pending: make([]ocr2keepers.UpkeepPayload, 0), + visited: make(map[string]visitedRecord), + poller: poller, + filterStore: filterStore, + states: stateStore, + packer: packer, + client: client, + blockTimeResolver: newBlockTimeResolver(poller), + + finalityDepth: opts.FinalityDepth, } rec.lookbackBlocks.Store(opts.LookbackBlocks) @@ -92,68 +113,75 @@ func NewLogRecoverer(lggr logger.Logger, poller logpoller.LogPoller, client clie return rec } -func (r *logRecoverer) Start(pctx context.Context) error { - ctx, cancel := context.WithCancel(context.Background()) +// Start starts the log recoverer, which runs 3 threads in the background: +// 1. Recovery thread: scans for logs that were missed by the log poller +// 2. Cleanup thread: cleans up the cache of logs that were already processed +// 3. Block time thread: updates the block time of the chain +func (r *logRecoverer) Start(ctx context.Context) error { + return r.StartOnce(LogRecovererServiceName, func() error { + r.updateBlockTime(ctx) - r.lock.Lock() - if r.cancel != nil { - r.lock.Unlock() - cancel() // Cancel the created context - return errors.New("already started") - } - r.cancel = cancel - r.lock.Unlock() + r.lggr.Infow("starting log recoverer", "blockTime", r.blockTime.Load(), "lookbackBlocks", r.lookbackBlocks.Load(), "interval", r.interval) - blockTimeResolver := newBlockTimeResolver(r.poller) - blockTime, err := blockTimeResolver.BlockTime(ctx, defaultSampleSize) - if err != nil { - // TODO: TBD exit or just log a warning - // return fmt.Errorf("failed to compute block time: %w", err) - r.lggr.Warnw("failed to compute block time", "err", err) - } - if blockTime > 0 { - r.blockTime.Store(int64(blockTime)) - } - - r.lggr.Infow("starting log recoverer", "blockTime", r.blockTime.Load(), "lookbackBlocks", r.lookbackBlocks.Load(), "interval", r.interval) - - { - go func(ctx context.Context, interval time.Duration) { - ticker := time.NewTicker(interval) - defer ticker.Stop() - gcTicker := time.NewTicker(utils.WithJitter(GCInterval)) - defer gcTicker.Stop() + r.threadCtrl.Go(func(ctx context.Context) { + recoveryTicker := time.NewTicker(r.interval) + defer recoveryTicker.Stop() for { select { - case <-ticker.C: + case <-recoveryTicker.C: if err := r.recover(ctx); err != nil { r.lggr.Warnw("failed to recover logs", "err", err) } - case <-gcTicker.C: + case <-ctx.Done(): + return + } + } + }) + + r.threadCtrl.Go(func(ctx context.Context) { + cleanupTicker := time.NewTicker(utils.WithJitter(GCInterval)) + defer cleanupTicker.Stop() + + for { + select { + case <-cleanupTicker.C: r.clean(ctx) - gcTicker.Reset(utils.WithJitter(GCInterval)) + cleanupTicker.Reset(utils.WithJitter(GCInterval)) case <-ctx.Done(): return } } - }(ctx, r.interval) - } + }) - return nil + r.threadCtrl.Go(func(ctx context.Context) { + blockTimeTicker := time.NewTicker(blockTimeUpdateCadence) + defer blockTimeTicker.Stop() + + for { + select { + case <-blockTimeTicker.C: + r.updateBlockTime(ctx) + blockTimeTicker.Reset(utils.WithJitter(blockTimeUpdateCadence)) + case <-ctx.Done(): + return + } + } + }) + + return nil + }) } func (r *logRecoverer) Close() error { - r.lock.Lock() - defer r.lock.Unlock() + return r.StopOnce(LogRecovererServiceName, func() error { + r.threadCtrl.Close() + return nil + }) +} - if cancel := r.cancel; cancel != nil { - r.cancel = nil - cancel() - } else { - return errors.New("already stopped") - } - return nil +func (r *logRecoverer) HealthReport() map[string]error { + return map[string]error{LogRecovererServiceName: r.Healthy()} } func (r *logRecoverer) GetProposalData(ctx context.Context, proposal ocr2keepers.CoordinatedBlockProposal) ([]byte, error) { @@ -178,26 +206,30 @@ func (r *logRecoverer) getLogTriggerCheckData(ctx context.Context, proposal ocr2 if proposal.Trigger.LogTriggerExtension == nil { return nil, errors.New("missing log trigger extension") } - logBlock := int64(proposal.Trigger.LogTriggerExtension.BlockNumber) - if logBlock == 0 { - var number *big.Int - number, _, err = core.GetTxBlock(ctx, r.client, proposal.Trigger.LogTriggerExtension.TxHash) - if err != nil { - return nil, err - } - if number == nil { - return nil, errors.New("failed to get tx block") - } - logBlock = number.Int64() + + // Verify the log is still present on chain, not reorged and is within recoverable range + // Do not trust the logBlockNumber from proposal since it's not included in workID + logBlockHash := common.BytesToHash(proposal.Trigger.LogTriggerExtension.BlockHash[:]) + bn, bh, err := core.GetTxBlock(ctx, r.client, proposal.Trigger.LogTriggerExtension.TxHash) + if err != nil { + return nil, err + } + if bn == nil { + return nil, errors.New("failed to get tx block") + } + if bh.Hex() != logBlockHash.Hex() { + return nil, errors.New("log tx reorged") } + logBlock := bn.Int64() if isRecoverable := logBlock < offsetBlock && logBlock > start; !isRecoverable { return nil, errors.New("log block is not recoverable") } + + // Check if the log was already performed or ineligible upkeepStates, err := r.states.SelectByWorkIDs(ctx, proposal.WorkID) if err != nil { return nil, err } - for _, upkeepState := range upkeepStates { switch upkeepState { case ocr2keepers.Performed, ocr2keepers.Ineligible: @@ -244,6 +276,11 @@ func (r *logRecoverer) getLogTriggerCheckData(ctx context.Context, proposal ocr2 } func (r *logRecoverer) GetRecoveryProposals(ctx context.Context) ([]ocr2keepers.UpkeepPayload, error) { + latestBlock, err := r.poller.LatestBlock(pg.WithParentCtx(ctx)) + if err != nil { + return nil, fmt.Errorf("%w: %s", ErrHeadNotAvailable, err) + } + r.lock.Lock() defer r.lock.Unlock() @@ -251,21 +288,32 @@ func (r *logRecoverer) GetRecoveryProposals(ctx context.Context) ([]ocr2keepers. return nil, nil } + allLogsCounter := 0 logsCount := map[string]int{} + r.sortPending(uint64(latestBlock)) + var results, pending []ocr2keepers.UpkeepPayload for _, payload := range r.pending { + if allLogsCounter >= MaxProposals { + // we have enough proposals, pushed the rest are pushed back to pending + pending = append(pending, payload) + continue + } uid := payload.UpkeepID.String() if logsCount[uid] >= AllowedLogsPerUpkeep { + // we have enough proposals for this upkeep, the rest are pushed back to pending pending = append(pending, payload) continue } - logsCount[uid]++ results = append(results, payload) + logsCount[uid]++ + allLogsCounter++ } + r.pending = pending - r.lggr.Debugf("found %d pending payloads", len(pending)) + r.lggr.Debugf("found %d recoverable payloads", len(results)) return results, nil } @@ -309,10 +357,10 @@ func (r *logRecoverer) recover(ctx context.Context) error { // recoverFilter recovers logs for a single upkeep filter. func (r *logRecoverer) recoverFilter(ctx context.Context, f upkeepFilter, startBlock, offsetBlock int64) error { - start := f.lastRePollBlock + start := f.lastRePollBlock + 1 // NOTE: we expect f.lastRePollBlock + 1 <= offsetBlock, as others would have been filtered out // ensure we don't recover logs from before the filter was created - // NOTE: we expect that filter with configUpdateBlock > offsetBlock were already filtered out. if configUpdateBlock := int64(f.configUpdateBlock); start < configUpdateBlock { + // NOTE: we expect that configUpdateBlock <= offsetBlock, as others would have been filtered out start = configUpdateBlock } if start < startBlock { @@ -323,6 +371,7 @@ func (r *logRecoverer) recoverFilter(ctx context.Context, f upkeepFilter, startB // If recoverer is lagging by a lot (more than 100x recoveryLogsBuffer), allow // a range of recoveryLogsBurst // Exploratory: Store lastRePollBlock in DB to prevent bursts during restarts + // (while also taking into account exisitng pending payloads) end = start + recoveryLogsBurst } if end > offsetBlock { @@ -414,7 +463,7 @@ func (r *logRecoverer) populatePending(f upkeepFilter, filteredLogs []logpoller. } // filterFinalizedStates filters out the log upkeeps that have already been completed (performed or ineligible). -func (r *logRecoverer) filterFinalizedStates(f upkeepFilter, logs []logpoller.Log, states []ocr2keepers.UpkeepState) []logpoller.Log { +func (r *logRecoverer) filterFinalizedStates(_ upkeepFilter, logs []logpoller.Log, states []ocr2keepers.UpkeepState) []logpoller.Log { filtered := make([]logpoller.Log, 0) for i, log := range logs { @@ -433,7 +482,16 @@ func (r *logRecoverer) getRecoveryWindow(latest int64) (int64, int64) { lookbackBlocks := r.lookbackBlocks.Load() blockTime := r.blockTime.Load() blocksInDay := int64(24*time.Hour) / blockTime - return latest - blocksInDay, latest - lookbackBlocks + start := latest - blocksInDay + // Exploratory: Instead of subtracting finality depth to account for finalized performs + // keep two pointers of lastRePollBlock for soft and hard finalization, i.e. manage + // unfinalized perform logs better + end := latest - lookbackBlocks - r.finalityDepth + if start > end { + // In this case, allow starting from more than a day behind + start = end + } + return start, end } // getFilterBatch returns a batch of filters that are ready to be recovered. @@ -441,7 +499,7 @@ func (r *logRecoverer) getFilterBatch(offsetBlock int64) []upkeepFilter { filters := r.filterStore.GetFilters(func(f upkeepFilter) bool { // ensure we work only on filters that are ready to be recovered // no need to recover in case f.configUpdateBlock is after offsetBlock - return f.lastRePollBlock <= offsetBlock && int64(f.configUpdateBlock) <= offsetBlock + return f.lastRePollBlock < offsetBlock && int64(f.configUpdateBlock) <= offsetBlock }) sort.Slice(filters, func(i, j int) bool { @@ -603,3 +661,41 @@ func (r *logRecoverer) removePending(workID string) { } r.pending = updated } + +// sortPending sorts the pending list by a random order based on the normalized latest block number. +// Divided by 10 to ensure that nodes with similar block numbers won't end up with different order. +// NOTE: the lock must be held before calling this function. +func (r *logRecoverer) sortPending(latestBlock uint64) { + normalized := latestBlock / 100 + if normalized == 0 { + normalized = 1 + } + randSeed := random.GetRandomKeySource(nil, normalized) + + shuffledIDs := make(map[string]string, len(r.pending)) + for _, p := range r.pending { + shuffledIDs[p.WorkID] = random.ShuffleString(p.WorkID, randSeed) + } + + sort.SliceStable(r.pending, func(i, j int) bool { + return shuffledIDs[r.pending[i].WorkID] < shuffledIDs[r.pending[j].WorkID] + }) +} + +func (r *logRecoverer) updateBlockTime(ctx context.Context) { + blockTime, err := r.blockTimeResolver.BlockTime(ctx, defaultSampleSize) + if err != nil { + r.lggr.Warnw("failed to compute block time", "err", err) + return + } + if blockTime > 0 { + currentBlockTime := r.blockTime.Load() + newBlockTime := int64(blockTime) + if currentBlockTime > 0 && (int64(math.Abs(float64(currentBlockTime-newBlockTime)))*100/currentBlockTime) > 20 { + r.lggr.Warnf("updating blocktime from %d to %d, this change is larger than 20%", currentBlockTime, newBlockTime) + } else { + r.lggr.Debugf("updating blocktime from %d to %d", currentBlockTime, newBlockTime) + } + r.blockTime.Store(newBlockTime) + } +} diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/recoverer_test.go b/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/recoverer_test.go index 0a993831b7b..59c4244304a 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/recoverer_test.go +++ b/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/recoverer_test.go @@ -31,7 +31,9 @@ import ( func TestLogRecoverer_GetRecoverables(t *testing.T) { ctx, cancel := context.WithCancel(context.Background()) defer cancel() - r := NewLogRecoverer(logger.TestLogger(t), nil, nil, nil, nil, nil, NewOptions(200)) + lp := &lpmocks.LogPoller{} + lp.On("LatestBlock", mock.Anything).Return(int64(100), nil) + r := NewLogRecoverer(logger.TestLogger(t), lp, nil, nil, nil, nil, NewOptions(200)) tests := []struct { name string @@ -349,8 +351,8 @@ func TestLogRecoverer_Recover(t *testing.T) { }, nil, nil, - []string{"84c83c79c2be2c3eabd8d35986a2a798d9187564d7f4f8f96c5a0f40f50bed3f"}, - []int64{200, 0, 450}, + []string{"c207451fa897f9bb13b09d54d8655edf0644e027c53521b4a92eafbb64ba4d14"}, + []int64{201, 0, 450}, }, { "lastRePollBlock updated with burst when lagging behind", @@ -364,7 +366,7 @@ func TestLogRecoverer_Recover(t *testing.T) { topics: []common.Hash{ common.HexToHash("0x1"), }, - lastRePollBlock: 100, // Should be updated with burst + lastRePollBlock: 99, // Should be updated with burst }, }, []ocr2keepers.UpkeepState{ocr2keepers.UnknownState}, @@ -379,7 +381,7 @@ func TestLogRecoverer_Recover(t *testing.T) { }, nil, nil, - []string{"84c83c79c2be2c3eabd8d35986a2a798d9187564d7f4f8f96c5a0f40f50bed3f"}, + []string{"c207451fa897f9bb13b09d54d8655edf0644e027c53521b4a92eafbb64ba4d14"}, []int64{600}, }, { @@ -410,7 +412,7 @@ func TestLogRecoverer_Recover(t *testing.T) { }, nil, nil, - []string{"84c83c79c2be2c3eabd8d35986a2a798d9187564d7f4f8f96c5a0f40f50bed3f"}, + []string{"c207451fa897f9bb13b09d54d8655edf0644e027c53521b4a92eafbb64ba4d14"}, []int64{700}, // should be configUpdateBlock + recoveryLogsBuffer }, } @@ -717,9 +719,48 @@ func TestLogRecoverer_GetProposalData(t *testing.T) { return 100, nil }, }, + client: &mockClient{ + CallContextFn: func(ctx context.Context, receipt *types.Receipt, method string, args ...interface{}) error { + receipt.Status = 1 + receipt.BlockNumber = big.NewInt(200) + return nil + }, + }, expectErr: true, wantErr: errors.New("log block is not recoverable"), }, + { + name: "if a log block has does not match, an error is returned", + proposal: ocr2keepers.CoordinatedBlockProposal{ + UpkeepID: core.GenUpkeepID(ocr2keepers.LogTrigger, "123"), + Trigger: ocr2keepers.Trigger{ + LogTriggerExtension: &ocr2keepers.LogTriggerExtension{ + BlockNumber: 200, + BlockHash: common.HexToHash("0x2"), + }, + }, + }, + filterStore: &mockFilterStore{ + HasFn: func(id *big.Int) bool { + return true + }, + }, + logPoller: &mockLogPoller{ + LatestBlockFn: func(qopts ...pg.QOpt) (int64, error) { + return 100, nil + }, + }, + client: &mockClient{ + CallContextFn: func(ctx context.Context, receipt *types.Receipt, method string, args ...interface{}) error { + receipt.Status = 1 + receipt.BlockNumber = big.NewInt(200) + receipt.BlockHash = common.HexToHash("0x1") + return nil + }, + }, + expectErr: true, + wantErr: errors.New("log tx reorged"), + }, { name: "if a log block is recoverable, when the upkeep state reader errors, an error is returned", proposal: ocr2keepers.CoordinatedBlockProposal{ @@ -737,7 +778,7 @@ func TestLogRecoverer_GetProposalData(t *testing.T) { }, logPoller: &mockLogPoller{ LatestBlockFn: func(qopts ...pg.QOpt) (int64, error) { - return 100, nil + return 300, nil }, }, stateReader: &mockStateReader{ @@ -745,6 +786,13 @@ func TestLogRecoverer_GetProposalData(t *testing.T) { return nil, errors.New("upkeep state boom") }, }, + client: &mockClient{ + CallContextFn: func(ctx context.Context, receipt *types.Receipt, method string, args ...interface{}) error { + receipt.Status = 1 + receipt.BlockNumber = big.NewInt(80) + return nil + }, + }, expectErr: true, wantErr: errors.New("upkeep state boom"), }, @@ -765,7 +813,14 @@ func TestLogRecoverer_GetProposalData(t *testing.T) { }, logPoller: &mockLogPoller{ LatestBlockFn: func(qopts ...pg.QOpt) (int64, error) { - return 100, nil + return 300, nil + }, + }, + client: &mockClient{ + CallContextFn: func(ctx context.Context, receipt *types.Receipt, method string, args ...interface{}) error { + receipt.Status = 1 + receipt.BlockNumber = big.NewInt(80) + return nil }, }, stateReader: &mockStateReader{ @@ -798,7 +853,14 @@ func TestLogRecoverer_GetProposalData(t *testing.T) { }, logPoller: &mockLogPoller{ LatestBlockFn: func(qopts ...pg.QOpt) (int64, error) { - return 100, nil + return 300, nil + }, + }, + client: &mockClient{ + CallContextFn: func(ctx context.Context, receipt *types.Receipt, method string, args ...interface{}) error { + receipt.Status = 1 + receipt.BlockNumber = big.NewInt(80) + return nil }, }, stateReader: &mockStateReader{ @@ -823,12 +885,19 @@ func TestLogRecoverer_GetProposalData(t *testing.T) { }, logPoller: &mockLogPoller{ LatestBlockFn: func(qopts ...pg.QOpt) (int64, error) { - return 100, nil + return 300, nil }, LogsWithSigsFn: func(start, end int64, eventSigs []common.Hash, address common.Address, qopts ...pg.QOpt) ([]logpoller.Log, error) { return nil, errors.New("logs with sigs boom") }, }, + client: &mockClient{ + CallContextFn: func(ctx context.Context, receipt *types.Receipt, method string, args ...interface{}) error { + receipt.Status = 1 + receipt.BlockNumber = big.NewInt(80) + return nil + }, + }, stateReader: &mockStateReader{ SelectByWorkIDsFn: func(ctx context.Context, workIDs ...string) ([]ocr2keepers.UpkeepState, error) { return []ocr2keepers.UpkeepState{ @@ -851,7 +920,7 @@ func TestLogRecoverer_GetProposalData(t *testing.T) { }, logPoller: &mockLogPoller{ LatestBlockFn: func(qopts ...pg.QOpt) (int64, error) { - return 100, nil + return 300, nil }, LogsWithSigsFn: func(start, end int64, eventSigs []common.Hash, address common.Address, qopts ...pg.QOpt) ([]logpoller.Log, error) { return []logpoller.Log{ @@ -861,6 +930,13 @@ func TestLogRecoverer_GetProposalData(t *testing.T) { }, nil }, }, + client: &mockClient{ + CallContextFn: func(ctx context.Context, receipt *types.Receipt, method string, args ...interface{}) error { + receipt.Status = 1 + receipt.BlockNumber = big.NewInt(80) + return nil + }, + }, stateReader: &mockStateReader{ SelectByWorkIDsFn: func(ctx context.Context, workIDs ...string) ([]ocr2keepers.UpkeepState, error) { return []ocr2keepers.UpkeepState{ @@ -888,11 +964,11 @@ func TestLogRecoverer_GetProposalData(t *testing.T) { } return t }(), - WorkID: "d91c6f090b8477f434cf775182e4ff12c90618ba4da5b8ec06aa719768b7743a", + WorkID: "7f775793422d178c90e99c3bbdf05181bc6bb6ce13170e87c92ac396bb7ddda0", }, logPoller: &mockLogPoller{ LatestBlockFn: func(qopts ...pg.QOpt) (int64, error) { - return 100, nil + return 300, nil }, LogsWithSigsFn: func(start, end int64, eventSigs []common.Hash, address common.Address, qopts ...pg.QOpt) ([]logpoller.Log, error) { return []logpoller.Log{ @@ -905,6 +981,14 @@ func TestLogRecoverer_GetProposalData(t *testing.T) { }, nil }, }, + client: &mockClient{ + CallContextFn: func(ctx context.Context, receipt *types.Receipt, method string, args ...interface{}) error { + receipt.Status = 1 + receipt.BlockNumber = big.NewInt(80) + receipt.BlockHash = [32]byte{1} + return nil + }, + }, stateReader: &mockStateReader{ SelectByWorkIDsFn: func(ctx context.Context, workIDs ...string) ([]ocr2keepers.UpkeepState, error) { return []ocr2keepers.UpkeepState{ @@ -931,11 +1015,11 @@ func TestLogRecoverer_GetProposalData(t *testing.T) { } return t }(), - WorkID: "d91c6f090b8477f434cf775182e4ff12c90618ba4da5b8ec06aa719768b7743a", + WorkID: "7f775793422d178c90e99c3bbdf05181bc6bb6ce13170e87c92ac396bb7ddda0", }, logPoller: &mockLogPoller{ LatestBlockFn: func(qopts ...pg.QOpt) (int64, error) { - return 100, nil + return 300, nil }, LogsWithSigsFn: func(start, end int64, eventSigs []common.Hash, address common.Address, qopts ...pg.QOpt) ([]logpoller.Log, error) { return []logpoller.Log{ @@ -953,6 +1037,14 @@ func TestLogRecoverer_GetProposalData(t *testing.T) { }, nil }, }, + client: &mockClient{ + CallContextFn: func(ctx context.Context, receipt *types.Receipt, method string, args ...interface{}) error { + receipt.Status = 1 + receipt.BlockNumber = big.NewInt(80) + receipt.BlockHash = [32]byte{1} + return nil + }, + }, stateReader: &mockStateReader{ SelectByWorkIDsFn: func(ctx context.Context, workIDs ...string) ([]ocr2keepers.UpkeepState, error) { return []ocr2keepers.UpkeepState{ diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/payload_builder.go b/core/services/ocr2/plugins/ocr2keeper/evm21/payload_builder.go index 9351aa71d65..b14e687b5d1 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm21/payload_builder.go +++ b/core/services/ocr2/plugins/ocr2keeper/evm21/payload_builder.go @@ -33,7 +33,7 @@ func (b *payloadBuilder) BuildPayloads(ctx context.Context, proposals ...ocr2kee var payload ocr2keepers.UpkeepPayload if b.upkeepList.IsActive(proposal.UpkeepID.BigInt()) { b.lggr.Debugf("building payload for coordinated block proposal %+v", proposal) - checkData := []byte{} + var checkData []byte var err error switch core.GetUpkeepType(proposal.UpkeepID) { case ocr2keepers.LogTrigger: diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/payload_builder_test.go b/core/services/ocr2/plugins/ocr2keeper/evm21/payload_builder_test.go index 6c0ef78bbc4..e75084ff968 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm21/payload_builder_test.go +++ b/core/services/ocr2/plugins/ocr2keeper/evm21/payload_builder_test.go @@ -184,7 +184,6 @@ func TestNewPayloadBuilder(t *testing.T) { BlockNumber: 1, BlockHash: [32]byte{1}, }, - CheckData: make([]byte, 0), }, }, }, diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/registry.go b/core/services/ocr2/plugins/ocr2keeper/evm21/registry.go index 849463e53a2..a4684e67078 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm21/registry.go +++ b/core/services/ocr2/plugins/ocr2keeper/evm21/registry.go @@ -36,13 +36,13 @@ const ( // defaultAllowListExpiration decides how long an upkeep's allow list info will be valid for. defaultAllowListExpiration = 20 * time.Minute // allowListCleanupInterval decides when the expired items in allowList cache will be deleted. - allowListCleanupInterval = 5 * time.Minute - // TODO decide on a value for this - indexedLogsConfirmations = 10 + allowListCleanupInterval = 5 * time.Minute logTriggerRefreshBatchSize = 32 ) var ( + RegistryServiceName = "AutomationRegistry" + ErrLogReadFailure = fmt.Errorf("failure reading logs") ErrHeadNotAvailable = fmt.Errorf("head not available") ErrInitializationFailure = fmt.Errorf("failed to initialize registry") @@ -82,8 +82,11 @@ func NewEvmRegistry( logEventProvider logprovider.LogEventProvider, packer encoding.Packer, blockSub *BlockSubscriber, + finalityDepth uint32, ) *EvmRegistry { return &EvmRegistry{ + ctx: context.Background(), + threadCtrl: utils.NewThreadControl(), lggr: lggr.Named("EvmRegistry"), poller: client.LogPoller(), addr: addr, @@ -103,6 +106,7 @@ func NewEvmRegistry( hc: http.DefaultClient, logEventProvider: logEventProvider, bs: blockSub, + finalityDepth: finalityDepth, } } @@ -124,7 +128,8 @@ type MercuryConfig struct { } type EvmRegistry struct { - sync utils.StartStopOnce + utils.StartStopOnce + threadCtrl utils.ThreadControl lggr logger.Logger poller logpoller.LogPoller addr common.Address @@ -134,13 +139,11 @@ type EvmRegistry struct { abi abi.ABI packer encoding.Packer chLog chan logpoller.Log - reInit *time.Timer mu sync.RWMutex logProcessed map[string]bool active ActiveUpkeepList lastPollBlock int64 ctx context.Context - cancel context.CancelFunc headFunc func(ocr2keepers.BlockKey) runState int runError error @@ -148,6 +151,7 @@ type EvmRegistry struct { hc HttpClient bs *BlockSubscriber logEventProvider logprovider.LogEventProvider + finalityDepth uint32 } func (r *EvmRegistry) Name() string { @@ -155,109 +159,82 @@ func (r *EvmRegistry) Name() string { } func (r *EvmRegistry) Start(ctx context.Context) error { - return r.sync.StartOnce("AutomationRegistry", func() error { - r.mu.Lock() - defer r.mu.Unlock() - r.ctx, r.cancel = context.WithCancel(context.Background()) - r.reInit = time.NewTimer(refreshInterval) - + return r.StartOnce(RegistryServiceName, func() error { if err := r.registerEvents(r.chainID, r.addr); err != nil { return fmt.Errorf("logPoller error while registering automation events: %w", err) } - // refresh the active upkeep keys; if the reInit timer returns, do it again - { - go func(cx context.Context, tmr *time.Timer, lggr logger.Logger, f func() error) { - err := f() - if err != nil { - lggr.Errorf("failed to initialize upkeeps", err) - } + r.threadCtrl.Go(func(ctx context.Context) { + lggr := r.lggr.With("where", "upkeeps_referesh") + err := r.refreshActiveUpkeeps() + if err != nil { + lggr.Errorf("failed to initialize upkeeps", err) + } + + ticker := time.NewTicker(refreshInterval) + defer ticker.Stop() - for { - select { - case <-tmr.C: - err = f() - if err != nil { - lggr.Errorf("failed to re-initialize upkeeps", err) - } - tmr.Reset(refreshInterval) - case <-cx.Done(): - return + for { + select { + case <-ticker.C: + err = r.refreshActiveUpkeeps() + if err != nil { + lggr.Errorf("failed to refresh upkeeps", err) } + case <-ctx.Done(): + return } - }(r.ctx, r.reInit, r.lggr, r.refreshActiveUpkeeps) - } - - // start polling logs on an interval - { - go func(cx context.Context, lggr logger.Logger, f func() error) { - ticker := time.NewTicker(time.Second) - for { - select { - case <-ticker.C: - err := f() - if err != nil { - lggr.Errorf("failed to poll logs for upkeeps", err) - } - case <-cx.Done(): - ticker.Stop() - return + } + }) + + r.threadCtrl.Go(func(ctx context.Context) { + lggr := r.lggr.With("where", "logs_polling") + ticker := time.NewTicker(time.Second) + defer ticker.Stop() + + for { + select { + case <-ticker.C: + err := r.pollUpkeepStateLogs() + if err != nil { + lggr.Errorf("failed to poll logs for upkeeps", err) } + case <-ctx.Done(): + return } - }(r.ctx, r.lggr, r.pollUpkeepStateLogs) - } - - // run process to process logs from log channel - { - go func(cx context.Context, ch chan logpoller.Log, lggr logger.Logger, f func(logpoller.Log) error) { - for { - select { - case l := <-ch: - err := f(l) - if err != nil { - lggr.Errorf("failed to process log for upkeep", err) - } - case <-cx.Done(): - return + } + }) + + r.threadCtrl.Go(func(ctx context.Context) { + lggr := r.lggr.With("where", "logs_processing") + ch := r.chLog + + for { + select { + case l := <-ch: + err := r.processUpkeepStateLog(l) + if err != nil { + lggr.Errorf("failed to process log for upkeep", err) } + case <-ctx.Done(): + return } - }(r.ctx, r.chLog, r.lggr, r.processUpkeepStateLog) - } + } + }) - r.runState = 1 return nil }) } func (r *EvmRegistry) Close() error { - return r.sync.StopOnce("AutomationRegistry", func() error { - r.mu.Lock() - defer r.mu.Unlock() - r.cancel() - r.runState = 0 - r.runError = nil + return r.StopOnce(RegistryServiceName, func() error { + r.threadCtrl.Close() return nil }) } -func (r *EvmRegistry) Ready() error { - r.mu.RLock() - defer r.mu.RUnlock() - - if r.runState == 1 { - return nil - } - return r.sync.Ready() -} - func (r *EvmRegistry) HealthReport() map[string]error { - r.mu.RLock() - defer r.mu.RUnlock() - - if r.runState > 1 { - r.sync.SvcErrBuffer.Append(fmt.Errorf("failed run state: %w", r.runError)) - } - return map[string]error{r.Name(): r.sync.Healthy()} + return map[string]error{RegistryServiceName: r.Healthy()} } func (r *EvmRegistry) refreshActiveUpkeeps() error { @@ -283,20 +260,20 @@ func (r *EvmRegistry) refreshActiveUpkeeps() error { switch core.GetUpkeepType(*uid) { case ocr2keepers.LogTrigger: logTriggerIDs = append(logTriggerIDs, id) + default: } } - newUpkeeps, err := r.logEventProvider.RefreshActiveUpkeeps(logTriggerIDs...) + _, err = r.logEventProvider.RefreshActiveUpkeeps(logTriggerIDs...) if err != nil { return fmt.Errorf("failed to refresh active upkeep ids in log event provider: %w", err) } - return r.refreshLogTriggerUpkeeps(newUpkeeps) + // Try to refersh log trigger config for all log upkeeps + return r.refreshLogTriggerUpkeeps(logTriggerIDs) } // refreshLogTriggerUpkeeps refreshes the active upkeep ids for log trigger upkeeps -// -// TODO: check for updated config for log trigger upkeeps and update it, currently we ignore them. func (r *EvmRegistry) refreshLogTriggerUpkeeps(ids []*big.Int) error { var err error for i := 0; i < len(ids); i += logTriggerRefreshBatchSize { @@ -322,11 +299,11 @@ func (r *EvmRegistry) refreshLogTriggerUpkeepsBatch(logTriggerIDs []*big.Int) er logTriggerHashes = append(logTriggerHashes, common.BigToHash(id)) } - unpausedLogs, err := r.poller.IndexedLogs(iregistry21.IKeeperRegistryMasterUpkeepUnpaused{}.Topic(), r.addr, 1, logTriggerHashes, indexedLogsConfirmations, pg.WithParentCtx(r.ctx)) + unpausedLogs, err := r.poller.IndexedLogs(iregistry21.IKeeperRegistryMasterUpkeepUnpaused{}.Topic(), r.addr, 1, logTriggerHashes, int(r.finalityDepth), pg.WithParentCtx(r.ctx)) if err != nil { return err } - configSetLogs, err := r.poller.IndexedLogs(iregistry21.IKeeperRegistryMasterUpkeepTriggerConfigSet{}.Topic(), r.addr, 1, logTriggerHashes, indexedLogsConfirmations, pg.WithParentCtx(r.ctx)) + configSetLogs, err := r.poller.IndexedLogs(iregistry21.IKeeperRegistryMasterUpkeepTriggerConfigSet{}.Topic(), r.addr, 1, logTriggerHashes, int(r.finalityDepth), pg.WithParentCtx(r.ctx)) if err != nil { return err } @@ -360,13 +337,13 @@ func (r *EvmRegistry) refreshLogTriggerUpkeepsBatch(logTriggerIDs []*big.Int) er for _, id := range logTriggerIDs { logBlock, ok := configSetBlockNumbers[id.String()] if !ok { - r.lggr.Warnf("unable to find config set block number for %s", id.String()) + r.lggr.Warnf("unable to find finalized config set block number for %s, skipping refresh", id.String()) continue } config, ok := perUpkeepConfig[id.String()] if !ok { - r.lggr.Warnf("unable to find per upkeep config for %s", id.String()) + r.lggr.Warnf("unable to find per finalized log config for %s, skipping refresh", id.String()) continue } @@ -483,9 +460,9 @@ func RegistryUpkeepFilterName(addr common.Address) string { return logpoller.FilterName("KeeperRegistry Events", addr.String()) } -func (r *EvmRegistry) registerEvents(chainID uint64, addr common.Address) error { - // Add log filters for the log poller so that it can poll and find the logs that - // we need +// registerEvents registers upkeep state events from keeper registry on log poller +func (r *EvmRegistry) registerEvents(_ uint64, addr common.Address) error { + // Add log filters for the log poller so that it can poll and find the logs that we need return r.poller.RegisterFilter(logpoller.Filter{ Name: RegistryUpkeepFilterName(addr), EventSigs: upkeepStateEvents, @@ -493,7 +470,7 @@ func (r *EvmRegistry) registerEvents(chainID uint64, addr common.Address) error }) } -// Removes an upkeepID from active list and unregisters the log filter for log upkeeps +// removeFromActive removes an upkeepID from active list and unregisters the log filter for log upkeeps func (r *EvmRegistry) removeFromActive(id *big.Int) { r.active.Remove(id) @@ -564,6 +541,7 @@ func (r *EvmRegistry) getLatestIDsFromContract(ctx context.Context) ([]*big.Int, return ids, nil } +// updateTriggerConfig updates the trigger config for an upkeep. it will re-register a filter for this upkeep. func (r *EvmRegistry) updateTriggerConfig(id *big.Int, cfg []byte, logBlock uint64) error { uid := &ocr2keepers.UpkeepIdentifier{} uid.FromBigInt(id) @@ -595,7 +573,7 @@ func (r *EvmRegistry) updateTriggerConfig(id *big.Int, cfg []byte, logBlock uint return nil } -// updateTriggerConfig gets invoked upon changes in the trigger config of an upkeep. +// fetchTriggerConfig fetches trigger config in raw bytes for an upkeep. func (r *EvmRegistry) fetchTriggerConfig(id *big.Int) ([]byte, error) { opts := r.buildCallOpts(r.ctx, nil) cfg, err := r.registry.GetUpkeepTriggerConfig(opts, id) diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/registry_check_pipeline.go b/core/services/ocr2/plugins/ocr2keeper/evm21/registry_check_pipeline.go index 5cf2dfa0981..b9b04fabe43 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm21/registry_check_pipeline.go +++ b/core/services/ocr2/plugins/ocr2keeper/evm21/registry_check_pipeline.go @@ -16,9 +16,9 @@ import ( ) const ( - // validCheckBlockRange decides the max distance between the check block and the current block - // allowed in checkPipeline - validCheckBlockRange = 128 + // checkBlockTooOldRange is the number of blocks that can be behind the latest block before + // we return a CheckBlockTooOld error + checkBlockTooOldRange = 128 ) type checkResult struct { @@ -98,14 +98,7 @@ func (r *EvmRegistry) getBlockHash(blockNumber *big.Int) (common.Hash, error) { } // verifyCheckBlock checks that the check block and hash are valid, returns the pipeline execution state and retryable -func (r *EvmRegistry) verifyCheckBlock(ctx context.Context, checkBlock, upkeepId *big.Int, checkHash common.Hash) (state encoding.PipelineExecutionState, retryable bool) { - // verify check block number is not too old - latestBlock := r.bs.latestBlock.Load() - if int64(latestBlock.Number)-checkBlock.Int64() > validCheckBlockRange { - r.lggr.Warnf("latest block is %d, check block number %s is too old for upkeepId %s", r.bs.latestBlock.Load(), checkBlock, upkeepId) - return encoding.CheckBlockTooOld, false - } - +func (r *EvmRegistry) verifyCheckBlock(_ context.Context, checkBlock, upkeepId *big.Int, checkHash common.Hash) (state encoding.PipelineExecutionState, retryable bool) { var h string var ok bool // verify check block number and hash are valid @@ -134,7 +127,7 @@ func (r *EvmRegistry) verifyLogExists(upkeepId *big.Int, p ocr2keepers.UpkeepPay if logBlockNumber != 0 { h, ok := r.bs.queryBlocksMap(logBlockNumber) if ok && h == logBlockHash.Hex() { - r.lggr.Debugf("tx hash %s exists on chain at block number %d for upkeepId %s", hexutil.Encode(p.Trigger.LogTriggerExtension.TxHash[:]), logBlockNumber, upkeepId) + r.lggr.Debugf("tx hash %s exists on chain at block number %d, block hash %s for upkeepId %s", hexutil.Encode(p.Trigger.LogTriggerExtension.TxHash[:]), logBlockHash.Hex(), logBlockNumber, upkeepId) return encoding.UpkeepFailureReasonNone, encoding.NoPipelineError, false } r.lggr.Debugf("log block %d does not exist in block subscriber for upkeepId %s, querying eth client", logBlockNumber, upkeepId) @@ -142,7 +135,7 @@ func (r *EvmRegistry) verifyLogExists(upkeepId *big.Int, p ocr2keepers.UpkeepPay r.lggr.Debugf("log block not provided, querying eth client for tx hash %s for upkeepId %s", hexutil.Encode(p.Trigger.LogTriggerExtension.TxHash[:]), upkeepId) } // query eth client as a fallback - bn, _, err := core.GetTxBlock(r.ctx, r.client, p.Trigger.LogTriggerExtension.TxHash) + bn, bh, err := core.GetTxBlock(r.ctx, r.client, p.Trigger.LogTriggerExtension.TxHash) if err != nil { // primitive way of checking errors if strings.Contains(err.Error(), "missing required field") || strings.Contains(err.Error(), "not found") { @@ -155,6 +148,10 @@ func (r *EvmRegistry) verifyLogExists(upkeepId *big.Int, p ocr2keepers.UpkeepPay r.lggr.Warnf("tx hash %s does not exist on chain for upkeepId %s.", hexutil.Encode(p.Trigger.LogTriggerExtension.TxHash[:]), upkeepId) return encoding.UpkeepFailureReasonTxHashNoLongerExists, encoding.NoPipelineError, false } + if bh.Hex() != logBlockHash.Hex() { + r.lggr.Warnf("tx hash %s reorged from expected blockhash %s to %s for upkeepId %s.", hexutil.Encode(p.Trigger.LogTriggerExtension.TxHash[:]), logBlockHash.Hex(), bh.Hex(), upkeepId) + return encoding.UpkeepFailureReasonTxHashReorged, encoding.NoPipelineError, false + } r.lggr.Debugf("tx hash %s exists on chain for upkeepId %s", hexutil.Encode(p.Trigger.LogTriggerExtension.TxHash[:]), upkeepId) return encoding.UpkeepFailureReasonNone, encoding.NoPipelineError, false } @@ -240,10 +237,20 @@ func (r *EvmRegistry) checkUpkeeps(ctx context.Context, payloads []ocr2keepers.U for i, req := range checkReqs { index := indices[i] if req.Error != nil { - // individual upkeep failed in a batch call, retryable - r.lggr.Warnf("error encountered in check result for upkeepId %s: %s", results[index].UpkeepID.String(), req.Error) - results[index].Retryable = true - results[index].PipelineExecutionState = uint8(encoding.RpcFlakyFailure) + latestBlock := r.bs.latestBlock.Load() + checkBlock, _, _ := r.getBlockAndUpkeepId(payloads[index].UpkeepID, payloads[index].Trigger) + // primitive way of checking errors + if strings.Contains(req.Error.Error(), "header not found") && int64(latestBlock.Number)-checkBlock.Int64() > checkBlockTooOldRange { + // Check block not found in RPC and it is too old, non-retryable error + r.lggr.Warnf("header not found error encountered in check result for upkeepId %s, check block %d, latest block %d: %s", results[index].UpkeepID.String(), checkBlock.Int64(), int64(latestBlock.Number), req.Error) + results[index].Retryable = false + results[index].PipelineExecutionState = uint8(encoding.CheckBlockTooOld) + } else { + // individual upkeep failed in a batch call, likely a flay RPC error, consider retryable + r.lggr.Warnf("rpc error encountered in check result for upkeepId %s: %s", results[index].UpkeepID.String(), req.Error) + results[index].Retryable = true + results[index].PipelineExecutionState = uint8(encoding.RpcFlakyFailure) + } } else { var err error results[index], err = r.packer.UnpackCheckResult(payloads[index], *checkResults[i]) diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/registry_check_pipeline_test.go b/core/services/ocr2/plugins/ocr2keeper/evm21/registry_check_pipeline_test.go index 69364396e8b..152c912f70f 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm21/registry_check_pipeline_test.go +++ b/core/services/ocr2/plugins/ocr2keeper/evm21/registry_check_pipeline_test.go @@ -85,19 +85,6 @@ func TestRegistry_VerifyCheckBlock(t *testing.T) { retryable bool makeEthCall bool }{ - { - name: "check block number too told", - checkBlock: big.NewInt(500), - latestBlock: ocr2keepers.BlockKey{Number: 800}, - upkeepId: big.NewInt(12345), - checkHash: common.HexToHash("0x5bff03de234fe771ac0d685f9ee0fb0b757ea02ec9e6f10e8e2ee806db1b6b83"), - payload: ocr2keepers.UpkeepPayload{ - UpkeepID: upkeepId, - Trigger: ocr2keepers.NewTrigger(500, common.HexToHash("0x5bff03de234fe771ac0d685f9ee0fb0b757ea02ec9e6f10e8e2ee806db1b6b83")), - WorkID: "work", - }, - state: encoding.CheckBlockTooOld, - }, { name: "for an invalid check block number, if hash does not match the check hash, return CheckBlockInvalid", checkBlock: big.NewInt(500), @@ -279,6 +266,26 @@ func TestRegistry_VerifyLogExists(t *testing.T) { }, receipt: &types.Receipt{Status: 0}, }, + { + name: "eth client returns a matching block but different hash", + upkeepId: big.NewInt(12345), + payload: ocr2keepers.UpkeepPayload{ + UpkeepID: upkeepId, + Trigger: ocr2keepers.NewLogTrigger(550, common.HexToHash("0x5bff03de234fe771ac0d685f9ee0fb0b757ea02ec9e6f10e8e2ee806db1b6b83"), extension1), + WorkID: "work", + }, + reason: encoding.UpkeepFailureReasonTxHashReorged, + retryable: false, + blocks: map[int64]string{ + 500: "0xa518faeadcc423338c62572da84dda35fe44b34f521ce88f6081b703b250cca4", + }, + makeEthCall: true, + receipt: &types.Receipt{ + Status: 1, + BlockNumber: big.NewInt(550), + BlockHash: common.HexToHash("0x5bff03de234fe771ac0d685f9ee0fb0b757ea02ec9e6f10e8e2ee806db1b6b83"), + }, + }, { name: "eth client returns a matching block", upkeepId: big.NewInt(12345), @@ -296,7 +303,7 @@ func TestRegistry_VerifyLogExists(t *testing.T) { receipt: &types.Receipt{ Status: 1, BlockNumber: big.NewInt(550), - BlockHash: common.HexToHash("0x5bff03de234fe771ac0d685f9ee0fb0b757ea02ec9e6f10e8e2ee806db1b6b83"), + BlockHash: common.HexToHash("0x3df0e926f3e21ec1195ffe007a2899214905eb02e768aa89ce0b94accd7f3d71"), }, }, { @@ -368,7 +375,7 @@ func TestRegistry_CheckUpkeeps(t *testing.T) { BlockNumber: 550, } - trigger0 := ocr2keepers.NewTrigger(150, common.HexToHash("0x1c77db0abe32327cf3ea9de2aadf79876f9e6b6dfcee9d4719a8a2dc8ca289d0")) + trigger0 := ocr2keepers.NewTrigger(575, common.HexToHash("0x1c77db0abe32327cf3ea9de2aadf79876f9e6b6dfcee9d4719a8a2dc8ca289d0")) trigger1 := ocr2keepers.NewLogTrigger(560, common.HexToHash("0x9840e5b709bfccf6a1b44f34c884bc39403f57923f3f5ead6243cc090546b857"), extension1) trigger2 := ocr2keepers.NewLogTrigger(570, common.HexToHash("0x1222d75217e2dd461cc77e4091c37abe76277430d97f1963a822b4e94ebb83fc"), extension2) @@ -408,11 +415,12 @@ func TestRegistry_CheckUpkeeps(t *testing.T) { 550: "0x9840e5b709bfccf6a1b44f34c884bc39403f57923f3f5ead6243cc090546b857", 560: "0x9840e5b709bfccf6a1b44f34c884bc39403f57923f3f5ead6243cc090546b857", 570: "0x1222d75217e2dd461cc77e4091c37abe76277430d97f1963a822b4e94ebb83fc", + 575: "0x9840e5b709bfccf6a1b44f34c884bc39403f57923f3f5ead6243cc090546b857", }, latestBlock: ocr2keepers.BlockKey{Number: 580}, results: []ocr2keepers.CheckResult{ { - PipelineExecutionState: uint8(encoding.CheckBlockTooOld), + PipelineExecutionState: uint8(encoding.CheckBlockInvalid), Retryable: false, Eligible: false, IneligibilityReason: 0, diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/services.go b/core/services/ocr2/plugins/ocr2keeper/evm21/services.go index 55466d28996..91479b5e619 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm21/services.go +++ b/core/services/ocr2/plugins/ocr2keeper/evm21/services.go @@ -28,7 +28,7 @@ import ( type AutomationServices interface { Registry() *EvmRegistry Encoder() ocr2keepers.Encoder - TransmitEventProvider() *transmit.TransmitEventProvider + TransmitEventProvider() *transmit.EventProvider BlockSubscriber() *BlockSubscriber PayloadBuilder() ocr2keepers.PayloadBuilder UpkeepStateStore() upkeepstate.UpkeepStateStore @@ -87,7 +87,7 @@ func New(addr common.Address, client evm.Chain, mc *models.MercuryCredentials, k services.reg = NewEvmRegistry(lggr, addr, client, streamsLookupCompatibleABI, keeperRegistryABI, registryContract, mc, al, services.logProvider, - packer, services.blockSub) + packer, services.blockSub, finalityDepth) services.upkeepProvider = NewUpkeepProvider(al, services.blockSub, client.LogPoller()) @@ -97,7 +97,7 @@ func New(addr common.Address, client evm.Chain, mc *models.MercuryCredentials, k type automationServices struct { reg *EvmRegistry encoder ocr2keepers.Encoder - transmitEventProvider *transmit.TransmitEventProvider + transmitEventProvider *transmit.EventProvider blockSub *BlockSubscriber payloadBuilder ocr2keepers.PayloadBuilder upkeepState upkeepstate.UpkeepStateStore @@ -117,7 +117,7 @@ func (f *automationServices) Encoder() ocr2keepers.Encoder { return f.encoder } -func (f *automationServices) TransmitEventProvider() *transmit.TransmitEventProvider { +func (f *automationServices) TransmitEventProvider() *transmit.EventProvider { return f.transmitEventProvider } diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/streams_lookup.go b/core/services/ocr2/plugins/ocr2keeper/evm21/streams_lookup.go index 80ad68cdca1..c7345e4ed2f 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm21/streams_lookup.go +++ b/core/services/ocr2/plugins/ocr2keeper/evm21/streams_lookup.go @@ -66,10 +66,10 @@ type MercuryV03Response struct { } type MercuryV03Report struct { - FeedID string `json:"feedID"` // feed id in hex - ValidFromTimestamp string `json:"validFromTimestamp"` - ObservationsTimestamp string `json:"observationsTimestamp"` - FullReport string `json:"fullReport"` // the actual mercury report of this feed, can be sent to verifier + FeedID []byte `json:"feedID"` // feed id in hex + ValidFromTimestamp uint32 `json:"validFromTimestamp"` + ObservationsTimestamp uint32 `json:"observationsTimestamp"` + FullReport []byte `json:"fullReport"` // the actual mercury report of this feed, can be sent to verifier } type MercuryData struct { @@ -108,6 +108,10 @@ func (r *EvmRegistry) streamsLookup(ctx context.Context, checkResults []ocr2keep // user contract did not revert with StreamsLookup error continue } + if r.mercury.cred == nil { + lggr.Errorf("at block %d upkeep %s tries to access mercury server but mercury credential is not configured", block, upkeepId) + continue + } if len(l.feeds) == 0 { checkResults[i].IneligibilityReason = uint8(encoding.UpkeepFailureReasonInvalidRevertDataInput) @@ -163,7 +167,7 @@ func (r *EvmRegistry) doLookup(ctx context.Context, wg *sync.WaitGroup, lookup * state, reason, values, retryable, err := r.doMercuryRequest(ctx, lookup, lggr) if err != nil { - lggr.Errorf("upkeep %s retryable %v doMercuryRequest: %v", lookup.upkeepId, retryable, err) + lggr.Errorf("upkeep %s retryable %v doMercuryRequest: %s", lookup.upkeepId, retryable, err.Error()) checkResults[i].Retryable = retryable checkResults[i].PipelineExecutionState = uint8(state) checkResults[i].IneligibilityReason = uint8(reason) @@ -176,7 +180,7 @@ func (r *EvmRegistry) doLookup(ctx context.Context, wg *sync.WaitGroup, lookup * state, retryable, mercuryBytes, err := r.checkCallback(ctx, values, lookup) if err != nil { - lggr.Errorf("at block %d upkeep %s checkCallback err: %v", lookup.block, lookup.upkeepId, err) + lggr.Errorf("at block %d upkeep %s checkCallback err: %s", lookup.block, lookup.upkeepId, err.Error()) checkResults[i].Retryable = retryable checkResults[i].PipelineExecutionState = uint8(state) return @@ -185,7 +189,7 @@ func (r *EvmRegistry) doLookup(ctx context.Context, wg *sync.WaitGroup, lookup * state, needed, performData, failureReason, _, err := r.packer.UnpackCheckCallbackResult(mercuryBytes) if err != nil { - lggr.Errorf("at block %d upkeep %s UnpackCheckCallbackResult err: %v", lookup.block, lookup.upkeepId, err) + lggr.Errorf("at block %d upkeep %s UnpackCheckCallbackResult err: %s", lookup.block, lookup.upkeepId, err.Error()) checkResults[i].PipelineExecutionState = uint8(state) return } @@ -318,7 +322,6 @@ func (r *EvmRegistry) doMercuryRequest(ctx context.Context, sl *StreamsLookup, l results[m.Index] = m.Bytes[0] } } - lggr.Debugf("upkeep %s retryable %t reqErr %w", sl.upkeepId.String(), retryable && !allSuccess, reqErr) // only retry when not all successful AND none are not retryable return state, encoding.UpkeepFailureReasonNone, results, retryable && !allSuccess, reqErr } @@ -329,7 +332,7 @@ func (r *EvmRegistry) singleFeedRequest(ctx context.Context, ch chan<- MercuryDa sl.feedParamKey: {sl.feeds[index]}, sl.timeParamKey: {sl.time.String()}, } - mercuryURL := r.mercury.cred.URL + mercuryURL := r.mercury.cred.LegacyURL reqUrl := fmt.Sprintf("%s%s%s", mercuryURL, mercuryPathV02, q.Encode()) lggr.Debugf("request URL for upkeep %s feed %s: %s", sl.upkeepId.String(), sl.feeds[index], reqUrl) @@ -385,6 +388,8 @@ func (r *EvmRegistry) singleFeedRequest(ctx context.Context, ch chan<- MercuryDa return fmt.Errorf("at block %s upkeep %s received status code %d for feed %s", sl.time.String(), sl.upkeepId.String(), resp.StatusCode, sl.feeds[index]) } + lggr.Debugf("at block %s upkeep %s received status code %d from mercury v0.2 with BODY=%s", sl.time.String(), sl.upkeepId.String(), resp.StatusCode, hexutil.Encode(body)) + var m MercuryV02Response err1 = json.Unmarshal(body, &m) if err1 != nil { @@ -431,13 +436,14 @@ func (r *EvmRegistry) singleFeedRequest(ctx context.Context, ch chan<- MercuryDa // multiFeedsRequest sends a Mercury v0.3 request for a multi-feed report func (r *EvmRegistry) multiFeedsRequest(ctx context.Context, ch chan<- MercuryData, sl *StreamsLookup, lggr logger.Logger) { - q := url.Values{ - feedIDs: {strings.Join(sl.feeds, ",")}, - timestamp: {sl.time.String()}, - } - - reqUrl := fmt.Sprintf("%s%s%s", r.mercury.cred.URL, mercuryBatchPathV03, q.Encode()) - lggr.Debugf("request URL for upkeep %s feed %s: %s", sl.upkeepId.String(), strings.Join(sl.feeds, ","), reqUrl) + // this won't work bc q.Encode() will encode commas as '%2C' but the server is strictly expecting a comma separated list + //q := url.Values{ + // feedIDs: {strings.Join(sl.feeds, ",")}, + // timestamp: {sl.time.String()}, + //} + params := fmt.Sprintf("%s=%s&%s=%s", feedIDs, strings.Join(sl.feeds, ","), timestamp, sl.time.String()) + reqUrl := fmt.Sprintf("%s%s%s", r.mercury.cred.URL, mercuryBatchPathV03, params) + lggr.Debugf("request URL for upkeep %s userId %s: %s", sl.upkeepId.String(), r.mercury.cred.Username, reqUrl) req, err := http.NewRequestWithContext(ctx, http.MethodGet, reqUrl, nil) if err != nil { @@ -446,7 +452,7 @@ func (r *EvmRegistry) multiFeedsRequest(ctx context.Context, ch chan<- MercuryDa } ts := time.Now().UTC().UnixMilli() - signature := r.generateHMAC(http.MethodGet, mercuryBatchPathV03+q.Encode(), []byte{}, r.mercury.cred.Username, r.mercury.cred.Password, ts) + signature := r.generateHMAC(http.MethodGet, mercuryBatchPathV03+params, []byte{}, r.mercury.cred.Username, r.mercury.cred.Password, ts) req.Header.Set(headerContentType, applicationJson) // username here is often referred to as user id req.Header.Set(headerAuthorization, r.mercury.cred.Username) @@ -465,7 +471,7 @@ func (r *EvmRegistry) multiFeedsRequest(ctx context.Context, ch chan<- MercuryDa retryable = false resp, err1 := r.hc.Do(req) if err1 != nil { - lggr.Warnf("at block %s upkeep %s GET request fails from mercury v0.3: %v", sl.time.String(), sl.upkeepId.String(), err1) + lggr.Warnf("at timestamp %s upkeep %s GET request fails from mercury v0.3: %v", sl.time.String(), sl.upkeepId.String(), err1) retryable = true state = encoding.MercuryFlakyFailure return err1 @@ -484,43 +490,50 @@ func (r *EvmRegistry) multiFeedsRequest(ctx context.Context, ch chan<- MercuryDa return err1 } - if resp.StatusCode == http.StatusNotFound || resp.StatusCode == http.StatusInternalServerError { - lggr.Warnf("at block %s upkeep %s received status code %d from mercury v0.3", sl.time.String(), sl.upkeepId.String(), resp.StatusCode) + lggr.Infof("at timestamp %s upkeep %s received status code %d from mercury v0.3", sl.time.String(), sl.upkeepId.String(), resp.StatusCode) + if resp.StatusCode == http.StatusUnauthorized { + retryable = false + state = encoding.UpkeepNotAuthorized + return fmt.Errorf("at timestamp %s upkeep %s received status code %d from mercury v0.3, most likely this is caused by unauthorized upkeep", sl.time.String(), sl.upkeepId.String(), resp.StatusCode) + } else if resp.StatusCode == http.StatusBadRequest { + retryable = false + state = encoding.InvalidMercuryRequest + return fmt.Errorf("at timestamp %s upkeep %s received status code %d from mercury v0.3, most likely this is caused by invalid format of timestamp", sl.time.String(), sl.upkeepId.String(), resp.StatusCode) + } else if resp.StatusCode == http.StatusInternalServerError { retryable = true state = encoding.MercuryFlakyFailure - return errors.New(strconv.FormatInt(int64(resp.StatusCode), 10)) + return fmt.Errorf("%d", http.StatusInternalServerError) + } else if resp.StatusCode == 420 { + // in 0.3, this will happen when missing/malformed query args, missing or bad required headers, non-existent feeds, or no permissions for feeds + retryable = false + return fmt.Errorf("at timestamp %s upkeep %s received status code %d from mercury v0.3, most likely this is caused by missing/malformed query args, missing or bad required headers, non-existent feeds, or no permissions for feeds", sl.time.String(), sl.upkeepId.String(), resp.StatusCode) } else if resp.StatusCode != http.StatusOK { retryable = false state = encoding.InvalidMercuryRequest - return fmt.Errorf("at block %s upkeep %s received status code %d from mercury v0.3", sl.time.String(), sl.upkeepId.String(), resp.StatusCode) + return fmt.Errorf("at timestamp %s upkeep %s received status code %d from mercury v0.3", sl.time.String(), sl.upkeepId.String(), resp.StatusCode) } + lggr.Debugf("at block %s upkeep %s received status code %d from mercury v0.3 with BODY=%s", sl.time.String(), sl.upkeepId.String(), resp.StatusCode, hexutil.Encode(body)) + var response MercuryV03Response err1 = json.Unmarshal(body, &response) if err1 != nil { - lggr.Warnf("at block %s upkeep %s failed to unmarshal body to MercuryV03Response from mercury v0.3: %v", sl.time.String(), sl.upkeepId.String(), err1) + lggr.Warnf("at timestamp %s upkeep %s failed to unmarshal body to MercuryV03Response from mercury v0.3: %v", sl.time.String(), sl.upkeepId.String(), err1) retryable = false state = encoding.MercuryUnmarshalError return err1 } + // in v0.3, if some feeds are not available, the server will only return available feeds, but we need to make sure ALL feeds are retrieved before calling user contract + // hence, retry in this case. retry will help when we send a very new timestamp and reports are not yet generated if len(response.Reports) != len(sl.feeds) { - // this should never happen. if this upkeep does not have permission for any feeds it requests, or if certain feeds are - // missing in mercury server, the mercury server v0.3 should respond with 400s, rather than returning partial results - retryable = false - state = encoding.InvalidMercuryResponse - return fmt.Errorf("at block %s upkeep %s requested %d feeds but received %d reports from mercury v0.3", sl.time.String(), sl.upkeepId.String(), len(sl.feeds), len(response.Reports)) + // TODO: AUTO-5044: calculate what reports are missing and log a warning + retryable = true + state = encoding.MercuryFlakyFailure + return fmt.Errorf("%d", http.StatusNotFound) } var reportBytes [][]byte - var b []byte for _, rsp := range response.Reports { - b, err1 = hexutil.Decode(rsp.FullReport) - if err1 != nil { - lggr.Warnf("upkeep %s block %s failed to decode fullReport %s from mercury v0.3: %v", sl.upkeepId.String(), sl.time.String(), rsp.FullReport, err1) - retryable = false - state = encoding.InvalidMercuryResponse - return err1 - } - reportBytes = append(reportBytes, b) + reportBytes = append(reportBytes, rsp.FullReport) } ch <- MercuryData{ Index: 0, diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/streams_lookup_test.go b/core/services/ocr2/plugins/ocr2keeper/evm21/streams_lookup_test.go index a860f633512..95b43c98195 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm21/streams_lookup_test.go +++ b/core/services/ocr2/plugins/ocr2keeper/evm21/streams_lookup_test.go @@ -62,9 +62,10 @@ func setupEVMRegistry(t *testing.T) *EvmRegistry { chLog: make(chan logpoller.Log, 1000), mercury: &MercuryConfig{ cred: &models.MercuryCredentials{ - URL: "https://google.com", - Username: "FakeClientID", - Password: "FakeClientKey", + LegacyURL: "https://google.old.com", + URL: "https://google.com", + Username: "FakeClientID", + Password: "FakeClientKey", }, abi: streamsLookupCompatibleABI, allowListCache: cache.New(defaultAllowListExpiration, allowListCleanupInterval), @@ -665,7 +666,8 @@ func TestEvmRegistry_MultiFeedRequest(t *testing.T) { retryNumber int retryable bool errorMessage string - response MercuryV03Response + firstResponse *MercuryV03Response + response *MercuryV03Response }{ { name: "success - mercury responds in the first try", @@ -676,53 +678,24 @@ func TestEvmRegistry_MultiFeedRequest(t *testing.T) { time: big.NewInt(123456), upkeepId: upkeepId, }, - response: MercuryV03Response{ + response: &MercuryV03Response{ Reports: []MercuryV03Report{ { - FeedID: "0x4554482d5553442d415242495452554d2d544553544e45540000000000000000", - ValidFromTimestamp: "123456", - ObservationsTimestamp: "123456", - FullReport: "0xab2123dc00000012", + FeedID: hexutil.MustDecode("0x4554482d5553442d415242495452554d2d544553544e45540000000000000000"), + ValidFromTimestamp: 123456, + ObservationsTimestamp: 123456, + FullReport: hexutil.MustDecode("0xab2123dc00000012"), }, { - FeedID: "0x4254432d5553442d415242495452554d2d544553544e45540000000000000000", - ValidFromTimestamp: "123458", - ObservationsTimestamp: "123458", - FullReport: "0xab2123dc00000016", + FeedID: hexutil.MustDecode("0x4254432d5553442d415242495452554d2d544553544e45540000000000000000"), + ValidFromTimestamp: 123458, + ObservationsTimestamp: 123458, + FullReport: hexutil.MustDecode("0xab2123dc00000016"), }, }, }, statusCode: http.StatusOK, }, - { - name: "success - retry for 404", - lookup: &StreamsLookup{ - feedParamKey: feedIDs, - feeds: []string{"0x4554482d5553442d415242495452554d2d544553544e45540000000000000000", "0x4254432d5553442d415242495452554d2d544553544e45540000000000000000"}, - timeParamKey: timestamp, - time: big.NewInt(123456), - upkeepId: upkeepId, - }, - retryNumber: 1, - statusCode: http.StatusNotFound, - lastStatusCode: http.StatusOK, - response: MercuryV03Response{ - Reports: []MercuryV03Report{ - { - FeedID: "0x4554482d5553442d415242495452554d2d544553544e45540000000000000000", - ValidFromTimestamp: "123456", - ObservationsTimestamp: "123456", - FullReport: "0xab2123dc00000012", - }, - { - FeedID: "0x4254432d5553442d415242495452554d2d544553544e45540000000000000000", - ValidFromTimestamp: "123458", - ObservationsTimestamp: "123458", - FullReport: "0xab2123dc00000012", - }, - }, - }, - }, { name: "success - retry for 500", lookup: &StreamsLookup{ @@ -735,19 +708,19 @@ func TestEvmRegistry_MultiFeedRequest(t *testing.T) { retryNumber: 2, statusCode: http.StatusInternalServerError, lastStatusCode: http.StatusOK, - response: MercuryV03Response{ + response: &MercuryV03Response{ Reports: []MercuryV03Report{ { - FeedID: "0x4554482d5553442d415242495452554d2d544553544e45540000000000000000", - ValidFromTimestamp: "123456", - ObservationsTimestamp: "123456", - FullReport: "0xab2123dc00000012", + FeedID: hexutil.MustDecode("0x4554482d5553442d415242495452554d2d544553544e45540000000000000000"), + ValidFromTimestamp: 123456, + ObservationsTimestamp: 123456, + FullReport: hexutil.MustDecode("0xab2123dc00000012"), }, { - FeedID: "0x4254432d5553442d415242495452554d2d544553544e45540000000000000000", - ValidFromTimestamp: "123458", - ObservationsTimestamp: "123458", - FullReport: "0xab2123dc00000019", + FeedID: hexutil.MustDecode("0x4254432d5553442d415242495452554d2d544553544e45540000000000000000"), + ValidFromTimestamp: 123458, + ObservationsTimestamp: 123458, + FullReport: hexutil.MustDecode("0xab2123dc00000019"), }, }, }, @@ -762,9 +735,9 @@ func TestEvmRegistry_MultiFeedRequest(t *testing.T) { upkeepId: upkeepId, }, retryNumber: totalAttempt, - statusCode: http.StatusNotFound, + statusCode: http.StatusInternalServerError, retryable: true, - errorMessage: "All attempts fail:\n#1: 404\n#2: 404\n#3: 404", + errorMessage: "All attempts fail:\n#1: 500\n#2: 500\n#3: 500", }, { name: "failure - returns retryable and then non-retryable", @@ -776,12 +749,24 @@ func TestEvmRegistry_MultiFeedRequest(t *testing.T) { upkeepId: upkeepId, }, retryNumber: 1, - statusCode: http.StatusNotFound, - lastStatusCode: http.StatusBadGateway, - errorMessage: "All attempts fail:\n#1: 404\n#2: at block 123456 upkeep 123456789 received status code 502 from mercury v0.3", + statusCode: http.StatusInternalServerError, + lastStatusCode: http.StatusUnauthorized, + errorMessage: "All attempts fail:\n#1: 500\n#2: at timestamp 123456 upkeep 123456789 received status code 401 from mercury v0.3, most likely this is caused by unauthorized upkeep", + }, + { + name: "failure - returns status code 420 not retryable", + lookup: &StreamsLookup{ + feedParamKey: feedIDs, + feeds: []string{"0x4554482d5553442d415242495452554d2d544553544e45540000000000000000"}, + timeParamKey: timestamp, + time: big.NewInt(123456), + upkeepId: upkeepId, + }, + statusCode: 420, + errorMessage: "All attempts fail:\n#1: at timestamp 123456 upkeep 123456789 received status code 420 from mercury v0.3, most likely this is caused by missing/malformed query args, missing or bad required headers, non-existent feeds, or no permissions for feeds", }, { - name: "failure - returns not retryable", + name: "failure - returns status code 502 not retryable", lookup: &StreamsLookup{ feedParamKey: feedIDs, feeds: []string{"0x4554482d5553442d415242495452554d2d544553544e45540000000000000000"}, @@ -790,10 +775,10 @@ func TestEvmRegistry_MultiFeedRequest(t *testing.T) { upkeepId: upkeepId, }, statusCode: http.StatusBadGateway, - errorMessage: "All attempts fail:\n#1: at block 123456 upkeep 123456789 received status code 502 from mercury v0.3", + errorMessage: "All attempts fail:\n#1: at timestamp 123456 upkeep 123456789 received status code 502 from mercury v0.3", }, { - name: "failure - reports length does not match feeds length", + name: "success - retry when reports length does not match feeds length", lookup: &StreamsLookup{ feedParamKey: feedIDs, feeds: []string{"0x4554482d5553442d415242495452554d2d544553544e45540000000000000000", "0x4254432d5553442d415242495452554d2d544553544e45540000000000000000"}, @@ -801,18 +786,34 @@ func TestEvmRegistry_MultiFeedRequest(t *testing.T) { time: big.NewInt(123456), upkeepId: upkeepId, }, - response: MercuryV03Response{ + firstResponse: &MercuryV03Response{ Reports: []MercuryV03Report{ { - FeedID: "0x4554482d5553442d415242495452554d2d544553544e45540000000000000000", - ValidFromTimestamp: "123456", - ObservationsTimestamp: "123456", - FullReport: "0xab2123dc00000012", + FeedID: hexutil.MustDecode("0x4554482d5553442d415242495452554d2d544553544e45540000000000000000"), + ValidFromTimestamp: 123456, + ObservationsTimestamp: 123456, + FullReport: hexutil.MustDecode("0xab2123dc00000012"), }, }, }, - statusCode: http.StatusOK, - errorMessage: "All attempts fail:\n#1: at block 123456 upkeep 123456789 requested 2 feeds but received 1 reports from mercury v0.3", + response: &MercuryV03Response{ + Reports: []MercuryV03Report{ + { + FeedID: hexutil.MustDecode("0x4554482d5553442d415242495452554d2d544553544e45540000000000000000"), + ValidFromTimestamp: 123456, + ObservationsTimestamp: 123456, + FullReport: hexutil.MustDecode("0xab2123dc00000012"), + }, + { + FeedID: hexutil.MustDecode("0x4254432d5553442d415242495452554d2d544553544e45540000000000000000"), + ValidFromTimestamp: 123458, + ObservationsTimestamp: 123458, + FullReport: hexutil.MustDecode("0xab2123dc00000019"), + }, + }, + }, + retryNumber: 1, + statusCode: http.StatusOK, }, } @@ -830,17 +831,33 @@ func TestEvmRegistry_MultiFeedRequest(t *testing.T) { } hc.On("Do", mock.Anything).Return(resp, nil).Once() } else if tt.retryNumber < totalAttempt { - retryResp := &http.Response{ - StatusCode: tt.statusCode, - Body: io.NopCloser(bytes.NewReader(b)), - } - hc.On("Do", mock.Anything).Return(retryResp, nil).Times(tt.retryNumber) + if tt.firstResponse != nil && tt.response != nil { + b0, err := json.Marshal(tt.firstResponse) + assert.Nil(t, err) + resp0 := &http.Response{ + StatusCode: tt.statusCode, + Body: io.NopCloser(bytes.NewReader(b0)), + } + b1, err := json.Marshal(tt.response) + assert.Nil(t, err) + resp1 := &http.Response{ + StatusCode: tt.statusCode, + Body: io.NopCloser(bytes.NewReader(b1)), + } + hc.On("Do", mock.Anything).Return(resp0, nil).Once().On("Do", mock.Anything).Return(resp1, nil).Once() + } else { + retryResp := &http.Response{ + StatusCode: tt.statusCode, + Body: io.NopCloser(bytes.NewReader(b)), + } + hc.On("Do", mock.Anything).Return(retryResp, nil).Times(tt.retryNumber) - resp := &http.Response{ - StatusCode: tt.lastStatusCode, - Body: io.NopCloser(bytes.NewReader(b)), + resp := &http.Response{ + StatusCode: tt.lastStatusCode, + Body: io.NopCloser(bytes.NewReader(b)), + } + hc.On("Do", mock.Anything).Return(resp, nil).Once() } - hc.On("Do", mock.Anything).Return(resp, nil).Once() } else { resp := &http.Response{ StatusCode: tt.statusCode, @@ -862,11 +879,8 @@ func TestEvmRegistry_MultiFeedRequest(t *testing.T) { } else { assert.Nil(t, m.Error) var reports [][]byte - var report []byte for _, rsp := range tt.response.Reports { - report, err = hexutil.Decode(rsp.FullReport) - assert.Nil(t, err) - reports = append(reports, report) + reports = append(reports, rsp.FullReport) } assert.Equal(t, reports, m.Bytes) } diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/transmit/event_provider.go b/core/services/ocr2/plugins/ocr2keeper/evm21/transmit/event_provider.go index 1ea456ed3d5..b0ae2a7bf63 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm21/transmit/event_provider.go +++ b/core/services/ocr2/plugins/ocr2keeper/evm21/transmit/event_provider.go @@ -18,11 +18,11 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/utils" ) -var _ ocr2keepers.TransmitEventProvider = &TransmitEventProvider{} +var _ ocr2keepers.TransmitEventProvider = &EventProvider{} type logParser func(registry *iregistry21.IKeeperRegistryMaster, log logpoller.Log) (transmitEventLog, error) -type TransmitEventProvider struct { +type EventProvider struct { sync utils.StartStopOnce mu sync.RWMutex runState int @@ -40,7 +40,7 @@ type TransmitEventProvider struct { cache transmitEventCache } -func TransmitEventProviderFilterName(addr common.Address) string { +func EventProviderFilterName(addr common.Address) string { return logpoller.FilterName("KeepersRegistry TransmitEventProvider", addr) } @@ -50,7 +50,7 @@ func NewTransmitEventProvider( registryAddress common.Address, client evmclient.Client, lookbackBlocks int64, -) (*TransmitEventProvider, error) { +) (*EventProvider, error) { var err error contract, err := iregistry21.NewIKeeperRegistryMaster(registryAddress, client) @@ -58,7 +58,7 @@ func NewTransmitEventProvider( return nil, err } err = logPoller.RegisterFilter(logpoller.Filter{ - Name: TransmitEventProviderFilterName(contract.Address()), + Name: EventProviderFilterName(contract.Address()), EventSigs: []common.Hash{ // These are the events that are emitted when a node transmits a report iregistry21.IKeeperRegistryMasterUpkeepPerformed{}.Topic(), // Happy path: report performed the upkeep @@ -74,7 +74,7 @@ func NewTransmitEventProvider( return nil, err } - return &TransmitEventProvider{ + return &EventProvider{ logger: logger, logPoller: logPoller, registryAddress: registryAddress, @@ -86,11 +86,11 @@ func NewTransmitEventProvider( }, nil } -func (c *TransmitEventProvider) Name() string { +func (c *EventProvider) Name() string { return c.logger.Name() } -func (c *TransmitEventProvider) Start(ctx context.Context) error { +func (c *EventProvider) Start(_ context.Context) error { return c.sync.StartOnce("AutomationTransmitEventProvider", func() error { c.mu.Lock() defer c.mu.Unlock() @@ -100,7 +100,7 @@ func (c *TransmitEventProvider) Start(ctx context.Context) error { }) } -func (c *TransmitEventProvider) Close() error { +func (c *EventProvider) Close() error { return c.sync.StopOnce("AutomationRegistry", func() error { c.mu.Lock() defer c.mu.Unlock() @@ -111,7 +111,7 @@ func (c *TransmitEventProvider) Close() error { }) } -func (c *TransmitEventProvider) Ready() error { +func (c *EventProvider) Ready() error { c.mu.RLock() defer c.mu.RUnlock() @@ -121,7 +121,7 @@ func (c *TransmitEventProvider) Ready() error { return c.sync.Ready() } -func (c *TransmitEventProvider) HealthReport() map[string]error { +func (c *EventProvider) HealthReport() map[string]error { c.mu.RLock() defer c.mu.RUnlock() @@ -131,7 +131,7 @@ func (c *TransmitEventProvider) HealthReport() map[string]error { return map[string]error{c.Name(): c.sync.Healthy()} } -func (c *TransmitEventProvider) GetLatestEvents(ctx context.Context) ([]ocr2keepers.TransmitEvent, error) { +func (c *EventProvider) GetLatestEvents(ctx context.Context) ([]ocr2keepers.TransmitEvent, error) { end, err := c.logPoller.LatestBlock(pg.WithParentCtx(ctx)) if err != nil { return nil, fmt.Errorf("%w: failed to get latest block from log poller", err) @@ -159,8 +159,8 @@ func (c *TransmitEventProvider) GetLatestEvents(ctx context.Context) ([]ocr2keep } // processLogs will parse the unseen logs and return the corresponding transmit events. -func (c *TransmitEventProvider) processLogs(latestBlock int64, logs ...logpoller.Log) ([]ocr2keepers.TransmitEvent, error) { - vals := []ocr2keepers.TransmitEvent{} +func (c *EventProvider) processLogs(latestBlock int64, logs ...logpoller.Log) ([]ocr2keepers.TransmitEvent, error) { + var vals []ocr2keepers.TransmitEvent for _, log := range logs { k := c.logKey(log) @@ -191,6 +191,7 @@ func (c *TransmitEventProvider) processLogs(latestBlock int64, logs ...logpoller trigger.LogTriggerExtension = &ocr2keepers.LogTriggerExtension{} trigger.LogTriggerExtension.TxHash = triggerW.TxHash trigger.LogTriggerExtension.Index = triggerW.LogIndex + trigger.LogTriggerExtension.BlockHash = triggerW.LogBlockHash default: } workID := core.UpkeepWorkID(*upkeepId, trigger) @@ -213,10 +214,11 @@ func (c *TransmitEventProvider) processLogs(latestBlock int64, logs ...logpoller return vals, nil } -func (c *TransmitEventProvider) logKey(log logpoller.Log) string { +func (c *EventProvider) logKey(log logpoller.Log) string { logExt := ocr2keepers.LogTriggerExtension{ - TxHash: log.TxHash, - Index: uint32(log.LogIndex), + TxHash: log.TxHash, + Index: uint32(log.LogIndex), + BlockHash: log.BlockHash, } logId := logExt.LogIdentifier() return hex.EncodeToString(logId) diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/transmit/event_provider_test.go b/core/services/ocr2/plugins/ocr2keeper/evm21/transmit/event_provider_test.go index aa3480c8c26..72f3b63088d 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm21/transmit/event_provider_test.go +++ b/core/services/ocr2/plugins/ocr2keeper/evm21/transmit/event_provider_test.go @@ -127,7 +127,7 @@ func TestTransmitEventProvider_ProcessLogs(t *testing.T) { Performed: &iregistry21.IKeeperRegistryMasterUpkeepPerformed{ Id: id.BigInt(), Trigger: func() []byte { - b, _ := hexutil.Decode("0x0000000000000000000000000000000000000000000000000000000001111111000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000001111111") + b, _ := hexutil.Decode("0x0000000000000000000000000000000000000000000000000000000001111abc0000000000000000000000000000000000000000000000000000000001111111000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000001111111") return b }(), }, @@ -161,7 +161,7 @@ func TestTransmitEventProvider_ProcessLogs(t *testing.T) { Performed: &iregistry21.IKeeperRegistryMasterUpkeepPerformed{ Id: id.BigInt(), Trigger: func() []byte { - b, _ := hexutil.Decode("0x0000000000000000000000000000000000000000000000000000000001111111000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000001111111") + b, _ := hexutil.Decode("0x0000000000000000000000000000000000000000000000000000000001111abc0000000000000000000000000000000000000000000000000000000001111111000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000001111111") return b }(), }, @@ -174,7 +174,7 @@ func TestTransmitEventProvider_ProcessLogs(t *testing.T) { Performed: &iregistry21.IKeeperRegistryMasterUpkeepPerformed{ Id: id.BigInt(), Trigger: func() []byte { - b, _ := hexutil.Decode("0x0000000000000000000000000000000000000000000000000000000001111111000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000001111111") + b, _ := hexutil.Decode("0x0000000000000000000000000000000000000000000000000000000001111abc0000000000000000000000000000000000000000000000000000000001111111000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000001111111") return b }(), }, diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/upkeep_provider.go b/core/services/ocr2/plugins/ocr2keeper/evm21/upkeep_provider.go index 8e08008eca4..5cb60d5dc1d 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm21/upkeep_provider.go +++ b/core/services/ocr2/plugins/ocr2keeper/evm21/upkeep_provider.go @@ -26,7 +26,7 @@ func NewUpkeepProvider(activeUpkeeps ActiveUpkeepList, bs *BlockSubscriber, lp l } } -func (p *upkeepProvider) GetActiveUpkeeps(ctx context.Context) ([]ocr2keepers.UpkeepPayload, error) { +func (p *upkeepProvider) GetActiveUpkeeps(_ context.Context) ([]ocr2keepers.UpkeepPayload, error) { latestBlock := p.bs.latestBlock.Load() if latestBlock == nil { return nil, fmt.Errorf("no latest block found when fetching active upkeeps") @@ -35,7 +35,7 @@ func (p *upkeepProvider) GetActiveUpkeeps(ctx context.Context) ([]ocr2keepers.Up for _, uid := range p.activeUpkeeps.View(ocr2keepers.ConditionTrigger) { payload, err := core.NewUpkeepPayload( uid, - ocr2keepers.NewTrigger(ocr2keepers.BlockNumber(latestBlock.Number), latestBlock.Hash), + ocr2keepers.NewTrigger(latestBlock.Number, latestBlock.Hash), nil, ) if err != nil { diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/upkeepstate/orm.go b/core/services/ocr2/plugins/ocr2keeper/evm21/upkeepstate/orm.go index 94a16f23dfe..d441b71819e 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm21/upkeepstate/orm.go +++ b/core/services/ocr2/plugins/ocr2keeper/evm21/upkeepstate/orm.go @@ -34,16 +34,40 @@ func NewORM(chainID *big.Int, db *sqlx.DB, lggr logger.Logger, cfg pg.QConfig) * } } -// InsertUpkeepState is idempotent and sets upkeep state values in db -func (o *orm) InsertUpkeepState(state persistedStateRecord, qopts ...pg.QOpt) error { +// BatchInsertRecords is idempotent and sets upkeep state values in db +func (o *orm) BatchInsertRecords(state []persistedStateRecord, qopts ...pg.QOpt) error { q := o.q.WithOpts(qopts...) - query := `INSERT INTO evm_upkeep_states (evm_chain_id, work_id, completion_state, block_number, inserted_at, upkeep_id, ineligibility_reason) - VALUES ($1::NUMERIC, $2, $3, $4, $5, $6::NUMERIC, $7) - ON CONFLICT (evm_chain_id, work_id) - DO NOTHING` + if len(state) == 0 { + return nil + } + + type row struct { + EvmChainId *utils.Big + WorkId string + CompletionState uint8 + BlockNumber int64 + InsertedAt time.Time + UpkeepId *utils.Big + IneligibilityReason uint8 + } + + var rows []row + for _, record := range state { + rows = append(rows, row{ + EvmChainId: o.chainID, + WorkId: record.WorkID, + CompletionState: record.CompletionState, + BlockNumber: record.BlockNumber, + InsertedAt: record.InsertedAt, + UpkeepId: record.UpkeepID, + IneligibilityReason: record.IneligibilityReason, + }) + } - return q.ExecQ(query, o.chainID, state.WorkID, state.CompletionState, state.BlockNumber, state.InsertedAt, state.UpkeepID, state.IneligibilityReason) + return q.ExecQNamed(`INSERT INTO evm_upkeep_states +(evm_chain_id, work_id, completion_state, block_number, inserted_at, upkeep_id, ineligibility_reason) VALUES +(:evm_chain_id, :work_id, :completion_state, :block_number, :inserted_at, :upkeep_id, :ineligibility_reason) ON CONFLICT (evm_chain_id, work_id) DO NOTHING`, rows) } // SelectStatesByWorkIDs searches the data store for stored states for the diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/upkeepstate/orm_test.go b/core/services/ocr2/plugins/ocr2keeper/evm21/upkeepstate/orm_test.go index c816627e92c..54ca7285dd0 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm21/upkeepstate/orm_test.go +++ b/core/services/ocr2/plugins/ocr2keeper/evm21/upkeepstate/orm_test.go @@ -21,16 +21,18 @@ func TestInsertSelectDelete(t *testing.T) { db := pgtest.NewSqlxDB(t) orm := NewORM(chainID, db, lggr, pgtest.NewQConfig(true)) - inserted := persistedStateRecord{ - UpkeepID: utils.NewBig(big.NewInt(2)), - WorkID: "0x1", - CompletionState: 100, - BlockNumber: 2, - IneligibilityReason: 2, - InsertedAt: time.Now(), + inserted := []persistedStateRecord{ + { + UpkeepID: utils.NewBig(big.NewInt(2)), + WorkID: "0x1", + CompletionState: 100, + BlockNumber: 2, + IneligibilityReason: 2, + InsertedAt: time.Now(), + }, } - err := orm.InsertUpkeepState(inserted) + err := orm.BatchInsertRecords(inserted) require.NoError(t, err, "no error expected from insert") diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/upkeepstate/scanner.go b/core/services/ocr2/plugins/ocr2keeper/evm21/upkeepstate/scanner.go index 7879ec45bf9..9ce9a10ac73 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm21/upkeepstate/scanner.go +++ b/core/services/ocr2/plugins/ocr2keeper/evm21/upkeepstate/scanner.go @@ -15,6 +15,12 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/services/pg" ) +var ( + _ PerformedLogsScanner = &performedEventsScanner{} + + workIDsBatchSize = 25 +) + type PerformedLogsScanner interface { ScanWorkIDs(ctx context.Context, workIDs ...string) ([]string, error) @@ -56,7 +62,7 @@ func (s *performedEventsScanner) Start(_ context.Context) error { }) } -// implements io.Closer, does nothing upon close +// Close implements io.Closer and does nothing func (s *performedEventsScanner) Close() error { return nil } @@ -66,9 +72,18 @@ func (s *performedEventsScanner) ScanWorkIDs(ctx context.Context, workID ...stri for _, id := range workID { ids = append(ids, common.HexToHash(id)) } - logs, err := s.poller.IndexedLogs(iregistry21.IKeeperRegistryMasterDedupKeyAdded{}.Topic(), s.registryAddress, 1, ids, int(s.finalityDepth), pg.WithParentCtx(ctx)) - if err != nil { - return nil, fmt.Errorf("error fetching logs: %w", err) + logs := make([]logpoller.Log, 0) + for i := 0; i < len(ids); i += workIDsBatchSize { + end := i + workIDsBatchSize + if end > len(ids) { + end = len(ids) + } + batch := ids[i:end] + batchLogs, err := s.poller.IndexedLogs(iregistry21.IKeeperRegistryMasterDedupKeyAdded{}.Topic(), s.registryAddress, 1, batch, int(s.finalityDepth), pg.WithParentCtx(ctx)) + if err != nil { + return nil, fmt.Errorf("error fetching logs: %w", err) + } + logs = append(logs, batchLogs...) } return s.logsToWorkIDs(logs), nil diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/upkeepstate/scanner_test.go b/core/services/ocr2/plugins/ocr2keeper/evm21/upkeepstate/scanner_test.go index f1962373fe9..9442a5f5d7a 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm21/upkeepstate/scanner_test.go +++ b/core/services/ocr2/plugins/ocr2keeper/evm21/upkeepstate/scanner_test.go @@ -2,6 +2,7 @@ package upkeepstate import ( "fmt" + "sort" "testing" "github.com/ethereum/go-ethereum/common" @@ -110,6 +111,57 @@ func TestPerformedEventsScanner(t *testing.T) { } } +func TestPerformedEventsScanner_Batch(t *testing.T) { + ctx := testutils.Context(t) + registryAddr := common.HexToAddress("0x12345") + lggr := logger.TestLogger(t) + lp := new(mocks.LogPoller) + scanner := NewPerformedEventsScanner(lggr, lp, registryAddr, 100) + + lp.On("IndexedLogs", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return([]logpoller.Log{ + { + BlockNumber: 1, + Address: registryAddr, + Topics: convertTopics([]common.Hash{ + iregistry21.IKeeperRegistryMasterDedupKeyAdded{}.Topic(), + common.HexToHash("0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e563"), + }), + }, + }, nil).Times(1) + lp.On("IndexedLogs", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return([]logpoller.Log{ + { + BlockNumber: 3, + Address: registryAddr, + Topics: convertTopics([]common.Hash{ + iregistry21.IKeeperRegistryMasterDedupKeyAdded{}.Topic(), + common.HexToHash("0x331decd9548b62a8d603457658386fc84ba6bc95888008f6362f93160ef3b663"), + }), + }, + }, nil).Times(1) + + origWorkIDsBatchSize := workIDsBatchSize + workIDsBatchSize = 8 + defer func() { + workIDsBatchSize = origWorkIDsBatchSize + }() + + ids, err := scanner.ScanWorkIDs(ctx, + "290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e563", + "1111", "2222", "3333", "4444", "5555", "6666", "7777", "8888", "9999", + "331decd9548b62a8d603457658386fc84ba6bc95888008f6362f93160ef3b663", + ) + + require.NoError(t, err) + require.Equal(t, 2, len(ids)) + sort.Slice(ids, func(i, j int) bool { + return ids[i] < ids[j] + }) + require.Equal(t, "290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e563", ids[0]) + require.Equal(t, "331decd9548b62a8d603457658386fc84ba6bc95888008f6362f93160ef3b663", ids[1]) + + lp.AssertExpectations(t) +} + func convertTopics(topics []common.Hash) [][]byte { var topicsForDB [][]byte for _, t := range topics { diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/upkeepstate/store.go b/core/services/ocr2/plugins/ocr2keeper/evm21/upkeepstate/store.go index 3b37b58d03d..cd123212376 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm21/upkeepstate/store.go +++ b/core/services/ocr2/plugins/ocr2keeper/evm21/upkeepstate/store.go @@ -2,7 +2,6 @@ package upkeepstate import ( "context" - "errors" "fmt" "io" "math/big" @@ -18,14 +17,18 @@ import ( ) const ( + UpkeepStateStoreServiceName = "UpkeepStateStore" // CacheExpiration is the amount of time that we keep a record in the cache. CacheExpiration = 24 * time.Hour // GCInterval is the amount of time between cache cleanups. GCInterval = 2 * time.Hour + // flushCadence is the amount of time between flushes to the DB. + flushCadence = 30 * time.Second + concurrentBatchCalls = 10 ) type ORM interface { - InsertUpkeepState(persistedStateRecord, ...pg.QOpt) error + BatchInsertRecords([]persistedStateRecord, ...pg.QOpt) error SelectStatesByWorkIDs([]string, ...pg.QOpt) ([]persistedStateRecord, error) DeleteExpired(time.Time, ...pg.QOpt) error } @@ -39,7 +42,9 @@ type UpkeepStateStore interface { } var ( - _ UpkeepStateStore = &upkeepStateStore{} + _ UpkeepStateStore = &upkeepStateStore{} + newTickerFn = time.NewTicker + batchSize = 1000 ) // upkeepStateRecord is a record that we save in a local cache. @@ -54,97 +59,115 @@ type upkeepStateRecord struct { // It stores the state of ineligible upkeeps in a local, in-memory cache. // In addition, performed events are fetched by the scanner on demand. type upkeepStateStore struct { - // dependencies + utils.StartStopOnce + threadCtrl utils.ThreadControl + orm ORM lggr logger.Logger scanner PerformedLogsScanner - // configuration retention time.Duration cleanCadence time.Duration mu sync.RWMutex cache map[string]*upkeepStateRecord - // service values - cancel context.CancelFunc + pendingRecords []persistedStateRecord + sem chan struct{} + batchSize int } // NewUpkeepStateStore creates a new state store func NewUpkeepStateStore(orm ORM, lggr logger.Logger, scanner PerformedLogsScanner) *upkeepStateStore { return &upkeepStateStore{ - orm: orm, - lggr: lggr.Named("UpkeepStateStore"), - cache: map[string]*upkeepStateRecord{}, - scanner: scanner, - retention: CacheExpiration, - cleanCadence: GCInterval, + orm: orm, + lggr: lggr.Named(UpkeepStateStoreServiceName), + cache: map[string]*upkeepStateRecord{}, + scanner: scanner, + retention: CacheExpiration, + cleanCadence: GCInterval, + threadCtrl: utils.NewThreadControl(), + pendingRecords: []persistedStateRecord{}, + sem: make(chan struct{}, concurrentBatchCalls), + batchSize: batchSize, } } // Start starts the upkeep state store. -// it does background cleanup of the cache. +// it does background cleanup of the cache every GCInterval, +// and flush records to DB every flushCadence. func (u *upkeepStateStore) Start(pctx context.Context) error { - if u.retention == 0 { - return errors.New("pruneDepth must be greater than zero") - } - - u.mu.Lock() - if u.cancel != nil { - u.mu.Unlock() - return fmt.Errorf("already started") - } - - ctx, cancel := context.WithCancel(context.Background()) - - u.cancel = cancel - u.mu.Unlock() - - if err := u.scanner.Start(ctx); err != nil { - return fmt.Errorf("failed to start scanner") - } + return u.StartOnce(UpkeepStateStoreServiceName, func() error { + if err := u.scanner.Start(pctx); err != nil { + return fmt.Errorf("failed to start scanner") + } - u.lggr.Debug("Starting upkeep state store") + u.lggr.Debug("Starting upkeep state store") - { - go func(ctx context.Context) { + u.threadCtrl.Go(func(ctx context.Context) { ticker := time.NewTicker(utils.WithJitter(u.cleanCadence)) defer ticker.Stop() + flushTicker := newTickerFn(utils.WithJitter(flushCadence)) + defer flushTicker.Stop() + for { select { case <-ticker.C: if err := u.cleanup(ctx); err != nil { u.lggr.Errorw("unable to clean old state values", "err", err) } - ticker.Reset(utils.WithJitter(u.cleanCadence)) + case <-flushTicker.C: + u.flush(ctx) + flushTicker.Reset(utils.WithJitter(flushCadence)) case <-ctx.Done(): - + u.flush(ctx) + return } } - }(ctx) - } - - return nil + }) + return nil + }) } -// Close stops the service of pruning stale data; implements io.Closer -func (u *upkeepStateStore) Close() error { +func (u *upkeepStateStore) flush(ctx context.Context) { + cloneRecords := make([]persistedStateRecord, len(u.pendingRecords)) + u.mu.Lock() - defer u.mu.Unlock() + copy(cloneRecords, u.pendingRecords) + u.pendingRecords = []persistedStateRecord{} + u.mu.Unlock() - if cancel := u.cancel; cancel != nil { - u.cancel = nil - cancel() - } else { - return fmt.Errorf("already stopped") - } - if err := u.scanner.Close(); err != nil { - return fmt.Errorf("failed to start scanner") + for i := 0; i < len(cloneRecords); i += u.batchSize { + end := i + u.batchSize + if end > len(cloneRecords) { + end = len(cloneRecords) + } + + batch := cloneRecords[i:end] + + u.sem <- struct{}{} + + go func() { + if err := u.orm.BatchInsertRecords(batch, pg.WithParentCtx(ctx)); err != nil { + u.lggr.Errorw("error inserting records", "err", err) + } + <-u.sem + }() } +} - return nil +// Close stops the service of pruning stale data; implements io.Closer +func (u *upkeepStateStore) Close() error { + return u.StopOnce(UpkeepStateStoreServiceName, func() error { + u.threadCtrl.Close() + return nil + }) +} + +func (u *upkeepStateStore) HealthReport() map[string]error { + return map[string]error{UpkeepStateStoreServiceName: u.Healthy()} } // SelectByWorkIDs returns the current state of the upkeep for the provided ids. @@ -200,13 +223,15 @@ func (u *upkeepStateStore) upsertStateRecord(ctx context.Context, workID string, u.cache[workID] = record - return u.orm.InsertUpkeepState(persistedStateRecord{ + u.pendingRecords = append(u.pendingRecords, persistedStateRecord{ UpkeepID: utils.NewBig(upkeepID), WorkID: record.workID, CompletionState: uint8(record.state), IneligibilityReason: reason, InsertedAt: record.addedAt, - }, pg.WithParentCtx(ctx)) + }) + + return nil } // fetchPerformed fetches all performed logs from the scanner to populate the cache. diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/upkeepstate/store_test.go b/core/services/ocr2/plugins/ocr2keeper/evm21/upkeepstate/store_test.go index fd2e6464239..cc4f6d0a23f 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm21/upkeepstate/store_test.go +++ b/core/services/ocr2/plugins/ocr2keeper/evm21/upkeepstate/store_test.go @@ -220,29 +220,23 @@ func TestUpkeepStateStore_SetSelectIntegration(t *testing.T) { } tests := []struct { - name string - queryIDs []string - storedValues []storedValue - expected []ocr2keepers.UpkeepState + name string + flushSize int + expectedWrites int + queryIDs []string + storedValues []storedValue + expected []ocr2keepers.UpkeepState }{ { - name: "querying non-stored workIDs on empty db returns unknown state results", - queryIDs: []string{"0x1", "0x2", "0x3", "0x4"}, - expected: []ocr2keepers.UpkeepState{ - ocr2keepers.UnknownState, - ocr2keepers.UnknownState, - ocr2keepers.UnknownState, - ocr2keepers.UnknownState, - }, - }, - { - name: "querying non-stored workIDs on db with values returns unknown state results", - queryIDs: []string{"0x1", "0x2", "0x3", "0x4"}, + name: "querying non-stored workIDs on db with values returns unknown state results", + queryIDs: []string{"0x1", "0x2", "0x3", "0x4"}, + flushSize: 10, + expectedWrites: 1, storedValues: []storedValue{ - {result: makeTestResult(1, "0x11", false, 1), state: ocr2keepers.Ineligible}, - {result: makeTestResult(2, "0x22", false, 1), state: ocr2keepers.Ineligible}, - {result: makeTestResult(3, "0x33", false, 1), state: ocr2keepers.Ineligible}, - {result: makeTestResult(4, "0x44", false, 1), state: ocr2keepers.Ineligible}, + {result: makeTestResult(1, "0x11", false, 1), state: ocr2keepers.Performed}, + {result: makeTestResult(2, "0x22", false, 1), state: ocr2keepers.Performed}, + {result: makeTestResult(3, "0x33", false, 1), state: ocr2keepers.Performed}, + {result: makeTestResult(4, "0x44", false, 1), state: ocr2keepers.Performed}, }, expected: []ocr2keepers.UpkeepState{ ocr2keepers.UnknownState, @@ -252,13 +246,15 @@ func TestUpkeepStateStore_SetSelectIntegration(t *testing.T) { }, }, { - name: "querying workIDs with non-stored values returns valid results", - queryIDs: []string{"0x1", "0x2", "0x3", "0x4"}, + name: "storing eligible values is a noop", + queryIDs: []string{"0x1", "0x2", "0x3", "0x4"}, + flushSize: 4, + expectedWrites: 1, storedValues: []storedValue{ - {result: makeTestResult(5, "0x1", false, 1), state: ocr2keepers.Ineligible}, - {result: makeTestResult(6, "0x2", false, 1), state: ocr2keepers.Ineligible}, - {result: makeTestResult(7, "0x3", false, 1), state: ocr2keepers.Ineligible}, - {result: makeTestResult(8, "0x44", false, 1), state: ocr2keepers.Ineligible}, + {result: makeTestResult(9, "0x1", false, 1), state: ocr2keepers.Ineligible}, + {result: makeTestResult(10, "0x2", false, 1), state: ocr2keepers.Ineligible}, + {result: makeTestResult(11, "0x3", false, 1), state: ocr2keepers.Ineligible}, + {result: makeTestResult(12, "0x4", true, 1), state: ocr2keepers.Performed}, // gets inserted }, expected: []ocr2keepers.UpkeepState{ ocr2keepers.Ineligible, @@ -268,31 +264,43 @@ func TestUpkeepStateStore_SetSelectIntegration(t *testing.T) { }, }, { - name: "storing eligible values is a noop", - queryIDs: []string{"0x1", "0x2", "0x3", "0x4"}, + name: "provided state on setupkeepstate is currently ignored for eligible check results", + queryIDs: []string{"0x1", "0x2"}, + flushSize: 1, + expectedWrites: 1, storedValues: []storedValue{ - {result: makeTestResult(9, "0x1", false, 1), state: ocr2keepers.Ineligible}, - {result: makeTestResult(10, "0x2", false, 1), state: ocr2keepers.Ineligible}, - {result: makeTestResult(11, "0x3", false, 1), state: ocr2keepers.Ineligible}, - {result: makeTestResult(12, "0x4", true, 1), state: ocr2keepers.Performed}, + {result: makeTestResult(13, "0x1", true, 1), state: ocr2keepers.Ineligible}, + {result: makeTestResult(14, "0x2", false, 1), state: ocr2keepers.Performed}, // gets inserted }, expected: []ocr2keepers.UpkeepState{ - ocr2keepers.Ineligible, - ocr2keepers.Ineligible, - ocr2keepers.Ineligible, ocr2keepers.UnknownState, + ocr2keepers.Ineligible, }, }, { - name: "provided state on setupkeepstate is currently ignored for eligible check results", - queryIDs: []string{"0x1", "0x2"}, + name: "provided state outside the flush batch isn't registered in the db", + queryIDs: []string{"0x1", "0x2", "0x3", "0x4", "0x5", "0x6", "0x7", "0x8"}, + flushSize: 3, + expectedWrites: 2, storedValues: []storedValue{ {result: makeTestResult(13, "0x1", true, 1), state: ocr2keepers.Ineligible}, - {result: makeTestResult(14, "0x2", false, 1), state: ocr2keepers.Performed}, + {result: makeTestResult(14, "0x2", false, 1), state: ocr2keepers.Performed}, // gets inserted + {result: makeTestResult(15, "0x3", true, 1), state: ocr2keepers.Ineligible}, + {result: makeTestResult(16, "0x4", false, 1), state: ocr2keepers.Performed}, // gets inserted + {result: makeTestResult(17, "0x5", true, 1), state: ocr2keepers.Ineligible}, + {result: makeTestResult(18, "0x6", false, 1), state: ocr2keepers.Performed}, // gets inserted + {result: makeTestResult(19, "0x7", true, 1), state: ocr2keepers.Ineligible}, + {result: makeTestResult(20, "0x8", false, 1), state: ocr2keepers.Performed}, // gets inserted }, expected: []ocr2keepers.UpkeepState{ ocr2keepers.UnknownState, ocr2keepers.Ineligible, + ocr2keepers.UnknownState, + ocr2keepers.Ineligible, + ocr2keepers.UnknownState, + ocr2keepers.Ineligible, + ocr2keepers.UnknownState, + ocr2keepers.Ineligible, }, }, } @@ -301,13 +309,44 @@ func TestUpkeepStateStore_SetSelectIntegration(t *testing.T) { t.Run(test.name, func(t *testing.T) { ctx := testutils.Context(t) + tickerCh := make(chan time.Time) + + oldNewTickerFn := newTickerFn + oldFlushSize := batchSize + newTickerFn = func(d time.Duration) *time.Ticker { + t := time.NewTicker(d) + t.C = tickerCh + return t + } + batchSize = test.flushSize + defer func() { + newTickerFn = oldNewTickerFn + batchSize = oldFlushSize + }() + lggr, observedLogs := logger.TestLoggerObserved(t, zapcore.ErrorLevel) chainID := testutils.FixtureChainID db := pgtest.NewSqlxDB(t) - orm := NewORM(chainID, db, lggr, pgtest.NewQConfig(true)) + realORM := NewORM(chainID, db, lggr, pgtest.NewQConfig(true)) + insertFinished := make(chan struct{}, 1) + orm := &wrappedORM{ + BatchInsertRecordsFn: func(records []persistedStateRecord, opt ...pg.QOpt) error { + err := realORM.BatchInsertRecords(records, opt...) + insertFinished <- struct{}{} + return err + }, + SelectStatesByWorkIDsFn: func(strings []string, opt ...pg.QOpt) ([]persistedStateRecord, error) { + return realORM.SelectStatesByWorkIDs(strings, opt...) + }, + DeleteExpiredFn: func(t time.Time, opt ...pg.QOpt) error { + return realORM.DeleteExpired(t, opt...) + }, + } scanner := &mockScanner{} store := NewUpkeepStateStore(orm, lggr, scanner) + require.NoError(t, store.Start(ctx)) + t.Cleanup(func() { t.Log("cleaning up database") @@ -320,6 +359,13 @@ func TestUpkeepStateStore_SetSelectIntegration(t *testing.T) { require.NoError(t, store.SetUpkeepState(context.Background(), insert.result, insert.state), "storing states should not produce an error") } + tickerCh <- time.Now() + + // if this test inserts data, wait for the insert to complete before proceeding + for i := 0; i < test.expectedWrites; i++ { + <-insertFinished + } + // empty the cache before doing selects to force a db lookup store.cache = make(map[string]*upkeepStateRecord) @@ -332,10 +378,50 @@ func TestUpkeepStateStore_SetSelectIntegration(t *testing.T) { observedLogs.TakeAll() require.Equal(t, 0, observedLogs.Len()) + + require.NoError(t, store.Close()) }) } } +func TestUpkeepStateStore_emptyDB(t *testing.T) { + t.Run("querying non-stored workIDs on empty db returns unknown state results", func(t *testing.T) { + lggr, observedLogs := logger.TestLoggerObserved(t, zapcore.ErrorLevel) + chainID := testutils.FixtureChainID + db := pgtest.NewSqlxDB(t) + realORM := NewORM(chainID, db, lggr, pgtest.NewQConfig(true)) + insertFinished := make(chan struct{}, 1) + orm := &wrappedORM{ + BatchInsertRecordsFn: func(records []persistedStateRecord, opt ...pg.QOpt) error { + err := realORM.BatchInsertRecords(records, opt...) + insertFinished <- struct{}{} + return err + }, + SelectStatesByWorkIDsFn: func(strings []string, opt ...pg.QOpt) ([]persistedStateRecord, error) { + return realORM.SelectStatesByWorkIDs(strings, opt...) + }, + DeleteExpiredFn: func(t time.Time, opt ...pg.QOpt) error { + return realORM.DeleteExpired(t, opt...) + }, + } + scanner := &mockScanner{} + store := NewUpkeepStateStore(orm, lggr, scanner) + + states, err := store.SelectByWorkIDs(context.Background(), []string{"0x1", "0x2", "0x3", "0x4"}...) + assert.NoError(t, err) + assert.Equal(t, []ocr2keepers.UpkeepState{ + ocr2keepers.UnknownState, + ocr2keepers.UnknownState, + ocr2keepers.UnknownState, + ocr2keepers.UnknownState, + }, states) + + observedLogs.TakeAll() + + require.Equal(t, 0, observedLogs.Len()) + }) +} + func TestUpkeepStateStore_Upsert(t *testing.T) { db := pgtest.NewSqlxDB(t) ctx := testutils.Context(t) @@ -475,7 +561,7 @@ func (_m *mockORM) setErr(err error) { _m.err = err } -func (_m *mockORM) InsertUpkeepState(state persistedStateRecord, _ ...pg.QOpt) error { +func (_m *mockORM) BatchInsertRecords(state []persistedStateRecord, _ ...pg.QOpt) error { return nil } @@ -498,3 +584,21 @@ func (_m *mockORM) DeleteExpired(tm time.Time, _ ...pg.QOpt) error { return _m.err } + +type wrappedORM struct { + BatchInsertRecordsFn func([]persistedStateRecord, ...pg.QOpt) error + SelectStatesByWorkIDsFn func([]string, ...pg.QOpt) ([]persistedStateRecord, error) + DeleteExpiredFn func(time.Time, ...pg.QOpt) error +} + +func (o *wrappedORM) BatchInsertRecords(r []persistedStateRecord, q ...pg.QOpt) error { + return o.BatchInsertRecordsFn(r, q...) +} + +func (o *wrappedORM) SelectStatesByWorkIDs(ids []string, q ...pg.QOpt) ([]persistedStateRecord, error) { + return o.SelectStatesByWorkIDsFn(ids, q...) +} + +func (o *wrappedORM) DeleteExpired(t time.Time, q ...pg.QOpt) error { + return o.DeleteExpiredFn(t, q...) +} diff --git a/core/services/ocr2/plugins/ocr2keeper/integration_21_test.go b/core/services/ocr2/plugins/ocr2keeper/integration_21_test.go index 6ce8b0aa8cf..7d69ea6522d 100644 --- a/core/services/ocr2/plugins/ocr2keeper/integration_21_test.go +++ b/core/services/ocr2/plugins/ocr2keeper/integration_21_test.go @@ -29,6 +29,7 @@ import ( "github.com/stretchr/testify/require" "github.com/umbracle/ethgo/abi" + relaytypes "github.com/smartcontractkit/chainlink-relay/pkg/types" "github.com/smartcontractkit/chainlink/v2/core/assets" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller" automationForwarderLogic "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/automation_forwarder_logic" @@ -57,7 +58,7 @@ func TestFilterNamesFromSpec21(t *testing.T) { address := common.HexToAddress(hexutil.Encode(b)) spec := &job.OCR2OracleSpec{ - PluginType: job.OCR2Keeper, + PluginType: relaytypes.OCR2Keeper, ContractID: address.String(), // valid contract addr } @@ -69,7 +70,7 @@ func TestFilterNamesFromSpec21(t *testing.T) { assert.Equal(t, logpoller.FilterName("KeeperRegistry Events", address), names[1]) spec = &job.OCR2OracleSpec{ - PluginType: job.OCR2Keeper, + PluginType: relaytypes.OCR2Keeper, ContractID: "0x5431", // invalid contract addr } _, err = ocr2keeper.FilterNamesFromSpec21(spec) diff --git a/core/services/ocr2/plugins/ocr2keeper/integration_test.go b/core/services/ocr2/plugins/ocr2keeper/integration_test.go index 8b7e92c40fe..f51aa43e199 100644 --- a/core/services/ocr2/plugins/ocr2keeper/integration_test.go +++ b/core/services/ocr2/plugins/ocr2keeper/integration_test.go @@ -56,6 +56,8 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm" "github.com/smartcontractkit/chainlink/v2/core/store/models" "github.com/smartcontractkit/chainlink/v2/core/utils" + + relaytypes "github.com/smartcontractkit/chainlink-relay/pkg/types" ) const ( @@ -112,7 +114,7 @@ func setupNode( p2pKey, err := p2pkey.NewV2() require.NoError(t, err) p2paddresses := []string{fmt.Sprintf("127.0.0.1:%d", port)} - config, _ := heavyweight.FullTestDBV2(t, fmt.Sprintf("%s%d", dbName, port), func(c *chainlink.Config, s *chainlink.Secrets) { + cfg, _ := heavyweight.FullTestDBV2(t, fmt.Sprintf("%s%d", dbName, port), func(c *chainlink.Config, s *chainlink.Secrets) { c.Feature.LogPoller = ptr(true) c.OCR.Enabled = ptr(false) @@ -133,14 +135,15 @@ func setupNode( c.EVM[0].GasEstimator.Mode = ptr("FixedPrice") s.Mercury.Credentials = map[string]toml.MercuryCredentials{ MercuryCredName: { - URL: models.MustSecretURL("https://mercury.chain.link"), - Username: models.NewSecret("username1"), - Password: models.NewSecret("password1"), + LegacyURL: models.MustSecretURL("https://old.api.link"), + URL: models.MustSecretURL("https://new.api.link"), + Username: models.NewSecret("username1"), + Password: models.NewSecret("password1"), }, } }) - app := cltest.NewApplicationWithConfigV2AndKeyOnSimulatedBlockchain(t, config, backend, nodeKey, p2pKey) + app := cltest.NewApplicationWithConfigV2AndKeyOnSimulatedBlockchain(t, cfg, backend, nodeKey, p2pKey) kb, err := app.GetKeyStore().OCR2().Create(chaintype.EVM) require.NoError(t, err) @@ -162,16 +165,16 @@ type Node struct { func (node *Node) AddJob(t *testing.T, spec string) { c := node.App.GetConfig() - job, err := validate.ValidatedOracleSpecToml(c.OCR2(), c.Insecure(), spec) + jb, err := validate.ValidatedOracleSpecToml(c.OCR2(), c.Insecure(), spec) require.NoError(t, err) - err = node.App.AddJobV2(context.Background(), &job) + err = node.App.AddJobV2(context.Background(), &jb) require.NoError(t, err) } func (node *Node) AddBootstrapJob(t *testing.T, spec string) { - job, err := ocrbootstrap.ValidatedBootstrapSpecToml(spec) + jb, err := ocrbootstrap.ValidatedBootstrapSpecToml(spec) require.NoError(t, err) - err = node.App.AddJobV2(context.Background(), &job) + err = node.App.AddJobV2(context.Background(), &jb) require.NoError(t, err) } @@ -705,7 +708,7 @@ func TestFilterNamesFromSpec20(t *testing.T) { address := common.HexToAddress(hexutil.Encode(b)) spec := &job.OCR2OracleSpec{ - PluginType: job.OCR2Keeper, + PluginType: relaytypes.OCR2Keeper, ContractID: address.String(), // valid contract addr } @@ -717,7 +720,7 @@ func TestFilterNamesFromSpec20(t *testing.T) { assert.Equal(t, logpoller.FilterName("EvmRegistry - Upkeep events for", address), names[1]) spec = &job.OCR2OracleSpec{ - PluginType: job.OCR2Keeper, + PluginType: relaytypes.OCR2Keeper, ContractID: "0x5431", // invalid contract addr } _, err = ocr2keeper.FilterNamesFromSpec20(spec) diff --git a/core/services/ocr2/plugins/ocr2keeper/util.go b/core/services/ocr2/plugins/ocr2keeper/util.go index ff1cd0940dd..132afd0d29d 100644 --- a/core/services/ocr2/plugins/ocr2keeper/util.go +++ b/core/services/ocr2/plugins/ocr2keeper/util.go @@ -140,5 +140,5 @@ func FilterNamesFromSpec21(spec *job.OCR2OracleSpec) (names []string, err error) if err != nil { return nil, err } - return []string{kevm21transmit.TransmitEventProviderFilterName(addr.Address()), kevm21.RegistryUpkeepFilterName(addr.Address())}, err + return []string{kevm21transmit.EventProviderFilterName(addr.Address()), kevm21.RegistryUpkeepFilterName(addr.Address())}, err } diff --git a/core/services/ocr2/plugins/ocr2vrf/coordinator/coordinator_test.go b/core/services/ocr2/plugins/ocr2vrf/coordinator/coordinator_test.go index 5a32644d0ee..1222ab7b2a4 100644 --- a/core/services/ocr2/plugins/ocr2vrf/coordinator/coordinator_test.go +++ b/core/services/ocr2/plugins/ocr2vrf/coordinator/coordinator_test.go @@ -25,6 +25,7 @@ import ( "github.com/smartcontractkit/ocr2vrf/ocr2vrf" ocr2vrftypes "github.com/smartcontractkit/ocr2vrf/types" + relaytypes "github.com/smartcontractkit/chainlink-relay/pkg/types" evmclimocks "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client/mocks" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller" lp_mocks "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller/mocks" @@ -1761,7 +1762,7 @@ func TestFilterNamesFromSpec(t *testing.T) { spec := &job.OCR2OracleSpec{ ContractID: beaconAddress.String(), - PluginType: job.OCR2VRF, + PluginType: relaytypes.OCR2VRF, PluginConfig: job.JSONConfig{ "VRFCoordinatorAddress": coordinatorAddress.String(), "DKGContractAddress": dkgAddress.String(), @@ -1775,7 +1776,7 @@ func TestFilterNamesFromSpec(t *testing.T) { assert.Equal(t, logpoller.FilterName("VRF Coordinator", beaconAddress, coordinatorAddress, dkgAddress), names[0]) spec = &job.OCR2OracleSpec{ - PluginType: job.OCR2VRF, + PluginType: relaytypes.OCR2VRF, ContractID: beaconAddress.String(), PluginConfig: nil, // missing coordinator & dkg addresses } diff --git a/core/services/ocr2/plugins/s4/messages_test.go b/core/services/ocr2/plugins/s4/messages_test.go index 78fcabf9899..55c65eec8df 100644 --- a/core/services/ocr2/plugins/s4/messages_test.go +++ b/core/services/ocr2/plugins/s4/messages_test.go @@ -1,14 +1,16 @@ package s4_test import ( + "crypto/ecdsa" "testing" "time" + "github.com/ethereum/go-ethereum/common" + "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/s4" s4_svc "github.com/smartcontractkit/chainlink/v2/core/services/s4" - "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) @@ -55,6 +57,32 @@ func Test_MarshalUnmarshalQuery(t *testing.T) { require.Equal(t, addressRange, ar) } +func signRow(t *testing.T, row *s4.Row, address common.Address, pk *ecdsa.PrivateKey) { + t.Helper() + + env := &s4_svc.Envelope{ + Address: address.Bytes(), + SlotID: uint(row.Slotid), + Version: row.Version, + Expiration: row.Expiration, + Payload: row.Payload, + } + sig, err := env.Sign(pk) + require.NoError(t, err) + row.Signature = sig +} + +func marshalUnmarshal(t *testing.T, row *s4.Row) *s4.Row { + t.Helper() + + data, err := s4.MarshalRows([]*s4.Row{row}) + require.NoError(t, err) + rows, err := s4.UnmarshalRows(data) + require.NoError(t, err) + require.Len(t, rows, 1) + return rows[0] +} + func Test_VerifySignature(t *testing.T) { t.Parallel() @@ -71,20 +99,24 @@ func Test_VerifySignature(t *testing.T) { for addr[0] != 0 { pk, addr = testutils.NewPrivateKeyAndAddress(t) } - rows := generateTestRows(t, 1, time.Minute) - rows[0].Address = addr.Big().Bytes() - env := &s4_svc.Envelope{ - Address: addr.Bytes(), - SlotID: uint(rows[0].Slotid), - Version: rows[0].Version, - Expiration: rows[0].Expiration, - Payload: rows[0].Payload, - } - sig, err := env.Sign(pk) - assert.NoError(t, err) - rows[0].Signature = sig + row := generateTestRows(t, 1, time.Minute)[0] + row.Address = addr.Big().Bytes() + signRow(t, row, addr, pk) - err = rows[0].VerifySignature() - require.NoError(t, err) + require.NoError(t, row.VerifySignature()) + sameRow := marshalUnmarshal(t, row) + require.NoError(t, sameRow.VerifySignature()) + }) + + t.Run("empty payload", func(t *testing.T) { + pk, addr := testutils.NewPrivateKeyAndAddress(t) + row := generateTestRows(t, 1, time.Minute)[0] + row.Payload = []byte{} + row.Address = addr.Big().Bytes() + signRow(t, row, addr, pk) + + require.NoError(t, row.VerifySignature()) + sameRow := marshalUnmarshal(t, row) + require.NoError(t, sameRow.VerifySignature()) }) } diff --git a/core/services/ocr2/plugins/threshold/decryption_queue.go b/core/services/ocr2/plugins/threshold/decryption_queue.go index fae72685a2f..1ffc63e5898 100644 --- a/core/services/ocr2/plugins/threshold/decryption_queue.go +++ b/core/services/ocr2/plugins/threshold/decryption_queue.go @@ -171,7 +171,11 @@ func (dq *decryptionQueue) GetRequests(requestCountLimit int, totalBytesLimit in dq.pendingRequestQueue = removeMultipleIndices(dq.pendingRequestQueue, indicesToRemove) - dq.lggr.Debugf("returning first %d of %d total requests awaiting decryption", len(requests), len(dq.pendingRequestQueue)) + if len(dq.pendingRequestQueue) > 0 { + dq.lggr.Debugf("returning first %d of %d total requests awaiting decryption", len(requests), len(dq.pendingRequestQueue)) + } else { + dq.lggr.Debug("no requests awaiting decryption") + } return requests } diff --git a/core/services/ocr2/validate/validate.go b/core/services/ocr2/validate/validate.go index ca1ab60deb9..cde1a1f9276 100644 --- a/core/services/ocr2/validate/validate.go +++ b/core/services/ocr2/validate/validate.go @@ -12,6 +12,7 @@ import ( libocr2 "github.com/smartcontractkit/libocr/offchainreporting2plus" + "github.com/smartcontractkit/chainlink-relay/pkg/types" "github.com/smartcontractkit/chainlink/v2/core/services/job" dkgconfig "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/dkg/config" mercuryconfig "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/mercury/config" @@ -98,20 +99,20 @@ func validateSpec(tree *toml.Tree, spec job.Job) error { } switch spec.OCR2OracleSpec.PluginType { - case job.Median: + case types.Median: if spec.Pipeline.Source == "" { return errors.New("no pipeline specified") } - case job.DKG: + case types.DKG: return validateDKGSpec(spec.OCR2OracleSpec.PluginConfig) - case job.OCR2VRF: + case types.OCR2VRF: return validateOCR2VRFSpec(spec.OCR2OracleSpec.PluginConfig) - case job.OCR2Keeper: + case types.OCR2Keeper: return validateOCR2KeeperSpec(spec.OCR2OracleSpec.PluginConfig) - case job.OCR2Functions: + case types.Functions: // TODO validator for DR-OCR spec: https://app.shortcut.com/chainlinklabs/story/54054/ocr-plugin-for-directrequest-ocr return nil - case job.Mercury: + case types.Mercury: return validateOCR2MercurySpec(spec.OCR2OracleSpec.PluginConfig, *spec.OCR2OracleSpec.FeedID) case "": return errors.New("no plugin specified") diff --git a/core/services/ocrbootstrap/delegate.go b/core/services/ocrbootstrap/delegate.go index b39f9eec6ec..d530797367f 100644 --- a/core/services/ocrbootstrap/delegate.go +++ b/core/services/ocrbootstrap/delegate.go @@ -118,7 +118,7 @@ func (d *Delegate) ServicesForSpec(jobSpec job.Job, qopts ...pg.QOpt) (services if routerFields.ContractVersion != 1 || routerFields.ContractUpdateCheckFrequencySec == 0 { return nil, errors.New("invalid router contract config") } - configProvider, err = relayer.NewFunctionsProvider( + configProvider, err = relayer.NewPluginProvider( ctx, types.RelayArgs{ ExternalJobID: jobSpec.ExternalJobID, @@ -126,6 +126,7 @@ func (d *Delegate) ServicesForSpec(jobSpec job.Job, qopts ...pg.QOpt) (services ContractID: spec.ContractID, RelayConfig: spec.RelayConfig.Bytes(), New: d.isNewlyCreatedJob, + ProviderType: string(types.Functions), }, types.PluginArgs{ PluginConfig: spec.RelayConfig.Bytes(), // contains all necessary fields for config provider diff --git a/core/services/ocrcommon/transmitter_pipeline.go b/core/services/ocrcommon/transmitter_pipeline.go index 23b672a5e32..d07be5a5409 100644 --- a/core/services/ocrcommon/transmitter_pipeline.go +++ b/core/services/ocrcommon/transmitter_pipeline.go @@ -86,7 +86,7 @@ func (t *pipelineTransmitter) CreateEthTransaction(ctx context.Context, toAddres } if run.State != pipeline.RunStatusCompleted { - return fmt.Errorf("unexpected pipeline run state: %s", run.State) + return fmt.Errorf("unexpected pipeline run state: %s with fatal errors %w", run.State, run.FatalErrors.ToError()) } return nil diff --git a/core/services/relay/evm/config_poller.go b/core/services/relay/evm/config_poller.go index aada1242303..6d8d4588d07 100644 --- a/core/services/relay/evm/config_poller.go +++ b/core/services/relay/evm/config_poller.go @@ -138,6 +138,9 @@ func (cp *configPoller) LatestConfig(ctx context.Context, changedInBlock uint64) if err != nil { return ocrtypes.ContractConfig{}, err } + if len(lgs) == 0 { + return ocrtypes.ContractConfig{}, errors.New("no logs found") + } latestConfigSet, err := configFromLog(lgs[len(lgs)-1].Data) if err != nil { return ocrtypes.ContractConfig{}, err diff --git a/core/services/relay/evm/config_poller_test.go b/core/services/relay/evm/config_poller_test.go index 724c303210b..75e033dfeb7 100644 --- a/core/services/relay/evm/config_poller_test.go +++ b/core/services/relay/evm/config_poller_test.go @@ -64,12 +64,14 @@ func TestConfigPoller(t *testing.T) { lp := logpoller.NewLogPoller(lorm, ethClient, lggr, 100*time.Millisecond, 1, 2, 2, 1000) require.NoError(t, lp.Start(ctx)) t.Cleanup(func() { lp.Close() }) - logPoller, err := NewConfigPoller(lggr, lp, ocrAddress) + configPoller, err := NewConfigPoller(lggr, lp, ocrAddress) require.NoError(t, err) // Should have no config to begin with. - _, config, err := logPoller.LatestConfigDetails(testutils.Context(t)) + _, config, err := configPoller.LatestConfigDetails(testutils.Context(t)) require.NoError(t, err) require.Equal(t, ocrtypes2.ConfigDigest{}, config) + _, err = configPoller.LatestConfig(testutils.Context(t), 0) + require.Error(t, err) // Set the config contractConfig := setConfig(t, median.OffchainConfig{ AlphaReportInfinite: false, @@ -89,13 +91,13 @@ func TestConfigPoller(t *testing.T) { var digest [32]byte gomega.NewGomegaWithT(t).Eventually(func() bool { b.Commit() - configBlock, digest, err = logPoller.LatestConfigDetails(testutils.Context(t)) + configBlock, digest, err = configPoller.LatestConfigDetails(testutils.Context(t)) require.NoError(t, err) return ocrtypes2.ConfigDigest{} != digest }, testutils.WaitTimeout(t), 100*time.Millisecond).Should(gomega.BeTrue()) // Assert the config returned is the one we configured. - newConfig, err := logPoller.LatestConfig(testutils.Context(t), configBlock) + newConfig, err := configPoller.LatestConfig(testutils.Context(t), configBlock) require.NoError(t, err) // Note we don't check onchainConfig, as that is populated in the contract itself. assert.Equal(t, digest, [32]byte(newConfig.ConfigDigest)) diff --git a/core/services/relay/evm/contract_transmitter.go b/core/services/relay/evm/contract_transmitter.go index d4a2c6204ca..470b5bae076 100644 --- a/core/services/relay/evm/contract_transmitter.go +++ b/core/services/relay/evm/contract_transmitter.go @@ -93,6 +93,9 @@ func (oc *contractTransmitter) Transmit(ctx context.Context, reportCtx ocrtypes. var rs [][32]byte var ss [][32]byte var vs [32]byte + if len(signatures) > 32 { + return errors.New("too many signatures, maximum is 32") + } for i, as := range signatures { r, s, v, err := evmutil.SplitSignature(as.Signature) if err != nil { @@ -138,6 +141,9 @@ func parseTransmitted(log []byte) ([32]byte, uint32, error) { if err != nil { return [32]byte{}, 0, err } + if len(transmitted) < 2 { + return [32]byte{}, 0, errors.New("transmitted event log has too few arguments") + } configDigest := *abi.ConvertType(transmitted[0], new([32]byte)).(*[32]byte) epoch := *abi.ConvertType(transmitted[1], new(uint32)).(*uint32) return configDigest, epoch, err diff --git a/core/services/relay/evm/evm.go b/core/services/relay/evm/evm.go index 9578d4e0b0f..1ce68f2d944 100644 --- a/core/services/relay/evm/evm.go +++ b/core/services/relay/evm/evm.go @@ -35,6 +35,7 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/services/pipeline" "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/functions" "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/mercury" + mercuryutils "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/mercury/utils" reportcodecv1 "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/mercury/v1/reportcodec" reportcodecv2 "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/mercury/v2/reportcodec" reportcodecv3 "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/mercury/v3/reportcodec" @@ -112,6 +113,7 @@ func (r *Relayer) NewMercuryProvider(rargs relaytypes.RelayArgs, pargs relaytype if relayConfig.FeedID == nil { return nil, errors.New("FeedID must be specified") } + feedID := mercuryutils.FeedID(*relayConfig.FeedID) if relayConfig.ChainID.String() != r.chain.ID().String() { return nil, fmt.Errorf("internal error: chain id in spec does not match this relayer's chain: have %s expected %s", relayConfig.ChainID.String(), r.chain.ID().String()) @@ -121,13 +123,6 @@ func (r *Relayer) NewMercuryProvider(rargs relaytypes.RelayArgs, pargs relaytype return nil, errors.WithStack(err) } - // FIXME: We actually know the version here since it's in the feed ID, can - // we use generics to avoid passing three of this? - // https://smartcontract-it.atlassian.net/browse/MERC-1414 - reportCodecV1 := reportcodecv1.NewReportCodec(*relayConfig.FeedID, r.lggr.Named("ReportCodecV1")) - reportCodecV2 := reportcodecv2.NewReportCodec(*relayConfig.FeedID, r.lggr.Named("ReportCodecV2")) - reportCodecV3 := reportcodecv3.NewReportCodec(*relayConfig.FeedID, r.lggr.Named("ReportCodecV3")) - if !relayConfig.EffectiveTransmitterID.Valid { return nil, errors.New("EffectiveTransmitterID must be specified") } @@ -140,7 +135,26 @@ func (r *Relayer) NewMercuryProvider(rargs relaytypes.RelayArgs, pargs relaytype if err != nil { return nil, err } - transmitter := mercury.NewTransmitter(r.lggr, configWatcher.ContractConfigTracker(), client, privKey.PublicKey, rargs.JobID, *relayConfig.FeedID, r.db, r.pgCfg) + + // FIXME: We actually know the version here since it's in the feed ID, can + // we use generics to avoid passing three of this? + // https://smartcontract-it.atlassian.net/browse/MERC-1414 + reportCodecV1 := reportcodecv1.NewReportCodec(*relayConfig.FeedID, r.lggr.Named("ReportCodecV1")) + reportCodecV2 := reportcodecv2.NewReportCodec(*relayConfig.FeedID, r.lggr.Named("ReportCodecV2")) + reportCodecV3 := reportcodecv3.NewReportCodec(*relayConfig.FeedID, r.lggr.Named("ReportCodecV3")) + + var transmitterCodec mercury.TransmitterReportDecoder + switch feedID.Version() { + case 1: + transmitterCodec = reportCodecV1 + case 2: + transmitterCodec = reportCodecV2 + case 3: + transmitterCodec = reportCodecV3 + default: + return nil, fmt.Errorf("invalid feed version %d", feedID.Version()) + } + transmitter := mercury.NewTransmitter(r.lggr, configWatcher.ContractConfigTracker(), client, privKey.PublicKey, rargs.JobID, *relayConfig.FeedID, r.db, r.pgCfg, transmitterCodec) return NewMercuryProvider(configWatcher, transmitter, reportCodecV1, reportCodecV2, reportCodecV3, r.lggr), nil } diff --git a/core/services/relay/evm/functions/config_poller.go b/core/services/relay/evm/functions/config_poller.go index 4feff842ce3..f068f13cc77 100644 --- a/core/services/relay/evm/functions/config_poller.go +++ b/core/services/relay/evm/functions/config_poller.go @@ -162,6 +162,9 @@ func (cp *configPoller) LatestConfig(ctx context.Context, changedInBlock uint64) if err != nil { return ocrtypes.ContractConfig{}, err } + if len(lgs) == 0 { + return ocrtypes.ContractConfig{}, errors.New("no logs found") + } latestConfigSet, err := configFromLog(lgs[len(lgs)-1].Data, cp.pluginType) if err != nil { return ocrtypes.ContractConfig{}, err diff --git a/core/services/relay/evm/functions/config_poller_test.go b/core/services/relay/evm/functions/config_poller_test.go index b6de78b49df..b53b2751b15 100644 --- a/core/services/relay/evm/functions/config_poller_test.go +++ b/core/services/relay/evm/functions/config_poller_test.go @@ -89,6 +89,8 @@ func runTest(t *testing.T, pluginType functions.FunctionsPluginType, expectedDig _, config, err := configPoller.LatestConfigDetails(testutils.Context(t)) require.NoError(t, err) require.Equal(t, ocrtypes2.ConfigDigest{}, config) + _, err = configPoller.LatestConfig(testutils.Context(t), 0) + require.Error(t, err) pluginConfig := &functionsConfig.ReportingPluginConfigWrapper{ Config: &functionsConfig.ReportingPluginConfig{ diff --git a/core/services/relay/evm/functions/contract_transmitter.go b/core/services/relay/evm/functions/contract_transmitter.go index ecbe3c49f96..3c6399fbd83 100644 --- a/core/services/relay/evm/functions/contract_transmitter.go +++ b/core/services/relay/evm/functions/contract_transmitter.go @@ -99,6 +99,9 @@ func (oc *contractTransmitter) Transmit(ctx context.Context, reportCtx ocrtypes. var rs [][32]byte var ss [][32]byte var vs [32]byte + if len(signatures) > 32 { + return errors.New("too many signatures, maximum is 32") + } for i, as := range signatures { r, s, v, err := evmutil.SplitSignature(as.Signature) if err != nil { @@ -169,6 +172,9 @@ func parseTransmitted(log []byte) ([32]byte, uint32, error) { if err != nil { return [32]byte{}, 0, err } + if len(transmitted) < 2 { + return [32]byte{}, 0, errors.New("transmitted event log has too few arguments") + } configDigest := *abi.ConvertType(transmitted[0], new([32]byte)).(*[32]byte) epoch := *abi.ConvertType(transmitted[1], new(uint32)).(*uint32) return configDigest, epoch, err diff --git a/core/services/relay/evm/functions/contract_transmitter_test.go b/core/services/relay/evm/functions/contract_transmitter_test.go index fb4a071de2a..6ce61c83a09 100644 --- a/core/services/relay/evm/functions/contract_transmitter_test.go +++ b/core/services/relay/evm/functions/contract_transmitter_test.go @@ -116,6 +116,14 @@ func TestContractTransmitter_Transmit_V1(t *testing.T) { reportBytes, err := codec.EncodeReport(processedRequests) require.NoError(t, err) + // success require.NoError(t, ot.Transmit(testutils.Context(t), ocrtypes.ReportContext{}, reportBytes, []ocrtypes.AttributedOnchainSignature{})) require.Equal(t, coordinatorAddress, ocrTransmitter.toAddress) + + // failure on too many signatures + signatures := []ocrtypes.AttributedOnchainSignature{} + for i := 0; i < 33; i++ { + signatures = append(signatures, ocrtypes.AttributedOnchainSignature{}) + } + require.Error(t, ot.Transmit(testutils.Context(t), ocrtypes.ReportContext{}, reportBytes, signatures)) } diff --git a/core/services/relay/evm/loop_impl.go b/core/services/relay/evm/loop_impl.go index 02a9194b380..87f7aed1a55 100644 --- a/core/services/relay/evm/loop_impl.go +++ b/core/services/relay/evm/loop_impl.go @@ -19,8 +19,8 @@ type LoopRelayer struct { var _ loop.Relayer = &LoopRelayer{} -func NewLoopRelayAdapter(r *Relayer, cs EVMChainRelayerExtender) *LoopRelayer { - ra := relay.NewRelayerAdapter(r, cs) +func NewLoopRelayServerAdapter(r *Relayer, cs EVMChainRelayerExtender) *LoopRelayer { + ra := relay.NewRelayerServerAdapter(r, cs) return &LoopRelayer{ Relayer: ra, ext: cs, diff --git a/core/services/relay/evm/mercury/persistence_manager.go b/core/services/relay/evm/mercury/persistence_manager.go index a840918df66..b8ae9bf72c0 100644 --- a/core/services/relay/evm/mercury/persistence_manager.go +++ b/core/services/relay/evm/mercury/persistence_manager.go @@ -30,14 +30,21 @@ type PersistenceManager struct { deleteQueue []*pb.TransmitRequest jobID int32 + + maxTransmitQueueSize int + flushDeletesFrequency time.Duration + pruneFrequency time.Duration } -func NewPersistenceManager(lggr logger.Logger, orm ORM, jobID int32) *PersistenceManager { +func NewPersistenceManager(lggr logger.Logger, orm ORM, jobID int32, maxTransmitQueueSize int, flushDeletesFrequency, pruneFrequency time.Duration) *PersistenceManager { return &PersistenceManager{ - lggr: lggr.Named("MercuryPersistenceManager"), - orm: orm, - stopCh: make(chan struct{}), - jobID: jobID, + lggr: lggr.Named("MercuryPersistenceManager"), + orm: orm, + stopCh: make(chan struct{}), + jobID: jobID, + maxTransmitQueueSize: maxTransmitQueueSize, + flushDeletesFrequency: flushDeletesFrequency, + pruneFrequency: pruneFrequency, } } @@ -80,7 +87,7 @@ func (pm *PersistenceManager) runFlushDeletesLoop() { ctx, cancel := pm.stopCh.Ctx(context.Background()) defer cancel() - ticker := time.NewTicker(utils.WithJitter(flushDeletesFrequency)) + ticker := time.NewTicker(utils.WithJitter(pm.flushDeletesFrequency)) for { select { case <-ctx.Done(): @@ -103,7 +110,7 @@ func (pm *PersistenceManager) runPruneLoop() { ctx, cancel := pm.stopCh.Ctx(context.Background()) defer cancel() - ticker := time.NewTicker(utils.WithJitter(pruneFrequency)) + ticker := time.NewTicker(utils.WithJitter(pm.pruneFrequency)) for { select { case <-ctx.Done(): @@ -111,7 +118,7 @@ func (pm *PersistenceManager) runPruneLoop() { return case <-ticker.C: pm.lggr.Trace("Pruning transmit requests table") - if err := pm.orm.PruneTransmitRequests(maxTransmitQueueSize, pg.WithParentCtx(ctx), pg.WithLongQueryTimeout()); err != nil { + if err := pm.orm.PruneTransmitRequests(pm.maxTransmitQueueSize, pg.WithParentCtx(ctx), pg.WithLongQueryTimeout()); err != nil { pm.lggr.Errorw("Failed to prune transmit requests table", "err", err) } } diff --git a/core/services/relay/evm/mercury/persistence_manager_test.go b/core/services/relay/evm/mercury/persistence_manager_test.go index 1b4a72f47f5..211e2c20c32 100644 --- a/core/services/relay/evm/mercury/persistence_manager_test.go +++ b/core/services/relay/evm/mercury/persistence_manager_test.go @@ -14,12 +14,13 @@ import ( ) func bootstrapPersistenceManager(t *testing.T) *PersistenceManager { + t.Helper() db := pgtest.NewSqlxDB(t) pgtest.MustExec(t, db, `SET CONSTRAINTS mercury_transmit_requests_job_id_fkey DEFERRED`) pgtest.MustExec(t, db, `SET CONSTRAINTS feed_latest_reports_job_id_fkey DEFERRED`) lggr := logger.TestLogger(t) orm := NewORM(db, lggr, pgtest.NewQConfig(true)) - return NewPersistenceManager(lggr, orm, 0) + return NewPersistenceManager(lggr, orm, 0, 2, 10*time.Millisecond, 10*time.Millisecond) } func TestPersistenceManager(t *testing.T) { @@ -61,7 +62,6 @@ func TestPersistenceManagerAsyncDelete(t *testing.T) { err = pm.Insert(ctx, &pb.TransmitRequest{Payload: reports[1]}, ocrtypes.ReportContext{}) require.NoError(t, err) - flushDeletesFrequency = 10 * time.Millisecond err = pm.Start(ctx) require.NoError(t, err) @@ -103,8 +103,6 @@ func TestPersistenceManagerPrune(t *testing.T) { err = pm.Insert(ctx, &pb.TransmitRequest{Payload: reports[2]}, ocrtypes.ReportContext{ReportTimestamp: ocrtypes.ReportTimestamp{Epoch: 3}}) require.NoError(t, err) - maxTransmitQueueSize = 2 - pruneFrequency = 10 * time.Millisecond err = pm.Start(ctx) require.NoError(t, err) diff --git a/core/services/relay/evm/mercury/queue.go b/core/services/relay/evm/mercury/queue.go index 743a6553dff..44042c57725 100644 --- a/core/services/relay/evm/mercury/queue.go +++ b/core/services/relay/evm/mercury/queue.go @@ -1,13 +1,13 @@ package mercury import ( - "container/heap" "context" "errors" "fmt" "sync" "time" + heap "github.com/esote/minmaxheap" "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/promauto" @@ -59,11 +59,6 @@ type TransmitQueue struct { type Transmission struct { Req *pb.TransmitRequest // the payload to transmit ReportCtx ocrtypes.ReportContext // contains priority information (latest epoch/round wins) - - // The index is needed by update and is maintained by the heap.Interface - // methods - // It should NOT be set manually - index int // the index of the item in the heap } // maxlen controls how many items will be stored in the queue @@ -97,13 +92,13 @@ func (tq *TransmitQueue) Push(req *pb.TransmitRequest, reportCtx ocrtypes.Report if tq.maxlen != 0 && tq.pq.Len() == tq.maxlen { // evict oldest entry to make room tq.lggr.Criticalf("Transmit queue is full; dropping oldest transmission (reached max length of %d)", tq.maxlen) - removed := heap.Remove(tq.pq, tq.pq.Len()-1) + removed := heap.PopMax(tq.pq) if transmission, ok := removed.(*Transmission); ok { tq.asyncDeleter.AsyncDelete(transmission.Req) } } - heap.Push(tq.pq, &Transmission{req, reportCtx, -1}) + heap.Push(tq.pq, &Transmission{req, reportCtx}) tq.cond.Signal() return true @@ -231,6 +226,10 @@ func (pq priorityQueue) Less(i, j int) bool { pq[i].ReportCtx.ReportTimestamp.Round > pq[j].ReportCtx.ReportTimestamp.Round } +func (pq priorityQueue) Swap(i, j int) { + pq[i], pq[j] = pq[j], pq[i] +} + func (pq *priorityQueue) Pop() any { n := len(*pq) if n == 0 { @@ -238,21 +237,11 @@ func (pq *priorityQueue) Pop() any { } old := *pq item := old[n-1] - old[n-1] = nil // avoid memory leak - item.index = -1 // for safety + old[n-1] = nil // avoid memory leak *pq = old[0 : n-1] return item } func (pq *priorityQueue) Push(x any) { - n := len(*pq) - item := x.(*Transmission) - item.index = n - *pq = append(*pq, item) -} - -func (pq priorityQueue) Swap(i, j int) { - pq[i], pq[j] = pq[j], pq[i] - pq[i].index = i - pq[j].index = j + *pq = append(*pq, x.(*Transmission)) } diff --git a/core/services/relay/evm/mercury/queue_test.go b/core/services/relay/evm/mercury/queue_test.go index 9fa2520147d..de2f64f9fe9 100644 --- a/core/services/relay/evm/mercury/queue_test.go +++ b/core/services/relay/evm/mercury/queue_test.go @@ -5,7 +5,6 @@ import ( "testing" "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" "go.uber.org/zap/zapcore" @@ -81,7 +80,7 @@ func Test_Queue(t *testing.T) { }) t.Run("transmit queue is more than 50% full", func(t *testing.T) { - transmitQueue.Push(testTransmissions[2].tr, testTransmissions[0].ctx) + transmitQueue.Push(testTransmissions[2].tr, testTransmissions[2].ctx) report := transmitQueue.HealthReport() assert.Equal(t, report[transmitQueue.Name()].Error(), "transmit priority queue is greater than 50% full (4/7)") }) @@ -92,21 +91,18 @@ func Test_Queue(t *testing.T) { }) t.Run("transmit queue is full and evicts the oldest transmission", func(t *testing.T) { - // There is a bug with queue eviction where the evicted transmission is NOT the oldest. - // TODO: MERC-1049 Once this bug is fixed, replace the expectation with the one below. - // deleter.On("AsyncDelete", testTransmissions[0].tr).Once() - deleter.On("AsyncDelete", mock.Anything).Once() + deleter.On("AsyncDelete", testTransmissions[0].tr).Once() - // add 5 more transmissions to overflow the queue + // add 5 more transmissions to overflow the queue by 1 for i := 0; i < 5; i++ { transmitQueue.Push(testTransmissions[1].tr, testTransmissions[1].ctx) } + // expecting testTransmissions[0] to get evicted and not present in the queue anymore testutils.WaitForLogMessage(t, observedLogs, "Transmit queue is full; dropping oldest transmission (reached max length of 7)") for i := 0; i < 7; i++ { tr := transmitQueue.BlockingPop() - // TODO: Should be tr.Req instead of tr. - assert.NotEqual(t, tr, testTransmissions[0].tr) + assert.NotEqual(t, tr.Req, testTransmissions[0].tr) } }) diff --git a/core/services/relay/evm/mercury/transmitter.go b/core/services/relay/evm/mercury/transmitter.go index f01ee474885..199dbfcdf88 100644 --- a/core/services/relay/evm/mercury/transmitter.go +++ b/core/services/relay/evm/mercury/transmitter.go @@ -15,19 +15,16 @@ import ( pkgerrors "github.com/pkg/errors" "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/promauto" - "golang.org/x/exp/maps" - "github.com/smartcontractkit/libocr/offchainreporting2plus/chains/evmutil" ocrtypes "github.com/smartcontractkit/libocr/offchainreporting2plus/types" "github.com/smartcontractkit/sqlx" + "golang.org/x/exp/maps" relaymercury "github.com/smartcontractkit/chainlink-relay/pkg/reportingplugins/mercury" - mercuryutils "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/mercury/utils" - "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services" - "github.com/smartcontractkit/chainlink/v2/core/services/pg" + mercuryutils "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/mercury/utils" "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/mercury/wsrpc" "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/mercury/wsrpc/pb" "github.com/smartcontractkit/chainlink/v2/core/utils" @@ -79,7 +76,11 @@ type ConfigTracker interface { LatestConfigDetails(ctx context.Context) (changedInBlock uint64, configDigest ocrtypes.ConfigDigest, err error) } -var _ Transmitter = &mercuryTransmitter{} +type TransmitterReportDecoder interface { + BenchmarkPriceFromReport(report ocrtypes.Report) (*big.Int, error) +} + +var _ Transmitter = (*mercuryTransmitter)(nil) type mercuryTransmitter struct { utils.StartStopOnce @@ -87,6 +88,7 @@ type mercuryTransmitter struct { rpcClient wsrpc.Client cfgTracker ConfigTracker persistenceManager *PersistenceManager + codec TransmitterReportDecoder feedID mercuryutils.FeedID jobID int32 @@ -120,15 +122,16 @@ func getPayloadTypes() abi.Arguments { }) } -func NewTransmitter(lggr logger.Logger, cfgTracker ConfigTracker, rpcClient wsrpc.Client, fromAccount ed25519.PublicKey, jobID int32, feedID [32]byte, db *sqlx.DB, cfg pg.QConfig) *mercuryTransmitter { +func NewTransmitter(lggr logger.Logger, cfgTracker ConfigTracker, rpcClient wsrpc.Client, fromAccount ed25519.PublicKey, jobID int32, feedID [32]byte, db *sqlx.DB, cfg pg.QConfig, codec TransmitterReportDecoder) *mercuryTransmitter { feedIDHex := fmt.Sprintf("0x%x", feedID[:]) - persistenceManager := NewPersistenceManager(lggr, NewORM(db, lggr, cfg), jobID) + persistenceManager := NewPersistenceManager(lggr, NewORM(db, lggr, cfg), jobID, maxTransmitQueueSize, flushDeletesFrequency, pruneFrequency) return &mercuryTransmitter{ utils.StartStopOnce{}, lggr.Named("MercuryTransmitter").With("feedID", feedIDHex), rpcClient, cfgTracker, persistenceManager, + codec, feedID, jobID, fmt.Sprintf("%x", fromAccount), @@ -325,18 +328,23 @@ func (mt *mercuryTransmitter) FetchInitialMaxFinalizedBlockNumber(ctx context.Co func (mt *mercuryTransmitter) LatestPrice(ctx context.Context, feedID [32]byte) (*big.Int, error) { mt.lggr.Trace("LatestPrice") - report, err := mt.latestReport(ctx, feedID) + fullReport, err := mt.latestReport(ctx, feedID) if err != nil { return nil, err } - if report == nil { + if fullReport == nil { return nil, nil } - price, err := relaymercury.DecodeValueInt192(report.Price) - if err != nil { - return nil, pkgerrors.Wrap(err, "failed to decode report.Price as *big.Int") + payload := fullReport.Payload + m := make(map[string]interface{}) + if err := PayloadTypes.UnpackIntoMap(m, payload); err != nil { + return nil, err + } + report, is := m["report"].([]byte) + if !is { + return nil, fmt.Errorf("expected report to be []byte, but it was %T", m["report"]) } - return price, nil + return mt.codec.BenchmarkPriceFromReport(report) } // LatestTimestamp will return -1, nil if the feed is missing diff --git a/core/services/relay/evm/mercury/transmitter_test.go b/core/services/relay/evm/mercury/transmitter_test.go index 247959609f9..6723ffcbcac 100644 --- a/core/services/relay/evm/mercury/transmitter_test.go +++ b/core/services/relay/evm/mercury/transmitter_test.go @@ -10,11 +10,12 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - relaymercury "github.com/smartcontractkit/chainlink-relay/pkg/reportingplugins/mercury" + ocrtypes "github.com/smartcontractkit/libocr/offchainreporting2plus/types" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest" "github.com/smartcontractkit/chainlink/v2/core/logger" + mercurytypes "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/mercury/types" mocks "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/mercury/wsrpc/mocks" "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/mercury/wsrpc/pb" ) @@ -38,7 +39,7 @@ func Test_MercuryTransmitter_Transmit(t *testing.T) { return out, nil }, } - mt := NewTransmitter(lggr, nil, c, sampleClientPubKey, jobID, sampleFeedID, db, pgtest.NewQConfig(true)) + mt := NewTransmitter(lggr, nil, c, sampleClientPubKey, jobID, sampleFeedID, db, pgtest.NewQConfig(true), nil) err := mt.Transmit(testutils.Context(t), sampleReportContext, report, sampleSigs) require.NoError(t, err) @@ -55,7 +56,7 @@ func Test_MercuryTransmitter_Transmit(t *testing.T) { return out, nil }, } - mt := NewTransmitter(lggr, nil, c, sampleClientPubKey, jobID, sampleFeedID, db, pgtest.NewQConfig(true)) + mt := NewTransmitter(lggr, nil, c, sampleClientPubKey, jobID, sampleFeedID, db, pgtest.NewQConfig(true), nil) err := mt.Transmit(testutils.Context(t), sampleReportContext, report, sampleSigs) require.NoError(t, err) @@ -72,7 +73,7 @@ func Test_MercuryTransmitter_Transmit(t *testing.T) { return out, nil }, } - mt := NewTransmitter(lggr, nil, c, sampleClientPubKey, jobID, sampleFeedID, db, pgtest.NewQConfig(true)) + mt := NewTransmitter(lggr, nil, c, sampleClientPubKey, jobID, sampleFeedID, db, pgtest.NewQConfig(true), nil) err := mt.Transmit(testutils.Context(t), sampleReportContext, report, sampleSigs) require.NoError(t, err) @@ -96,7 +97,7 @@ func Test_MercuryTransmitter_LatestTimestamp(t *testing.T) { return out, nil }, } - mt := NewTransmitter(lggr, nil, c, sampleClientPubKey, 0, sampleFeedID, db, pgtest.NewQConfig(true)) + mt := NewTransmitter(lggr, nil, c, sampleClientPubKey, 0, sampleFeedID, db, pgtest.NewQConfig(true), nil) ts, err := mt.LatestTimestamp(testutils.Context(t)) require.NoError(t, err) @@ -111,7 +112,7 @@ func Test_MercuryTransmitter_LatestTimestamp(t *testing.T) { return out, nil }, } - mt := NewTransmitter(lggr, nil, c, sampleClientPubKey, 0, sampleFeedID, db, pgtest.NewQConfig(true)) + mt := NewTransmitter(lggr, nil, c, sampleClientPubKey, 0, sampleFeedID, db, pgtest.NewQConfig(true), nil) ts, err := mt.LatestTimestamp(testutils.Context(t)) require.NoError(t, err) @@ -124,21 +125,33 @@ func Test_MercuryTransmitter_LatestTimestamp(t *testing.T) { return nil, errors.New("something exploded") }, } - mt := NewTransmitter(lggr, nil, c, sampleClientPubKey, 0, sampleFeedID, db, pgtest.NewQConfig(true)) + mt := NewTransmitter(lggr, nil, c, sampleClientPubKey, 0, sampleFeedID, db, pgtest.NewQConfig(true), nil) _, err := mt.LatestTimestamp(testutils.Context(t)) require.Error(t, err) assert.Contains(t, err.Error(), "something exploded") }) } +type mockCodec struct { + val *big.Int + err error +} + +var _ mercurytypes.ReportCodec = &mockCodec{} + +func (m *mockCodec) BenchmarkPriceFromReport(_ ocrtypes.Report) (*big.Int, error) { + return m.val, m.err +} + func Test_MercuryTransmitter_LatestPrice(t *testing.T) { t.Parallel() lggr := logger.TestLogger(t) db := pgtest.NewSqlxDB(t) + codec := new(mockCodec) + t.Run("successful query", func(t *testing.T) { originalPrice := big.NewInt(123456789) - encodedPrice, _ := relaymercury.EncodeValueInt192(originalPrice) c := mocks.MockWSRPCClient{ LatestReportF: func(ctx context.Context, in *pb.LatestReportRequest) (out *pb.LatestReportResponse, err error) { require.NotNil(t, in) @@ -146,15 +159,30 @@ func Test_MercuryTransmitter_LatestPrice(t *testing.T) { out = new(pb.LatestReportResponse) out.Report = new(pb.Report) out.Report.FeedId = sampleFeedID[:] - out.Report.Price = encodedPrice + out.Report.Payload = buildSamplePayload([]byte("doesn't matter")) return out, nil }, } - mt := NewTransmitter(lggr, nil, c, sampleClientPubKey, 0, sampleFeedID, db, pgtest.NewQConfig(true)) - price, err := mt.LatestPrice(testutils.Context(t), sampleFeedID) - require.NoError(t, err) + mt := NewTransmitter(lggr, nil, c, sampleClientPubKey, 0, sampleFeedID, db, pgtest.NewQConfig(true), codec) + + t.Run("BenchmarkPriceFromReport succeeds", func(t *testing.T) { + codec.val = originalPrice + codec.err = nil + + price, err := mt.LatestPrice(testutils.Context(t), sampleFeedID) + require.NoError(t, err) + + assert.Equal(t, originalPrice, price) + }) + t.Run("BenchmarkPriceFromReport fails", func(t *testing.T) { + codec.val = nil + codec.err = errors.New("something exploded") + + _, err := mt.LatestPrice(testutils.Context(t), sampleFeedID) + require.Error(t, err) - assert.Equal(t, price, originalPrice) + assert.EqualError(t, err, "something exploded") + }) }) t.Run("successful query returning nil report (new feed)", func(t *testing.T) { @@ -165,7 +193,7 @@ func Test_MercuryTransmitter_LatestPrice(t *testing.T) { return out, nil }, } - mt := NewTransmitter(lggr, nil, c, sampleClientPubKey, 0, sampleFeedID, db, pgtest.NewQConfig(true)) + mt := NewTransmitter(lggr, nil, c, sampleClientPubKey, 0, sampleFeedID, db, pgtest.NewQConfig(true), nil) price, err := mt.LatestPrice(testutils.Context(t), sampleFeedID) require.NoError(t, err) @@ -178,7 +206,7 @@ func Test_MercuryTransmitter_LatestPrice(t *testing.T) { return nil, errors.New("something exploded") }, } - mt := NewTransmitter(lggr, nil, c, sampleClientPubKey, 0, sampleFeedID, db, pgtest.NewQConfig(true)) + mt := NewTransmitter(lggr, nil, c, sampleClientPubKey, 0, sampleFeedID, db, pgtest.NewQConfig(true), nil) _, err := mt.LatestPrice(testutils.Context(t), sampleFeedID) require.Error(t, err) assert.Contains(t, err.Error(), "something exploded") @@ -203,7 +231,7 @@ func Test_MercuryTransmitter_FetchInitialMaxFinalizedBlockNumber(t *testing.T) { return out, nil }, } - mt := NewTransmitter(lggr, nil, c, sampleClientPubKey, 0, sampleFeedID, db, pgtest.NewQConfig(true)) + mt := NewTransmitter(lggr, nil, c, sampleClientPubKey, 0, sampleFeedID, db, pgtest.NewQConfig(true), nil) bn, err := mt.FetchInitialMaxFinalizedBlockNumber(testutils.Context(t)) require.NoError(t, err) @@ -218,7 +246,7 @@ func Test_MercuryTransmitter_FetchInitialMaxFinalizedBlockNumber(t *testing.T) { return out, nil }, } - mt := NewTransmitter(lggr, nil, c, sampleClientPubKey, 0, sampleFeedID, db, pgtest.NewQConfig(true)) + mt := NewTransmitter(lggr, nil, c, sampleClientPubKey, 0, sampleFeedID, db, pgtest.NewQConfig(true), nil) bn, err := mt.FetchInitialMaxFinalizedBlockNumber(testutils.Context(t)) require.NoError(t, err) @@ -230,7 +258,7 @@ func Test_MercuryTransmitter_FetchInitialMaxFinalizedBlockNumber(t *testing.T) { return nil, errors.New("something exploded") }, } - mt := NewTransmitter(lggr, nil, c, sampleClientPubKey, 0, sampleFeedID, db, pgtest.NewQConfig(true)) + mt := NewTransmitter(lggr, nil, c, sampleClientPubKey, 0, sampleFeedID, db, pgtest.NewQConfig(true), nil) _, err := mt.FetchInitialMaxFinalizedBlockNumber(testutils.Context(t)) require.Error(t, err) assert.Contains(t, err.Error(), "something exploded") @@ -247,7 +275,7 @@ func Test_MercuryTransmitter_FetchInitialMaxFinalizedBlockNumber(t *testing.T) { return out, nil }, } - mt := NewTransmitter(lggr, nil, c, sampleClientPubKey, 0, sampleFeedID, db, pgtest.NewQConfig(true)) + mt := NewTransmitter(lggr, nil, c, sampleClientPubKey, 0, sampleFeedID, db, pgtest.NewQConfig(true), nil) _, err := mt.FetchInitialMaxFinalizedBlockNumber(testutils.Context(t)) require.Error(t, err) assert.Contains(t, err.Error(), "latestReport failed; mismatched feed IDs, expected: 0x1c916b4aa7e57ca7b68ae1bf45653f56b656fd3aa335ef7fae696b663f1b8472, got: 0x") diff --git a/core/services/relay/evm/mercury/types/types.go b/core/services/relay/evm/mercury/types/types.go index 6affba58169..4c606ed9eae 100644 --- a/core/services/relay/evm/mercury/types/types.go +++ b/core/services/relay/evm/mercury/types/types.go @@ -2,6 +2,9 @@ package types import ( "context" + "math/big" + + ocrtypes "github.com/smartcontractkit/libocr/offchainreporting2plus/types" evmclient "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" httypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/headtracker/types" @@ -17,3 +20,7 @@ type ChainHeadTracker interface { type DataSourceORM interface { LatestReport(ctx context.Context, feedID [32]byte, qopts ...pg.QOpt) (report []byte, err error) } + +type ReportCodec interface { + BenchmarkPriceFromReport(report ocrtypes.Report) (*big.Int, error) +} diff --git a/core/services/relay/evm/mercury/v1/reportcodec/report_codec.go b/core/services/relay/evm/mercury/v1/reportcodec/report_codec.go index a28186cce9c..fefddd6395b 100644 --- a/core/services/relay/evm/mercury/v1/reportcodec/report_codec.go +++ b/core/services/relay/evm/mercury/v1/reportcodec/report_codec.go @@ -4,6 +4,7 @@ import ( "errors" "fmt" "math" + "math/big" "github.com/ethereum/go-ethereum/common" pkgerrors "github.com/pkg/errors" @@ -89,3 +90,11 @@ func (r *ReportCodec) ValidFromBlockNumFromReport(report ocrtypes.Report) (int64 func (r *ReportCodec) Decode(report ocrtypes.Report) (*reporttypes.Report, error) { return reporttypes.Decode(report) } + +func (r *ReportCodec) BenchmarkPriceFromReport(report ocrtypes.Report) (*big.Int, error) { + decoded, err := r.Decode(report) + if err != nil { + return nil, err + } + return decoded.BenchmarkPrice, nil +} diff --git a/core/services/relay/evm/mercury/v1/reportcodec/report_codec_test.go b/core/services/relay/evm/mercury/v1/reportcodec/report_codec_test.go index 6e6a58af4ca..3f4838c3e7c 100644 --- a/core/services/relay/evm/mercury/v1/reportcodec/report_codec_test.go +++ b/core/services/relay/evm/mercury/v1/reportcodec/report_codec_test.go @@ -161,3 +161,22 @@ func Test_ReportCodec_ValidFromBlockNumFromReport(t *testing.T) { assert.Contains(t, err.Error(), "ValidFromBlockNum=18446744073709551615 overflows max int64") }) } + +func Test_ReportCodec_BenchmarkPriceFromReport(t *testing.T) { + r := ReportCodec{} + feedID := utils.NewHash() + + t.Run("BenchmarkPriceFromReport extracts the benchmark price from valid report", func(t *testing.T) { + report := buildSampleReport(42, 999, feedID) + + bp, err := r.BenchmarkPriceFromReport(report) + require.NoError(t, err) + + assert.Equal(t, big.NewInt(242), bp) + }) + t.Run("BenchmarkPriceFromReport errors on invalid report", func(t *testing.T) { + _, err := r.BenchmarkPriceFromReport([]byte{1, 2, 3}) + require.Error(t, err) + assert.EqualError(t, err, "failed to decode report: abi: cannot marshal in to go type: length insufficient 3 require 32") + }) +} diff --git a/core/services/relay/evm/mercury/v2/reportcodec/report_codec.go b/core/services/relay/evm/mercury/v2/reportcodec/report_codec.go index 60dde81f1cb..0e1dfe9c46f 100644 --- a/core/services/relay/evm/mercury/v2/reportcodec/report_codec.go +++ b/core/services/relay/evm/mercury/v2/reportcodec/report_codec.go @@ -67,3 +67,11 @@ func (r *ReportCodec) ObservationTimestampFromReport(report ocrtypes.Report) (ui func (r *ReportCodec) Decode(report ocrtypes.Report) (*reporttypes.Report, error) { return reporttypes.Decode(report) } + +func (r *ReportCodec) BenchmarkPriceFromReport(report ocrtypes.Report) (*big.Int, error) { + decoded, err := r.Decode(report) + if err != nil { + return nil, err + } + return decoded.BenchmarkPrice, nil +} diff --git a/core/services/relay/evm/mercury/v2/reportcodec/report_codec_test.go b/core/services/relay/evm/mercury/v2/reportcodec/report_codec_test.go index c0c931dfe3a..8cf16a5dab4 100644 --- a/core/services/relay/evm/mercury/v2/reportcodec/report_codec_test.go +++ b/core/services/relay/evm/mercury/v2/reportcodec/report_codec_test.go @@ -132,3 +132,21 @@ func Test_ReportCodec_ObservationTimestampFromReport(t *testing.T) { assert.EqualError(t, err, "failed to decode report: abi: cannot marshal in to go type: length insufficient 3 require 32") }) } + +func Test_ReportCodec_BenchmarkPriceFromReport(t *testing.T) { + r := ReportCodec{} + + t.Run("BenchmarkPriceFromReport extracts the benchmark price from valid report", func(t *testing.T) { + report := buildSampleReport(123) + + bp, err := r.BenchmarkPriceFromReport(report) + require.NoError(t, err) + + assert.Equal(t, big.NewInt(242), bp) + }) + t.Run("BenchmarkPriceFromReport errors on invalid report", func(t *testing.T) { + _, err := r.BenchmarkPriceFromReport([]byte{1, 2, 3}) + require.Error(t, err) + assert.EqualError(t, err, "failed to decode report: abi: cannot marshal in to go type: length insufficient 3 require 32") + }) +} diff --git a/core/services/relay/evm/mercury/v3/reportcodec/report_codec.go b/core/services/relay/evm/mercury/v3/reportcodec/report_codec.go index 66995e74ea7..4c0b3756d7b 100644 --- a/core/services/relay/evm/mercury/v3/reportcodec/report_codec.go +++ b/core/services/relay/evm/mercury/v3/reportcodec/report_codec.go @@ -74,3 +74,11 @@ func (r *ReportCodec) ObservationTimestampFromReport(report ocrtypes.Report) (ui func (r *ReportCodec) Decode(report ocrtypes.Report) (*reporttypes.Report, error) { return reporttypes.Decode(report) } + +func (r *ReportCodec) BenchmarkPriceFromReport(report ocrtypes.Report) (*big.Int, error) { + decoded, err := r.Decode(report) + if err != nil { + return nil, err + } + return decoded.BenchmarkPrice, nil +} diff --git a/core/services/relay/evm/mercury/v3/reportcodec/report_codec_test.go b/core/services/relay/evm/mercury/v3/reportcodec/report_codec_test.go index 80cf4c9665b..98b81edb002 100644 --- a/core/services/relay/evm/mercury/v3/reportcodec/report_codec_test.go +++ b/core/services/relay/evm/mercury/v3/reportcodec/report_codec_test.go @@ -140,3 +140,21 @@ func Test_ReportCodec_ObservationTimestampFromReport(t *testing.T) { assert.EqualError(t, err, "failed to decode report: abi: cannot marshal in to go type: length insufficient 3 require 32") }) } + +func Test_ReportCodec_BenchmarkPriceFromReport(t *testing.T) { + r := ReportCodec{} + + t.Run("BenchmarkPriceFromReport extracts the benchmark price from valid report", func(t *testing.T) { + report := buildSampleReport(123) + + bp, err := r.BenchmarkPriceFromReport(report) + require.NoError(t, err) + + assert.Equal(t, big.NewInt(242), bp) + }) + t.Run("BenchmarkPriceFromReport errors on invalid report", func(t *testing.T) { + _, err := r.BenchmarkPriceFromReport([]byte{1, 2, 3}) + require.Error(t, err) + assert.EqualError(t, err, "failed to decode report: abi: cannot marshal in to go type: length insufficient 3 require 32") + }) +} diff --git a/core/services/relay/evm/mercury_provider.go b/core/services/relay/evm/mercury_provider.go index ee32b8d99be..74072167061 100644 --- a/core/services/relay/evm/mercury_provider.go +++ b/core/services/relay/evm/mercury_provider.go @@ -4,13 +4,15 @@ import ( "context" "errors" + "golang.org/x/exp/maps" + + ocrtypes "github.com/smartcontractkit/libocr/offchainreporting2plus/types" + relaymercury "github.com/smartcontractkit/chainlink-relay/pkg/reportingplugins/mercury" relaymercuryv1 "github.com/smartcontractkit/chainlink-relay/pkg/reportingplugins/mercury/v1" relaymercuryv2 "github.com/smartcontractkit/chainlink-relay/pkg/reportingplugins/mercury/v2" relaymercuryv3 "github.com/smartcontractkit/chainlink-relay/pkg/reportingplugins/mercury/v3" relaytypes "github.com/smartcontractkit/chainlink-relay/pkg/types" - ocrtypes "github.com/smartcontractkit/libocr/offchainreporting2plus/types" - "golang.org/x/exp/maps" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services" @@ -96,6 +98,10 @@ func (p *mercuryProvider) ReportCodecV3() relaymercuryv3.ReportCodec { return p.reportCodecV3 } -func (p *mercuryProvider) ContractTransmitter() relaymercury.Transmitter { +func (p *mercuryProvider) ContractTransmitter() ocrtypes.ContractTransmitter { + return p.transmitter +} + +func (p *mercuryProvider) MercuryServerFetcher() relaymercury.MercuryServerFetcher { return p.transmitter } diff --git a/core/services/relay/evm/mocks/loop_relay_adapter.go b/core/services/relay/evm/mocks/loop_relay_adapter.go index b0d9b7cf95e..02064c2ea9f 100644 --- a/core/services/relay/evm/mocks/loop_relay_adapter.go +++ b/core/services/relay/evm/mocks/loop_relay_adapter.go @@ -33,63 +33,6 @@ func (_m *LoopRelayAdapter) Chain() evm.Chain { return r0 } -// ChainStatus provides a mock function with given fields: ctx, id -func (_m *LoopRelayAdapter) ChainStatus(ctx context.Context, id string) (types.ChainStatus, error) { - ret := _m.Called(ctx, id) - - var r0 types.ChainStatus - var r1 error - if rf, ok := ret.Get(0).(func(context.Context, string) (types.ChainStatus, error)); ok { - return rf(ctx, id) - } - if rf, ok := ret.Get(0).(func(context.Context, string) types.ChainStatus); ok { - r0 = rf(ctx, id) - } else { - r0 = ret.Get(0).(types.ChainStatus) - } - - if rf, ok := ret.Get(1).(func(context.Context, string) error); ok { - r1 = rf(ctx, id) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// ChainStatuses provides a mock function with given fields: ctx, offset, limit -func (_m *LoopRelayAdapter) ChainStatuses(ctx context.Context, offset int, limit int) ([]types.ChainStatus, int, error) { - ret := _m.Called(ctx, offset, limit) - - var r0 []types.ChainStatus - var r1 int - var r2 error - if rf, ok := ret.Get(0).(func(context.Context, int, int) ([]types.ChainStatus, int, error)); ok { - return rf(ctx, offset, limit) - } - if rf, ok := ret.Get(0).(func(context.Context, int, int) []types.ChainStatus); ok { - r0 = rf(ctx, offset, limit) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).([]types.ChainStatus) - } - } - - if rf, ok := ret.Get(1).(func(context.Context, int, int) int); ok { - r1 = rf(ctx, offset, limit) - } else { - r1 = ret.Get(1).(int) - } - - if rf, ok := ret.Get(2).(func(context.Context, int, int) error); ok { - r2 = rf(ctx, offset, limit) - } else { - r2 = ret.Error(2) - } - - return r0, r1, r2 -} - // Close provides a mock function with given fields: func (_m *LoopRelayAdapter) Close() error { ret := _m.Called() @@ -118,6 +61,30 @@ func (_m *LoopRelayAdapter) Default() bool { return r0 } +// GetChainStatus provides a mock function with given fields: ctx +func (_m *LoopRelayAdapter) GetChainStatus(ctx context.Context) (types.ChainStatus, error) { + ret := _m.Called(ctx) + + var r0 types.ChainStatus + var r1 error + if rf, ok := ret.Get(0).(func(context.Context) (types.ChainStatus, error)); ok { + return rf(ctx) + } + if rf, ok := ret.Get(0).(func(context.Context) types.ChainStatus); ok { + r0 = rf(ctx) + } else { + r0 = ret.Get(0).(types.ChainStatus) + } + + if rf, ok := ret.Get(1).(func(context.Context) error); ok { + r1 = rf(ctx) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + // HealthReport provides a mock function with given fields: func (_m *LoopRelayAdapter) HealthReport() map[string]error { ret := _m.Called() @@ -134,6 +101,46 @@ func (_m *LoopRelayAdapter) HealthReport() map[string]error { return r0 } +// ListNodeStatuses provides a mock function with given fields: ctx, pageSize, pageToken +func (_m *LoopRelayAdapter) ListNodeStatuses(ctx context.Context, pageSize int32, pageToken string) ([]types.NodeStatus, string, int, error) { + ret := _m.Called(ctx, pageSize, pageToken) + + var r0 []types.NodeStatus + var r1 string + var r2 int + var r3 error + if rf, ok := ret.Get(0).(func(context.Context, int32, string) ([]types.NodeStatus, string, int, error)); ok { + return rf(ctx, pageSize, pageToken) + } + if rf, ok := ret.Get(0).(func(context.Context, int32, string) []types.NodeStatus); ok { + r0 = rf(ctx, pageSize, pageToken) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).([]types.NodeStatus) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, int32, string) string); ok { + r1 = rf(ctx, pageSize, pageToken) + } else { + r1 = ret.Get(1).(string) + } + + if rf, ok := ret.Get(2).(func(context.Context, int32, string) int); ok { + r2 = rf(ctx, pageSize, pageToken) + } else { + r2 = ret.Get(2).(int) + } + + if rf, ok := ret.Get(3).(func(context.Context, int32, string) error); ok { + r3 = rf(ctx, pageSize, pageToken) + } else { + r3 = ret.Error(3) + } + + return r0, r1, r2, r3 +} + // Name provides a mock function with given fields: func (_m *LoopRelayAdapter) Name() string { ret := _m.Called() @@ -174,72 +181,20 @@ func (_m *LoopRelayAdapter) NewConfigProvider(_a0 context.Context, _a1 types.Rel return r0, r1 } -// NewFunctionsProvider provides a mock function with given fields: _a0, _a1, _a2 -func (_m *LoopRelayAdapter) NewFunctionsProvider(_a0 context.Context, _a1 types.RelayArgs, _a2 types.PluginArgs) (types.FunctionsProvider, error) { - ret := _m.Called(_a0, _a1, _a2) - - var r0 types.FunctionsProvider - var r1 error - if rf, ok := ret.Get(0).(func(context.Context, types.RelayArgs, types.PluginArgs) (types.FunctionsProvider, error)); ok { - return rf(_a0, _a1, _a2) - } - if rf, ok := ret.Get(0).(func(context.Context, types.RelayArgs, types.PluginArgs) types.FunctionsProvider); ok { - r0 = rf(_a0, _a1, _a2) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(types.FunctionsProvider) - } - } - - if rf, ok := ret.Get(1).(func(context.Context, types.RelayArgs, types.PluginArgs) error); ok { - r1 = rf(_a0, _a1, _a2) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// NewMedianProvider provides a mock function with given fields: _a0, _a1, _a2 -func (_m *LoopRelayAdapter) NewMedianProvider(_a0 context.Context, _a1 types.RelayArgs, _a2 types.PluginArgs) (types.MedianProvider, error) { - ret := _m.Called(_a0, _a1, _a2) - - var r0 types.MedianProvider - var r1 error - if rf, ok := ret.Get(0).(func(context.Context, types.RelayArgs, types.PluginArgs) (types.MedianProvider, error)); ok { - return rf(_a0, _a1, _a2) - } - if rf, ok := ret.Get(0).(func(context.Context, types.RelayArgs, types.PluginArgs) types.MedianProvider); ok { - r0 = rf(_a0, _a1, _a2) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(types.MedianProvider) - } - } - - if rf, ok := ret.Get(1).(func(context.Context, types.RelayArgs, types.PluginArgs) error); ok { - r1 = rf(_a0, _a1, _a2) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// NewMercuryProvider provides a mock function with given fields: _a0, _a1, _a2 -func (_m *LoopRelayAdapter) NewMercuryProvider(_a0 context.Context, _a1 types.RelayArgs, _a2 types.PluginArgs) (types.MercuryProvider, error) { +// NewPluginProvider provides a mock function with given fields: _a0, _a1, _a2 +func (_m *LoopRelayAdapter) NewPluginProvider(_a0 context.Context, _a1 types.RelayArgs, _a2 types.PluginArgs) (types.PluginProvider, error) { ret := _m.Called(_a0, _a1, _a2) - var r0 types.MercuryProvider + var r0 types.PluginProvider var r1 error - if rf, ok := ret.Get(0).(func(context.Context, types.RelayArgs, types.PluginArgs) (types.MercuryProvider, error)); ok { + if rf, ok := ret.Get(0).(func(context.Context, types.RelayArgs, types.PluginArgs) (types.PluginProvider, error)); ok { return rf(_a0, _a1, _a2) } - if rf, ok := ret.Get(0).(func(context.Context, types.RelayArgs, types.PluginArgs) types.MercuryProvider); ok { + if rf, ok := ret.Get(0).(func(context.Context, types.RelayArgs, types.PluginArgs) types.PluginProvider); ok { r0 = rf(_a0, _a1, _a2) } else { if ret.Get(0) != nil { - r0 = ret.Get(0).(types.MercuryProvider) + r0 = ret.Get(0).(types.PluginProvider) } } @@ -252,46 +207,6 @@ func (_m *LoopRelayAdapter) NewMercuryProvider(_a0 context.Context, _a1 types.Re return r0, r1 } -// NodeStatuses provides a mock function with given fields: ctx, offset, limit, chainIDs -func (_m *LoopRelayAdapter) NodeStatuses(ctx context.Context, offset int, limit int, chainIDs ...string) ([]types.NodeStatus, int, error) { - _va := make([]interface{}, len(chainIDs)) - for _i := range chainIDs { - _va[_i] = chainIDs[_i] - } - var _ca []interface{} - _ca = append(_ca, ctx, offset, limit) - _ca = append(_ca, _va...) - ret := _m.Called(_ca...) - - var r0 []types.NodeStatus - var r1 int - var r2 error - if rf, ok := ret.Get(0).(func(context.Context, int, int, ...string) ([]types.NodeStatus, int, error)); ok { - return rf(ctx, offset, limit, chainIDs...) - } - if rf, ok := ret.Get(0).(func(context.Context, int, int, ...string) []types.NodeStatus); ok { - r0 = rf(ctx, offset, limit, chainIDs...) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).([]types.NodeStatus) - } - } - - if rf, ok := ret.Get(1).(func(context.Context, int, int, ...string) int); ok { - r1 = rf(ctx, offset, limit, chainIDs...) - } else { - r1 = ret.Get(1).(int) - } - - if rf, ok := ret.Get(2).(func(context.Context, int, int, ...string) error); ok { - r2 = rf(ctx, offset, limit, chainIDs...) - } else { - r2 = ret.Error(2) - } - - return r0, r1, r2 -} - // Ready provides a mock function with given fields: func (_m *LoopRelayAdapter) Ready() error { ret := _m.Called() @@ -306,13 +221,13 @@ func (_m *LoopRelayAdapter) Ready() error { return r0 } -// SendTx provides a mock function with given fields: ctx, chainID, from, to, amount, balanceCheck -func (_m *LoopRelayAdapter) SendTx(ctx context.Context, chainID string, from string, to string, amount *big.Int, balanceCheck bool) error { - ret := _m.Called(ctx, chainID, from, to, amount, balanceCheck) +// Start provides a mock function with given fields: _a0 +func (_m *LoopRelayAdapter) Start(_a0 context.Context) error { + ret := _m.Called(_a0) var r0 error - if rf, ok := ret.Get(0).(func(context.Context, string, string, string, *big.Int, bool) error); ok { - r0 = rf(ctx, chainID, from, to, amount, balanceCheck) + if rf, ok := ret.Get(0).(func(context.Context) error); ok { + r0 = rf(_a0) } else { r0 = ret.Error(0) } @@ -320,13 +235,13 @@ func (_m *LoopRelayAdapter) SendTx(ctx context.Context, chainID string, from str return r0 } -// Start provides a mock function with given fields: _a0 -func (_m *LoopRelayAdapter) Start(_a0 context.Context) error { - ret := _m.Called(_a0) +// Transact provides a mock function with given fields: ctx, from, to, amount, balanceCheck +func (_m *LoopRelayAdapter) Transact(ctx context.Context, from string, to string, amount *big.Int, balanceCheck bool) error { + ret := _m.Called(ctx, from, to, amount, balanceCheck) var r0 error - if rf, ok := ret.Get(0).(func(context.Context) error); ok { - r0 = rf(_a0) + if rf, ok := ret.Get(0).(func(context.Context, string, string, *big.Int, bool) error); ok { + r0 = rf(ctx, from, to, amount, balanceCheck) } else { r0 = ret.Error(0) } diff --git a/core/services/relay/evm/relayer_extender.go b/core/services/relay/evm/relayer_extender.go index 5b3a3535c51..9f19ef13143 100644 --- a/core/services/relay/evm/relayer_extender.go +++ b/core/services/relay/evm/relayer_extender.go @@ -23,10 +23,6 @@ type EVMChainRelayerExtender interface { relay.RelayerExt Chain() evmchain.Chain Default() bool - // compatibility remove after BCF-2441 - ChainStatus(ctx context.Context, id string) (relaytypes.ChainStatus, error) - ChainStatuses(ctx context.Context, offset, limit int) ([]relaytypes.ChainStatus, int, error) - NodeStatuses(ctx context.Context, offset, limit int, chainIDs ...string) (nodes []relaytypes.NodeStatus, count int, err error) } type EVMChainRelayerExtenderSlicer interface { @@ -135,54 +131,6 @@ func (s *ChainRelayerExt) Ready() (err error) { return s.chain.Ready() } -var ErrInconsistentChainRelayerExtender = errors.New("inconsistent evm chain relayer extender") - -// Legacy interface remove after BFC-2441, BCF-2564 - -func (s *ChainRelayerExt) SendTx(ctx context.Context, from, to string, amount *big.Int, balanceCheck bool) error { - return s.Transact(ctx, from, to, amount, balanceCheck) -} - -func (s *ChainRelayerExt) ChainStatus(ctx context.Context, id string) (relaytypes.ChainStatus, error) { - if s.chain.ID().String() != id { - return relaytypes.ChainStatus{}, fmt.Errorf("%w: given id %q does not match expected id %q", ErrInconsistentChainRelayerExtender, id, s.chain.ID()) - } - return s.chain.GetChainStatus(ctx) -} - -func (s *ChainRelayerExt) ChainStatuses(ctx context.Context, offset, limit int) ([]relaytypes.ChainStatus, int, error) { - stat, err := s.chain.GetChainStatus(ctx) - if err != nil { - return nil, -1, err - } - return []relaytypes.ChainStatus{stat}, 1, nil - -} - -func (s *ChainRelayerExt) NodeStatuses(ctx context.Context, offset, limit int, chainIDs ...string) (nodes []relaytypes.NodeStatus, total int, err error) { - if len(chainIDs) > 1 { - return nil, -1, fmt.Errorf("single chain chain set only support one chain id. got %v", chainIDs) - } - cid := chainIDs[0] - if cid != s.chain.ID().String() { - return nil, -1, fmt.Errorf("unknown chain id %s. expected %s", cid, s.chain.ID()) - } - nodes, _, total, err = s.ListNodeStatuses(ctx, int32(limit), "") - if err != nil { - return nil, -1, err - } - if len(nodes) < offset { - return []relaytypes.NodeStatus{}, -1, fmt.Errorf("out of range") - } - if limit <= 0 { - limit = len(nodes) - } else if len(nodes) < limit { - limit = len(nodes) - } - return nodes[offset:limit], total, nil - -} - func NewChainRelayerExtenders(ctx context.Context, opts evmchain.ChainRelayExtenderConfig) (*ChainRelayerExtenders, error) { if err := opts.Check(); err != nil { return nil, err diff --git a/core/services/relay/evm/relayer_extender_test.go b/core/services/relay/evm/relayer_extender_test.go index d4cbb1368c2..361a7468f30 100644 --- a/core/services/relay/evm/relayer_extender_test.go +++ b/core/services/relay/evm/relayer_extender_test.go @@ -62,28 +62,8 @@ func TestChainRelayExtenders(t *testing.T) { // test extender methods on single instance relayExt := relayExtendersInstances[0] - s, err := relayExt.ChainStatus(testutils.Context(t), "not a chain") - assert.Error(t, err) - assert.Empty(t, s) - // the 0-th extender corresponds to the test fixture default chain - s, err = relayExt.ChainStatus(testutils.Context(t), cltest.FixtureChainID.String()) + s, err := relayExt.GetChainStatus(testutils.Context(t)) assert.NotEmpty(t, s) assert.NoError(t, err) - stats, cnt, err := relayExt.ChainStatuses(testutils.Context(t), 0, 0) - assert.NoError(t, err) - assert.Len(t, stats, 1) - assert.Equal(t, 1, cnt) - - // test error conditions for NodeStatuses - nstats, cnt, err := relayExt.NodeStatuses(testutils.Context(t), 0, 0, cltest.FixtureChainID.String(), "error, only one chain supported") - assert.Error(t, err) - assert.Nil(t, nstats) - assert.Equal(t, -1, cnt) - - nstats, cnt, err = relayExt.NodeStatuses(testutils.Context(t), 0, 0, "not the chain id") - assert.Error(t, err) - assert.Nil(t, nstats) - assert.Equal(t, -1, cnt) - } diff --git a/core/services/relay/relay.go b/core/services/relay/relay.go index d7c71eebac2..c96abb4b8c8 100644 --- a/core/services/relay/relay.go +++ b/core/services/relay/relay.go @@ -4,9 +4,7 @@ import ( "context" "errors" "fmt" - "math/big" "regexp" - "strconv" "golang.org/x/exp/maps" @@ -15,7 +13,8 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/services" ) -type Network string +type Network = string +type ChainID = string var ( EVM Network = "evm" @@ -37,29 +36,14 @@ type ID struct { } func (i *ID) Name() string { - return fmt.Sprintf("%s.%s", i.Network, i.ChainID.String()) + return fmt.Sprintf("%s.%s", i.Network, i.ChainID) } func (i *ID) String() string { return i.Name() } -func NewID(n Network, c ChainID) (ID, error) { - id := ID{Network: n, ChainID: c} - err := id.validate() - if err != nil { - return ID{}, err - } - return id, nil -} -func (i *ID) validate() error { - // the only validation is to ensure that EVM chain ids are compatible with int64 - if i.Network == EVM { - _, err := i.ChainID.Int64() - if err != nil { - return fmt.Errorf("RelayIdentifier invalid: EVM relayer must have integer-compatible chain ID: %w", err) - } - } - return nil +func NewID(n Network, c ChainID) ID { + return ID{Network: n, ChainID: c} } var idRegex = regexp.MustCompile( @@ -89,28 +73,10 @@ func (i *ID) UnmarshalString(s string) error { return nil } -type ChainID string - -func (c ChainID) String() string { - return string(c) -} -func (c ChainID) Int64() (int64, error) { - i, err := strconv.Atoi(c.String()) - if err != nil { - return int64(0), err - } - return int64(i), nil -} - // RelayerExt is a subset of [loop.Relayer] for adapting [types.Relayer], typically with a Chain. See [relayerAdapter]. type RelayerExt interface { types.ChainService - // TODO remove after BFC-2441 ID() string - GetChainStatus(ctx context.Context) (types.ChainStatus, error) - ListNodeStatuses(ctx context.Context, pageSize int32, pageToken string) (stats []types.NodeStatus, nextPageToken string, total int, err error) - // choose different name than SendTx to avoid collison during refactor. - Transact(ctx context.Context, from, to string, amount *big.Int, balanceCheck bool) error } var _ loop.Relayer = (*relayerAdapter)(nil) @@ -118,14 +84,14 @@ var _ loop.Relayer = (*relayerAdapter)(nil) // relayerAdapter adapts a [types.Relayer] and [RelayerExt] to implement [loop.Relayer]. type relayerAdapter struct { types.Relayer - // TODO we can un-embedded `ext` once BFC-2441 is merged. Right now that's not possible - // because this are conflicting definitions of SendTx - ext RelayerExt + RelayerExt } // NewRelayerAdapter returns a [loop.Relayer] adapted from a [types.Relayer] and [RelayerExt]. +// Unlike NewRelayerServerAdapter which is used to adapt non-LOOPP relayers, this is used to adapt +// LOOPP-based relayer which are then server over GRPC (by the relayerServer). func NewRelayerAdapter(r types.Relayer, e RelayerExt) loop.Relayer { - return &relayerAdapter{Relayer: r, ext: e} + return &relayerAdapter{Relayer: r, RelayerExt: e} } func (r *relayerAdapter) NewConfigProvider(ctx context.Context, rargs types.RelayArgs) (types.ConfigProvider, error) { @@ -144,56 +110,43 @@ func (r *relayerAdapter) NewFunctionsProvider(ctx context.Context, rargs types.R return r.Relayer.NewFunctionsProvider(rargs, pargs) } +func (r *relayerAdapter) NewPluginProvider(ctx context.Context, rargs types.RelayArgs, pargs types.PluginArgs) (types.PluginProvider, error) { + return nil, fmt.Errorf("unexpected call to NewPluginProvider: did you forget to wrap relayerAdapter in a relayerServerAdapter?") +} + func (r *relayerAdapter) Start(ctx context.Context) error { var ms services.MultiStart - return ms.Start(ctx, r.ext, r.Relayer) + return ms.Start(ctx, r.RelayerExt, r.Relayer) } func (r *relayerAdapter) Close() error { - return services.CloseAll(r.Relayer, r.ext) + return services.CloseAll(r.Relayer, r.RelayerExt) } func (r *relayerAdapter) Name() string { - return fmt.Sprintf("%s-%s", r.Relayer.Name(), r.ext.Name()) + return fmt.Sprintf("%s-%s", r.Relayer.Name(), r.RelayerExt.Name()) } func (r *relayerAdapter) Ready() (err error) { - return errors.Join(r.Relayer.Ready(), r.ext.Ready()) + return errors.Join(r.Relayer.Ready(), r.RelayerExt.Ready()) } func (r *relayerAdapter) HealthReport() map[string]error { hr := make(map[string]error) maps.Copy(r.Relayer.HealthReport(), hr) - maps.Copy(r.ext.HealthReport(), hr) + maps.Copy(r.RelayerExt.HealthReport(), hr) return hr } -// Implement the existing [loop.Relayer] interface using the underlaying chain service -// TODO Delete this code after BFC-2441 - -func (r *relayerAdapter) ChainStatus(ctx context.Context, id string) (types.ChainStatus, error) { - if id != r.ext.ID() { - return types.ChainStatus{}, fmt.Errorf("unexpected chain id. got %s want %s", id, r.ID()) - } - return r.ext.GetChainStatus(ctx) -} -func (r *relayerAdapter) ChainStatuses(ctx context.Context, offset, limit int) ([]types.ChainStatus, int, error) { - stat, err := r.ext.GetChainStatus(ctx) - if err != nil { - return nil, -1, err - } - return []types.ChainStatus{stat}, 1, nil -} - func (r *relayerAdapter) NodeStatuses(ctx context.Context, offset, limit int, chainIDs ...string) (nodes []types.NodeStatus, total int, err error) { if len(chainIDs) > 1 { return nil, 0, fmt.Errorf("internal error: node statuses expects at most one chain id got %v", chainIDs) } - if len(chainIDs) == 1 && chainIDs[0] != r.ext.ID() { + if len(chainIDs) == 1 && chainIDs[0] != r.ID() { return nil, 0, fmt.Errorf("node statuses unexpected chain id got %s want %s", chainIDs[0], r.ID()) } - nodes, _, total, err = r.ext.ListNodeStatuses(ctx, int32(limit), "") + nodes, _, total, err = r.ListNodeStatuses(ctx, int32(limit), "") if err != nil { return nil, 0, err } @@ -208,26 +161,32 @@ func (r *relayerAdapter) NodeStatuses(ctx context.Context, offset, limit int, ch return nodes[offset:limit], total, nil } -func (r *relayerAdapter) SendTx(ctx context.Context, chainID, from, to string, amount *big.Int, balanceCheck bool) error { - if chainID != r.ext.ID() { - return fmt.Errorf("send tx unexpected chain id. got %s want %s", chainID, r.ext.ID()) - } - return r.ext.Transact(ctx, from, to, amount, balanceCheck) -} - -func (r *relayerAdapter) ID() string { - return r.ext.ID() +type relayerServerAdapter struct { + *relayerAdapter } -func (r *relayerAdapter) GetChainStatus(ctx context.Context) (types.ChainStatus, error) { - return r.ext.GetChainStatus(ctx) -} +func (r *relayerServerAdapter) NewPluginProvider(ctx context.Context, rargs types.RelayArgs, pargs types.PluginArgs) (types.PluginProvider, error) { + switch types.OCR2PluginType(rargs.ProviderType) { + case types.Median: + return r.NewMedianProvider(ctx, rargs, pargs) + case types.Functions: + return r.NewFunctionsProvider(ctx, rargs, pargs) + case types.Mercury: + return r.NewMercuryProvider(ctx, rargs, pargs) + case types.DKG, types.OCR2VRF, types.OCR2Keeper, types.GenericPlugin: + return r.relayerAdapter.NewPluginProvider(ctx, rargs, pargs) + } -func (r *relayerAdapter) ListNodeStatuses(ctx context.Context, pageSize int32, pageToken string) (stats []types.NodeStatus, nextPageToken string, total int, err error) { - return r.ext.ListNodeStatuses(ctx, pageSize, pageToken) + return nil, fmt.Errorf("provider type not supported: %s", rargs.ProviderType) } -// choose different name than SendTx to avoid collison during refactor. -func (r *relayerAdapter) Transact(ctx context.Context, from, to string, amount *big.Int, balanceCheck bool) error { - return r.ext.Transact(ctx, from, to, amount, balanceCheck) +// NewRelayerServerAdapter returns a [loop.Relayer] adapted from a [types.Relayer] and [RelayerExt]. +// Unlike NewRelayerAdapter, this behaves like the loop `RelayerServer` and dispatches calls +// to `NewPluginProvider` according to the passed in `RelayArgs.ProviderType`. +// This should only be used to adapt relayers not running via GRPC in a LOOPP. +// +// nolint:staticcheck // SA1019 +func NewRelayerServerAdapter(r types.Relayer, e RelayerExt) loop.Relayer { + ra := &relayerAdapter{Relayer: r, RelayerExt: e} + return &relayerServerAdapter{relayerAdapter: ra} } diff --git a/core/services/relay/relay_test.go b/core/services/relay/relay_test.go index 0ed14b6c5b7..28ee0172c20 100644 --- a/core/services/relay/relay_test.go +++ b/core/services/relay/relay_test.go @@ -1,9 +1,12 @@ package relay import ( + "context" "testing" "github.com/stretchr/testify/assert" + + "github.com/smartcontractkit/chainlink-relay/pkg/types" ) func TestIdentifier_UnmarshalString(t *testing.T) { @@ -48,34 +51,91 @@ func TestIdentifier_UnmarshalString(t *testing.T) { } func TestNewID(t *testing.T) { - type args struct { - n Network - c ChainID - } - tests := []struct { - name string - args args - want ID - wantErr bool + rid := NewID(EVM, "chain id") + assert.Equal(t, EVM, rid.Network) + assert.Equal(t, "chain id", rid.ChainID) +} + +type staticMedianProvider struct { + types.MedianProvider +} + +type staticFunctionsProvider struct { + types.FunctionsProvider +} + +type staticMercuryProvider struct { + types.MercuryProvider +} + +type mockRelayer struct { + types.Relayer +} + +func (m *mockRelayer) NewMedianProvider(rargs types.RelayArgs, pargs types.PluginArgs) (types.MedianProvider, error) { + return staticMedianProvider{}, nil +} + +func (m *mockRelayer) NewFunctionsProvider(rargs types.RelayArgs, pargs types.PluginArgs) (types.FunctionsProvider, error) { + return staticFunctionsProvider{}, nil +} + +func (m *mockRelayer) NewMercuryProvider(rargs types.RelayArgs, pargs types.PluginArgs) (types.MercuryProvider, error) { + return staticMercuryProvider{}, nil +} + +type mockRelayerExt struct { + RelayerExt +} + +func isType[T any](p any) bool { + _, ok := p.(T) + return ok +} + +func TestRelayerServerAdapter(t *testing.T) { + r := &mockRelayer{} + sa := NewRelayerServerAdapter(r, mockRelayerExt{}) + + testCases := []struct { + ProviderType string + Test func(p any) bool + Error string }{ - {name: "good evm", - args: args{n: EVM, c: "1"}, - want: ID{Network: EVM, ChainID: "1"}, + { + ProviderType: string(types.Median), + Test: isType[types.MedianProvider], }, - {name: "bad evm", - args: args{n: EVM, c: "not a number"}, - want: ID{}, - wantErr: true, + { + ProviderType: string(types.Functions), + Test: isType[types.FunctionsProvider], + }, + { + ProviderType: string(types.Mercury), + Test: isType[types.MercuryProvider], + }, + { + ProviderType: "unknown", + Error: "provider type not supported", + }, + { + ProviderType: string(types.GenericPlugin), + Error: "unexpected call to NewPluginProvider", }, } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - got, err := NewID(tt.args.n, tt.args.c) - if (err != nil) != tt.wantErr { - t.Errorf("NewID() error = %v, wantErr %v", err, tt.wantErr) - return - } - assert.Equal(t, tt.want, got, "got id %v", got) - }) + + for _, tc := range testCases { + pp, err := sa.NewPluginProvider( + context.Background(), + types.RelayArgs{ProviderType: tc.ProviderType}, + types.PluginArgs{}, + ) + + if tc.Error != "" { + assert.ErrorContains(t, err, tc.Error) + } else { + assert.NoError(t, err) + assert.True(t, tc.Test(pp)) + } } } diff --git a/core/services/s4/envelope.go b/core/services/s4/envelope.go index 07e4201341c..5c917e7ebda 100644 --- a/core/services/s4/envelope.go +++ b/core/services/s4/envelope.go @@ -6,6 +6,7 @@ import ( "fmt" "github.com/ethereum/go-ethereum/common" + "github.com/smartcontractkit/chainlink/v2/core/utils" ) @@ -62,7 +63,12 @@ func (e Envelope) ToJson() ([]byte, error) { if err != nil { return nil, err } - payload, err := json.Marshal(e.Payload) + nonNilPayload := e.Payload + if nonNilPayload == nil { + // prevent unwanted "null" values in JSON representation + nonNilPayload = []byte{} + } + payload, err := json.Marshal(nonNilPayload) if err != nil { return nil, err } diff --git a/core/services/s4/postgres_orm.go b/core/services/s4/postgres_orm.go index e562273d33a..d0a79dba959 100644 --- a/core/services/s4/postgres_orm.go +++ b/core/services/s4/postgres_orm.go @@ -71,7 +71,7 @@ RETURNING id;`, o.tableName) if errors.Is(err, sql.ErrNoRows) { return ErrVersionTooLow } - return nil + return err } func (o orm) DeleteExpired(limit uint, utcNow time.Time, qopts ...pg.QOpt) (int64, error) { diff --git a/core/services/s4/postgres_orm_test.go b/core/services/s4/postgres_orm_test.go index fdfa007f705..c233fe2361a 100644 --- a/core/services/s4/postgres_orm_test.go +++ b/core/services/s4/postgres_orm_test.go @@ -2,6 +2,7 @@ package s4_test import ( "errors" + "math" "testing" "time" @@ -257,3 +258,22 @@ func TestPostgresORM_Namespace(t *testing.T) { assert.NoError(t, err) assert.Len(t, snapshotA, n) } + +func TestPostgresORM_BigIntVersion(t *testing.T) { + t.Parallel() + + orm := setupORM(t, "test") + row := generateTestRows(t, 1)[0] + row.Version = math.MaxUint64 - 10 + + err := orm.Update(row) + assert.NoError(t, err) + + row.Version++ + err = orm.Update(row) + assert.NoError(t, err) + + gotRow, err := orm.Get(row.Address, row.SlotId) + assert.NoError(t, err) + assert.Equal(t, row, gotRow) +} diff --git a/core/services/vrf/v2/integration_v2_test.go b/core/services/vrf/v2/integration_v2_test.go index 3609754df3d..7c7e4122b0b 100644 --- a/core/services/vrf/v2/integration_v2_test.go +++ b/core/services/vrf/v2/integration_v2_test.go @@ -1318,6 +1318,7 @@ func TestVRFV2Integration_SingleConsumer_NeedsTrustedBlockhashStore(t *testing.T } func TestVRFV2Integration_SingleConsumer_NeedsTrustedBlockhashStore_AfterDelay(t *testing.T) { + t.Skip("TODO: VRF-616") t.Parallel() ownerKey := cltest.MustGenerateRandomKey(t) uni := newVRFCoordinatorV2PlusUniverse(t, ownerKey, 2, true) @@ -2140,10 +2141,10 @@ VALUES (:nonce, :from_address, :to_address, :encoded_payload, :value, :gas_limit sql = `INSERT INTO eth_tx_attempts (eth_tx_id, gas_price, signed_raw_tx, hash, state, created_at, chain_specific_gas_limit) VALUES (:eth_tx_id, :gas_price, :signed_raw_tx, :hash, :state, :created_at, :chain_specific_gas_limit)` for _, attempt := range txAttempts { - dbAttempt := txmgr.DbEthTxAttemptFromEthTxAttempt(&attempt) //nolint:gosec - just copying fields + dbAttempt := txmgr.DbEthTxAttemptFromEthTxAttempt(&attempt) //nolint:gosec // just copying fields _, err = db.NamedExec(sql, &dbAttempt) require.NoError(t, err) - txmgr.DbEthTxAttemptToEthTxAttempt(dbAttempt, &attempt) //nolin:gosec - just copying fields + txmgr.DbEthTxAttemptToEthTxAttempt(dbAttempt, &attempt) //nolint:gosec // just copying fields } // add eth_receipts diff --git a/core/sessions/orm.go b/core/sessions/orm.go index a4060ce487c..eaac211f242 100644 --- a/core/sessions/orm.go +++ b/core/sessions/orm.go @@ -86,43 +86,44 @@ func (o *orm) ListUsers() (users []User, err error) { return } +// findValidSession finds an unexpired session by its ID and returns the associated email. +func (o *orm) findValidSession(sessionID string) (email string, err error) { + if err := o.q.Get(&email, "SELECT email FROM sessions WHERE id = $1 AND last_used + $2 >= now() FOR UPDATE", sessionID, o.sessionDuration); err != nil { + o.lggr.Infof("query result: %v", email) + return email, errors.Wrap(err, "no matching user for provided session token") + } + return email, nil +} + +// updateSessionLastUsed updates a session by its ID and sets the LastUsed field to now(). +func (o *orm) updateSessionLastUsed(sessionID string) error { + return o.q.ExecQ("UPDATE sessions SET last_used = now() WHERE id = $1", sessionID) +} + // ErrUserSessionExpired defines the error triggered when the user session has expired -var ErrUserSessionExpired = errors.New("session missing or expired, please login again") +var ( + ErrUserSessionExpired = errors.New("user session missing or expired, please login again") + ErrEmptySessionID = errors.New("session ID cannot be empty") +) // AuthorizedUserWithSession will return the API user associated with the Session ID if it // exists and hasn't expired, and update session's LastUsed field. -func (o *orm) AuthorizedUserWithSession(sessionID string) (User, error) { +func (o *orm) AuthorizedUserWithSession(sessionID string) (user User, err error) { if len(sessionID) == 0 { - return User{}, errors.New("Session ID cannot be empty") + return User{}, ErrEmptySessionID } - var user User - err := o.q.Transaction(func(tx pg.Queryer) error { - // First find user based on session token - var foundSession struct { - Email string - Valid bool - } - if err := tx.Get(&foundSession, "SELECT email, last_used + $2 >= now() as valid FROM sessions WHERE id = $1 FOR UPDATE", sessionID, o.sessionDuration); err != nil { - return errors.Wrap(err, "no matching user for provided session token") - } - - if !foundSession.Valid { - return ErrUserSessionExpired - } - - if err := tx.Get(&user, "SELECT * FROM users WHERE lower(email) = lower($1)", foundSession.Email); err != nil { - return errors.Wrap(err, "no matching user for provided session email") - } - // Session valid and tied to user, update last_used - _, err := tx.Exec("UPDATE sessions SET last_used = now() WHERE id = $1 AND last_used + $2 >= now()", sessionID, o.sessionDuration) - if err != nil { - return errors.Wrap(err, "unable to update sessions table") - } - return nil - }) + email, err := o.findValidSession(sessionID) + if err != nil { + return User{}, ErrUserSessionExpired + } + user, err = o.findUser(email) if err != nil { + return User{}, ErrUserSessionExpired + } + + if err := o.updateSessionLastUsed(sessionID); err != nil { return User{}, err } diff --git a/core/sessions/orm_test.go b/core/sessions/orm_test.go index 681b50987bf..804ea2dbb87 100644 --- a/core/sessions/orm_test.go +++ b/core/sessions/orm_test.go @@ -59,9 +59,9 @@ func TestORM_AuthorizedUserWithSession(t *testing.T) { wantEmail string }{ {"authorized", "correctID", cltest.MustParseDuration(t, "3m"), "", "have@email"}, - {"expired", "correctID", cltest.MustParseDuration(t, "0m"), "session missing or expired, please login again", ""}, - {"incorrect", "wrong", cltest.MustParseDuration(t, "3m"), "no matching user for provided session token: sql: no rows in result set", ""}, - {"empty", "", cltest.MustParseDuration(t, "3m"), "Session ID cannot be empty", ""}, + {"expired", "correctID", cltest.MustParseDuration(t, "0m"), sessions.ErrUserSessionExpired.Error(), ""}, + {"incorrect", "wrong", cltest.MustParseDuration(t, "3m"), sessions.ErrUserSessionExpired.Error(), ""}, + {"empty", "", cltest.MustParseDuration(t, "3m"), sessions.ErrEmptySessionID.Error(), ""}, } for _, test := range tests { diff --git a/core/store/migrate/migrate_test.go b/core/store/migrate/migrate_test.go index 97d0ec5b182..66764a266f0 100644 --- a/core/store/migrate/migrate_test.go +++ b/core/store/migrate/migrate_test.go @@ -10,6 +10,7 @@ import ( "github.com/stretchr/testify/require" "gopkg.in/guregu/null.v4" + "github.com/smartcontractkit/chainlink-relay/pkg/types" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest/heavyweight" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/job" @@ -350,7 +351,7 @@ func TestMigrate_101_GenericOCR2(t *testing.T) { require.NoError(t, err) type PluginValues struct { - PluginType job.OCR2PluginType + PluginType types.OCR2PluginType PluginConfig job.JSONConfig } @@ -360,7 +361,7 @@ func TestMigrate_101_GenericOCR2(t *testing.T) { err = db.Get(&pluginValues, sql) require.NoError(t, err) - require.Equal(t, job.Median, pluginValues.PluginType) + require.Equal(t, types.Median, pluginValues.PluginType) require.Equal(t, job.JSONConfig{"juelsPerFeeCoinSource": spec.JuelsPerFeeCoinPipeline}, pluginValues.PluginConfig) err = goose.Down(db.DB, migrationDir) diff --git a/core/store/migrate/migrations/0193_s4_alter_version_type.sql b/core/store/migrate/migrations/0193_s4_alter_version_type.sql new file mode 100644 index 00000000000..36179d5d7f0 --- /dev/null +++ b/core/store/migrate/migrations/0193_s4_alter_version_type.sql @@ -0,0 +1,7 @@ +-- +goose Up + +ALTER TABLE "s4".shared ALTER COLUMN version TYPE NUMERIC; + +-- +goose Down + +ALTER TABLE "s4".shared ALTER COLUMN version TYPE INT USING version::integer; diff --git a/core/utils/thread_control.go b/core/utils/thread_control.go new file mode 100644 index 00000000000..8f7fff42496 --- /dev/null +++ b/core/utils/thread_control.go @@ -0,0 +1,44 @@ +package utils + +import ( + "context" + "sync" +) + +var _ ThreadControl = &threadControl{} + +// ThreadControl is a helper for managing a group of goroutines. +type ThreadControl interface { + // Go starts a goroutine and tracks the lifetime of the goroutine. + Go(fn func(context.Context)) + // Close cancels the goroutines and waits for all of them to exit. + Close() +} + +func NewThreadControl() *threadControl { + tc := &threadControl{ + stop: make(chan struct{}), + } + + return tc +} + +type threadControl struct { + threadsWG sync.WaitGroup + stop StopChan +} + +func (tc *threadControl) Go(fn func(context.Context)) { + tc.threadsWG.Add(1) + go func() { + defer tc.threadsWG.Done() + ctx, cancel := tc.stop.NewCtx() + defer cancel() + fn(ctx) + }() +} + +func (tc *threadControl) Close() { + close(tc.stop) + tc.threadsWG.Wait() +} diff --git a/core/utils/thread_control_test.go b/core/utils/thread_control_test.go new file mode 100644 index 00000000000..9001ca7241c --- /dev/null +++ b/core/utils/thread_control_test.go @@ -0,0 +1,27 @@ +package utils + +import ( + "context" + "sync/atomic" + "testing" + + "github.com/stretchr/testify/require" +) + +func TestThreadControl_Close(t *testing.T) { + n := 10 + tc := NewThreadControl() + + finished := atomic.Int32{} + + for i := 0; i < n; i++ { + tc.Go(func(ctx context.Context) { + <-ctx.Done() + finished.Add(1) + }) + } + + tc.Close() + + require.Equal(t, int32(n), finished.Load()) +} diff --git a/core/web/cosmos_nodes_controller.go b/core/web/cosmos_nodes_controller.go index 756d1ded741..121d7d8422b 100644 --- a/core/web/cosmos_nodes_controller.go +++ b/core/web/cosmos_nodes_controller.go @@ -10,7 +10,9 @@ import ( var ErrCosmosNotEnabled = errChainDisabled{name: "Cosmos", tomlKey: "Cosmos.Enabled"} func NewCosmosNodesController(app chainlink.Application) NodesController { + scopedNodeStatuser := NewNetworkScopedNodeStatuser(app.GetRelayers(), relay.Cosmos) + return newNodesController[presenters.CosmosNodeResource]( - app.GetRelayers().List(chainlink.FilterRelayersByType(relay.Cosmos)), ErrCosmosNotEnabled, presenters.NewCosmosNodeResource, app.GetAuditLogger(), + scopedNodeStatuser, ErrCosmosNotEnabled, presenters.NewCosmosNodeResource, app.GetAuditLogger(), ) } diff --git a/core/web/evm_nodes_controller.go b/core/web/evm_nodes_controller.go index aba0faca8e8..c8d0b91c0f7 100644 --- a/core/web/evm_nodes_controller.go +++ b/core/web/evm_nodes_controller.go @@ -7,6 +7,8 @@ import ( ) func NewEVMNodesController(app chainlink.Application) NodesController { + scopedNodeStatuser := NewNetworkScopedNodeStatuser(app.GetRelayers(), relay.EVM) + return newNodesController[presenters.EVMNodeResource]( - app.GetRelayers().List(chainlink.FilterRelayersByType(relay.EVM)), ErrEVMNotEnabled, presenters.NewEVMNodeResource, app.GetAuditLogger()) + scopedNodeStatuser, ErrEVMNotEnabled, presenters.NewEVMNodeResource, app.GetAuditLogger()) } diff --git a/core/web/loader/chain.go b/core/web/loader/chain.go index 77e231ace13..c91c2f02a3b 100644 --- a/core/web/loader/chain.go +++ b/core/web/loader/chain.go @@ -7,6 +7,7 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/chains" "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" + "github.com/smartcontractkit/chainlink/v2/core/services/relay" ) type chainBatcher struct { @@ -17,14 +18,14 @@ func (b *chainBatcher) loadByIDs(_ context.Context, keys dataloader.Keys) []*dat // Create a map for remembering the order of keys passed in keyOrder := make(map[string]int, len(keys)) // Collect the keys to search for - var chainIDs []string + var chainIDs []relay.ChainID for ix, key := range keys { - chainIDs = append(chainIDs, key.String()) + chainIDs = append(chainIDs, relay.ChainID(key.String())) keyOrder[key.String()] = ix } // Fetch the chains - cs, _, err := b.app.EVMORM().Chains(0, -1, chainIDs...) + cs, _, err := b.app.EVMORM().Chains(chainIDs...) if err != nil { return []*dataloader.Result{{Data: nil, Error: err}} } diff --git a/core/web/loader/loader_test.go b/core/web/loader/loader_test.go index d5123053cf2..0dd45a1735d 100644 --- a/core/web/loader/loader_test.go +++ b/core/web/loader/loader_test.go @@ -81,7 +81,7 @@ func TestLoader_Nodes(t *testing.T) { } rcInterops := chainlinkmocks.NewRelayerChainInteroperators(t) rcInterops.On("NodeStatuses", mock.Anything, 0, -1, - relayID2.String(), relayID1.String(), notARelayID.String()).Return([]relaytypes.NodeStatus{ + relayID2, relayID1, notARelayID).Return([]relaytypes.NodeStatus{ genNodeStat(chainID2.String()), genNodeStat(chainID1.String()), }, 2, nil) diff --git a/core/web/loader/node.go b/core/web/loader/node.go index fb0c58d1f2c..9ea6062dc29 100644 --- a/core/web/loader/node.go +++ b/core/web/loader/node.go @@ -20,15 +20,15 @@ func (b *nodeBatcher) loadByChainIDs(ctx context.Context, keys dataloader.Keys) keyOrder := make(map[string]int, len(keys)) // Collect the keys to search for // note backward compatibility -- this only ever supported evm chains - var evmrelayIdStrs []string + evmrelayIDs := make([]relay.ID, 0, len(keys)) for ix, key := range keys { rid := relay.ID{Network: relay.EVM, ChainID: relay.ChainID(key.String())} - evmrelayIdStrs = append(evmrelayIdStrs, rid.String()) + evmrelayIDs = append(evmrelayIDs, rid) keyOrder[key.String()] = ix } - allNodes, _, err := b.app.GetRelayers().NodeStatuses(ctx, 0, -1, evmrelayIdStrs...) + allNodes, _, err := b.app.GetRelayers().NodeStatuses(ctx, 0, -1, evmrelayIDs...) if err != nil { return []*dataloader.Result{{Data: nil, Error: err}} } diff --git a/core/web/loop_registry.go b/core/web/loop_registry.go index 4bbcef2b44a..345ff03704e 100644 --- a/core/web/loop_registry.go +++ b/core/web/loop_registry.go @@ -48,19 +48,12 @@ func (l *LoopRegistryServer) discoveryHandler(w http.ResponseWriter, req *http.R w.Header().Set("Content-Type", "application/json") var groups []*targetgroup.Group - for _, registeredPlugin := range l.registry.List() { - // create a metric target for each running plugin - target := &targetgroup.Group{ - Targets: []model.LabelSet{ - // target address will be called by external prometheus - {model.AddressLabel: model.LabelValue(fmt.Sprintf("%s:%d", l.discoveryHostName, l.exposedPromPort))}, - }, - Labels: map[model.LabelName]model.LabelValue{ - model.MetricsPathLabel: model.LabelValue(pluginMetricPath(registeredPlugin.Name)), - }, - } + // add node metrics to service discovery + groups = append(groups, metricTarget(l.discoveryHostName, l.exposedPromPort, "/metrics")) - groups = append(groups, target) + // add all the plugins + for _, registeredPlugin := range l.registry.List() { + groups = append(groups, metricTarget(l.discoveryHostName, l.exposedPromPort, pluginMetricPath(registeredPlugin.Name))) } b, err := l.jsonMarshalFn(groups) @@ -80,6 +73,18 @@ func (l *LoopRegistryServer) discoveryHandler(w http.ResponseWriter, req *http.R } +func metricTarget(hostName string, port int, path string) *targetgroup.Group { + return &targetgroup.Group{ + Targets: []model.LabelSet{ + // target address will be called by external prometheus + {model.AddressLabel: model.LabelValue(fmt.Sprintf("%s:%d", hostName, port))}, + }, + Labels: map[model.LabelName]model.LabelValue{ + model.MetricsPathLabel: model.LabelValue(path), + }, + } +} + // pluginMetricHandlers routes from endpoints published in service discovery to the the backing LOOP endpoint func (l *LoopRegistryServer) pluginMetricHandler(gc *gin.Context) { pluginName := gc.Param("name") diff --git a/core/web/loop_registry_test.go b/core/web/loop_registry_test.go index 5f737952aec..58a88dad21d 100644 --- a/core/web/loop_registry_test.go +++ b/core/web/loop_registry_test.go @@ -1,6 +1,7 @@ package web_test import ( + "encoding/json" "fmt" "io" "net/http" @@ -8,6 +9,9 @@ import ( "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/promhttp" + "github.com/prometheus/common/model" + "github.com/prometheus/prometheus/discovery/targetgroup" + "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" @@ -67,7 +71,13 @@ func TestLoopRegistry(t *testing.T) { // shim a reference to the promserver that is running in our mock loop // this ensures the client.Get calls below have a reference to mock loop impl - expectedEndPoint := "/plugins/mockLoopImpl/metrics" + expectedLooppEndPoint, expectedCoreEndPoint := "/plugins/mockLoopImpl/metrics", "/metrics" + + // note we expect this to be an ordered result + expectedLabels := []model.LabelSet{ + model.LabelSet{"__metrics_path__": model.LabelValue(expectedCoreEndPoint)}, + model.LabelSet{"__metrics_path__": model.LabelValue(expectedLooppEndPoint)}, + } require.NoError(t, app.KeyStore.OCR().Add(cltest.DefaultOCRKey)) require.NoError(t, app.Start(testutils.Context(t))) @@ -97,12 +107,22 @@ func TestLoopRegistry(t *testing.T) { b, err := io.ReadAll(resp.Body) require.NoError(t, err) t.Logf("discovery response %s", b) - require.Contains(t, string(b), expectedEndPoint) + var got []*targetgroup.Group + require.NoError(t, json.Unmarshal(b, &got)) + + gotLabels := make([]model.LabelSet, 0) + for _, ls := range got { + gotLabels = append(gotLabels, ls.Labels) + } + assert.Equal(t, len(expectedLabels), len(gotLabels)) + for i := range expectedLabels { + assert.EqualValues(t, expectedLabels[i], gotLabels[i]) + } }) t.Run("plugin metrics OK", func(t *testing.T) { // plugin name `mockLoopImpl` matches key in PluginConfigs - resp, cleanup := client.Get(expectedEndPoint) + resp, cleanup := client.Get(expectedLooppEndPoint) t.Cleanup(cleanup) cltest.AssertServerResponse(t, resp, http.StatusOK) @@ -117,6 +137,17 @@ func TestLoopRegistry(t *testing.T) { require.Contains(t, string(b), expectedMetric) }) + t.Run("core metrics OK", func(t *testing.T) { + // core node metrics endpoint + resp, cleanup := client.Get(expectedCoreEndPoint) + t.Cleanup(cleanup) + cltest.AssertServerResponse(t, resp, http.StatusOK) + + b, err := io.ReadAll(resp.Body) + require.NoError(t, err) + t.Logf("core metrics response %s", b) + }) + t.Run("no existent plugin metrics ", func(t *testing.T) { // request plugin that doesn't exist resp, cleanup := client.Get("/plugins/noexist/metrics") diff --git a/core/web/nodes_controller.go b/core/web/nodes_controller.go index e65f3e68a8a..1eddc67c364 100644 --- a/core/web/nodes_controller.go +++ b/core/web/nodes_controller.go @@ -1,6 +1,7 @@ package web import ( + "context" "net/http" "github.com/gin-gonic/gin" @@ -8,8 +9,9 @@ import ( "github.com/smartcontractkit/chainlink-relay/pkg/types" - "github.com/smartcontractkit/chainlink/v2/core/chains" "github.com/smartcontractkit/chainlink/v2/core/logger/audit" + "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" + "github.com/smartcontractkit/chainlink/v2/core/services/relay" ) type NodesController interface { @@ -17,15 +19,32 @@ type NodesController interface { Index(c *gin.Context, size, page, offset int) } +type NetworkScopedNodeStatuser struct { + network relay.Network + relayers chainlink.RelayerChainInteroperators +} + +func NewNetworkScopedNodeStatuser(relayers chainlink.RelayerChainInteroperators, network relay.Network) *NetworkScopedNodeStatuser { + scoped := relayers.List(chainlink.FilterRelayersByType(network)) + return &NetworkScopedNodeStatuser{ + network: network, + relayers: scoped, + } +} + +func (n *NetworkScopedNodeStatuser) NodeStatuses(ctx context.Context, offset, limit int, relayIDs ...relay.ID) (nodes []types.NodeStatus, count int, err error) { + return n.relayers.NodeStatuses(ctx, offset, limit, relayIDs...) +} + type nodesController[R jsonapi.EntityNamer] struct { - nodeSet chains.NodesStatuser + nodeSet *NetworkScopedNodeStatuser errNotEnabled error newResource func(status types.NodeStatus) R auditLogger audit.AuditLogger } func newNodesController[R jsonapi.EntityNamer]( - nodeSet chains.NodesStatuser, + nodeSet *NetworkScopedNodeStatuser, errNotEnabled error, newResource func(status types.NodeStatus) R, auditLogger audit.AuditLogger, @@ -55,7 +74,14 @@ func (n *nodesController[R]) Index(c *gin.Context, size, page, offset int) { nodes, count, err = n.nodeSet.NodeStatuses(c, offset, size) } else { // fetch nodes for chain ID - nodes, count, err = n.nodeSet.NodeStatuses(c, offset, size, id) + // backward compatibility + var rid relay.ID + err := rid.UnmarshalString(id) + if err != nil { + rid.ChainID = relay.ChainID(id) + rid.Network = n.nodeSet.network + } + nodes, count, err = n.nodeSet.NodeStatuses(c, offset, size, rid) } var resources []R diff --git a/core/web/resolver/query.go b/core/web/resolver/query.go index 22b95a2d2ef..e9fd18cf19a 100644 --- a/core/web/resolver/query.go +++ b/core/web/resolver/query.go @@ -15,6 +15,7 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/chains" "github.com/smartcontractkit/chainlink/v2/core/services/keystore" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/vrfkey" + "github.com/smartcontractkit/chainlink/v2/core/services/relay" evmrelay "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm" "github.com/smartcontractkit/chainlink/v2/core/utils/stringutils" ) @@ -68,7 +69,7 @@ func (r *Resolver) Chain(ctx context.Context, args struct{ ID graphql.ID }) (*Ch return nil, err } - cs, _, err := r.App.EVMORM().Chains(0, -1, string(args.ID)) + cs, _, err := r.App.EVMORM().Chains(relay.ChainID(args.ID)) if err != nil { return nil, err } @@ -94,12 +95,20 @@ func (r *Resolver) Chains(ctx context.Context, args struct { offset := pageOffset(args.Offset) limit := pageLimit(args.Limit) - page, count, err := r.App.EVMORM().Chains(offset, limit) + chains, count, err := r.App.EVMORM().Chains() if err != nil { return nil, err } + // bound the chain results + if offset >= len(chains) { + return nil, fmt.Errorf("offset %d out of range", offset) + } + end := len(chains) + if limit > 0 && offset+limit < end { + end = offset + limit + } - return NewChainsPayload(page, int32(count)), nil + return NewChainsPayload(chains[offset:end], int32(count)), nil } // FeedsManager retrieves a feeds manager by id. diff --git a/core/web/resolver/spec_test.go b/core/web/resolver/spec_test.go index 8c6dadc880e..c4efbb65825 100644 --- a/core/web/resolver/spec_test.go +++ b/core/web/resolver/spec_test.go @@ -9,6 +9,7 @@ import ( "github.com/stretchr/testify/require" "gopkg.in/guregu/null.v4" + "github.com/smartcontractkit/chainlink-relay/pkg/types" "github.com/smartcontractkit/chainlink/v2/core/assets" clnull "github.com/smartcontractkit/chainlink/v2/core/null" "github.com/smartcontractkit/chainlink/v2/core/services/job" @@ -515,7 +516,7 @@ func TestResolver_OCR2Spec(t *testing.T) { Relay: relay.EVM, RelayConfig: relayConfig, TransmitterID: null.StringFrom(transmitterAddress.String()), - PluginType: job.Median, + PluginType: types.Median, PluginConfig: pluginConfig, }, }, nil) diff --git a/core/web/schema/type/feeds_manager.graphql b/core/web/schema/type/feeds_manager.graphql index 6a2b019aae3..0d6d5f61788 100644 --- a/core/web/schema/type/feeds_manager.graphql +++ b/core/web/schema/type/feeds_manager.graphql @@ -49,6 +49,7 @@ type OCR2JobConfig { enabled: Boolean! isBootstrap: Boolean! multiaddr: String + forwarderAddress: String p2pPeerID: String keyBundleID: String plugins: Plugins! diff --git a/core/web/solana_nodes_controller.go b/core/web/solana_nodes_controller.go index 1c12418a5b2..d5fbc05ccf5 100644 --- a/core/web/solana_nodes_controller.go +++ b/core/web/solana_nodes_controller.go @@ -10,6 +10,8 @@ import ( var ErrSolanaNotEnabled = errChainDisabled{name: "Solana", tomlKey: "Solana.Enabled"} func NewSolanaNodesController(app chainlink.Application) NodesController { + scopedNodeStatuser := NewNetworkScopedNodeStatuser(app.GetRelayers(), relay.Solana) + return newNodesController[presenters.SolanaNodeResource]( - app.GetRelayers().List(chainlink.FilterRelayersByType(relay.Solana)), ErrSolanaNotEnabled, presenters.NewSolanaNodeResource, app.GetAuditLogger()) + scopedNodeStatuser, ErrSolanaNotEnabled, presenters.NewSolanaNodeResource, app.GetAuditLogger()) } diff --git a/core/web/solana_transfer_controller.go b/core/web/solana_transfer_controller.go index 5f92c02269b..df750586a46 100644 --- a/core/web/solana_transfer_controller.go +++ b/core/web/solana_transfer_controller.go @@ -58,9 +58,8 @@ func (tc *SolanaTransfersController) Create(c *gin.Context) { jsonAPIError(c, http.StatusInternalServerError, err) return } - // note the [loop.Relayer] API is in intermediate state. we found the relayer above; we should not need to pass - // the chain id here - err = relayer.SendTx(c, tr.SolanaChainID, tr.From.String(), tr.To.String(), amount, !tr.AllowHigherAmounts) + + err = relayer.Transact(c, tr.From.String(), tr.To.String(), amount, !tr.AllowHigherAmounts) if err != nil { switch err { case chains.ErrNotFound, chains.ErrChainIDEmpty: diff --git a/core/web/starknet_nodes_controller.go b/core/web/starknet_nodes_controller.go index d630bc102c1..d2881f2e65a 100644 --- a/core/web/starknet_nodes_controller.go +++ b/core/web/starknet_nodes_controller.go @@ -10,9 +10,8 @@ import ( var ErrStarkNetNotEnabled = errChainDisabled{name: "StarkNet", tomlKey: "Starknet.Enabled"} func NewStarkNetNodesController(app chainlink.Application) NodesController { + scopedNodeStatuser := NewNetworkScopedNodeStatuser(app.GetRelayers(), relay.StarkNet) + return newNodesController[presenters.StarkNetNodeResource]( - app.GetRelayers().List(chainlink.FilterRelayersByType(relay.StarkNet)), - ErrStarkNetNotEnabled, - presenters.NewStarkNetNodeResource, - app.GetAuditLogger()) + scopedNodeStatuser, ErrStarkNetNotEnabled, presenters.NewStarkNetNodeResource, app.GetAuditLogger()) } diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index 93ae8b611f5..5ce56b429cb 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -10,18 +10,17 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [dev] ### Fixed + - Unauthenticated users executing CLI commands previously generated a confusing error log, which is now removed: +```[ERROR] Error in transaction, rolling back: session missing or expired, please login again pg/transaction.go:118 ``` - Fixed a bug that was preventing job runs to be displayed when the job `chainID` was disabled. +- `chainlink txs evm create` returns a transaction hash for the attempted transaction in the CLI. Previously only the sender, receipient and `unstarted` state were returned. - +... ## 2.5.0 - UNRELEASED -### Fixed -- `chainlink txs evm create` returns a transaction hash for the attempted transaction in the CLI. Previously only the sender, receipient and `unstarted` state were returned. - ### Upcoming Required Configuration Change - Starting in 2.6.0, chainlink nodes will no longer allow insecure configuration for production builds. Any TOML configuration that sets the following line will fail validation checks in `node start` or `node validate`: - ``` AllowSimplePasswords=true ``` diff --git a/docs/SECRETS.md b/docs/SECRETS.md index 3bbf51cae6f..717603a4779 100644 --- a/docs/SECRETS.md +++ b/docs/SECRETS.md @@ -135,6 +135,7 @@ Environment variable: `CL_PROMETHEUS_AUTH_TOKEN` Username = "A-Mercury-Username" # Example Password = "A-Mercury-Password" # Example URL = "https://example.com" # Example +LegacyURL = "https://example.v1.com" # Example ``` @@ -154,7 +155,13 @@ Password is used for basic auth of the Mercury endpoint ```toml URL = "https://example.com" # Example ``` -URL is the Mercury endpoint URL which is used by OCR2 Automation to access Mercury price feed +URL is the Mercury endpoint base URL used to access Mercury price feed + +### LegacyURL +```toml +LegacyURL = "https://example.v1.com" # Example +``` +LegacyURL is the Mercury legacy endpoint base URL used to access Mercury v0.2 price feed ## Threshold ```toml diff --git a/go.mod b/go.mod index 7d5b1757992..24bf77eebf1 100644 --- a/go.mod +++ b/go.mod @@ -12,6 +12,7 @@ require ( github.com/cometbft/cometbft v0.37.2 github.com/cosmos/cosmos-sdk v0.47.4 github.com/danielkov/gin-helmet v0.0.0-20171108135313-1387e224435e + github.com/esote/minmaxheap v1.0.0 github.com/ethereum/go-ethereum v1.12.0 github.com/fatih/color v1.15.0 github.com/fxamacker/cbor/v2 v2.4.0 @@ -66,15 +67,15 @@ require ( github.com/shopspring/decimal v1.3.1 github.com/smartcontractkit/caigo v0.0.0-20230621050857-b29a4ca8c704 github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20230831132059-42af68994512 - github.com/smartcontractkit/chainlink-relay v0.1.7-0.20230901143551-bf6bd84d6938 + github.com/smartcontractkit/chainlink-relay v0.1.7-0.20230908162043-e2f9fcf758d8 github.com/smartcontractkit/chainlink-solana v1.0.3-0.20230831134610-680240b97aca github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20230901115736-bbabe542a918 github.com/smartcontractkit/libocr v0.0.0-20230816220705-665e93233ae5 - github.com/smartcontractkit/ocr2keepers v0.7.19 + github.com/smartcontractkit/ocr2keepers v0.7.23 github.com/smartcontractkit/ocr2vrf v0.0.0-20230804151440-2f1eb1e20687 github.com/smartcontractkit/sqlx v1.3.5-0.20210805004948-4be295aacbeb - github.com/smartcontractkit/tdh2/go/ocr2/decryptionplugin v0.0.0-20230829114801-14bf715f805e - github.com/smartcontractkit/tdh2/go/tdh2 v0.0.0-20230829114801-14bf715f805e + 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 github.com/spf13/cast v1.5.1 github.com/stretchr/testify v1.8.4 diff --git a/go.sum b/go.sum index a0243097bc0..b1ec22c6350 100644 --- a/go.sum +++ b/go.sum @@ -314,6 +314,8 @@ github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.m github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/envoyproxy/protoc-gen-validate v1.0.2 h1:QkIBuU5k+x7/QXPvPPnWXWlCdaBFApVqftFV6k087DA= +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/go-ethereum v1.12.0 h1:bdnhLPtqETd4m3mS8BGMNvBTf36bO5bx/hxE2zljOa0= github.com/ethereum/go-ethereum v1.12.0/go.mod h1:/oo2X/dZLJjf2mJ6YT9wcWxa4nNJDBKDBU6sFIpx1Gs= @@ -1375,8 +1377,8 @@ github.com/smartcontractkit/caigo v0.0.0-20230621050857-b29a4ca8c704 h1:T3lFWumv github.com/smartcontractkit/caigo v0.0.0-20230621050857-b29a4ca8c704/go.mod h1:2QuJdEouTWjh5BDy5o/vgGXQtR4Gz8yH1IYB5eT7u4M= github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20230831132059-42af68994512 h1:DojChlaudA1HAxwQPKmt/EDf36OUeFJ0LJBYClauMyU= github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20230831132059-42af68994512/go.mod h1:xMwqRdj5vqYhCJXgKVqvyAwdcqM6ZAEhnwEQ4Khsop8= -github.com/smartcontractkit/chainlink-relay v0.1.7-0.20230901143551-bf6bd84d6938 h1:LnxS4RoDcUS4+zXoY/gaV4BB6u90DgW3LtyFCoCpJzY= -github.com/smartcontractkit/chainlink-relay v0.1.7-0.20230901143551-bf6bd84d6938/go.mod h1:gWclxGW7rLkbjXn7FGizYlyKhp/boekto4MEYGyiMG4= +github.com/smartcontractkit/chainlink-relay v0.1.7-0.20230908162043-e2f9fcf758d8 h1:JRXkI/eE1S0E3VatXVc24vD5e8Zu+YwSV6uSvOh23xU= +github.com/smartcontractkit/chainlink-relay v0.1.7-0.20230908162043-e2f9fcf758d8/go.mod h1:gWclxGW7rLkbjXn7FGizYlyKhp/boekto4MEYGyiMG4= github.com/smartcontractkit/chainlink-solana v1.0.3-0.20230831134610-680240b97aca h1:x7M0m512gtXw5Z4B1WJPZ52VgshoIv+IvHqQ8hsH4AE= github.com/smartcontractkit/chainlink-solana v1.0.3-0.20230831134610-680240b97aca/go.mod h1:RIUJXn7EVp24TL2p4FW79dYjyno23x5mjt1nKN+5WEk= github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20230901115736-bbabe542a918 h1:ByVauKFXphRlSNG47lNuxZ9aicu+r8AoNp933VRPpCw= @@ -1387,16 +1389,16 @@ github.com/smartcontractkit/grpc-proxy v0.0.0-20230731113816-f1be6620749f h1:hgJ github.com/smartcontractkit/grpc-proxy v0.0.0-20230731113816-f1be6620749f/go.mod h1:MvMXoufZAtqExNexqi4cjrNYE9MefKddKylxjS+//n0= github.com/smartcontractkit/libocr v0.0.0-20230816220705-665e93233ae5 h1:rzbqGoScs9VHGnyCKF7AoQEuUfwJnzcKmGIfaczeanA= github.com/smartcontractkit/libocr v0.0.0-20230816220705-665e93233ae5/go.mod h1:2lyRkw/qLQgUWlrWWmq5nj0y90rWeO6Y+v+fCakRgb0= -github.com/smartcontractkit/ocr2keepers v0.7.19 h1:w9CMs1V8pmxdRX6ME98goIRPMuN9DOkfMmZHeDPDQXY= -github.com/smartcontractkit/ocr2keepers v0.7.19/go.mod h1:AjcIEKeNnU7NRlvnuMCTjBIQ1kpW0YHhlFdeDa/3hs0= +github.com/smartcontractkit/ocr2keepers v0.7.23 h1:hvMCHm9zTOKGELc40n+JLGmbiW1tkFnHW17qAtoVews= +github.com/smartcontractkit/ocr2keepers v0.7.23/go.mod h1:AjcIEKeNnU7NRlvnuMCTjBIQ1kpW0YHhlFdeDa/3hs0= github.com/smartcontractkit/ocr2vrf v0.0.0-20230804151440-2f1eb1e20687 h1:NwC3SOc25noBTe1KUQjt45fyTIuInhoE2UfgcHAdihM= github.com/smartcontractkit/ocr2vrf v0.0.0-20230804151440-2f1eb1e20687/go.mod h1:YYZq52t4wcHoMQeITksYsorD+tZcOyuVU5+lvot3VFM= github.com/smartcontractkit/sqlx v1.3.5-0.20210805004948-4be295aacbeb h1:OMaBUb4X9IFPLbGbCHsMU+kw/BPCrewaVwWGIBc0I4A= github.com/smartcontractkit/sqlx v1.3.5-0.20210805004948-4be295aacbeb/go.mod h1:HNUu4cJekUdsJbwRBCiOybtkPJEfGRELQPe2tkoDEyk= -github.com/smartcontractkit/tdh2/go/ocr2/decryptionplugin v0.0.0-20230829114801-14bf715f805e h1:faa7bAs8xCVsnJoNmAtV18la0wqBoaWSWFqNdjkPdAw= -github.com/smartcontractkit/tdh2/go/ocr2/decryptionplugin v0.0.0-20230829114801-14bf715f805e/go.mod h1:q6f4fe39oZPdsh1i57WznEZgxd8siidMaSFq3wdPmVg= -github.com/smartcontractkit/tdh2/go/tdh2 v0.0.0-20230829114801-14bf715f805e h1:JMCSFOQIYOh7zUYi9C3UQG9Lz5ECNejTURBN+Khhwz4= -github.com/smartcontractkit/tdh2/go/tdh2 v0.0.0-20230829114801-14bf715f805e/go.mod h1:G5Sd/yzHWf26rQ+X0nG9E0buKPqRGPMJAfk2gwCzOOw= +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/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= diff --git a/integration-tests/actions/actions_local.go b/integration-tests/actions/actions_local.go new file mode 100644 index 00000000000..d2e2fde3217 --- /dev/null +++ b/integration-tests/actions/actions_local.go @@ -0,0 +1,25 @@ +// Package actions enables common chainlink interactions +package actions + +import ( + "github.com/pkg/errors" + + "github.com/smartcontractkit/chainlink/integration-tests/docker/test_env" +) + +// UpgradeChainlinkNodeVersions upgrades all Chainlink nodes to a new version, and then runs the test environment +// to apply the upgrades +func UpgradeChainlinkNodeVersionsLocal( + newImage, newVersion string, + nodes ...*test_env.ClNode, +) error { + if newImage == "" && newVersion == "" { + return errors.New("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(node.NodeConfig, newImage, newVersion); err != nil { + return err + } + } + return nil +} diff --git a/integration-tests/actions/automation_ocr_helpers_local.go b/integration-tests/actions/automation_ocr_helpers_local.go new file mode 100644 index 00000000000..dce55e42275 --- /dev/null +++ b/integration-tests/actions/automation_ocr_helpers_local.go @@ -0,0 +1,258 @@ +package actions + +//revive:disable:dot-imports +import ( + "encoding/json" + "fmt" + "testing" + "time" + + "github.com/ethereum/go-ethereum/common" + "github.com/lib/pq" + "github.com/pkg/errors" + "github.com/rs/zerolog/log" + "github.com/stretchr/testify/require" + "gopkg.in/guregu/null.v4" + + "github.com/smartcontractkit/chainlink-testing-framework/utils" + "github.com/smartcontractkit/chainlink/integration-tests/client" + "github.com/smartcontractkit/chainlink/integration-tests/contracts" + "github.com/smartcontractkit/chainlink/integration-tests/contracts/ethereum" + ocr2 "github.com/smartcontractkit/libocr/offchainreporting2plus/confighelper" + ocr3 "github.com/smartcontractkit/libocr/offchainreporting2plus/ocr3confighelper" + "github.com/smartcontractkit/libocr/offchainreporting2plus/types" + ocr2keepers20config "github.com/smartcontractkit/ocr2keepers/pkg/v2/config" + ocr2keepers30config "github.com/smartcontractkit/ocr2keepers/pkg/v3/config" + + "github.com/smartcontractkit/chainlink/v2/core/services/job" + "github.com/smartcontractkit/chainlink/v2/core/services/keystore/chaintype" + "github.com/smartcontractkit/chainlink/v2/core/store/models" +) + +func BuildAutoOCR2ConfigVarsLocal( + t *testing.T, + chainlinkNodes []*client.ChainlinkClient, + registryConfig contracts.KeeperRegistrySettings, + registrar string, + deltaStage time.Duration, +) (contracts.OCRv2Config, error) { + return BuildAutoOCR2ConfigVarsWithKeyIndexLocal(t, chainlinkNodes, registryConfig, registrar, deltaStage, 0) +} + +func BuildAutoOCR2ConfigVarsWithKeyIndexLocal( + t *testing.T, + chainlinkNodes []*client.ChainlinkClient, + registryConfig contracts.KeeperRegistrySettings, + registrar string, + deltaStage time.Duration, + keyIndex int, +) (contracts.OCRv2Config, error) { + l := utils.GetTestLogger(t) + S, oracleIdentities, err := GetOracleIdentitiesWithKeyIndexLocal(chainlinkNodes, keyIndex) + if err != nil { + return contracts.OCRv2Config{}, err + } + + var offC []byte + var signerOnchainPublicKeys []types.OnchainPublicKey + var transmitterAccounts []types.Account + var f uint8 + var offchainConfigVersion uint64 + var offchainConfig []byte + + if registryConfig.RegistryVersion == ethereum.RegistryVersion_2_1 { + offC, err = json.Marshal(ocr2keepers30config.OffchainConfig{ + TargetProbability: "0.999", + TargetInRounds: 1, + PerformLockoutWindow: 3600000, // Intentionally set to be higher than in prod for testing purpose + GasLimitPerReport: 5_300_000, + GasOverheadPerUpkeep: 300_000, + MinConfirmations: 0, + MaxUpkeepBatchSize: 1, + }) + if err != nil { + return contracts.OCRv2Config{}, err + } + + signerOnchainPublicKeys, transmitterAccounts, f, _, offchainConfigVersion, offchainConfig, err = ocr3.ContractSetConfigArgsForTests( + 10*time.Second, // deltaProgress time.Duration, + 15*time.Second, // deltaResend time.Duration, + 500*time.Millisecond, // deltaInitial time.Duration, + 1000*time.Millisecond, // deltaRound time.Duration, + 200*time.Millisecond, // deltaGrace time.Duration, + 300*time.Millisecond, // deltaCertifiedCommitRequest time.Duration + deltaStage, // deltaStage time.Duration, + 24, // rMax uint64, + S, // s []int, + oracleIdentities, // oracles []OracleIdentityExtra, + offC, // reportingPluginConfig []byte, + 20*time.Millisecond, // maxDurationQuery time.Duration, + 20*time.Millisecond, // maxDurationObservation time.Duration, // good to here + 1200*time.Millisecond, // maxDurationShouldAcceptAttestedReport time.Duration, + 20*time.Millisecond, // maxDurationShouldTransmitAcceptedReport time.Duration, + 1, // f int, + nil, // onchainConfig []byte, + ) + if err != nil { + return contracts.OCRv2Config{}, err + } + } else { + offC, err = json.Marshal(ocr2keepers20config.OffchainConfig{ + TargetProbability: "0.999", + TargetInRounds: 1, + PerformLockoutWindow: 3600000, // Intentionally set to be higher than in prod for testing purpose + GasLimitPerReport: 5_300_000, + GasOverheadPerUpkeep: 300_000, + SamplingJobDuration: 3000, + MinConfirmations: 0, + MaxUpkeepBatchSize: 1, + }) + if err != nil { + return contracts.OCRv2Config{}, err + } + + signerOnchainPublicKeys, transmitterAccounts, f, _, offchainConfigVersion, offchainConfig, err = ocr2.ContractSetConfigArgsForTests( + 10*time.Second, // deltaProgress time.Duration, + 15*time.Second, // deltaResend time.Duration, + 3000*time.Millisecond, // deltaRound time.Duration, + 200*time.Millisecond, // deltaGrace time.Duration, + deltaStage, // deltaStage time.Duration, + 24, // rMax uint8, + S, // s []int, + oracleIdentities, // oracles []OracleIdentityExtra, + offC, // reportingPluginConfig []byte, + 20*time.Millisecond, // maxDurationQuery time.Duration, + 20*time.Millisecond, // maxDurationObservation time.Duration, + 1200*time.Millisecond, // maxDurationReport time.Duration, + 20*time.Millisecond, // maxDurationShouldAcceptFinalizedReport time.Duration, + 20*time.Millisecond, // maxDurationShouldTransmitAcceptedReport time.Duration, + 1, // f int, + nil, // onchainConfig []byte, + ) + if err != nil { + return contracts.OCRv2Config{}, err + } + } + + var signers []common.Address + for _, signer := range signerOnchainPublicKeys { + require.Equal(t, 20, len(signer), "OnChainPublicKey '%v' has wrong length for address", signer) + signers = append(signers, common.BytesToAddress(signer)) + } + + var transmitters []common.Address + for _, transmitter := range transmitterAccounts { + require.True(t, common.IsHexAddress(string(transmitter)), "TransmitAccount '%s' is not a valid Ethereum address", string(transmitter)) + transmitters = append(transmitters, common.HexToAddress(string(transmitter))) + } + + onchainConfig, err := registryConfig.EncodeOnChainConfig(registrar) + if err != nil { + return contracts.OCRv2Config{}, err + } + + l.Info().Msg("Done building OCR config") + return contracts.OCRv2Config{ + Signers: signers, + Transmitters: transmitters, + F: f, + OnchainConfig: onchainConfig, + OffchainConfigVersion: offchainConfigVersion, + OffchainConfig: offchainConfig, + }, nil +} + +// CreateOCRKeeperJobs bootstraps the first node and to the other nodes sends ocr jobs +func CreateOCRKeeperJobsLocal( + chainlinkNodes []*client.ChainlinkClient, + registryAddr string, + chainID int64, + keyIndex int, + registryVersion ethereum.KeeperRegistryVersion, +) error { + bootstrapNode := chainlinkNodes[0] + bootstrapP2PIds, err := bootstrapNode.MustReadP2PKeys() + if err != nil { + log.Error().Err(err).Msg("Shouldn't fail reading P2P keys from bootstrap node") + return err + } + bootstrapP2PId := bootstrapP2PIds.Data[0].Attributes.PeerID + + var contractVersion string + if registryVersion == ethereum.RegistryVersion_2_1 { + contractVersion = "v2.1" + } else if registryVersion == ethereum.RegistryVersion_2_0 { + contractVersion = "v2.0" + } else { + return errors.New("v2.0 and v2.1 are the only supported versions") + } + + bootstrapSpec := &client.OCR2TaskJobSpec{ + Name: "ocr2 bootstrap node " + registryAddr, + JobType: "bootstrap", + OCR2OracleSpec: job.OCR2OracleSpec{ + ContractID: registryAddr, + Relay: "evm", + RelayConfig: map[string]interface{}{ + "chainID": int(chainID), + }, + ContractConfigTrackerPollInterval: *models.NewInterval(time.Second * 15), + }, + } + _, err = bootstrapNode.MustCreateJob(bootstrapSpec) + if err != nil { + log.Error().Err(err).Msg("Shouldn't fail creating bootstrap job on bootstrap node") + return err + } + + P2Pv2Bootstrapper := fmt.Sprintf("%s@%s:%d", bootstrapP2PId, bootstrapNode.InternalIP(), 6690) + for nodeIndex := 1; nodeIndex < len(chainlinkNodes); nodeIndex++ { + nodeTransmitterAddress, err := chainlinkNodes[nodeIndex].EthAddresses() + if err != nil { + log.Error().Err(err).Msgf("Shouldn't fail getting primary ETH address from OCR node %d", nodeIndex+1) + return err + } + nodeOCRKeys, err := chainlinkNodes[nodeIndex].MustReadOCR2Keys() + if err != nil { + log.Error().Err(err).Msgf("Shouldn't fail getting OCR keys from OCR node %d", nodeIndex+1) + return err + } + var nodeOCRKeyId []string + for _, key := range nodeOCRKeys.Data { + if key.Attributes.ChainType == string(chaintype.EVM) { + nodeOCRKeyId = append(nodeOCRKeyId, key.ID) + break + } + } + + autoOCR2JobSpec := client.OCR2TaskJobSpec{ + Name: "ocr2 " + registryAddr, + JobType: "offchainreporting2", + OCR2OracleSpec: job.OCR2OracleSpec{ + PluginType: "ocr2automation", + Relay: "evm", + RelayConfig: map[string]interface{}{ + "chainID": int(chainID), + }, + PluginConfig: map[string]interface{}{ + "mercuryCredentialName": "\"cred1\"", + "contractVersion": "\"" + contractVersion + "\"", + }, + ContractConfigTrackerPollInterval: *models.NewInterval(time.Second * 15), + ContractID: registryAddr, // registryAddr + OCRKeyBundleID: null.StringFrom(nodeOCRKeyId[0]), // get node ocr2config.ID + TransmitterID: null.StringFrom(nodeTransmitterAddress[keyIndex]), // node addr + P2PV2Bootstrappers: pq.StringArray{P2Pv2Bootstrapper}, // bootstrap node key and address @bootstrap:8000 + }, + } + + _, err = chainlinkNodes[nodeIndex].MustCreateJob(&autoOCR2JobSpec) + if err != nil { + log.Error().Err(err).Msgf("Shouldn't fail creating OCR Task job on OCR node %d err: %+v", nodeIndex+1, err) + return err + } + + } + log.Info().Msg("Done creating OCR automation jobs") + return nil +} diff --git a/integration-tests/benchmark/keeper_test.go b/integration-tests/benchmark/keeper_test.go index 6ce0fb7138f..fbabfab78cc 100644 --- a/integration-tests/benchmark/keeper_test.go +++ b/integration-tests/benchmark/keeper_test.go @@ -20,11 +20,12 @@ import ( "github.com/smartcontractkit/chainlink-testing-framework/blockchain" "github.com/smartcontractkit/chainlink-testing-framework/utils" + "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/contracts" eth_contracts "github.com/smartcontractkit/chainlink/integration-tests/contracts/ethereum" - "github.com/smartcontractkit/chainlink/integration-tests/networks" "github.com/smartcontractkit/chainlink/integration-tests/testsetups" ) diff --git a/integration-tests/chaos/automation_chaos_test.go b/integration-tests/chaos/automation_chaos_test.go index 0da3271785e..bb7fe1b8f00 100644 --- a/integration-tests/chaos/automation_chaos_test.go +++ b/integration-tests/chaos/automation_chaos_test.go @@ -20,11 +20,12 @@ import ( "github.com/smartcontractkit/chainlink-testing-framework/blockchain" "github.com/smartcontractkit/chainlink-testing-framework/utils" + "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/contracts" eth_contracts "github.com/smartcontractkit/chainlink/integration-tests/contracts/ethereum" - "github.com/smartcontractkit/chainlink/integration-tests/networks" ) var ( diff --git a/integration-tests/chaos/ocr2vrf_chaos_test.go b/integration-tests/chaos/ocr2vrf_chaos_test.go index 7d10107ba56..91c9084d408 100644 --- a/integration-tests/chaos/ocr2vrf_chaos_test.go +++ b/integration-tests/chaos/ocr2vrf_chaos_test.go @@ -18,13 +18,14 @@ import ( "github.com/smartcontractkit/chainlink-testing-framework/blockchain" "github.com/smartcontractkit/chainlink-testing-framework/utils" + "github.com/smartcontractkit/chainlink-testing-framework/networks" + "github.com/smartcontractkit/chainlink/integration-tests/actions" "github.com/smartcontractkit/chainlink/integration-tests/actions/ocr2vrf_actions" "github.com/smartcontractkit/chainlink/integration-tests/actions/ocr2vrf_actions/ocr2vrf_constants" "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/networks" ) func TestOCR2VRFChaos(t *testing.T) { diff --git a/integration-tests/chaos/ocr_chaos_test.go b/integration-tests/chaos/ocr_chaos_test.go index 58b4d5bea65..1e5b8451454 100644 --- a/integration-tests/chaos/ocr_chaos_test.go +++ b/integration-tests/chaos/ocr_chaos_test.go @@ -22,11 +22,12 @@ import ( ctfClient "github.com/smartcontractkit/chainlink-testing-framework/client" "github.com/smartcontractkit/chainlink-testing-framework/utils" + "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/config" "github.com/smartcontractkit/chainlink/integration-tests/contracts" - "github.com/smartcontractkit/chainlink/integration-tests/networks" ) var ( diff --git a/integration-tests/contracts/contract_loader.go b/integration-tests/contracts/contract_loader.go index 7517ef7ba7e..2c079a61b8b 100644 --- a/integration-tests/contracts/contract_loader.go +++ b/integration-tests/contracts/contract_loader.go @@ -2,6 +2,7 @@ package contracts import ( "errors" + "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" @@ -12,6 +13,8 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/authorized_forwarder" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/link_token_interface" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/operator_wrapper" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/llo-feeds/generated/verifier" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/llo-feeds/generated/verifier_proxy" ) // ContractLoader is an interface for abstracting the contract loading methods across network implementations @@ -24,6 +27,10 @@ type ContractLoader interface { LoadFunctionsCoordinator(addr string) (FunctionsCoordinator, error) LoadFunctionsRouter(addr string) (FunctionsRouter, error) LoadFunctionsLoadTestClient(addr string) (FunctionsLoadTestClient, error) + + // Mercury + LoadMercuryVerifier(addr string) (MercuryVerifier, error) + LoadMercuryVerifierProxy(addr string) (MercuryVerifierProxy, error) } // NewContractLoader returns an instance of a contract Loader based on the client type @@ -189,3 +196,39 @@ func (e *EthereumContractLoader) LoadAuthorizedForwarder(address common.Address) authorizedForwarder: instance.(*authorized_forwarder.AuthorizedForwarder), }, err } + +// LoadMercuryVerifier returns Verifier contract deployed on given address +func (e *EthereumContractLoader) LoadMercuryVerifier(addr string) (MercuryVerifier, error) { + instance, err := e.client.LoadContract("Mercury Verifier", common.HexToAddress(addr), func( + address common.Address, + backend bind.ContractBackend, + ) (interface{}, error) { + return verifier.NewVerifier(address, backend) + }) + if err != nil { + return nil, err + } + return &EthereumMercuryVerifier{ + client: e.client, + instance: instance.(*verifier.Verifier), + address: common.HexToAddress(addr), + }, err +} + +// LoadMercuryVerifierProxy returns VerifierProxy contract deployed on given address +func (e *EthereumContractLoader) LoadMercuryVerifierProxy(addr string) (MercuryVerifierProxy, error) { + instance, err := e.client.LoadContract("Mercury Verifier Proxy", common.HexToAddress(addr), func( + address common.Address, + backend bind.ContractBackend, + ) (interface{}, error) { + return verifier_proxy.NewVerifierProxy(address, backend) + }) + if err != nil { + return nil, err + } + return &EthereumMercuryVerifierProxy{ + client: e.client, + instance: instance.(*verifier_proxy.VerifierProxy), + address: common.HexToAddress(addr), + }, err +} diff --git a/integration-tests/contracts/contract_models.go b/integration-tests/contracts/contract_models.go index 941eba73ebf..7bcddceae5e 100644 --- a/integration-tests/contracts/contract_models.go +++ b/integration-tests/contracts/contract_models.go @@ -365,4 +365,16 @@ type FunctionsLoadTestClient interface { ResetStats() error GetStats() (*EthereumFunctionsLoadStats, error) SendRequest(times uint32, source string, encryptedSecretsReferences []byte, args []string, subscriptionId uint64, jobId [32]byte) error + SendRequestWithDONHostedSecrets(times uint32, source string, slotID uint8, slotVersion uint64, args []string, subscriptionId uint64, donID [32]byte) error +} + +type MercuryVerifier interface { + Address() string + Verify(signedReport []byte, sender common.Address) error +} + +type MercuryVerifierProxy interface { + Address() string + Verify(signedReport []byte, value *big.Int) (*types.Transaction, error) + VerifyBulk(signedReports [][]byte, value *big.Int) (*types.Transaction, error) } diff --git a/integration-tests/contracts/ethereum_contracts.go b/integration-tests/contracts/ethereum_contracts.go index 8f80ed3896c..763faecace7 100644 --- a/integration-tests/contracts/ethereum_contracts.go +++ b/integration-tests/contracts/ethereum_contracts.go @@ -46,6 +46,8 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/operator_wrapper" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/oracle_wrapper" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/test_api_consumer_wrapper" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/llo-feeds/generated/verifier" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/llo-feeds/generated/verifier_proxy" ) // EthereumOracle oracle for "directrequest" job tests @@ -2197,8 +2199,8 @@ func (e *EthereumFunctionsLoadTestClient) GetStats() (*EthereumFunctionsLoadStat } return &EthereumFunctionsLoadStats{ LastRequestID: string(Bytes32ToSlice(lr)), - LastResponse: string(Bytes32ToSlice(lbody)), - LastError: string(Bytes32ToSlice(lerr)), + LastResponse: string(lbody), + LastError: string(lerr), Total: total, Succeeded: succeeded, Errored: errored, @@ -2232,3 +2234,77 @@ func (e *EthereumFunctionsLoadTestClient) SendRequest(times uint32, source strin } return e.client.ProcessTransaction(tx) } + +func (e *EthereumFunctionsLoadTestClient) SendRequestWithDONHostedSecrets(times uint32, source string, slotID uint8, slotVersion uint64, args []string, subscriptionId uint64, donID [32]byte) error { + opts, err := e.client.TransactionOpts(e.client.GetDefaultWallet()) + if err != nil { + return err + } + tx, err := e.instance.SendRequestWithDONHostedSecrets(opts, times, source, slotID, slotVersion, args, subscriptionId, donID) + if err != nil { + return err + } + return e.client.ProcessTransaction(tx) +} + +type EthereumMercuryVerifier struct { + address common.Address + client blockchain.EVMClient + instance *verifier.Verifier +} + +func (e *EthereumMercuryVerifier) Address() string { + return e.address.Hex() +} + +func (e *EthereumMercuryVerifier) Verify(signedReport []byte, sender common.Address) error { + opts, err := e.client.TransactionOpts(e.client.GetDefaultWallet()) + if err != nil { + return err + } + tx, err := e.instance.Verify(opts, signedReport, sender) + if err != nil { + return err + } + return e.client.ProcessTransaction(tx) +} + +type EthereumMercuryVerifierProxy struct { + address common.Address + client blockchain.EVMClient + instance *verifier_proxy.VerifierProxy +} + +func (e *EthereumMercuryVerifierProxy) Address() string { + return e.address.Hex() +} + +func (e *EthereumMercuryVerifierProxy) Verify(signedReport []byte, value *big.Int) (*types.Transaction, error) { + opts, err := e.client.TransactionOpts(e.client.GetDefaultWallet()) + if value != nil { + opts.Value = value + } + if err != nil { + return nil, err + } + tx, err := e.instance.Verify(opts, signedReport) + if err != nil { + return nil, err + } + return tx, e.client.ProcessTransaction(tx) +} + +func (e *EthereumMercuryVerifierProxy) VerifyBulk(signedReports [][]byte, value *big.Int) (*types.Transaction, error) { + opts, err := e.client.TransactionOpts(e.client.GetDefaultWallet()) + if value != nil { + opts.Value = value + } + if err != nil { + return nil, err + } + tx, err := e.instance.VerifyBulk(opts, signedReports) + if err != nil { + return nil, err + } + return tx, e.client.ProcessTransaction(tx) +} diff --git a/integration-tests/contracts/ethereum_keeper_contracts.go b/integration-tests/contracts/ethereum_keeper_contracts.go index e4279c8bceb..67d26960585 100644 --- a/integration-tests/contracts/ethereum_keeper_contracts.go +++ b/integration-tests/contracts/ethereum_keeper_contracts.go @@ -76,6 +76,7 @@ type KeeperRegistry interface { PauseUpkeep(id *big.Int) error UnpauseUpkeep(id *big.Int) error UpdateCheckData(id *big.Int, newCheckData []byte) error + SetUpkeepTriggerConfig(id *big.Int, triggerConfig []byte) error } type KeeperConsumer interface { @@ -903,6 +904,26 @@ func (v *EthereumKeeperRegistry) UpdateCheckData(id *big.Int, newCheckData []byt } } +// SetUpkeepTriggerConfig updates the trigger config of an upkeep (only for version 2.1) +func (v *EthereumKeeperRegistry) SetUpkeepTriggerConfig(id *big.Int, triggerConfig []byte) error { + + switch v.version { + case ethereum.RegistryVersion_2_1: + opts, err := v.client.TransactionOpts(v.client.GetDefaultWallet()) + if err != nil { + return err + } + + tx, err := v.registry2_1.SetUpkeepTriggerConfig(opts, id, triggerConfig) + if err != nil { + return err + } + return v.client.ProcessTransaction(tx) + default: + return fmt.Errorf("SetUpkeepTriggerConfig is not supported by keeper registry version %d", v.version) + } +} + // PauseUpkeep stops an upkeep from an upkeep func (v *EthereumKeeperRegistry) PauseUpkeep(id *big.Int) error { switch v.version { diff --git a/integration-tests/docker/test_env/cl_node.go b/integration-tests/docker/test_env/cl_node.go index a78f9e52ad6..4c2213b03ee 100644 --- a/integration-tests/docker/test_env/cl_node.go +++ b/integration-tests/docker/test_env/cl_node.go @@ -46,6 +46,8 @@ type ClNode struct { NodeSecretsConfigTOML string PostgresDb *test_env.PostgresDb lw *logwatch.LogWatch + ContainerImage string + ContainerVersion string } type ClNodeOption = func(c *ClNode) @@ -101,6 +103,19 @@ func (n *ClNode) Restart(cfg *chainlink.Config) error { return n.StartContainer() } +// UpgradeVersion restarts the cl node with new image and version +func (n *ClNode) UpgradeVersion(cfg *chainlink.Config, newImage, newVersion string) error { + if newVersion == "" { + return fmt.Errorf("new version is empty") + } + if newImage == "" { + newImage = os.Getenv("CHAINLINK_IMAGE") + } + n.ContainerImage = newImage + n.ContainerVersion = newVersion + return n.Restart(n.NodeConfig) +} + func (n *ClNode) PrimaryETHAddress() (string, error) { return n.API.PrimaryEthAddress() } @@ -203,7 +218,6 @@ func (n *ClNode) Fund(evmClient blockchain.EVMClient, amount *big.Float) error { } return evmClient.Fund(toAddress, amount, gasEstimates) } - func (n *ClNode) StartContainer() error { err := n.PostgresDb.StartContainer() if err != nil { @@ -313,18 +327,24 @@ func (n *ClNode) getContainerRequest() ( adminCredsPath := "/home/admin-credentials.txt" apiCredsPath := "/home/api-credentials.txt" - image, ok := os.LookupEnv("CHAINLINK_IMAGE") - if !ok { - return nil, errors.New("CHAINLINK_IMAGE env must be set") + if n.ContainerImage == "" { + image, ok := os.LookupEnv("CHAINLINK_IMAGE") + if !ok { + return nil, errors.New("CHAINLINK_IMAGE env must be set") + } + n.ContainerImage = image } - tag, ok := os.LookupEnv("CHAINLINK_VERSION") - if !ok { - return nil, errors.New("CHAINLINK_VERSION env must be set") + if n.ContainerVersion == "" { + version, ok := os.LookupEnv("CHAINLINK_VERSION") + if !ok { + return nil, errors.New("CHAINLINK_VERSION env must be set") + } + n.ContainerVersion = version } return &tc.ContainerRequest{ Name: n.ContainerName, - Image: fmt.Sprintf("%s:%s", image, tag), + Image: fmt.Sprintf("%s:%s", n.ContainerImage, n.ContainerVersion), ExposedPorts: []string{"6688/tcp"}, Entrypoint: []string{"chainlink", "-c", configPath, diff --git a/integration-tests/docker/test_env/test_env_builder.go b/integration-tests/docker/test_env/test_env_builder.go index 27f98b36139..7726c115fff 100644 --- a/integration-tests/docker/test_env/test_env_builder.go +++ b/integration-tests/docker/test_env/test_env_builder.go @@ -12,8 +12,9 @@ import ( "github.com/smartcontractkit/chainlink-testing-framework/logwatch" "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" + "github.com/smartcontractkit/chainlink-testing-framework/networks" + "github.com/smartcontractkit/chainlink/integration-tests/contracts" - "github.com/smartcontractkit/chainlink/integration-tests/networks" "github.com/smartcontractkit/chainlink/integration-tests/types/config/node" ) diff --git a/integration-tests/go.mod b/integration-tests/go.mod index d3a8b5a19cb..21ee3231280 100644 --- a/integration-tests/go.mod +++ b/integration-tests/go.mod @@ -20,12 +20,12 @@ require ( github.com/rs/zerolog v1.30.0 github.com/slack-go/slack v0.12.2 github.com/smartcontractkit/chainlink-env v0.36.0 - github.com/smartcontractkit/chainlink-testing-framework v1.16.1-0.20230829222228-4afd1b3d385c + github.com/smartcontractkit/chainlink-testing-framework v1.16.5-0.20230908202859-e75102cf5f40 github.com/smartcontractkit/chainlink/v2 v2.0.0-00010101000000-000000000000 github.com/smartcontractkit/libocr v0.0.0-20230816220705-665e93233ae5 - github.com/smartcontractkit/ocr2keepers v0.7.19 + github.com/smartcontractkit/ocr2keepers v0.7.23 github.com/smartcontractkit/ocr2vrf v0.0.0-20230804151440-2f1eb1e20687 - github.com/smartcontractkit/tdh2/go/tdh2 v0.0.0-20230829114801-14bf715f805e + github.com/smartcontractkit/tdh2/go/tdh2 v0.0.0-20230906073235-9e478e5e19f1 github.com/smartcontractkit/wasp v0.3.0 github.com/spf13/cobra v1.6.1 github.com/stretchr/testify v1.8.4 @@ -131,6 +131,7 @@ require ( github.com/dvsekhvalnov/jose2go v1.5.0 // indirect github.com/edsrzf/mmap-go v1.1.0 // indirect github.com/emicklei/go-restful/v3 v3.10.1 // indirect + github.com/esote/minmaxheap v1.0.0 // indirect github.com/evanphx/json-patch v5.6.0+incompatible // indirect github.com/evanphx/json-patch/v5 v5.6.0 // indirect github.com/exponent-io/jsonpath v0.0.0-20210407135951-1de76d718b3f // indirect @@ -230,7 +231,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.2 // indirect + github.com/holiman/uint256 v1.2.3 // indirect github.com/huandu/skiplist v1.2.0 // indirect github.com/huin/goupnp v1.0.3 // indirect github.com/imdario/mergo v0.3.16 // indirect @@ -359,7 +360,7 @@ require ( github.com/petermattis/goid v0.0.0-20230317030725-371a4b8eda08 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c // indirect - github.com/prometheus/alertmanager v0.25.0 // indirect + github.com/prometheus/alertmanager v0.25.1 // indirect github.com/prometheus/client_golang v1.16.0 // indirect github.com/prometheus/client_model v0.4.0 // indirect github.com/prometheus/common v0.44.0 // indirect @@ -383,11 +384,11 @@ require ( 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.20230831132059-42af68994512 // indirect - github.com/smartcontractkit/chainlink-relay v0.1.7-0.20230901143551-bf6bd84d6938 // indirect + github.com/smartcontractkit/chainlink-relay v0.1.7-0.20230908162043-e2f9fcf758d8 // indirect github.com/smartcontractkit/chainlink-solana v1.0.3-0.20230831134610-680240b97aca // indirect github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20230901115736-bbabe542a918 // indirect github.com/smartcontractkit/sqlx v1.3.5-0.20210805004948-4be295aacbeb // indirect - github.com/smartcontractkit/tdh2/go/ocr2/decryptionplugin v0.0.0-20230829114801-14bf715f805e // indirect + github.com/smartcontractkit/tdh2/go/ocr2/decryptionplugin v0.0.0-20230906073235-9e478e5e19f1 // indirect github.com/smartcontractkit/wsrpc v0.7.2 // indirect github.com/spacemonkeygo/spacelog v0.0.0-20180420211403-2296661a0572 // indirect github.com/spaolacci/murmur3 v1.1.0 // indirect diff --git a/integration-tests/go.sum b/integration-tests/go.sum index 5e77b2bddcc..e1a781be190 100644 --- a/integration-tests/go.sum +++ b/integration-tests/go.sum @@ -896,6 +896,8 @@ github.com/envoyproxy/protoc-gen-validate v0.6.7/go.mod h1:dyJXwwfPK2VSqiB9Klm1J github.com/envoyproxy/protoc-gen-validate v0.9.1/go.mod h1:OKNgG7TCp5pF4d6XftA0++PMirau2/yoOwVac3AbF2w= github.com/envoyproxy/protoc-gen-validate v0.10.0/go.mod h1:DRjgyB0I43LtJapqN6NiRwroiAU2PaFuvk/vjgh61ss= github.com/envoyproxy/protoc-gen-validate v0.10.1 h1:c0g45+xCJhdgFGw7a5QAfdS4byAbud7miNWJ1WwEVf8= +github.com/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/go-ethereum v1.12.0 h1:bdnhLPtqETd4m3mS8BGMNvBTf36bO5bx/hxE2zljOa0= github.com/ethereum/go-ethereum v1.12.0/go.mod h1:/oo2X/dZLJjf2mJ6YT9wcWxa4nNJDBKDBU6sFIpx1Gs= @@ -1393,8 +1395,8 @@ github.com/henvic/httpretty v0.0.6 h1:JdzGzKZBajBfnvlMALXXMVQWxWMF/ofTy8C3/OSUTx github.com/hetznercloud/hcloud-go v1.41.0 h1:KJGFRRc68QiVu4PrEP5BmCQVveCP2CM26UGQUKGpIUs= 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.2 h1:TXKcSGc2WaxPD2+bmzAsVthL4+pEN0YwXcL5qED83vk= -github.com/holiman/uint256 v1.2.2/go.mod h1:SC8Ryt4n+UBbPbIBKaG9zbbDlp4jOru9xFZmPzLUTxw= +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/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= @@ -2117,8 +2119,8 @@ github.com/posener/complete v1.2.3/go.mod h1:WZIdtGGp+qx0sLrYKtIRAruyNpv6hFCicSg github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c h1:ncq/mPwQF4JjgDlrVEn3C11VoGHZN7m8qihwgMEtzYw= github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE= github.com/pressly/goose/v3 v3.15.0 h1:6tY5aDqFknY6VZkorFGgZtWygodZQxfmmEF4rqyJW9k= -github.com/prometheus/alertmanager v0.25.0 h1:vbXKUR6PYRiZPRIKfmXaG+dmCKG52RtPL4Btl8hQGvg= -github.com/prometheus/alertmanager v0.25.0/go.mod h1:MEZ3rFVHqKZsw7IcNS/m4AWZeXThmJhumpiWR4eHU/w= +github.com/prometheus/alertmanager v0.25.1 h1:LGBNMspOfv8h7brb+LWj2wnwBCg2ZuuKWTh6CAVw2/Y= +github.com/prometheus/alertmanager v0.25.1/go.mod h1:MEZ3rFVHqKZsw7IcNS/m4AWZeXThmJhumpiWR4eHU/w= github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso= github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= @@ -2250,30 +2252,30 @@ github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20230831132059-42af6899451 github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20230831132059-42af68994512/go.mod h1:xMwqRdj5vqYhCJXgKVqvyAwdcqM6ZAEhnwEQ4Khsop8= github.com/smartcontractkit/chainlink-env v0.36.0 h1:CFOjs0c0y3lrHi/fl5qseCH9EQa5W/6CFyOvmhe2VnA= github.com/smartcontractkit/chainlink-env v0.36.0/go.mod h1:NbRExHmJGnKSYXmvNuJx5VErSx26GtE1AEN/CRzYOg8= -github.com/smartcontractkit/chainlink-relay v0.1.7-0.20230901143551-bf6bd84d6938 h1:LnxS4RoDcUS4+zXoY/gaV4BB6u90DgW3LtyFCoCpJzY= -github.com/smartcontractkit/chainlink-relay v0.1.7-0.20230901143551-bf6bd84d6938/go.mod h1:gWclxGW7rLkbjXn7FGizYlyKhp/boekto4MEYGyiMG4= +github.com/smartcontractkit/chainlink-relay v0.1.7-0.20230908162043-e2f9fcf758d8 h1:JRXkI/eE1S0E3VatXVc24vD5e8Zu+YwSV6uSvOh23xU= +github.com/smartcontractkit/chainlink-relay v0.1.7-0.20230908162043-e2f9fcf758d8/go.mod h1:gWclxGW7rLkbjXn7FGizYlyKhp/boekto4MEYGyiMG4= github.com/smartcontractkit/chainlink-solana v1.0.3-0.20230831134610-680240b97aca h1:x7M0m512gtXw5Z4B1WJPZ52VgshoIv+IvHqQ8hsH4AE= github.com/smartcontractkit/chainlink-solana v1.0.3-0.20230831134610-680240b97aca/go.mod h1:RIUJXn7EVp24TL2p4FW79dYjyno23x5mjt1nKN+5WEk= github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20230901115736-bbabe542a918 h1:ByVauKFXphRlSNG47lNuxZ9aicu+r8AoNp933VRPpCw= github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20230901115736-bbabe542a918/go.mod h1:/yp/sqD8Iz5GU5fcercjrw0ivJF7HDcupYg+Gjr7EPg= -github.com/smartcontractkit/chainlink-testing-framework v1.16.1-0.20230829222228-4afd1b3d385c h1:8/L+5JupikVsMga6z0WBElp1RgRO6BB5BF+QsBsSrOI= -github.com/smartcontractkit/chainlink-testing-framework v1.16.1-0.20230829222228-4afd1b3d385c/go.mod h1:t6FJX3akEfAO31p96ru0ilNPfE9P2UshUlXTIkI58LM= +github.com/smartcontractkit/chainlink-testing-framework v1.16.5-0.20230908202859-e75102cf5f40 h1:FWVrA9QiLjez+XmWJ9ZEHf8RgDVCA6NmAySN3bA/MXQ= +github.com/smartcontractkit/chainlink-testing-framework v1.16.5-0.20230908202859-e75102cf5f40/go.mod h1:Ry6fRPr8TwrIsYVNEF1pguAgzE3QW1s54tbLWnFtfI4= github.com/smartcontractkit/go-plugin v0.0.0-20230605132010-0f4d515d1472 h1:x3kNwgFlDmbE/n0gTSRMt9GBDfsfGrs4X9b9arPZtFI= github.com/smartcontractkit/go-plugin v0.0.0-20230605132010-0f4d515d1472/go.mod h1:6/1TEzT0eQznvI/gV2CM29DLSkAK/e58mUWKVsPaph0= github.com/smartcontractkit/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-20230816220705-665e93233ae5 h1:rzbqGoScs9VHGnyCKF7AoQEuUfwJnzcKmGIfaczeanA= github.com/smartcontractkit/libocr v0.0.0-20230816220705-665e93233ae5/go.mod h1:2lyRkw/qLQgUWlrWWmq5nj0y90rWeO6Y+v+fCakRgb0= -github.com/smartcontractkit/ocr2keepers v0.7.19 h1:w9CMs1V8pmxdRX6ME98goIRPMuN9DOkfMmZHeDPDQXY= -github.com/smartcontractkit/ocr2keepers v0.7.19/go.mod h1:AjcIEKeNnU7NRlvnuMCTjBIQ1kpW0YHhlFdeDa/3hs0= +github.com/smartcontractkit/ocr2keepers v0.7.23 h1:hvMCHm9zTOKGELc40n+JLGmbiW1tkFnHW17qAtoVews= +github.com/smartcontractkit/ocr2keepers v0.7.23/go.mod h1:AjcIEKeNnU7NRlvnuMCTjBIQ1kpW0YHhlFdeDa/3hs0= github.com/smartcontractkit/ocr2vrf v0.0.0-20230804151440-2f1eb1e20687 h1:NwC3SOc25noBTe1KUQjt45fyTIuInhoE2UfgcHAdihM= github.com/smartcontractkit/ocr2vrf v0.0.0-20230804151440-2f1eb1e20687/go.mod h1:YYZq52t4wcHoMQeITksYsorD+tZcOyuVU5+lvot3VFM= github.com/smartcontractkit/sqlx v1.3.5-0.20210805004948-4be295aacbeb h1:OMaBUb4X9IFPLbGbCHsMU+kw/BPCrewaVwWGIBc0I4A= github.com/smartcontractkit/sqlx v1.3.5-0.20210805004948-4be295aacbeb/go.mod h1:HNUu4cJekUdsJbwRBCiOybtkPJEfGRELQPe2tkoDEyk= -github.com/smartcontractkit/tdh2/go/ocr2/decryptionplugin v0.0.0-20230829114801-14bf715f805e h1:faa7bAs8xCVsnJoNmAtV18la0wqBoaWSWFqNdjkPdAw= -github.com/smartcontractkit/tdh2/go/ocr2/decryptionplugin v0.0.0-20230829114801-14bf715f805e/go.mod h1:q6f4fe39oZPdsh1i57WznEZgxd8siidMaSFq3wdPmVg= -github.com/smartcontractkit/tdh2/go/tdh2 v0.0.0-20230829114801-14bf715f805e h1:JMCSFOQIYOh7zUYi9C3UQG9Lz5ECNejTURBN+Khhwz4= -github.com/smartcontractkit/tdh2/go/tdh2 v0.0.0-20230829114801-14bf715f805e/go.mod h1:G5Sd/yzHWf26rQ+X0nG9E0buKPqRGPMJAfk2gwCzOOw= +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.3.0 h1:mueeLvpb6HyGNwILxCOKShDR6q18plQn7Gb1j3G/Qkk= github.com/smartcontractkit/wasp v0.3.0/go.mod h1:skquNdMbKxIrHi5O8Kyukf66AaaXuEpEEaSTxfHbhak= github.com/smartcontractkit/wsrpc v0.7.2 h1:iBXzMeg7vc5YoezIQBq896y25BARw7OKbhrb6vPbtRQ= diff --git a/integration-tests/load/functions/README.md b/integration-tests/load/functions/README.md index 6b80137cf48..d9eb9cc1ef3 100644 --- a/integration-tests/load/functions/README.md +++ b/integration-tests/load/functions/README.md @@ -13,21 +13,37 @@ See more config options in [config.toml](./config.toml) ## Usage -Soak `1 TX/sec - 40 requests per TX` -``` -go test -v -run TestFunctionsLoad/functions_soak_test -``` -Stress `1 TX/sec - 78 requests per TX` (max gas) -``` -go test -v -run TestFunctionsLoad/functions_stress_test -``` -Gateway `secrets_list` test +All tests are split by network and in 3 groups: +- HTTP payload only +- Secrets decoding payload only +- Realistic payload with args/http/secrets + +Load test client is [here](../../../contracts/src/v0.8/functions/tests/1_0_0/testhelpers/FunctionsLoadTestClient.sol) + +Load is controlled with 2 params: +- RPS +- requests_per_call (generating more events in a loop in the contract) + +`Soak` is a stable workload for which there **must** be no issues + +`Stress` is a peak workload for which issues **must** be analyzed + +Load test client can execute `78 calls per request` at max (gas limit) + +Functions tests: ``` -go test -v -timeout 24h -run TestGatewayLoad/gateway_secrets_list_soak_test +go test -v -run TestFunctionsLoad/mumbai_functions_soak_test_http +go test -v -run TestFunctionsLoad/mumbai_functions_stress_test_http +go test -v -run TestFunctionsLoad/mumbai_functions_soak_test_only_secrets +go test -v -run TestFunctionsLoad/mumbai_functions_stress_test_only_secrets +go test -v -run TestFunctionsLoad/mumbai_functions_soak_test_real +go test -v -run TestFunctionsLoad/mumbai_functions_stress_test_real ``` -Gateway `secrets_set` test + +Gateway tests: ``` -go test -v -timeout 24h -run TestGatewayLoad/gateway_secrets_set_soak_test +go test -v -run TestGatewayLoad/gateway_secrets_list_soak_test +go test -v -run TestGatewayLoad/gateway_secrets_set_soak_test ``` Chaos suite can be combined with any test, can be found [here](../../chaos/functions/full.yaml) diff --git a/integration-tests/load/functions/config.go b/integration-tests/load/functions/config.go index 9f0a5bda0c7..5c622401aba 100644 --- a/integration-tests/load/functions/config.go +++ b/integration-tests/load/functions/config.go @@ -18,7 +18,11 @@ const ( 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"` @@ -27,16 +31,21 @@ type PerformanceConfig struct { 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"` - FunctionsCallPayload string `toml:"functions_call_payload"` - Secrets string `toml:"secrets"` + 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 { @@ -50,12 +59,36 @@ type Soak struct { Duration *models.Duration `toml:"duration"` } +type SecretsSoak struct { + RPS int64 `toml:"rps"` + RequestsPerCall uint32 `toml:"requests_per_call"` + Duration *models.Duration `toml:"duration"` +} + +type RealSoak struct { + RPS int64 `toml:"rps"` + RequestsPerCall uint32 `toml:"requests_per_call"` + Duration *models.Duration `toml:"duration"` +} + type Stress struct { RPS int64 `toml:"rps"` RequestsPerCall uint32 `toml:"requests_per_call"` Duration *models.Duration `toml:"duration"` } +type SecretsStress struct { + RPS int64 `toml:"rps"` + RequestsPerCall uint32 `toml:"requests_per_call"` + Duration *models.Duration `toml:"duration"` +} + +type RealStress struct { + RPS int64 `toml:"rps"` + RequestsPerCall uint32 `toml:"requests_per_call"` + Duration *models.Duration `toml:"duration"` +} + type GatewayListSoak struct { RPS int64 `toml:"rps"` Duration *models.Duration `toml:"duration"` diff --git a/integration-tests/load/functions/config.toml b/integration-tests/load/functions/config.toml index a5cf4dbb379..2de3ba9282c 100644 --- a/integration-tests/load/functions/config.toml +++ b/integration-tests/load/functions/config.toml @@ -8,6 +8,26 @@ 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" @@ -20,16 +40,34 @@ duration = "10m" # Polygon Mumbai only for now receiver = "0x3098B6665589959711A48a6bAe5B7F2908f6a3bE" don_id = "fun-staging-mumbai-1" -gateway_url = "https://gateway-staging1.main.stage.cldev.sh" +gateway_url = "https://gateway-stg-one.main.stage.cldev.sh" link_token_addr = "0x326C977E6efc84E512bB9C30f76E30c160eD06FB" coordinator_addr = "0x6D6a83BB356b7242E88C1A2b290102fde26590D0" router_addr = "0x2673266D3Cd08b53494B5a92B66DEec7F1408E7A" -# comment both client and sub to automatically create a new pair -client_addr = "0x64a351fbAa61681A5a7e569Cc5A691150c4D73D2" -subscription_id = 23 + +# 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 = "const response = await Functions.makeHttpRequest({ url: 'http://dummyjson.com/products/1' }); return Functions.encodeUint256(response.data.id)" -#functions_call_payload = "return Functions.encodeUint256(BigInt(secrets.ltsecret))" -# uncomment to upload new secrets to s4 -#secrets = "{\"ltsecret\": \"1\"}" \ No newline at end of file +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 = 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 diff --git a/integration-tests/load/functions/functions_test.go b/integration-tests/load/functions/functions_test.go index 16311ac440b..7822035208e 100644 --- a/integration-tests/load/functions/functions_test.go +++ b/integration-tests/load/functions/functions_test.go @@ -21,7 +21,7 @@ func TestFunctionsLoad(t *testing.T) { MonitorLoadStats(t, ft, labels) - t.Run("functions soak test", func(t *testing.T) { + t.Run("mumbai functions soak test http", func(t *testing.T) { _, err := wasp.NewProfile(). Add(wasp.NewGenerator(&wasp.Config{ T: t, @@ -35,9 +35,11 @@ func TestFunctionsLoad(t *testing.T) { ), Gun: NewSingleFunctionCallGun( ft, + ModeHTTPPayload, cfg.Soak.RequestsPerCall, - cfg.Common.FunctionsCallPayload, - []byte{}, + cfg.Common.FunctionsCallPayloadHTTP, + cfg.Common.SecretsSlotID, + cfg.Common.SecretsVersionID, []string{}, cfg.Common.SubscriptionID, StringToByte32(cfg.Common.DONID), @@ -49,7 +51,7 @@ func TestFunctionsLoad(t *testing.T) { require.NoError(t, err) }) - t.Run("functions stress test", func(t *testing.T) { + t.Run("mumbai functions stress test http", func(t *testing.T) { _, err = wasp.NewProfile(). Add(wasp.NewGenerator(&wasp.Config{ T: t, @@ -63,9 +65,11 @@ func TestFunctionsLoad(t *testing.T) { ), Gun: NewSingleFunctionCallGun( ft, + ModeHTTPPayload, cfg.Stress.RequestsPerCall, - cfg.Common.FunctionsCallPayload, - []byte{}, + cfg.Common.FunctionsCallPayloadHTTP, + cfg.Common.SecretsSlotID, + cfg.Common.SecretsVersionID, []string{}, cfg.Common.SubscriptionID, StringToByte32(cfg.Common.DONID), @@ -76,4 +80,124 @@ func TestFunctionsLoad(t *testing.T) { Run(true) require.NoError(t, err) }) + + t.Run("mumbai functions soak test only secrets", func(t *testing.T) { + _, err := wasp.NewProfile(). + Add(wasp.NewGenerator(&wasp.Config{ + T: t, + LoadType: wasp.RPS, + GenName: "functions_soak_gen", + RateLimitUnitDuration: 5 * time.Second, + CallTimeout: 3 * time.Minute, + Schedule: wasp.Plain( + cfg.SecretsSoak.RPS, + cfg.SecretsSoak.Duration.Duration(), + ), + Gun: NewSingleFunctionCallGun( + ft, + ModeSecretsOnlyPayload, + cfg.SecretsSoak.RequestsPerCall, + cfg.Common.FunctionsCallPayloadWithSecrets, + cfg.Common.SecretsSlotID, + cfg.Common.SecretsVersionID, + []string{}, + cfg.Common.SubscriptionID, + StringToByte32(cfg.Common.DONID), + ), + Labels: labels, + LokiConfig: wasp.NewEnvLokiConfig(), + })). + Run(true) + require.NoError(t, err) + }) + + t.Run("mumbai functions stress test only secrets", func(t *testing.T) { + _, err = wasp.NewProfile(). + Add(wasp.NewGenerator(&wasp.Config{ + T: t, + LoadType: wasp.RPS, + GenName: "functions_stress_gen", + RateLimitUnitDuration: 5 * time.Second, + CallTimeout: 3 * time.Minute, + Schedule: wasp.Plain( + cfg.SecretsStress.RPS, + cfg.SecretsStress.Duration.Duration(), + ), + Gun: NewSingleFunctionCallGun( + ft, + ModeSecretsOnlyPayload, + cfg.SecretsStress.RequestsPerCall, + cfg.Common.FunctionsCallPayloadWithSecrets, + cfg.Common.SecretsSlotID, + cfg.Common.SecretsVersionID, + []string{}, + cfg.Common.SubscriptionID, + StringToByte32(cfg.Common.DONID), + ), + Labels: labels, + LokiConfig: wasp.NewEnvLokiConfig(), + })). + Run(true) + require.NoError(t, err) + }) + + t.Run("mumbai functions soak test real", func(t *testing.T) { + _, err := wasp.NewProfile(). + Add(wasp.NewGenerator(&wasp.Config{ + T: t, + LoadType: wasp.RPS, + GenName: "functions_soak_gen", + RateLimitUnitDuration: 5 * time.Second, + CallTimeout: 3 * time.Minute, + Schedule: wasp.Plain( + cfg.RealSoak.RPS, + cfg.RealSoak.Duration.Duration(), + ), + Gun: NewSingleFunctionCallGun( + ft, + ModeReal, + cfg.RealSoak.RequestsPerCall, + cfg.Common.FunctionsCallPayloadReal, + cfg.Common.SecretsSlotID, + cfg.Common.SecretsVersionID, + []string{"1", "2", "3", "4"}, + cfg.Common.SubscriptionID, + StringToByte32(cfg.Common.DONID), + ), + Labels: labels, + LokiConfig: wasp.NewEnvLokiConfig(), + })). + Run(true) + require.NoError(t, err) + }) + + t.Run("mumbai functions stress test real", func(t *testing.T) { + _, err = wasp.NewProfile(). + Add(wasp.NewGenerator(&wasp.Config{ + T: t, + LoadType: wasp.RPS, + GenName: "functions_stress_gen", + RateLimitUnitDuration: 5 * time.Second, + CallTimeout: 3 * time.Minute, + Schedule: wasp.Plain( + cfg.RealStress.RPS, + cfg.RealStress.Duration.Duration(), + ), + Gun: NewSingleFunctionCallGun( + ft, + ModeReal, + cfg.RealStress.RequestsPerCall, + cfg.Common.FunctionsCallPayloadReal, + cfg.Common.SecretsSlotID, + cfg.Common.SecretsVersionID, + []string{"1", "2", "3", "4"}, + cfg.Common.SubscriptionID, + StringToByte32(cfg.Common.DONID), + ), + Labels: labels, + LokiConfig: wasp.NewEnvLokiConfig(), + })). + Run(true) + require.NoError(t, err) + }) } diff --git a/integration-tests/load/functions/gateway.go b/integration-tests/load/functions/gateway.go index 12406c79eb1..aefe4fbedc2 100644 --- a/integration-tests/load/functions/gateway.go +++ b/integration-tests/load/functions/gateway.go @@ -49,38 +49,36 @@ type RPCResponse struct { } `json:"result"` } -func UploadS4Secrets(rc *resty.Client, s4Cfg *S4SecretsCfg) error { +func UploadS4Secrets(rc *resty.Client, s4Cfg *S4SecretsCfg) (uint8, uint64, error) { key, err := crypto.HexToECDSA(s4Cfg.PrivateKey) if err != nil { - return err + return 0, 0, err } address := crypto.PubkeyToAddress(key.PublicKey) var payloadJSON []byte - if s4Cfg.Method == functions.MethodSecretsSet { - envelope := s4.Envelope{ - Address: address.Bytes(), - SlotID: s4Cfg.S4SetSlotID, - Version: s4Cfg.S4SetVersion, - Payload: []byte(s4Cfg.S4SetPayload), - Expiration: time.Now().UnixMilli() + s4Cfg.S4SetExpirationPeriod, - } - signature, err := envelope.Sign(key) - if err != nil { - return err - } + envelope := s4.Envelope{ + Address: address.Bytes(), + SlotID: s4Cfg.S4SetSlotID, + Version: s4Cfg.S4SetVersion, + Payload: []byte(s4Cfg.S4SetPayload), + Expiration: time.Now().UnixMilli() + s4Cfg.S4SetExpirationPeriod, + } + signature, err := envelope.Sign(key) + if err != nil { + return 0, 0, err + } - s4SetPayload := functions.SecretsSetRequest{ - SlotID: envelope.SlotID, - Version: envelope.Version, - Expiration: envelope.Expiration, - Payload: []byte(s4Cfg.S4SetPayload), - Signature: signature, - } + s4SetPayload := functions.SecretsSetRequest{ + SlotID: envelope.SlotID, + Version: envelope.Version, + Expiration: envelope.Expiration, + Payload: []byte(s4Cfg.S4SetPayload), + Signature: signature, + } - payloadJSON, err = json.Marshal(s4SetPayload) - if err != nil { - return err - } + payloadJSON, err = json.Marshal(s4SetPayload) + if err != nil { + return 0, 0, err } msg := &api.Message{ @@ -94,33 +92,33 @@ func UploadS4Secrets(rc *resty.Client, s4Cfg *S4SecretsCfg) error { err = msg.Sign(key) if err != nil { - return err + return 0, 0, err } codec := api.JsonRPCCodec{} rawMsg, err := codec.EncodeRequest(msg) if err != nil { - return err + return 0, 0, err } var result *RPCResponse resp, err := rc.R(). SetBody(rawMsg). Post(s4Cfg.GatewayURL) if err != nil { - return err + return 0, 0, err } if resp.StatusCode() != 200 { - return fmt.Errorf("status code was %d, expected 200", resp.StatusCode()) + return 0, 0, fmt.Errorf("status code was %d, expected 200", resp.StatusCode()) } if err := json.Unmarshal(resp.Body(), &result); err != nil { - return err + return 0, 0, err } log.Debug().Interface("Result", result).Msg("S4 secrets_set response result") for _, nodeResponse := range result.Result.Body.Payload.NodeResponses { if !nodeResponse.Body.Payload.Success { - return fmt.Errorf("node response was not succesful") + return 0, 0, fmt.Errorf("node response was not succesful") } } - return nil + return uint8(envelope.SlotID), envelope.Version, nil } func ListS4Secrets(rc *resty.Client, s4Cfg *S4SecretsCfg) error { diff --git a/integration-tests/load/functions/gateway_gun.go b/integration-tests/load/functions/gateway_gun.go index 5677e79b105..fd13922d0a7 100644 --- a/integration-tests/load/functions/gateway_gun.go +++ b/integration-tests/load/functions/gateway_gun.go @@ -36,7 +36,7 @@ func NewGatewaySecretsSetGun(cfg *PerformanceConfig, method string, pKey *ecdsa. } } -func callSetSecrets(m *GatewaySecretsSetGun) *wasp.CallResult { +func callSecretsSet(m *GatewaySecretsSetGun) *wasp.CallResult { randNum := strconv.Itoa(rand.Intn(100000)) randSlot := uint(rand.Intn(5)) version := uint64(time.Now().UnixNano()) @@ -58,8 +58,8 @@ func callSetSecrets(m *GatewaySecretsSetGun) *wasp.CallResult { if err != nil { return &wasp.CallResult{Error: err.Error(), Failed: true} } - if err := UploadS4Secrets(m.Resty, &S4SecretsCfg{ - GatewayURL: fmt.Sprintf("%s/user", m.Cfg.Common.GatewayURL), + _, _, err = UploadS4Secrets(m.Resty, &S4SecretsCfg{ + GatewayURL: m.Cfg.Common.GatewayURL, PrivateKey: os.Getenv("MUMBAI_KEYS"), MessageID: randNum, Method: "secrets_set", @@ -68,7 +68,8 @@ func callSetSecrets(m *GatewaySecretsSetGun) *wasp.CallResult { S4SetVersion: version, S4SetExpirationPeriod: expiration, S4SetPayload: secrets, - }); err != nil { + }) + if err != nil { return &wasp.CallResult{Error: err.Error(), Failed: true} } return &wasp.CallResult{} @@ -80,7 +81,7 @@ func callSecretsList(m *GatewaySecretsSetGun) *wasp.CallResult { version := uint64(time.Now().UnixNano()) expiration := int64(60 * 60 * 1000) if err := ListS4Secrets(m.Resty, &S4SecretsCfg{ - GatewayURL: fmt.Sprintf("%s/user", m.Cfg.Common.GatewayURL), + GatewayURL: fmt.Sprintf(m.Cfg.Common.GatewayURL), RecieverAddr: m.Cfg.Common.Receiver, PrivateKey: os.Getenv("MUMBAI_KEYS"), MessageID: randNum, @@ -100,7 +101,7 @@ func (m *GatewaySecretsSetGun) Call(_ *wasp.Generator) *wasp.CallResult { var res *wasp.CallResult switch m.Method { case "secrets_set": - res = callSetSecrets(m) + res = callSecretsSet(m) case "secrets_list": res = callSecretsList(m) default: diff --git a/integration-tests/load/functions/gateway_test.go b/integration-tests/load/functions/gateway_test.go index 946afdd711a..c8e63f92f2b 100644 --- a/integration-tests/load/functions/gateway_test.go +++ b/integration-tests/load/functions/gateway_test.go @@ -1,10 +1,12 @@ package loadfunctions import ( - "github.com/smartcontractkit/chainlink/v2/core/services/gateway/handlers/functions" + "testing" + "github.com/smartcontractkit/wasp" "github.com/stretchr/testify/require" - "testing" + + "github.com/smartcontractkit/chainlink/v2/core/services/gateway/handlers/functions" ) func TestGatewayLoad(t *testing.T) { diff --git a/integration-tests/load/functions/request_gun.go b/integration-tests/load/functions/request_gun.go index 5cbff36179e..d9987eaa756 100644 --- a/integration-tests/load/functions/request_gun.go +++ b/integration-tests/load/functions/request_gun.go @@ -4,36 +4,88 @@ import ( "github.com/smartcontractkit/wasp" ) -/* SingleFunctionCallGun is a gun that constantly requests randomness for one feed */ +type TestMode int + +const ( + ModeHTTPPayload TestMode = iota + ModeSecretsOnlyPayload + ModeReal +) type SingleFunctionCallGun struct { - ft *FunctionsTest - times uint32 - source string - encryptedSecretsReferences []byte - args []string - subscriptionId uint64 - jobId [32]byte + ft *FunctionsTest + mode TestMode + times uint32 + source string + slotID uint8 + slotVersion uint64 + encryptedSecrets []byte + args []string + subscriptionId uint64 + jobId [32]byte } -func NewSingleFunctionCallGun(ft *FunctionsTest, times uint32, source string, encryptedSecretsReferences []byte, args []string, subscriptionId uint64, jobId [32]byte) *SingleFunctionCallGun { +func NewSingleFunctionCallGun( + ft *FunctionsTest, + mode TestMode, + times uint32, + source string, + slotID uint8, + slotVersion uint64, + args []string, + subscriptionId uint64, + jobId [32]byte, +) *SingleFunctionCallGun { return &SingleFunctionCallGun{ - ft: ft, - times: times, - source: source, - encryptedSecretsReferences: encryptedSecretsReferences, - args: args, - subscriptionId: subscriptionId, - jobId: jobId, + ft: ft, + mode: mode, + times: times, + source: source, + slotID: slotID, + slotVersion: slotVersion, + args: args, + subscriptionId: subscriptionId, + jobId: jobId, } } -// Call implements example gun call, assertions on response bodies should be done here -func (m *SingleFunctionCallGun) Call(l *wasp.Generator) *wasp.CallResult { +func (m *SingleFunctionCallGun) callReal() *wasp.CallResult { + err := m.ft.LoadTestClient.SendRequestWithDONHostedSecrets( + m.times, + m.source, + m.slotID, + m.slotVersion, + m.args, + m.subscriptionId, + m.jobId, + ) + if err != nil { + return &wasp.CallResult{Error: err.Error(), Failed: true} + } + return &wasp.CallResult{} +} + +func (m *SingleFunctionCallGun) callWithSecrets() *wasp.CallResult { + err := m.ft.LoadTestClient.SendRequestWithDONHostedSecrets( + m.times, + m.source, + m.slotID, + m.slotVersion, + m.args, + m.subscriptionId, + m.jobId, + ) + if err != nil { + return &wasp.CallResult{Error: err.Error(), Failed: true} + } + return &wasp.CallResult{} +} + +func (m *SingleFunctionCallGun) callWithHttp() *wasp.CallResult { err := m.ft.LoadTestClient.SendRequest( m.times, m.source, - m.encryptedSecretsReferences, + []byte{}, m.args, m.subscriptionId, m.jobId, @@ -43,3 +95,17 @@ func (m *SingleFunctionCallGun) Call(l *wasp.Generator) *wasp.CallResult { } return &wasp.CallResult{} } + +// Call implements example gun call, assertions on response bodies should be done here +func (m *SingleFunctionCallGun) Call(_ *wasp.Generator) *wasp.CallResult { + switch m.mode { + case ModeSecretsOnlyPayload: + return m.callWithSecrets() + case ModeHTTPPayload: + return m.callWithHttp() + case ModeReal: + return m.callReal() + default: + panic("test mode must be ModeSecretsOnlyPayload, ModeHTTPPayload or ModeReal") + } +} diff --git a/integration-tests/load/functions/setup.go b/integration-tests/load/functions/setup.go index 0433b5beb61..60986595b9f 100644 --- a/integration-tests/load/functions/setup.go +++ b/integration-tests/load/functions/setup.go @@ -2,21 +2,22 @@ package loadfunctions import ( "crypto/ecdsa" - "fmt" + "math/big" + mrand "math/rand" + "os" + "strconv" + "time" + "github.com/ethereum/go-ethereum/crypto" "github.com/go-resty/resty/v2" "github.com/pkg/errors" "github.com/rs/zerolog/log" "github.com/smartcontractkit/chainlink-testing-framework/blockchain" + "github.com/smartcontractkit/chainlink-testing-framework/networks" + "github.com/smartcontractkit/tdh2/go/tdh2/tdh2easy" + "github.com/smartcontractkit/chainlink/integration-tests/contracts" - "github.com/smartcontractkit/chainlink/integration-tests/networks" chainlinkutils "github.com/smartcontractkit/chainlink/v2/core/utils" - "github.com/smartcontractkit/tdh2/go/tdh2/tdh2easy" - "math/big" - mrand "math/rand" - "os" - "strconv" - "time" ) type FunctionsTest struct { @@ -115,7 +116,7 @@ func SetupLocalLoadTestEnv(cfg *PerformanceConfig) (*FunctionsTest, error) { if err != nil { return nil, errors.Wrap(err, "failed to get DON public key") } - log.Info().Hex("DONPublicKeyHex", donPubKey).Msg("Loaded coordinator keys") + log.Info().Hex("DONPublicKeyHex", donPubKey).Msg("Loaded DON key") tdh2pk, err := ParseTDH2Key(tpk) if err != nil { return nil, errors.Wrap(err, "failed to unmarshal tdh2 public key") @@ -126,8 +127,8 @@ func SetupLocalLoadTestEnv(cfg *PerformanceConfig) (*FunctionsTest, error) { if err != nil { return nil, errors.Wrap(err, "failed to generate tdh2 secrets") } - if err := UploadS4Secrets(resty.New(), &S4SecretsCfg{ - GatewayURL: fmt.Sprintf("%s/user", cfg.Common.GatewayURL), + slotID, slotVersion, err := UploadS4Secrets(resty.New(), &S4SecretsCfg{ + GatewayURL: cfg.Common.GatewayURL, PrivateKey: cfg.MumbaiPrivateKey, MessageID: strconv.Itoa(mrand.Intn(100000-1) + 1), Method: "secrets_set", @@ -136,9 +137,16 @@ func SetupLocalLoadTestEnv(cfg *PerformanceConfig) (*FunctionsTest, error) { S4SetVersion: uint64(time.Now().UnixNano()), S4SetExpirationPeriod: 60 * 60 * 1000, S4SetPayload: encryptedSecrets, - }); err != nil { + }) + if err != nil { return nil, errors.Wrap(err, "failed to upload secrets to S4") } + cfg.Common.SecretsSlotID = slotID + cfg.Common.SecretsVersionID = slotVersion + log.Info(). + Uint8("SlotID", slotID). + Uint64("SlotVersion", slotVersion). + Msg("Set new secret") } return &FunctionsTest{ EVMClient: bc, diff --git a/integration-tests/networks/known_networks.go b/integration-tests/networks/known_networks.go deleted file mode 100644 index 4d12d6b5b60..00000000000 --- a/integration-tests/networks/known_networks.go +++ /dev/null @@ -1,598 +0,0 @@ -// Package networks holds all known network information for the tests -package networks - -import ( - "crypto/ecdsa" - "fmt" - "os" - "strings" - "time" - - "github.com/ethereum/go-ethereum/crypto" - "github.com/rs/zerolog/log" - - "github.com/smartcontractkit/chainlink-testing-framework/utils" - - "github.com/smartcontractkit/chainlink-testing-framework/blockchain" - "github.com/smartcontractkit/chainlink-testing-framework/logging" -) - -// Pre-configured test networks and their connections -// Some networks with public RPC endpoints are already filled out, but make use of environment variables to use info like -// private RPC endpoints and private keys. -var ( - // To create replica of simulated EVM network, with different chain ids - AdditionalSimulatedChainIds = []int64{3337, 4337, 5337, 6337, 7337, 8337, 9337, 9338} - AdditionalSimulatedPvtKeys = []string{ - "5de4111afa1a4b94908f83103eb1f1706367c2e68ca870fc3fb9a804cdab365a", - "7c852118294e51e653712a81e05800f419141751be58f605c371e15141b007a6", - "47e179ec197488593b187f80a00eb0da91f1b9d0b13f8733639f19c30a34926a", - "8b3a350cf5c34c9194ca85829a2df0ec3153be0318b5e2d3348e872092edffba", - "92db14e403b83dfe3df233f83dfa3a0d7096f21ca9b0d6d6b8d88b2b4ec1564e", - "4bbbf85ce3377467afe5d46f804f221813b2bb87f24d81f60f1fcdbf7cbf4356", - "dbda1821b80551c9d65939329250298aa3472ba22feea921c0cf5d620ea67b97", - "2a871d0798f97d79848a013d4936a73bf4cc922c825d33c1cf7073dff6d409c6", - } - // SelectedNetworks uses the SELECTED_NETWORKS env var to determine which network to run the test on. - // For use in tests that utilize multiple chains. For tests on one chain, see SelectedNetwork - // For CCIP use index 1 and 2 of SELECTED_NETWORKS to denote source and destination network respectively - SelectedNetworks []blockchain.EVMNetwork = determineSelectedNetworks() - // SelectedNetwork uses the first listed network in SELECTED_NETWORKS, for use in tests on only one chain - SelectedNetwork blockchain.EVMNetwork = SelectedNetworks[0] - - // SimulatedEVM represents a simulated network - SimulatedEVM blockchain.EVMNetwork = blockchain.SimulatedEVMNetwork - // generalEVM is a customizable network through environment variables - // This is getting little use, and causes some confusion. Can re-enable if people want it. - // generalEVM blockchain.EVMNetwork = blockchain.LoadNetworkFromEnvironment() - - // SimulatedevmNonDev1 represents a simulated network which can be used to deploy a non-dev geth node - SimulatedEVMNonDev1 = blockchain.EVMNetwork{ - Name: "source-chain", - Simulated: true, - ClientImplementation: blockchain.EthereumClientImplementation, - SupportsEIP1559: true, - ChainID: 1337, - PrivateKeys: []string{ - "ac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80", - }, - URLs: []string{"ws://source-chain-ethereum-geth:8546"}, - HTTPURLs: []string{"http://source-chain-ethereum-geth:8544"}, - ChainlinkTransactionLimit: 500000, - Timeout: blockchain.JSONStrDuration{Duration: 2 * time.Minute}, - MinimumConfirmations: 1, - GasEstimationBuffer: 10000, - DefaultGasLimit: 6000000, - } - - // SimulatedEVM_NON_DEV_2 represents a simulated network with chain id 2337 which can be used to deploy a non-dev geth node - SimulatedEVMNonDev2 = blockchain.EVMNetwork{ - Name: "dest-chain", - Simulated: true, - SupportsEIP1559: true, - ClientImplementation: blockchain.EthereumClientImplementation, - ChainID: 2337, - PrivateKeys: []string{ - "59c6995e998f97a5a0044966f0945389dc9e86dae88c7a8412f4603b6b78690d", - }, - URLs: []string{"ws://dest-chain-ethereum-geth:8546"}, - HTTPURLs: []string{"http://dest-chain-ethereum-geth:8544"}, - ChainlinkTransactionLimit: 500000, - Timeout: blockchain.JSONStrDuration{Duration: 2 * time.Minute}, - MinimumConfirmations: 1, - GasEstimationBuffer: 10000, - DefaultGasLimit: 6000000, - } - - SimulatedEVMNonDev = blockchain.EVMNetwork{ - Name: "geth", - Simulated: true, - SupportsEIP1559: true, - ClientImplementation: blockchain.EthereumClientImplementation, - ChainID: 1337, - PrivateKeys: []string{ - "ac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80", - }, - URLs: []string{"ws://geth-ethereum-geth:8546"}, - HTTPURLs: []string{"http://geth-ethereum-geth:8544"}, - ChainlinkTransactionLimit: 500000, - Timeout: blockchain.JSONStrDuration{Duration: 2 * time.Minute}, - MinimumConfirmations: 1, - GasEstimationBuffer: 10000, - } - - EthereumMainnet blockchain.EVMNetwork = blockchain.EVMNetwork{ - Name: "Ethereum Mainnet", - SupportsEIP1559: true, - ClientImplementation: blockchain.EthereumClientImplementation, - ChainID: 1, - Simulated: false, - ChainlinkTransactionLimit: 5000, - Timeout: blockchain.JSONStrDuration{Duration: 5 * time.Minute}, - MinimumConfirmations: 1, - GasEstimationBuffer: 0, - FinalityTag: true, - DefaultGasLimit: 6000000, - } - - // sepoliaTestnet https://sepolia.dev/ - SepoliaTestnet blockchain.EVMNetwork = blockchain.EVMNetwork{ - Name: "Sepolia Testnet", - SupportsEIP1559: true, - ClientImplementation: blockchain.EthereumClientImplementation, - ChainID: 11155111, - Simulated: false, - ChainlinkTransactionLimit: 5000, - Timeout: blockchain.JSONStrDuration{Duration: time.Minute}, - MinimumConfirmations: 1, - GasEstimationBuffer: 1000, - FinalityTag: true, - DefaultGasLimit: 6000000, - } - - // goerliTestnet https://goerli.net/ - GoerliTestnet blockchain.EVMNetwork = blockchain.EVMNetwork{ - Name: "Goerli Testnet", - SupportsEIP1559: true, - ClientImplementation: blockchain.EthereumClientImplementation, - ChainID: 5, - Simulated: false, - ChainlinkTransactionLimit: 5000, - Timeout: blockchain.JSONStrDuration{Duration: 5 * time.Minute}, - MinimumConfirmations: 1, - GasEstimationBuffer: 1000, - FinalityTag: true, - DefaultGasLimit: 6000000, - } - - KlaytnMainnet blockchain.EVMNetwork = blockchain.EVMNetwork{ - Name: "Klaytn Mainnet", - SupportsEIP1559: false, - ClientImplementation: blockchain.KlaytnClientImplementation, - ChainID: 8217, - Simulated: false, - ChainlinkTransactionLimit: 5000, - Timeout: blockchain.JSONStrDuration{Duration: time.Minute}, - MinimumConfirmations: 1, - GasEstimationBuffer: 0, - } - - // klaytnBaobab https://klaytn.foundation/ - KlaytnBaobab blockchain.EVMNetwork = blockchain.EVMNetwork{ - Name: "Klaytn Baobab", - SupportsEIP1559: false, - ClientImplementation: blockchain.KlaytnClientImplementation, - ChainID: 1001, - Simulated: false, - ChainlinkTransactionLimit: 5000, - Timeout: blockchain.JSONStrDuration{Duration: time.Minute}, - MinimumConfirmations: 1, - GasEstimationBuffer: 0, - } - - MetisAndromeda blockchain.EVMNetwork = blockchain.EVMNetwork{ - Name: "Metis Andromeda", - SupportsEIP1559: false, - ClientImplementation: blockchain.MetisClientImplementation, - ChainID: 1088, - Simulated: false, - ChainlinkTransactionLimit: 5000, - Timeout: blockchain.JSONStrDuration{Duration: time.Minute}, - MinimumConfirmations: 1, - GasEstimationBuffer: 0, - } - - // metisStardust https://www.metis.io/ - MetisStardust blockchain.EVMNetwork = blockchain.EVMNetwork{ - Name: "Metis Stardust", - SupportsEIP1559: false, - ClientImplementation: blockchain.MetisClientImplementation, - ChainID: 588, - Simulated: false, - ChainlinkTransactionLimit: 5000, - Timeout: blockchain.JSONStrDuration{Duration: time.Minute}, - MinimumConfirmations: 1, - GasEstimationBuffer: 1000, - } - - ArbitrumMainnet blockchain.EVMNetwork = blockchain.EVMNetwork{ - Name: "Arbitrum Mainnet", - SupportsEIP1559: true, - ClientImplementation: blockchain.ArbitrumClientImplementation, - ChainID: 42161, - Simulated: false, - ChainlinkTransactionLimit: 5000, - Timeout: blockchain.JSONStrDuration{Duration: 2 * time.Minute}, - MinimumConfirmations: 0, - GasEstimationBuffer: 0, - FinalityTag: true, - DefaultGasLimit: 100000000, - } - - // arbitrumGoerli https://developer.offchainlabs.com/docs/public_chains - ArbitrumGoerli blockchain.EVMNetwork = blockchain.EVMNetwork{ - Name: "Arbitrum Goerli", - SupportsEIP1559: true, - ClientImplementation: blockchain.ArbitrumClientImplementation, - ChainID: 421613, - Simulated: false, - ChainlinkTransactionLimit: 5000, - Timeout: blockchain.JSONStrDuration{Duration: time.Minute}, - MinimumConfirmations: 0, - GasEstimationBuffer: 0, - FinalityTag: true, - DefaultGasLimit: 100000000, - } - - OptimismMainnet blockchain.EVMNetwork = blockchain.EVMNetwork{ - Name: "Optimism Mainnet", - SupportsEIP1559: true, - ClientImplementation: blockchain.OptimismClientImplementation, - ChainID: 10, - Simulated: false, - ChainlinkTransactionLimit: 5000, - Timeout: blockchain.JSONStrDuration{Duration: time.Minute}, - MinimumConfirmations: 1, - GasEstimationBuffer: 0, - FinalityTag: true, - DefaultGasLimit: 6000000, - } - - // optimismGoerli https://dev.optimism.io/kovan-to-goerli/ - OptimismGoerli blockchain.EVMNetwork = blockchain.EVMNetwork{ - Name: "Optimism Goerli", - SupportsEIP1559: true, - ClientImplementation: blockchain.OptimismClientImplementation, - ChainID: 420, - Simulated: false, - ChainlinkTransactionLimit: 5000, - Timeout: blockchain.JSONStrDuration{Duration: time.Minute}, - MinimumConfirmations: 1, - GasEstimationBuffer: 0, - FinalityTag: true, - DefaultGasLimit: 6000000, - } - - RSKMainnet blockchain.EVMNetwork = blockchain.EVMNetwork{ - Name: "RSK Mainnet", - SupportsEIP1559: false, - ClientImplementation: blockchain.RSKClientImplementation, - ChainID: 30, - Simulated: false, - ChainlinkTransactionLimit: 5000, - Timeout: blockchain.JSONStrDuration{Duration: time.Minute}, - MinimumConfirmations: 1, - GasEstimationBuffer: 1000, - } - - // rskTestnet https://www.rsk.co/ - RSKTestnet blockchain.EVMNetwork = blockchain.EVMNetwork{ - Name: "RSK Testnet", - SupportsEIP1559: false, - ClientImplementation: blockchain.RSKClientImplementation, - ChainID: 31, - Simulated: false, - ChainlinkTransactionLimit: 5000, - Timeout: blockchain.JSONStrDuration{Duration: time.Minute}, - MinimumConfirmations: 1, - GasEstimationBuffer: 1000, - } - - PolygonMainnet blockchain.EVMNetwork = blockchain.EVMNetwork{ - Name: "Polygon Mainnet", - SupportsEIP1559: true, - ClientImplementation: blockchain.PolygonClientImplementation, - ChainID: 137, - Simulated: false, - ChainlinkTransactionLimit: 5000, - Timeout: blockchain.JSONStrDuration{Duration: 2 * time.Minute}, - MinimumConfirmations: 1, - GasEstimationBuffer: 0, - FinalityDepth: 550, - DefaultGasLimit: 6000000, - } - - // PolygonMumbai https://mumbai.polygonscan.com/ - PolygonMumbai blockchain.EVMNetwork = blockchain.EVMNetwork{ - Name: "Polygon Mumbai", - SupportsEIP1559: true, - ClientImplementation: blockchain.PolygonClientImplementation, - ChainID: 80001, - Simulated: false, - ChainlinkTransactionLimit: 5000, - Timeout: blockchain.JSONStrDuration{Duration: 3 * time.Minute}, - MinimumConfirmations: 1, - GasEstimationBuffer: 100000, - FinalityDepth: 550, - DefaultGasLimit: 8000000, - } - - AvalancheMainnet blockchain.EVMNetwork = blockchain.EVMNetwork{ - Name: "Avalanche Mainnet", - SupportsEIP1559: true, - ClientImplementation: blockchain.EthereumClientImplementation, - ChainID: 43114, - Simulated: false, - ChainlinkTransactionLimit: 5000, - Timeout: blockchain.JSONStrDuration{Duration: time.Minute}, - MinimumConfirmations: 1, - GasEstimationBuffer: 0, - FinalityDepth: 35, - DefaultGasLimit: 6000000, - } - - AvalancheFuji = blockchain.EVMNetwork{ - Name: "Avalanche Fuji", - SupportsEIP1559: true, - ClientImplementation: blockchain.EthereumClientImplementation, - ChainID: 43113, - Simulated: false, - ChainlinkTransactionLimit: 5000, - Timeout: blockchain.JSONStrDuration{Duration: time.Minute}, - MinimumConfirmations: 1, - GasEstimationBuffer: 1000, - FinalityDepth: 35, - DefaultGasLimit: 6000000, - } - - Quorum = blockchain.EVMNetwork{ - Name: "Quorum", - SupportsEIP1559: false, - ClientImplementation: blockchain.QuorumClientImplementation, - ChainID: 1337, - Simulated: false, - ChainlinkTransactionLimit: 5000, - Timeout: blockchain.JSONStrDuration{Duration: time.Minute}, - MinimumConfirmations: 1, - GasEstimationBuffer: 0, - } - - BaseGoerli blockchain.EVMNetwork = blockchain.EVMNetwork{ - Name: "Base Goerli", - SupportsEIP1559: true, - ClientImplementation: blockchain.OptimismClientImplementation, - ChainID: 84531, - Simulated: false, - ChainlinkTransactionLimit: 5000, - Timeout: blockchain.JSONStrDuration{Duration: time.Minute}, - MinimumConfirmations: 0, - GasEstimationBuffer: 0, - } - - CeloAlfajores = blockchain.EVMNetwork{ - Name: "Celo Alfajores", - SupportsEIP1559: false, - ClientImplementation: blockchain.CeloClientImplementation, - ChainID: 44787, - Simulated: false, - ChainlinkTransactionLimit: 5000, - Timeout: blockchain.JSONStrDuration{Duration: time.Minute}, - MinimumConfirmations: 1, - GasEstimationBuffer: 1000, - } - - ScrollSepolia = blockchain.EVMNetwork{ - Name: "Scroll Sepolia", - ClientImplementation: blockchain.ScrollClientImplementation, - ChainID: 534351, - Simulated: false, - ChainlinkTransactionLimit: 5000, - Timeout: blockchain.JSONStrDuration{Duration: time.Minute}, - MinimumConfirmations: 1, - GasEstimationBuffer: 0, - } - - ScrollMainnet = blockchain.EVMNetwork{ - Name: "Scroll Mainnet", - ClientImplementation: blockchain.ScrollClientImplementation, - ChainID: 534352, - Simulated: false, - ChainlinkTransactionLimit: 5000, - Timeout: blockchain.JSONStrDuration{Duration: time.Minute}, - MinimumConfirmations: 1, - GasEstimationBuffer: 0, - } - - CeloMainnet = blockchain.EVMNetwork{ - Name: "Celo", - ClientImplementation: blockchain.CeloClientImplementation, - ChainID: 42220, - Simulated: false, - ChainlinkTransactionLimit: 5000, - Timeout: blockchain.JSONStrDuration{Duration: time.Minute}, - MinimumConfirmations: 1, - GasEstimationBuffer: 1000, - } - - BaseMainnet blockchain.EVMNetwork = blockchain.EVMNetwork{ - Name: "Base Mainnet", - SupportsEIP1559: true, - ClientImplementation: blockchain.OptimismClientImplementation, - ChainID: 8453, - Simulated: false, - ChainlinkTransactionLimit: 5000, - Timeout: blockchain.JSONStrDuration{Duration: time.Minute}, - MinimumConfirmations: 0, - GasEstimationBuffer: 0, - } - - BSCTestnet blockchain.EVMNetwork = blockchain.EVMNetwork{ - Name: "BSC Testnet", - SupportsEIP1559: true, - ClientImplementation: blockchain.BSCClientImplementation, - ChainID: 97, - Simulated: false, - ChainlinkTransactionLimit: 5000, - Timeout: blockchain.JSONStrDuration{Duration: time.Minute}, - MinimumConfirmations: 3, - GasEstimationBuffer: 0, - } - - BSCMainnet blockchain.EVMNetwork = blockchain.EVMNetwork{ - Name: "BSC Mainnet", - SupportsEIP1559: true, - ClientImplementation: blockchain.BSCClientImplementation, - ChainID: 56, - Simulated: false, - ChainlinkTransactionLimit: 5000, - Timeout: blockchain.JSONStrDuration{Duration: time.Minute}, - MinimumConfirmations: 3, - GasEstimationBuffer: 0, - } - - MappedNetworks = map[string]blockchain.EVMNetwork{ - "SIMULATED": SimulatedEVM, - "SIMULATED_1": SimulatedEVMNonDev1, - "SIMULATED_2": SimulatedEVMNonDev2, - "SIMULATED_NONDEV": SimulatedEVMNonDev, - // "GENERAL": generalEVM, // See above - "ETHEREUM_MAINNET": EthereumMainnet, - "GOERLI": GoerliTestnet, - "SEPOLIA": SepoliaTestnet, - "KLAYTN_MAINNET": KlaytnMainnet, - "KLAYTN_BAOBAB": KlaytnBaobab, - "METIS_ANDROMEDA": MetisAndromeda, - "METIS_STARDUST": MetisStardust, - "ARBITRUM_MAINNET": ArbitrumMainnet, - "ARBITRUM_GOERLI": ArbitrumGoerli, - "OPTIMISM_MAINNET": OptimismMainnet, - "OPTIMISM_GOERLI": OptimismGoerli, - "BASE_GOERLI": BaseGoerli, - "CELO_ALFAJORES": CeloAlfajores, - "CELO_MAINNET": CeloMainnet, - "RSK": RSKTestnet, - "MUMBAI": PolygonMumbai, - "POLYGON_MAINNET": PolygonMainnet, - "AVALANCHE_FUJI": AvalancheFuji, - "AVALANCHE_MAINNET": AvalancheMainnet, - "QUORUM": Quorum, - "SCROLL_SEPOLIA": ScrollSepolia, - "SCROLL_MAINNET": ScrollMainnet, - "BASE_MAINNET": BaseMainnet, - "BSC_TESTNET": BSCTestnet, - "BSC_MAINNET": BSCMainnet, - } -) - -// determineSelectedNetworks uses `SELECTED_NETWORKS` to determine which networks to run the tests on. -// Use DetermineSelectedNetwork for tests that only use one network -func determineSelectedNetworks() []blockchain.EVMNetwork { - logging.Init() - selectedNetworks := make([]blockchain.EVMNetwork, 0) - rawSelectedNetworks := strings.ToUpper(os.Getenv("SELECTED_NETWORKS")) - setNetworkNames := strings.Split(rawSelectedNetworks, ",") - - for _, setNetworkName := range setNetworkNames { - if chosenNetwork, valid := MappedNetworks[setNetworkName]; valid { - log.Info(). - Interface("SELECTED_NETWORKS", setNetworkNames). - Str("Network Name", chosenNetwork.Name). - Msg("Read network choice from 'SELECTED_NETWORKS'") - setURLs(setNetworkName, &chosenNetwork) - setKeys(setNetworkName, &chosenNetwork) - selectedNetworks = append(selectedNetworks, chosenNetwork) - } else { - validNetworks := make([]string, 0) - for validNetwork := range MappedNetworks { - validNetworks = append(validNetworks, validNetwork) - } - log.Fatal(). - Interface("SELECTED_NETWORKS", setNetworkNames). - Str("Valid Networks", strings.Join(validNetworks, ", ")). - Msg("SELECTED_NETWORKS value is invalid. Use a valid network(s).") - } - } - return selectedNetworks -} - -// setURLs sets a network URL(s) based on env vars -func setURLs(prefix string, network *blockchain.EVMNetwork) { - prefix = strings.Trim(prefix, "_") - prefix = strings.ToUpper(prefix) - - if strings.Contains(prefix, "SIMULATED") { // Use defaults for SIMULATED - return - } - - wsEnvVar := fmt.Sprintf("%s_URLS", prefix) - httpEnvVar := fmt.Sprintf("%s_HTTP_URLS", prefix) - wsEnvURLs, err := utils.GetEnv(wsEnvVar) - if err != nil { - log.Fatal().Err(err).Str("env var", wsEnvVar).Msg("Error getting env var") - } - httpEnvURLs, err := utils.GetEnv(httpEnvVar) - if err != nil { - log.Fatal().Err(err).Str("env var", httpEnvVar).Msg("Error getting env var") - } - if wsEnvURLs == "" { - evmUrls, err := utils.GetEnv("EVM_URLS") - if err != nil { - log.Fatal().Err(err).Str("env var", "EVM_URLS").Msg("Error getting env var") - } - evmhttpUrls, err := utils.GetEnv("EVM_HTTP_URLS") - if err != nil { - log.Fatal().Err(err).Str("env var", "EVM_HTTP_URLS").Msg("Error getting env var") - } - wsURLs := strings.Split(evmUrls, ",") - httpURLs := strings.Split(evmhttpUrls, ",") - log.Warn().Msgf("No '%s' env var defined, defaulting to 'EVM_URLS'", wsEnvVar) - network.URLs = wsURLs - network.HTTPURLs = httpURLs - return - } - - wsURLs := strings.Split(wsEnvURLs, ",") - httpURLs := strings.Split(httpEnvURLs, ",") - network.URLs = wsURLs - network.HTTPURLs = httpURLs - log.Info().Msg("Read network URLs") -} - -// setKeys sets a network's private key(s) based on env vars -func setKeys(prefix string, network *blockchain.EVMNetwork) { - prefix = strings.Trim(prefix, "_") - prefix = strings.ToUpper(prefix) - - if strings.Contains(prefix, "SIMULATED") { // Use defaults for SIMULATED - return - } - - envVar := fmt.Sprintf("%s_KEYS", prefix) - keysFromEnv, err := utils.GetEnv(envVar) - if err != nil { - log.Fatal().Err(err).Str("env var", envVar).Msg("Error getting env var") - } - if keysFromEnv == "" { - log.Warn().Msg(fmt.Sprintf("No '%s' env var defined, defaulting to 'EVM_KEYS'", envVar)) - keysFromEnv = os.Getenv("EVM_KEYS") - } - keys := strings.Split(keysFromEnv, ",") - for i, key := range keys { - keys[i] = strings.TrimPrefix(key, "0x") - } - network.PrivateKeys = keys - - // log public keys for debugging - publicKeys := []string{} - for _, key := range network.PrivateKeys { - publicKey, err := privateKeyToAddress(key) - if err != nil { - log.Fatal().Err(err).Msg("Error getting public key from private key") - } - publicKeys = append(publicKeys, publicKey) - } - log.Info().Interface("Funding Addresses", publicKeys).Msg("Read network Keys") -} - -func privateKeyToAddress(privateKeyString string) (string, error) { - privateKey, err := crypto.HexToECDSA(privateKeyString) - if err != nil { - return "", err - } - publicKey := privateKey.Public() - publicKeyECDSA, ok := publicKey.(*ecdsa.PublicKey) - if !ok { - return "", fmt.Errorf("error casting private key to public ECDSA key") - } - return crypto.PubkeyToAddress(*publicKeyECDSA).Hex(), nil -} diff --git a/integration-tests/performance/cron_test.go b/integration-tests/performance/cron_test.go index 933014a1698..c66a1803564 100644 --- a/integration-tests/performance/cron_test.go +++ b/integration-tests/performance/cron_test.go @@ -22,9 +22,10 @@ import ( ctfClient "github.com/smartcontractkit/chainlink-testing-framework/client" "github.com/smartcontractkit/chainlink-testing-framework/utils" + "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/networks" "github.com/smartcontractkit/chainlink/integration-tests/testreporters" "github.com/smartcontractkit/chainlink/integration-tests/testsetups" ) diff --git a/integration-tests/performance/directrequest_test.go b/integration-tests/performance/directrequest_test.go index 47a16de1091..dca84ab09c3 100644 --- a/integration-tests/performance/directrequest_test.go +++ b/integration-tests/performance/directrequest_test.go @@ -20,10 +20,11 @@ import ( ctfClient "github.com/smartcontractkit/chainlink-testing-framework/client" "github.com/smartcontractkit/chainlink-testing-framework/utils" + "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/contracts" - "github.com/smartcontractkit/chainlink/integration-tests/networks" "github.com/smartcontractkit/chainlink/integration-tests/testsetups" "github.com/google/uuid" diff --git a/integration-tests/performance/flux_test.go b/integration-tests/performance/flux_test.go index ecacce90ca7..bc914c329b9 100644 --- a/integration-tests/performance/flux_test.go +++ b/integration-tests/performance/flux_test.go @@ -21,10 +21,11 @@ import ( ctfClient "github.com/smartcontractkit/chainlink-testing-framework/client" "github.com/smartcontractkit/chainlink-testing-framework/utils" + "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/contracts" - "github.com/smartcontractkit/chainlink/integration-tests/networks" "github.com/smartcontractkit/chainlink/integration-tests/testsetups" ) diff --git a/integration-tests/performance/keeper_test.go b/integration-tests/performance/keeper_test.go index 346f0897d47..384729dfab3 100644 --- a/integration-tests/performance/keeper_test.go +++ b/integration-tests/performance/keeper_test.go @@ -20,11 +20,12 @@ import ( "github.com/smartcontractkit/chainlink-testing-framework/blockchain" "github.com/smartcontractkit/chainlink-testing-framework/utils" + "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/contracts" "github.com/smartcontractkit/chainlink/integration-tests/contracts/ethereum" - "github.com/smartcontractkit/chainlink/integration-tests/networks" "github.com/smartcontractkit/chainlink/integration-tests/testsetups" ) diff --git a/integration-tests/performance/ocr_test.go b/integration-tests/performance/ocr_test.go index 25791161bc2..d056d58e30b 100644 --- a/integration-tests/performance/ocr_test.go +++ b/integration-tests/performance/ocr_test.go @@ -18,10 +18,11 @@ import ( "github.com/smartcontractkit/chainlink-testing-framework/blockchain" ctfClient "github.com/smartcontractkit/chainlink-testing-framework/client" + "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/contracts" - "github.com/smartcontractkit/chainlink/integration-tests/networks" "github.com/smartcontractkit/chainlink/integration-tests/testsetups" ) diff --git a/integration-tests/performance/vrf_test.go b/integration-tests/performance/vrf_test.go index 2074eecaf78..59eb5e3980b 100644 --- a/integration-tests/performance/vrf_test.go +++ b/integration-tests/performance/vrf_test.go @@ -18,10 +18,11 @@ import ( "github.com/smartcontractkit/chainlink-testing-framework/blockchain" "github.com/smartcontractkit/chainlink-testing-framework/utils" + "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/contracts" - "github.com/smartcontractkit/chainlink/integration-tests/networks" "github.com/smartcontractkit/chainlink/integration-tests/testsetups" ) diff --git a/integration-tests/reorg/automation_reorg_test.go b/integration-tests/reorg/automation_reorg_test.go index 4a75d92d5d1..f3d3ed9369f 100644 --- a/integration-tests/reorg/automation_reorg_test.go +++ b/integration-tests/reorg/automation_reorg_test.go @@ -19,11 +19,12 @@ import ( "github.com/smartcontractkit/chainlink-testing-framework/blockchain" "github.com/smartcontractkit/chainlink-testing-framework/utils" + "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/contracts" "github.com/smartcontractkit/chainlink/integration-tests/contracts/ethereum" - "github.com/smartcontractkit/chainlink/integration-tests/networks" ) var ( diff --git a/integration-tests/reorg/reorg_test.go b/integration-tests/reorg/reorg_test.go index d6ac5ce1cf1..c944b7a7539 100644 --- a/integration-tests/reorg/reorg_test.go +++ b/integration-tests/reorg/reorg_test.go @@ -1,6 +1,7 @@ package reorg import ( + "context" "fmt" "math/big" "os" @@ -23,13 +24,13 @@ import ( ctfClient "github.com/smartcontractkit/chainlink-testing-framework/client" "github.com/smartcontractkit/chainlink-testing-framework/utils" - "context" "github.com/onsi/gomega" "github.com/rs/zerolog/log" + "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/contracts" - "github.com/smartcontractkit/chainlink/integration-tests/networks" ) const ( diff --git a/integration-tests/runner_helpers.go b/integration-tests/runner_helpers.go index 17950064575..43268a703ac 100644 --- a/integration-tests/runner_helpers.go +++ b/integration-tests/runner_helpers.go @@ -12,12 +12,12 @@ import ( "strings" "time" - gh "github.com/cli/go-gh/v2" + "github.com/cli/go-gh/v2" "github.com/ethereum/go-ethereum/crypto" "github.com/manifoldco/promptui" "github.com/rs/zerolog/log" - "github.com/smartcontractkit/chainlink/integration-tests/networks" + "github.com/smartcontractkit/chainlink-testing-framework/networks" ) func waitForWorkflowRun(branch, ghUser string) (string, error) { diff --git a/integration-tests/scripts/buildTestMatrixList.sh b/integration-tests/scripts/buildTestMatrixList.sh new file mode 100755 index 00000000000..25f72715095 --- /dev/null +++ b/integration-tests/scripts/buildTestMatrixList.sh @@ -0,0 +1,58 @@ +#!/usr/bin/env bash + +# requires a path to a test file to compare the test list against +# requires a matrix job name to be passed in, for example "automation" +# requires a node label to be passed in, for example "ubuntu-latest" + +set -e + +# get this scripts directory +SCRIPT_DIR=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" &>/dev/null && pwd) + +cd "$SCRIPT_DIR"/../ || exit 1 + +FILENAME=$1 +MATRIX_JOB_NAME=$2 +NODE_LABEL=$3 + +# Get list of test names from JSON file +JSONFILE="${FILENAME}_test_list.json" +COUNTER=1 + +# Build a JSON object in the format expected by our integration-tests workflow matrix +matrix_output() { + local counter=$1 + local job_name=$2 + local test_name=$3 + local node_label=$4 + local counter_out=$(printf "%02d\n" $counter) + echo -n "{\"name\": \"${job_name}-${counter_out}\", \"file\": \"${job_name}\",\"nodes\": 1, \"os\": \"${node_label}\", \"pyroscope_env\": \"ci-smoke-${job_name}-evm-simulated\", \"run\": \"-run '^${test_name}$'\"}" +} + +# Read the JSON file and loop through 'tests' and 'run' +jq -c '.tests[]' ${JSONFILE} | while read -r test; do + testName=$(echo ${test} | jq -r '.name') + subTests=$(echo ${test} | jq -r '.run[]?.name // empty') + output="" + + # Loop through subtests, if any, and print in the desired format + if [ -n "$subTests" ]; then + for subTest in $subTests; do + if [ $COUNTER -ne 1 ]; then + echo -n "," + fi + matrix_output $COUNTER $MATRIX_JOB_NAME "${testName}/${subTest}" ${NODE_LABEL} + ((COUNTER++)) + done + else + if [ $COUNTER -ne 1 ]; then + echo -n "," + fi + matrix_output $COUNTER $MATRIX_JOB_NAME "${testName}" ${NODE_LABEL} + ((COUNTER++)) + fi + +done > "./tmpout.json" +OUTPUT=$(cat ./tmpout.json) +echo "[${OUTPUT}]" +rm ./tmpout.json diff --git a/integration-tests/scripts/compareTestList.sh b/integration-tests/scripts/compareTestList.sh new file mode 100755 index 00000000000..8cc916c7d63 --- /dev/null +++ b/integration-tests/scripts/compareTestList.sh @@ -0,0 +1,48 @@ +#!/usr/bin/env bash + +# accepts a path to a test file to compare the test list against + +set -e + +# get this scripts directory +SCRIPT_DIR=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" &>/dev/null && pwd) + +cd "$SCRIPT_DIR"/../ || exit 1 + +FILENAME=$1 + +TESTLIST=$(cat ${FILENAME} | grep "func Test.*\(t \*testing.T\)" | grep -o 'Test[A-Za-z0-9_]*') + +# convert the test list from above into json in the form {"tests":[{"name":"TestName"}]} +TESTLISTJSON=$(echo $TESTLIST | jq -R -s -c '{tests: split(" ") | map({"name":.})}') + +# Get list of test names from JSON file +JSONFILE="${FILENAME}_test_list.json" +JSONTESTLIST=$(jq -r '.tests[].name' ${JSONFILE}) + +# Convert lists to arrays +TESTLIST_ARRAY=($(echo "$TESTLIST")) +JSONTESTLIST_ARRAY=($(echo "$JSONTESTLIST")) + +ERRORS_FOUND=false + +# Compare TESTLIST_ARRAY against JSONTESTLIST_ARRAY +for test in "${TESTLIST_ARRAY[@]}"; do + if [[ ! " ${JSONTESTLIST_ARRAY[@]} " =~ " ${test} " ]]; then + echo "$test exists only in ${FILENAME}." + ERRORS_FOUND=true + fi +done + +# Compare JSONTESTLIST_ARRAY against TESTLIST_ARRAY +for test in "${JSONTESTLIST_ARRAY[@]}"; do + if [[ ! " ${TESTLIST_ARRAY[@]} " =~ " ${test} " ]]; then + echo "$test exists only in ${JSONFILE}." + ERRORS_FOUND=true + fi +done + +if [ "$ERRORS_FOUND" = true ] ; then + echo "Test lists do not match. Please update ${JSONFILE} with the updated tests to run in CI." + exit 1 +fi diff --git a/integration-tests/smoke/automation_test.go b/integration-tests/smoke/automation_test.go index 57ca733b594..67b9b0b2648 100644 --- a/integration-tests/smoke/automation_test.go +++ b/integration-tests/smoke/automation_test.go @@ -6,29 +6,34 @@ import ( "math/big" "os" "strconv" - "strings" "testing" "time" + "github.com/ethereum/go-ethereum/common" "github.com/onsi/gomega" - "github.com/rs/zerolog/log" "github.com/stretchr/testify/require" - "go.uber.org/zap/zapcore" - "github.com/smartcontractkit/chainlink-env/environment" "github.com/smartcontractkit/chainlink-env/logging" - "github.com/smartcontractkit/chainlink-env/pkg/helm/chainlink" - eth "github.com/smartcontractkit/chainlink-env/pkg/helm/ethereum" "github.com/smartcontractkit/chainlink-testing-framework/blockchain" "github.com/smartcontractkit/chainlink-testing-framework/utils" + "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/contracts" "github.com/smartcontractkit/chainlink/integration-tests/contracts/ethereum" - "github.com/smartcontractkit/chainlink/integration-tests/networks" + + "github.com/smartcontractkit/chainlink/integration-tests/docker/test_env" + "github.com/smartcontractkit/chainlink/integration-tests/types/config/node" + it_utils "github.com/smartcontractkit/chainlink/integration-tests/utils" + cltypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/automation_utils_2_1" + "github.com/smartcontractkit/chainlink/v2/core/store/models" ) +var utilsABI = cltypes.MustGetABI(automation_utils_2_1.AutomationUtilsABI) + const ( automationDefaultUpkeepGasLimit = uint32(2500000) automationDefaultLinkFunds = int64(9e18) @@ -38,25 +43,6 @@ const ( ) var ( - automationBaseTOML = `[Feature] -LogPoller = true - -[OCR2] -Enabled = true - -[Keeper] -TurnLookBack = 0 - -[Keeper.Registry] -SyncInterval = '5m' -PerformGasOverhead = 150_000 - -[P2P] -[P2P.V2] -Enabled = true -AnnounceAddresses = ["0.0.0.0:6690"] -ListenAddresses = ["0.0.0.0:6690"]` - defaultOCRRegistryConfig = contracts.KeeperRegistrySettings{ PaymentPremiumPPB: uint32(200000000), FlatFeeMicroLINK: uint32(0), @@ -128,12 +114,9 @@ func SetupAutomationBasic(t *testing.T, nodeUpgrade bool) { require.NoError(t, err, "Error getting upgrade version") testName = "node-upgrade" } - chainClient, chainlinkNodes, contractDeployer, linkToken, registry, registrar, onlyStartRunner, testEnv := setupAutomationTest( + chainClient, _, contractDeployer, linkToken, registry, registrar, testEnv := setupAutomationTestDocker( t, testName, registryVersion, defaultOCRRegistryConfig, nodeUpgrade, ) - if onlyStartRunner { - return - } // Use the name to determine if this is a log trigger or not isLogTrigger := name == "registry_2_1_logtrigger" @@ -181,7 +164,7 @@ func SetupAutomationBasic(t *testing.T, nodeUpgrade bool) { expect := 5 // Upgrade the nodes one at a time and check that the upkeeps are still being performed for i := 0; i < 5; i++ { - actions.UpgradeChainlinkNodeVersions(testEnv, upgradeImage, upgradeVersion, chainlinkNodes[i]) + actions.UpgradeChainlinkNodeVersionsLocal(upgradeImage, upgradeVersion, testEnv.CLNodes[i]) time.Sleep(time.Second * 10) expect = expect + 5 gom.Eventually(func(g gomega.Gomega) { @@ -230,6 +213,172 @@ func SetupAutomationBasic(t *testing.T, nodeUpgrade bool) { } } +func TestSetUpkeepTriggerConfig(t *testing.T) { + t.Parallel() + l := utils.GetTestLogger(t) + + chainClient, _, contractDeployer, linkToken, registry, registrar, _ := setupAutomationTestDocker( + t, "set-trigger-config", ethereum.RegistryVersion_2_1, defaultOCRRegistryConfig, false, + ) + + consumers, upkeepIDs := actions.DeployConsumers( + t, + registry, + registrar, + linkToken, + contractDeployer, + chainClient, + defaultAmountOfUpkeeps, + big.NewInt(automationDefaultLinkFunds), + automationDefaultUpkeepGasLimit, + true, + ) + + // Start log trigger based upkeeps for all consumers + for i := 0; i < len(consumers); i++ { + err := consumers[i].Start() + if err != nil { + return + } + } + + l.Info().Msg("Waiting for all upkeeps to perform") + gom := gomega.NewGomegaWithT(t) + gom.Eventually(func(g gomega.Gomega) { + // Check if the upkeeps are performing multiple times by analyzing their counters + for i := 0; i < len(upkeepIDs); i++ { + counter, err := consumers[i].Counter(context.Background()) + require.NoError(t, err, "Failed to retrieve consumer counter for upkeep at index %d", i) + expect := 5 + l.Info().Int64("Upkeeps Performed", counter.Int64()).Int("Upkeep Index", i).Msg("Number of upkeeps performed") + g.Expect(counter.Int64()).Should(gomega.BeNumerically(">=", int64(expect)), + "Expected consumer counter to be greater than %d, but got %d", expect, counter.Int64()) + } + }, "5m", "1s").Should(gomega.Succeed()) // ~1m for cluster setup, ~2m for performing each upkeep 5 times, ~2m buffer + + topic0InBytesMatch := [32]byte{ + 61, 83, 163, 149, 80, 224, 70, 136, + 6, 88, 39, 243, 187, 134, 88, 76, + 176, 7, 171, 158, 188, 167, 235, + 213, 40, 231, 48, 28, 156, 49, 235, 93, + } // bytes representation of 0x3d53a39550e04688065827f3bb86584cb007ab9ebca7ebd528e7301c9c31eb5d + + topic0InBytesNoMatch := [32]byte{ + 62, 83, 163, 149, 80, 224, 70, 136, + 6, 88, 39, 243, 187, 134, 88, 76, + 176, 7, 171, 158, 188, 167, 235, + 213, 40, 231, 48, 28, 156, 49, 235, 93, + } // changed the first byte from 61 to 62 to make it not match + + bytes0 := [32]byte{ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + } // bytes representation of 0x0000000000000000000000000000000000000000000000000000000000000000 + + // Update the trigger config so no upkeeps are triggered + for i := 0; i < len(consumers); i++ { + upkeepAddr := consumers[i].Address() + + logTriggerConfigStruct := automation_utils_2_1.LogTriggerConfig{ + ContractAddress: common.HexToAddress(upkeepAddr), + FilterSelector: 0, + Topic0: topic0InBytesNoMatch, + Topic1: bytes0, + Topic2: bytes0, + Topic3: bytes0, + } + encodedLogTriggerConfig, err := utilsABI.Methods["_logTriggerConfig"].Inputs.Pack(&logTriggerConfigStruct) + if err != nil { + return + } + + err = registry.SetUpkeepTriggerConfig(upkeepIDs[i], encodedLogTriggerConfig) + require.NoError(t, err, "Could not set upkeep trigger config at index %d", i) + } + + err := chainClient.WaitForEvents() + require.NoError(t, err, "Error encountered when waiting for setting trigger config for upkeeps") + + var countersAfterSetNoMatch = make([]*big.Int, len(upkeepIDs)) + + // Wait for 10 seconds to let in-flight upkeeps finish + time.Sleep(10 * time.Second) + for i := 0; i < len(upkeepIDs); i++ { + // Obtain the amount of times the upkeep has been executed so far + countersAfterSetNoMatch[i], err = consumers[i].Counter(context.Background()) + require.NoError(t, err, "Failed to retrieve consumer counter for upkeep at index %d", i) + l.Info().Int64("Upkeep Count", countersAfterSetNoMatch[i].Int64()).Int("Upkeep Index", i).Msg("Upkeep") + } + + l.Info().Msg("Making sure the counter stays consistent") + gom.Consistently(func(g gomega.Gomega) { + for i := 0; i < len(upkeepIDs); i++ { + // Expect the counter to remain constant (At most increase by 2 to account for stale performs) because the upkeep trigger config is not met + bufferCount := int64(2) + latestCounter, err := consumers[i].Counter(context.Background()) + g.Expect(err).ShouldNot(gomega.HaveOccurred(), "Failed to retrieve consumer counter for upkeep at index %d", i) + g.Expect(latestCounter.Int64()).Should(gomega.BeNumerically("<=", countersAfterSetNoMatch[i].Int64()+bufferCount), + "Expected consumer counter to remain less than or equal to %d, but got %d", + countersAfterSetNoMatch[i].Int64()+bufferCount, latestCounter.Int64()) + } + }, "1m", "1s").Should(gomega.Succeed()) + + // Update the trigger config, so upkeeps start performing again + for i := 0; i < len(consumers); i++ { + upkeepAddr := consumers[i].Address() + + logTriggerConfigStruct := automation_utils_2_1.LogTriggerConfig{ + ContractAddress: common.HexToAddress(upkeepAddr), + FilterSelector: 0, + Topic0: topic0InBytesMatch, + Topic1: bytes0, + Topic2: bytes0, + Topic3: bytes0, + } + encodedLogTriggerConfig, err := utilsABI.Methods["_logTriggerConfig"].Inputs.Pack(&logTriggerConfigStruct) + if err != nil { + return + } + + err = registry.SetUpkeepTriggerConfig(upkeepIDs[i], encodedLogTriggerConfig) + require.NoError(t, err, "Could not set upkeep trigger config at index %d", i) + } + + err = chainClient.WaitForEvents() + require.NoError(t, err, "Error encountered when waiting for setting trigger config for upkeeps") + + var countersAfterSetMatch = make([]*big.Int, len(upkeepIDs)) + + for i := 0; i < len(upkeepIDs); i++ { + // Obtain the amount of times the upkeep has been executed so far + countersAfterSetMatch[i], err = consumers[i].Counter(context.Background()) + require.NoError(t, err, "Failed to retrieve consumer counter for upkeep at index %d", i) + l.Info().Int64("Upkeep Count", countersAfterSetMatch[i].Int64()).Int("Upkeep Index", i).Msg("Upkeep") + } + + // Wait for 30 seconds to make sure backend is ready + time.Sleep(30 * time.Second) + // Start the consumers again + for i := 0; i < len(consumers); i++ { + err := consumers[i].Start() + if err != nil { + return + } + } + + l.Info().Msg("Making sure the counter starts increasing again") + gom.Eventually(func(g gomega.Gomega) { + // Check if the upkeeps are performing multiple times by analyzing their counters + for i := 0; i < len(upkeepIDs); i++ { + counter, err := consumers[i].Counter(context.Background()) + require.NoError(t, err, "Failed to retrieve consumer counter for upkeep at index %d", i) + expect := int64(5) + l.Info().Int64("Upkeeps Performed", counter.Int64()).Int("Upkeep Index", i).Msg("Number of upkeeps performed") + g.Expect(counter.Int64()).Should(gomega.BeNumerically(">=", countersAfterSetMatch[i].Int64()+expect), + "Expected consumer counter to be greater than %d, but got %d", countersAfterSetMatch[i].Int64()+expect, counter.Int64()) + } + }, "5m", "1s").Should(gomega.Succeed()) // ~1m for cluster setup, ~2m for performing each upkeep 5 times, ~2m buffer +} + func TestAutomationAddFunds(t *testing.T) { t.Parallel() registryVersions := map[string]ethereum.KeeperRegistryVersion{ @@ -242,13 +391,9 @@ func TestAutomationAddFunds(t *testing.T) { registryVersion := rv t.Run(name, func(t *testing.T) { t.Parallel() - - chainClient, _, contractDeployer, linkToken, registry, registrar, onlyStartRunner, _ := setupAutomationTest( + chainClient, _, contractDeployer, linkToken, registry, registrar, _ := setupAutomationTestDocker( t, "add-funds", registryVersion, defaultOCRRegistryConfig, false, ) - if onlyStartRunner { - return - } consumers, upkeepIDs := actions.DeployConsumers(t, registry, registrar, linkToken, contractDeployer, chainClient, defaultAmountOfUpkeeps, big.NewInt(1), automationDefaultUpkeepGasLimit, false) @@ -298,13 +443,9 @@ func TestAutomationPauseUnPause(t *testing.T) { registryVersion := rv t.Run(name, func(t *testing.T) { t.Parallel() - - chainClient, _, contractDeployer, linkToken, registry, registrar, onlyStartRunner, _ := setupAutomationTest( + chainClient, _, contractDeployer, linkToken, registry, registrar, _ := setupAutomationTestDocker( t, "pause-unpause", registryVersion, defaultOCRRegistryConfig, false, ) - if onlyStartRunner { - return - } consumers, upkeepIDs := actions.DeployConsumers(t, registry, registrar, linkToken, contractDeployer, chainClient, defaultAmountOfUpkeeps, big.NewInt(automationDefaultLinkFunds), automationDefaultUpkeepGasLimit, false) @@ -386,13 +527,9 @@ func TestAutomationRegisterUpkeep(t *testing.T) { registryVersion := rv t.Run(name, func(t *testing.T) { t.Parallel() - - chainClient, _, contractDeployer, linkToken, registry, registrar, onlyStartRunner, _ := setupAutomationTest( + chainClient, _, contractDeployer, linkToken, registry, registrar, _ := setupAutomationTestDocker( t, "register-upkeep", registryVersion, defaultOCRRegistryConfig, false, ) - if onlyStartRunner { - return - } consumers, upkeepIDs := actions.DeployConsumers(t, registry, registrar, linkToken, contractDeployer, chainClient, defaultAmountOfUpkeeps, big.NewInt(automationDefaultLinkFunds), automationDefaultUpkeepGasLimit, false) @@ -462,12 +599,9 @@ func TestAutomationPauseRegistry(t *testing.T) { registryVersion := rv t.Run(name, func(t *testing.T) { t.Parallel() - chainClient, _, contractDeployer, linkToken, registry, registrar, onlyStartRunner, _ := setupAutomationTest( + chainClient, _, contractDeployer, linkToken, registry, registrar, _ := setupAutomationTestDocker( t, "pause-registry", registryVersion, defaultOCRRegistryConfig, false, ) - if onlyStartRunner { - return - } consumers, upkeepIDs := actions.DeployConsumers(t, registry, registrar, linkToken, contractDeployer, chainClient, defaultAmountOfUpkeeps, big.NewInt(automationDefaultLinkFunds), automationDefaultUpkeepGasLimit, false) gom := gomega.NewGomegaWithT(t) @@ -524,13 +658,9 @@ func TestAutomationKeeperNodesDown(t *testing.T) { registryVersion := rv t.Run(name, func(t *testing.T) { t.Parallel() - - chainClient, chainlinkNodes, contractDeployer, linkToken, registry, registrar, onlyStartRunner, _ := setupAutomationTest( + chainClient, chainlinkNodes, contractDeployer, linkToken, registry, registrar, _ := setupAutomationTestDocker( t, "keeper-nodes-down", registryVersion, defaultOCRRegistryConfig, false, ) - if onlyStartRunner { - return - } consumers, upkeepIDs := actions.DeployConsumers(t, registry, registrar, linkToken, contractDeployer, chainClient, defaultAmountOfUpkeeps, big.NewInt(automationDefaultLinkFunds), automationDefaultUpkeepGasLimit, false) gom := gomega.NewGomegaWithT(t) @@ -614,13 +744,9 @@ func TestAutomationPerformSimulation(t *testing.T) { registryVersion := rv t.Run(name, func(t *testing.T) { t.Parallel() - - chainClient, _, contractDeployer, linkToken, registry, registrar, onlyStartRunner, _ := setupAutomationTest( + chainClient, _, contractDeployer, linkToken, registry, registrar, _ := setupAutomationTestDocker( t, "perform-simulation", registryVersion, defaultOCRRegistryConfig, false, ) - if onlyStartRunner { - return - } consumersPerformance, _ := actions.DeployPerformanceConsumers( t, @@ -683,13 +809,9 @@ func TestAutomationCheckPerformGasLimit(t *testing.T) { registryVersion := rv t.Run(name, func(t *testing.T) { t.Parallel() - - chainClient, chainlinkNodes, contractDeployer, linkToken, registry, registrar, onlyStartRunner, _ := setupAutomationTest( + chainClient, chainlinkNodes, contractDeployer, linkToken, registry, registrar, _ := setupAutomationTestDocker( t, "gas-limit", registryVersion, defaultOCRRegistryConfig, false, ) - if onlyStartRunner { - return - } consumersPerformance, upkeepIDs := actions.DeployPerformanceConsumers( t, @@ -767,7 +889,7 @@ func TestAutomationCheckPerformGasLimit(t *testing.T) { highCheckGasLimit := automationDefaultRegistryConfig highCheckGasLimit.CheckGasLimit = uint32(5000000) highCheckGasLimit.RegistryVersion = registryVersion - ocrConfig, err := actions.BuildAutoOCR2ConfigVars(t, nodesWithoutBootstrap, highCheckGasLimit, registrar.Address(), 30*time.Second) + ocrConfig, err := actions.BuildAutoOCR2ConfigVarsLocal(t, nodesWithoutBootstrap, highCheckGasLimit, registrar.Address(), 30*time.Second) require.NoError(t, err, "Error building OCR config") err = registry.SetConfig(highCheckGasLimit, ocrConfig) @@ -801,13 +923,9 @@ func TestUpdateCheckData(t *testing.T) { registryVersion := rv t.Run(name, func(t *testing.T) { t.Parallel() - - chainClient, _, contractDeployer, linkToken, registry, registrar, onlyStartRunner, _ := setupAutomationTest( + chainClient, _, contractDeployer, linkToken, registry, registrar, _ := setupAutomationTestDocker( t, "update-check-data", registryVersion, defaultOCRRegistryConfig, false, ) - if onlyStartRunner { - return - } performDataChecker, upkeepIDs := actions.DeployPerformDataCheckerConsumers( t, @@ -865,103 +983,78 @@ func TestUpdateCheckData(t *testing.T) { } } -func setupAutomationTest( +func setupAutomationTestDocker( t *testing.T, testName string, registryVersion ethereum.KeeperRegistryVersion, registryConfig contracts.KeeperRegistrySettings, statefulDb bool, ) ( - chainClient blockchain.EVMClient, - chainlinkNodes []*client.ChainlinkK8sClient, - contractDeployer contracts.ContractDeployer, - linkToken contracts.LinkToken, - registry contracts.KeeperRegistry, - registrar contracts.KeeperRegistrar, - onlyStartRunner bool, - testEnvironment *environment.Environment, + blockchain.EVMClient, + []*client.ChainlinkClient, + contracts.ContractDeployer, + contracts.LinkToken, + contracts.KeeperRegistry, + contracts.KeeperRegistrar, + *test_env.CLClusterTestEnv, ) { // Add registry version to config registryConfig.RegistryVersion = registryVersion - network := networks.SelectedNetwork - evmConfig := eth.New(nil) - if !network.Simulated { - evmConfig = eth.New(ð.Props{ - NetworkName: network.Name, - Simulated: network.Simulated, - WsURLs: network.URLs, - }) - } - chainlinkProps := map[string]any{ - "toml": client.AddNetworksConfig(automationBaseTOML, network), - "secretsToml": client.AddSecretTomlConfig("https://google.com", "username1", "password1"), - "db": map[string]any{ - "stateful": statefulDb, - }, - } - - cd, err := chainlink.NewDeployment(5, chainlinkProps) - require.NoError(t, err, "Failed to create chainlink deployment") - testEnvironment = environment.New(&environment.Config{ - NamespacePrefix: fmt.Sprintf("smoke-automation-%s-%s", testName, strings.ReplaceAll(strings.ToLower(network.Name), " ", "-")), - Test: t, - }). - AddHelm(evmConfig). - AddHelmCharts(cd) - err = testEnvironment.Run() - - require.NoError(t, err, "Error setting up test environment") - - onlyStartRunner = testEnvironment.WillUseRemoteRunner() - if !onlyStartRunner { - chainClient, err = blockchain.NewEVMClient(network, testEnvironment) - require.NoError(t, err, "Error connecting to blockchain") - contractDeployer, err = contracts.NewContractDeployer(chainClient) - require.NoError(t, err, "Error building contract deployer") - chainlinkNodes, err = client.ConnectChainlinkNodes(testEnvironment) - require.NoError(t, err, "Error connecting to Chainlink nodes") - t.Cleanup(func() { - if err := actions.ReturnFunds(chainlinkNodes, chainClient); err != nil { - log.Error().Err(err).Msg("Error returning funds") - } - }) - chainClient.ParallelTransactions(true) - - txCost, err := chainClient.EstimateCostForChainlinkOperations(1000) - require.NoError(t, err, "Error estimating cost for Chainlink Operations") - err = actions.FundChainlinkNodes(chainlinkNodes, chainClient, txCost) - require.NoError(t, err, "Error funding Chainlink nodes") - - linkToken, err = contractDeployer.DeployLinkTokenContract() - require.NoError(t, err, "Error deploying LINK token") - - registry, registrar = actions.DeployAutoOCRRegistryAndRegistrar( - t, - registryVersion, - registryConfig, - linkToken, - contractDeployer, - chainClient, - ) - - // Fund the registry with LINK - err = linkToken.Transfer(registry.Address(), big.NewInt(0).Mul(big.NewInt(1e18), big.NewInt(int64(defaultAmountOfUpkeeps)))) - require.NoError(t, err, "Funding keeper registry contract shouldn't fail") - - actions.CreateOCRKeeperJobs(t, chainlinkNodes, registry.Address(), network.ChainID, 0, registryVersion) - nodesWithoutBootstrap := chainlinkNodes[1:] - ocrConfig, err := actions.BuildAutoOCR2ConfigVars(t, nodesWithoutBootstrap, registryConfig, registrar.Address(), 30*time.Second) - require.NoError(t, err, "Error building OCR config vars") - err = registry.SetConfig(automationDefaultRegistryConfig, ocrConfig) - require.NoError(t, err, "Registry config should be set successfully") - require.NoError(t, chainClient.WaitForEvents(), "Waiting for config to be set") - // Register cleanup for any test - t.Cleanup(func() { - err := actions.TeardownSuite(t, testEnvironment, utils.ProjectRoot, chainlinkNodes, nil, zapcore.ErrorLevel, chainClient) - require.NoError(t, err, "Error tearing down environment") - }) - } - return chainClient, chainlinkNodes, contractDeployer, linkToken, registry, registrar, onlyStartRunner, testEnvironment + // build the node config + clNodeConfig := node.NewConfig(node.BaseConf) + syncInterval := models.MustMakeDuration(5 * time.Minute) + clNodeConfig.Feature.LogPoller = it_utils.Ptr[bool](true) + clNodeConfig.OCR2.Enabled = it_utils.Ptr[bool](true) + clNodeConfig.Keeper.TurnLookBack = it_utils.Ptr[int64](int64(0)) + clNodeConfig.Keeper.Registry.SyncInterval = &syncInterval + clNodeConfig.Keeper.Registry.PerformGasOverhead = it_utils.Ptr[uint32](uint32(150000)) + clNodeConfig.P2P.V2.Enabled = it_utils.Ptr[bool](true) + clNodeConfig.P2P.V2.AnnounceAddresses = &[]string{"0.0.0.0:6690"} + clNodeConfig.P2P.V2.ListenAddresses = &[]string{"0.0.0.0:6690"} + + // launch the environment + env, err := test_env.NewCLTestEnvBuilder(). + WithGeth(). + WithMockServer(1). + WithCLNodes(5). + WithCLNodeConfig(clNodeConfig). + WithFunding(big.NewFloat(.5)). + Build() + require.NoError(t, err, "Error deploying test environment") + env.ParallelTransactions(true) + + txCost, err := env.EVMClient.EstimateCostForChainlinkOperations(1000) + require.NoError(t, err, "Error estimating cost for Chainlink Operations") + nodeClients := env.GetAPIs() + workerNodes := nodeClients[1:] + err = actions.FundChainlinkNodesLocal(workerNodes, env.EVMClient, txCost) + require.NoError(t, err, "Error funding Chainlink nodes") + + linkToken, err := env.ContractDeployer.DeployLinkTokenContract() + require.NoError(t, err, "Error deploying LINK token") + + registry, registrar := actions.DeployAutoOCRRegistryAndRegistrar( + t, + registryVersion, + registryConfig, + linkToken, + env.ContractDeployer, + env.EVMClient, + ) + + // Fund the registry with LINK + err = linkToken.Transfer(registry.Address(), big.NewInt(0).Mul(big.NewInt(1e18), big.NewInt(int64(defaultAmountOfUpkeeps)))) + require.NoError(t, err, "Funding keeper registry contract shouldn't fail") + + err = actions.CreateOCRKeeperJobsLocal(nodeClients, registry.Address(), network.ChainID, 0, registryVersion) + require.NoError(t, err, "Error creating OCR Keeper Jobs") + ocrConfig, err := actions.BuildAutoOCR2ConfigVarsLocal(t, workerNodes, registryConfig, registrar.Address(), 30*time.Second) + require.NoError(t, err, "Error building OCR config vars") + err = registry.SetConfig(automationDefaultRegistryConfig, ocrConfig) + require.NoError(t, err, "Registry config should be set successfully") + require.NoError(t, env.EVMClient.WaitForEvents(), "Waiting for config to be set") + + return env.EVMClient, nodeClients, env.ContractDeployer, linkToken, registry, registrar, env } diff --git a/integration-tests/smoke/automation_test.go_test_list.json b/integration-tests/smoke/automation_test.go_test_list.json new file mode 100644 index 00000000000..515e1632701 --- /dev/null +++ b/integration-tests/smoke/automation_test.go_test_list.json @@ -0,0 +1,109 @@ +{ + "tests": [ + { + "name": "TestAutomationBasic", + "run": [ + { + "name": "registry_2_0" + }, + { + "name": "registry_2_1_conditional" + }, + { + "name": "registry_2_1_logtrigger" + } + ] + }, + { + "name": "TestAutomationAddFunds", + "run": [ + { + "name": "registry_2_0" + }, + { + "name": "registry_2_1" + } + ] + }, + { + "name": "TestAutomationPauseUnPause", + "run": [ + { + "name": "registry_2_0" + }, + { + "name": "registry_2_1" + } + ] + }, + { + "name": "TestAutomationRegisterUpkeep", + "run": [ + { + "name": "registry_2_0" + }, + { + "name": "registry_2_1" + } + ] + }, + { + "name": "TestAutomationPauseRegistry", + "run": [ + { + "name": "registry_2_0" + }, + { + "name": "registry_2_1" + } + ] + }, + { + "name": "TestAutomationKeeperNodesDown", + "run": [ + { + "name": "registry_2_0" + }, + { + "name": "registry_2_1" + } + ] + }, + { + "name": "TestAutomationPerformSimulation", + "run": [ + { + "name": "registry_2_0" + }, + { + "name": "registry_2_1" + } + ] + }, + { + "name": "TestAutomationCheckPerformGasLimit", + "run": [ + { + "name": "registry_2_0" + }, + { + "name": "registry_2_1" + } + ] + }, + { + "name": "TestUpdateCheckData", + "run": [ + { + "name": "registry_2_0" + }, + { + "name": "registry_2_1" + } + ] + }, + { + "name": "TestSetUpkeepTriggerConfig" + } + ] +} diff --git a/integration-tests/smoke/keeper_test.go_test_list.json b/integration-tests/smoke/keeper_test.go_test_list.json new file mode 100644 index 00000000000..864dbfdb1cf --- /dev/null +++ b/integration-tests/smoke/keeper_test.go_test_list.json @@ -0,0 +1,70 @@ +{ + "tests": [ + { + "name": "TestKeeperBasicSmoke" + }, + { + "name": "TestKeeperBlockCountPerTurn", + "run": [ + { + "name": "registry_1_1" + }, + { + "name": "registry_1_2" + }, + { + "name": "registry_1_3" + } + ] + }, + { + "name": "TestKeeperSimulation" + }, + { + "name": "TestKeeperCheckPerformGasLimit", + "run": [ + { + "name": "registry_1_2" + }, + { + "name": "registry_1_3" + } + ] + }, + { + "name": "TestKeeperRegisterUpkeep" + }, + { + "name": "TestKeeperAddFunds" + }, + { + "name": "TestKeeperRemove" + }, + { + "name": "TestKeeperPauseRegistry" + }, + { + "name": "TestKeeperMigrateRegistry" + }, + { + "name": "TestKeeperNodeDown", + "run": [ + { + "name": "registry_1_1" + }, + { + "name": "registry_1_2" + }, + { + "name": "registry_1_3" + } + ] + }, + { + "name": "TestKeeperPauseUnPauseUpkeep" + }, + { + "name": "TestKeeperUpdateCheckData" + } + ] +} diff --git a/integration-tests/smoke/ocr2_test.go b/integration-tests/smoke/ocr2_test.go index 6588586c39d..adaaf21ba19 100644 --- a/integration-tests/smoke/ocr2_test.go +++ b/integration-tests/smoke/ocr2_test.go @@ -16,13 +16,14 @@ import ( "github.com/smartcontractkit/chainlink-env/pkg/helm/mockserver" mockservercfg "github.com/smartcontractkit/chainlink-env/pkg/helm/mockserver-cfg" "github.com/smartcontractkit/chainlink-testing-framework/blockchain" + + "github.com/smartcontractkit/chainlink-testing-framework/networks" "github.com/smartcontractkit/chainlink-testing-framework/utils" "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/docker/test_env" - "github.com/smartcontractkit/chainlink/integration-tests/networks" "github.com/smartcontractkit/chainlink/integration-tests/types/config/node" ) diff --git a/integration-tests/smoke/ocr2vrf_test.go b/integration-tests/smoke/ocr2vrf_test.go index 504750fdafb..50a21b81d8e 100644 --- a/integration-tests/smoke/ocr2vrf_test.go +++ b/integration-tests/smoke/ocr2vrf_test.go @@ -15,13 +15,14 @@ import ( "github.com/smartcontractkit/chainlink-testing-framework/blockchain" "github.com/smartcontractkit/chainlink-testing-framework/utils" + "github.com/smartcontractkit/chainlink-testing-framework/networks" + "github.com/smartcontractkit/chainlink/integration-tests/actions" "github.com/smartcontractkit/chainlink/integration-tests/actions/ocr2vrf_actions" "github.com/smartcontractkit/chainlink/integration-tests/actions/ocr2vrf_actions/ocr2vrf_constants" "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/networks" ) func TestOCR2VRFRedeemModel(t *testing.T) { diff --git a/integration-tests/testsetups/ocr.go b/integration-tests/testsetups/ocr.go index 1c210af1174..07aa3b2c4e8 100644 --- a/integration-tests/testsetups/ocr.go +++ b/integration-tests/testsetups/ocr.go @@ -36,11 +36,12 @@ import ( "github.com/smartcontractkit/chainlink-testing-framework/utils" "github.com/smartcontractkit/libocr/gethwrappers/offchainaggregator" + "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/config" "github.com/smartcontractkit/chainlink/integration-tests/contracts" - "github.com/smartcontractkit/chainlink/integration-tests/networks" "github.com/smartcontractkit/chainlink/integration-tests/testreporters" ) diff --git a/plugins/cmd/chainlink-solana/main.go b/plugins/cmd/chainlink-solana/main.go index 150a9d840dd..df2824fb338 100644 --- a/plugins/cmd/chainlink-solana/main.go +++ b/plugins/cmd/chainlink-solana/main.go @@ -63,19 +63,15 @@ func (c *pluginRelayer) NewRelayer(ctx context.Context, config string, keystore return nil, fmt.Errorf("failed to decode config toml: %w:\n\t%s", err, config) } - // TODO BCF-2605 clean this up when the internal details of Solana Chain construction - // doesn't need `Configs` - cfgAdapter := solana.SolanaConfigs{&cfg.Solana} opts := solana.ChainOpts{ Logger: c.Logger, KeyStore: keystore, - Configs: solana.NewConfigs(cfgAdapter), } - relayExt, err := solana.NewRelayExtender(&cfg.Solana, opts) + chain, err := solana.NewChain(&cfg.Solana, opts) if err != nil { return nil, fmt.Errorf("failed to create chain: %w", err) } - ra := relay.NewRelayerAdapter(pkgsol.NewRelayer(c.Logger, relayExt), relayExt) + ra := relay.NewRelayerAdapter(pkgsol.NewRelayer(c.Logger, chain), chain) c.SubService(ra) diff --git a/plugins/cmd/chainlink-starknet/main.go b/plugins/cmd/chainlink-starknet/main.go index 15bd0122121..5015f70be2e 100644 --- a/plugins/cmd/chainlink-starknet/main.go +++ b/plugins/cmd/chainlink-starknet/main.go @@ -66,20 +66,16 @@ func (c *pluginRelayer) NewRelayer(ctx context.Context, config string, loopKs lo return nil, fmt.Errorf("failed to decode config toml: %w:\n\t%s", err, config) } - // TODO BCF-2605 clean this up when the internal details of Chain construction - // doesn't need `Configs` - cfgAdapter := starknet.StarknetConfigs{&cfg.Starknet} opts := starknet.ChainOpts{ Logger: c.Logger, KeyStore: loopKs, - Configs: starknet.NewConfigs(cfgAdapter), } - relayExt, err := starknet.NewRelayExtender(&cfg.Starknet, opts) + chain, err := starknet.NewChain(&cfg.Starknet, opts) if err != nil { return nil, fmt.Errorf("failed to create chain: %w", err) } - ra := relay.NewRelayerAdapter(pkgstarknet.NewRelayer(c.Logger, relayExt), relayExt) + ra := relay.NewRelayerAdapter(pkgstarknet.NewRelayer(c.Logger, chain), chain) c.SubService(ra) diff --git a/tools/flakeytests/runner.go b/tools/flakeytests/runner.go index 592b673a23b..67ef27fca6d 100644 --- a/tools/flakeytests/runner.go +++ b/tools/flakeytests/runner.go @@ -3,6 +3,8 @@ package flakeytests import ( "bufio" "bytes" + "encoding/json" + "errors" "fmt" "io" "log" @@ -10,13 +12,11 @@ import ( "os/exec" "regexp" "strings" + "time" ) var ( - failedTestRe = regexp.MustCompile(`^--- FAIL: (Test\w+)`) - logPanicRe = regexp.MustCompile(`^panic: Log in goroutine after (Test\w+)`) - - failedPkgRe = regexp.MustCompile(`^FAIL\s+github\.com\/smartcontractkit\/chainlink\/v2\/(\S+)`) + panicRe = regexp.MustCompile(`^panic:`) ) type Runner struct { @@ -53,29 +53,55 @@ func runGoTest(pkg string, tests []string, numReruns int, w io.Writer) error { return cmd.Run() } +type TestEvent struct { + Time time.Time + Action string + Package string + Test string + Elapsed float64 // seconds + Output string +} + +func newEvent(b []byte) (*TestEvent, error) { + e := &TestEvent{} + err := json.Unmarshal(b, e) + if err != nil { + return nil, err + } + + e.Package = strings.Replace(e.Package, "github.com/smartcontractkit/chainlink/v2/", "", -1) + return e, nil + +} + func parseOutput(readers ...io.Reader) (map[string]map[string]int, error) { - testsWithoutPackage := []string{} tests := map[string]map[string]int{} for _, r := range readers { s := bufio.NewScanner(r) for s.Scan() { - t := s.Text() - switch { - case failedTestRe.MatchString(t): - m := failedTestRe.FindStringSubmatch(t) - testsWithoutPackage = append(testsWithoutPackage, m[1]) - case logPanicRe.MatchString(t): - m := logPanicRe.FindStringSubmatch(t) - testsWithoutPackage = append(testsWithoutPackage, m[1]) - case failedPkgRe.MatchString(t): - p := failedPkgRe.FindStringSubmatch(t) - for _, t := range testsWithoutPackage { - if tests[p[1]] == nil { - tests[p[1]] = map[string]int{} + t := s.Bytes() + if len(t) == 0 { + continue + } + + e, err := newEvent(t) + if err != nil { + return nil, err + } + + switch e.Action { + case "fail": + if tests[e.Package] == nil { + tests[e.Package] = map[string]int{} + } + tests[e.Package][e.Test]++ + case "output": + if panicRe.MatchString(e.Output) { + if tests[e.Package] == nil { + tests[e.Package] = map[string]int{} } - tests[p[1]][t]++ + tests[e.Package][e.Test]++ } - testsWithoutPackage = []string{} } } @@ -86,6 +112,10 @@ func parseOutput(readers ...io.Reader) (map[string]map[string]int, error) { return tests, nil } +type exitCoder interface { + ExitCode() int +} + func (r *Runner) runTests(failedTests map[string]map[string]int) (io.Reader, error) { var out bytes.Buffer for pkg, tests := range failedTests { @@ -98,6 +128,10 @@ func (r *Runner) runTests(failedTests map[string]map[string]int) (io.Reader, err err := r.runTestFn(pkg, ts, r.numReruns, &out) if err != nil { log.Printf("Test command errored: %s\n", err) + var exErr exitCoder + if errors.As(err, &exErr) && exErr.ExitCode() > 0 { + return &out, nil + } return &out, err } } diff --git a/tools/flakeytests/runner_test.go b/tools/flakeytests/runner_test.go index 6560d43e2f9..4aadf916976 100644 --- a/tools/flakeytests/runner_test.go +++ b/tools/flakeytests/runner_test.go @@ -23,25 +23,7 @@ func newMockReporter() *mockReporter { } func TestParser(t *testing.T) { - output := ` ---- FAIL: TestLink (0.00s) - --- FAIL: TestLink/1.1_link#01 (0.00s) - currencies_test.go:325: - Error Trace: /Users/ccordenier/Development/chainlink/core/assets/currencies_test.go:325 - Error: Not equal: - expected: "1.2 link" - actual : "1.1 link" - - Diff: - --- Expected - +++ Actual - @@ -1 +1 @@ - -1.2 link - +1.1 link - Test: TestLink/1.1_link#01 -FAIL -FAIL github.com/smartcontractkit/chainlink/v2/core/assets 0.338s -FAIL + output := `{"Time":"2023-09-07T15:39:46.378315+01:00","Action":"fail","Package":"github.com/smartcontractkit/chainlink/v2/core/assets","Test":"TestLink","Elapsed":0} ` r := strings.NewReader(output) @@ -53,65 +35,9 @@ FAIL assert.Equal(t, ts["core/assets"]["TestLink"], 1) } -func TestParser_PanicInTest(t *testing.T) { - output := ` -? github.com/smartcontractkit/chainlink/v2/tools/flakeytests/cmd/runner [no test files] ---- FAIL: TestParser (0.00s) -panic: foo [recovered] - panic: foo - -goroutine 21 [running]: -testing.tRunner.func1.2({0x1009953c0, 0x1009d1e40}) - /opt/homebrew/Cellar/go/1.20.3/libexec/src/testing/testing.go:1526 +0x1c8 -testing.tRunner.func1() - /opt/homebrew/Cellar/go/1.20.3/libexec/src/testing/testing.go:1529 +0x384 -panic({0x1009953c0, 0x1009d1e40}) - /opt/homebrew/Cellar/go/1.20.3/libexec/src/runtime/panic.go:884 +0x204 -github.com/smartcontractkit/chainlink/v2/tools/flakeytests.TestParser(0x0?) - /Users/ccordenier/Development/chainlink/tools/flakeytests/runner_test.go:50 +0xa4 -testing.tRunner(0x14000083520, 0x1009d1588) - /opt/homebrew/Cellar/go/1.20.3/libexec/src/testing/testing.go:1576 +0x10c -created by testing.(*T).Run - /opt/homebrew/Cellar/go/1.20.3/libexec/src/testing/testing.go:1629 +0x368 -FAIL github.com/smartcontractkit/chainlink/v2/tools/flakeytests 0.197s -FAIL` - - r := strings.NewReader(output) - ts, err := parseOutput(r) - require.NoError(t, err) - - assert.Len(t, ts, 1) - assert.Len(t, ts["tools/flakeytests"], 1) - assert.Equal(t, ts["tools/flakeytests"]["TestParser"], 1) -} - func TestParser_PanicDueToLogging(t *testing.T) { output := ` -panic: Log in goroutine after TestIntegration_LogEventProvider_Backfill has completed: 2023-07-19T10:10:45.925Z WARN KeepersRegistry.LogEventProvider logprovider/provider.go:218 failed to read logs {"version": "2.3.0@d898528", "where": "reader", "err": "fetched logs with errors: context canceled"} - -goroutine 4999 [running]: -testing.(*common).logDepth(0xc0051f6000, {0xc003011960, 0xd3}, 0x3) - /opt/hostedtoolcache/go/1.20.5/x64/src/testing/testing.go:1003 +0x4e7 -testing.(*common).log(...) - /opt/hostedtoolcache/go/1.20.5/x64/src/testing/testing.go:985 -testing.(*common).Logf(0xc0051f6000, {0x21ba777?, 0x41ac8a?}, {0xc00217c330?, 0x1e530c0?, 0x1?}) - /opt/hostedtoolcache/go/1.20.5/x64/src/testing/testing.go:1036 +0x5a -go.uber.org/zap/zaptest.testingWriter.Write({{0x7f4c5c94f018?, 0xc0051f6000?}, 0xa8?}, {0xc003017000?, 0xd4, 0xc00217c320?}) - /home/runner/go/pkg/mod/go.uber.org/zap@v1.24.0/zaptest/logger.go:130 +0xe6 -go.uber.org/zap/zapcore.(*ioCore).Write(0xc0022f60f0, {0x1, {0xc1260b897723e1ca, 0x4bdc75e54, 0x3d56e40}, {0x22e96a1, 0x20}, {0x22c3204, 0x13}, {0x1, ...}, ...}, ...) - /home/runner/go/pkg/mod/go.uber.org/zap@v1.24.0/zapcore/core.go:99 +0xb5 -go.uber.org/zap/zapcore.(*CheckedEntry).Write(0xc001265ba0, {0xc0023ca100, 0x1, 0x2}) - /home/runner/go/pkg/mod/go.uber.org/zap@v1.24.0/zapcore/entry.go:255 +0x1d9 -go.uber.org/zap.(*SugaredLogger).log(0xc00363a008, 0x1, {0x22c3204?, 0x13?}, {0x0?, 0x0?, 0x0?}, {0xc004ea3f80, 0x2, 0x2}) - /home/runner/go/pkg/mod/go.uber.org/zap@v1.24.0/sugar.go:295 +0xee -go.uber.org/zap.(*SugaredLogger).Warnw(...) - /home/runner/go/pkg/mod/go.uber.org/zap@v1.24.0/sugar.go:216 -github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider.(*logEventProvider).startReader(0xc00076d730, {0x2917018?, 0xc0043c4000?}, 0xc003b2a000) - /home/runner/work/chainlink/chainlink/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/provider.go:218 +0x29f -created by github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider.(*logEventProvider).Start - /home/runner/work/chainlink/chainlink/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/provider.go:108 +0x133 -FAIL github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider 20.380s -FAIL +{"Time":"2023-09-07T16:01:40.649849+01:00","Action":"output","Package":"github.com/smartcontractkit/chainlink/v2/core/assets","Test":"TestAssets_LinkScanValue","Output":"panic: foo\n"} ` r := strings.NewReader(output) @@ -119,14 +45,24 @@ FAIL require.NoError(t, err) assert.Len(t, ts, 1) - assert.Len(t, ts["core/services/ocr2/plugins/ocr2keeper/evm21/logprovider"], 1) - assert.Equal(t, ts["core/services/ocr2/plugins/ocr2keeper/evm21/logprovider"]["TestIntegration_LogEventProvider_Backfill"], 1) + assert.Len(t, ts["core/assets"], 1) + assert.Equal(t, ts["core/assets"]["TestAssets_LinkScanValue"], 1) } func TestParser_SuccessfulOutput(t *testing.T) { output := ` -? github.com/smartcontractkit/chainlink/v2/tools/flakeytests/cmd/runner [no test files] -ok github.com/smartcontractkit/chainlink/v2/tools/flakeytests 0.320s +{"Time":"2023-09-07T16:22:52.556853+01:00","Action":"start","Package":"github.com/smartcontractkit/chainlink/v2/core/assets"} +{"Time":"2023-09-07T16:22:52.762353+01:00","Action":"run","Package":"github.com/smartcontractkit/chainlink/v2/core/assets","Test":"TestAssets_NewLinkAndString"} +{"Time":"2023-09-07T16:22:52.762456+01:00","Action":"output","Package":"github.com/smartcontractkit/chainlink/v2/core/assets","Test":"TestAssets_NewLinkAndString","Output":"=== RUN TestAssets_NewLinkAndString\n"} +{"Time":"2023-09-07T16:22:52.76249+01:00","Action":"output","Package":"github.com/smartcontractkit/chainlink/v2/core/assets","Test":"TestAssets_NewLinkAndString","Output":"=== PAUSE TestAssets_NewLinkAndString\n"} +{"Time":"2023-09-07T16:22:52.7625+01:00","Action":"pause","Package":"github.com/smartcontractkit/chainlink/v2/core/assets","Test":"TestAssets_NewLinkAndString"} +{"Time":"2023-09-07T16:22:52.762511+01:00","Action":"cont","Package":"github.com/smartcontractkit/chainlink/v2/core/assets","Test":"TestAssets_NewLinkAndString"} +{"Time":"2023-09-07T16:22:52.762528+01:00","Action":"output","Package":"github.com/smartcontractkit/chainlink/v2/core/assets","Test":"TestAssets_NewLinkAndString","Output":"=== CONT TestAssets_NewLinkAndString\n"} +{"Time":"2023-09-07T16:22:52.762546+01:00","Action":"output","Package":"github.com/smartcontractkit/chainlink/v2/core/assets","Test":"TestAssets_NewLinkAndString","Output":"--- PASS: TestAssets_NewLinkAndString (0.00s)\n"} +{"Time":"2023-09-07T16:22:52.762557+01:00","Action":"pass","Package":"github.com/smartcontractkit/chainlink/v2/core/assets","Test":"TestAssets_NewLinkAndString","Elapsed":0} +{"Time":"2023-09-07T16:22:52.762566+01:00","Action":"output","Package":"github.com/smartcontractkit/chainlink/v2/core/assets","Output":"PASS\n"} +{"Time":"2023-09-07T16:22:52.762955+01:00","Action":"output","Package":"github.com/smartcontractkit/chainlink/v2/core/assets","Output":"ok \tgithub.com/smartcontractkit/chainlink/v2/core/assets\t0.206s\n"} +{"Time":"2023-09-07T16:22:52.765598+01:00","Action":"pass","Package":"github.com/smartcontractkit/chainlink/v2/core/assets","Elapsed":0.209} ` r := strings.NewReader(output) @@ -136,26 +72,7 @@ ok github.com/smartcontractkit/chainlink/v2/tools/flakeytests 0.320s } func TestRunner_WithFlake(t *testing.T) { - output := ` ---- FAIL: TestLink (0.00s) - --- FAIL: TestLink/1.1_link#01 (0.00s) - currencies_test.go:325: - Error Trace: /Users/ccordenier/Development/chainlink/core/assets/currencies_test.go:325 - Error: Not equal: - expected: "1.2 link" - actual : "1.1 link" - - Diff: - --- Expected - +++ Actual - @@ -1 +1 @@ - -1.2 link - +1.1 link - Test: TestLink/1.1_link#01 -FAIL -FAIL github.com/smartcontractkit/chainlink/v2/core/assets 0.338s -FAIL -` + output := `{"Time":"2023-09-07T15:39:46.378315+01:00","Action":"fail","Package":"github.com/smartcontractkit/chainlink/v2/core/assets","Test":"TestLink","Elapsed":0}` m := newMockReporter() r := &Runner{ numReruns: 2, @@ -177,61 +94,11 @@ FAIL } func TestRunner_AllFailures(t *testing.T) { - output := ` ---- FAIL: TestLink (0.00s) - --- FAIL: TestLink/1.1_link#01 (0.00s) - currencies_test.go:325: - Error Trace: /Users/ccordenier/Development/chainlink/core/assets/currencies_test.go:325 - Error: Not equal: - expected: "1.2 link" - actual : "1.1 link" - - Diff: - --- Expected - +++ Actual - @@ -1 +1 @@ - -1.2 link - +1.1 link - Test: TestLink/1.1_link#01 -FAIL -FAIL github.com/smartcontractkit/chainlink/v2/core/assets 0.338s -FAIL -` + output := `{"Time":"2023-09-07T15:39:46.378315+01:00","Action":"fail","Package":"github.com/smartcontractkit/chainlink/v2/core/assets","Test":"TestLink","Elapsed":0}` rerunOutput := ` ---- FAIL: TestLink (0.00s) - --- FAIL: TestLink/1.1_link#01 (0.00s) - currencies_test.go:325: - Error Trace: /Users/ccordenier/Development/chainlink/core/assets/currencies_test.go:325 - Error: Not equal: - expected: "1.2 link" - actual : "1.1 link" - - Diff: - --- Expected - +++ Actual - @@ -1 +1 @@ - -1.2 link - +1.1 link - Test: TestLink/1.1_link#01 ---- FAIL: TestLink (0.00s) - --- FAIL: TestLink/1.1_link#01 (0.00s) - currencies_test.go:325: - Error Trace: /Users/ccordenier/Development/chainlink/core/assets/currencies_test.go:325 - Error: Not equal: - expected: "1.2 link" - actual : "1.1 link" - - Diff: - --- Expected - +++ Actual - @@ -1 +1 @@ - -1.2 link - +1.1 link - Test: TestLink/1.1_link#01 -FAIL -FAIL github.com/smartcontractkit/chainlink/v2/core/assets 0.315s -FAIL +{"Time":"2023-09-07T15:39:46.378315+01:00","Action":"fail","Package":"github.com/smartcontractkit/chainlink/v2/core/assets","Test":"TestLink","Elapsed":0} +{"Time":"2023-09-07T15:39:46.378315+01:00","Action":"fail","Package":"github.com/smartcontractkit/chainlink/v2/core/assets","Test":"TestLink","Elapsed":0} ` m := newMockReporter() r := &Runner{ @@ -251,29 +118,11 @@ FAIL } func TestRunner_RerunSuccessful(t *testing.T) { - output := ` ---- FAIL: TestLink (0.00s) - --- FAIL: TestLink/1.1_link#01 (0.00s) - currencies_test.go:325: - Error Trace: /Users/ccordenier/Development/chainlink/core/assets/currencies_test.go:325 - Error: Not equal: - expected: "1.2 link" - actual : "1.1 link" - - Diff: - --- Expected - +++ Actual - @@ -1 +1 @@ - -1.2 link - +1.1 link - Test: TestLink/1.1_link#01 -FAIL -FAIL github.com/smartcontractkit/chainlink/v2/core/assets 0.338s -FAIL -` + output := `{"Time":"2023-09-07T15:39:46.378315+01:00","Action":"fail","Package":"github.com/smartcontractkit/chainlink/v2/core/assets","Test":"TestLink","Elapsed":0}` rerunOutput := ` -ok github.com/smartcontractkit/chainlink/v2/core/assets 0.320s +{"Time":"2023-09-07T15:39:46.378315+01:00","Action":"fail","Package":"github.com/smartcontractkit/chainlink/v2/core/assets","Test":"TestLink","Elapsed":0} +{"Time":"2023-09-07T15:39:46.378315+01:00","Action":"pass","Package":"github.com/smartcontractkit/chainlink/v2/core/assets","Test":"TestLink","Elapsed":0} ` m := newMockReporter() r := &Runner{ @@ -291,3 +140,33 @@ ok github.com/smartcontractkit/chainlink/v2/core/assets 0.320s require.NoError(t, err) assert.Equal(t, m.entries["core/assets"], []string{"TestLink"}) } + +type exitError struct{} + +func (e *exitError) ExitCode() int { return 1 } + +func (e *exitError) Error() string { return "exit code: 1" } + +func TestRunner_RerunFailsWithNonzeroExitCode(t *testing.T) { + output := `{"Time":"2023-09-07T15:39:46.378315+01:00","Action":"fail","Package":"github.com/smartcontractkit/chainlink/v2/core/assets","Test":"TestLink","Elapsed":0}` + + rerunOutput := ` +{"Time":"2023-09-07T15:39:46.378315+01:00","Action":"fail","Package":"github.com/smartcontractkit/chainlink/v2/core/assets","Test":"TestLink","Elapsed":0} +{"Time":"2023-09-07T15:39:46.378315+01:00","Action":"pass","Package":"github.com/smartcontractkit/chainlink/v2/core/assets","Test":"TestLink","Elapsed":0} +` + m := newMockReporter() + r := &Runner{ + numReruns: 2, + readers: []io.Reader{strings.NewReader(output)}, + runTestFn: func(pkg string, testNames []string, numReruns int, w io.Writer) error { + _, _ = w.Write([]byte(rerunOutput)) + return &exitError{} + }, + parse: parseOutput, + reporter: m, + } + + err := r.Run() + require.NoError(t, err) + assert.Equal(t, m.entries["core/assets"], []string{"TestLink"}) +}