diff --git a/.changeset/cyan-ladybugs-check.md b/.changeset/cyan-ladybugs-check.md new file mode 100644 index 00000000000..d430890001a --- /dev/null +++ b/.changeset/cyan-ladybugs-check.md @@ -0,0 +1,5 @@ +--- +"chainlink": patch +--- + +validates response from gateway in workflow/fetcher diff --git a/.changeset/eight-meals-march.md b/.changeset/eight-meals-march.md new file mode 100644 index 00000000000..f2439280063 --- /dev/null +++ b/.changeset/eight-meals-march.md @@ -0,0 +1,7 @@ +--- +"chainlink": patch +--- + +Prevents a panic in test helper for confirming transaction +and adds encrypted public key to a peer before calling addNodes +on CapabilitiesRegistry diff --git a/.changeset/long-apples-fold.md b/.changeset/long-apples-fold.md new file mode 100644 index 00000000000..ba3e731951f --- /dev/null +++ b/.changeset/long-apples-fold.md @@ -0,0 +1,5 @@ +--- +"chainlink": patch +--- + +DEVSVCS-958: fix automation v2.3 batching bug #bugfix diff --git a/.github/integration-in-memory-tests.yml b/.github/integration-in-memory-tests.yml index ef0bf95c596..01bb90044f4 100644 --- a/.github/integration-in-memory-tests.yml +++ b/.github/integration-in-memory-tests.yml @@ -55,13 +55,13 @@ runner-test-matrix: - PR Integration CCIP Tests test_cmd: cd integration-tests/smoke/ccip && go test ccip_batching_test.go -timeout 12m -test.parallel=2 -count=1 -json - - id: contracts/ccipreader_test.go:* - path: integration-tests/contracts/ccipreader_test.go + - id: smoke/ccip/ccip_reader_test.go:* + path: integration-tests/smoke/ccip/ccip_reader_test.go test_env_type: in-memory runs_on: ubuntu-latest triggers: - PR Integration CCIP Tests - test_cmd: cd integration-tests/contracts && go test ccipreader_test.go -timeout 5m -test.parallel=1 -count=1 -json + test_cmd: cd integration-tests/smoke/ccip && go test ccip_reader_test.go -timeout 5m -test.parallel=1 -count=1 -json - id: smoke/ccip/ccip_usdc_test.go:* path: integration-tests/smoke/ccip/ccip_usdc_test.go diff --git a/.github/workflows/integration-tests.yml b/.github/workflows/integration-tests.yml index 33bb7721d77..0677e9bc226 100644 --- a/.github/workflows/integration-tests.yml +++ b/.github/workflows/integration-tests.yml @@ -175,7 +175,7 @@ jobs: contents: read needs: [build-chainlink, changes] if: github.event_name == 'pull_request' && ( needs.changes.outputs.core_changes == 'true' || needs.changes.outputs.github_ci_changes == 'true') - uses: smartcontractkit/.github/.github/workflows/run-e2e-tests.yml@0632b5652dd5eb03bfa87e23a2b3e2911484fe59 + uses: smartcontractkit/.github/.github/workflows/run-e2e-tests.yml@fb79097de87a6391457ccc36f82387746d1cef55 with: workflow_name: Run Core E2E Tests For PR chainlink_version: ${{ inputs.evm-ref || github.sha }} @@ -192,7 +192,6 @@ jobs: PROD_AWS_ACCOUNT_NUMBER: ${{ secrets.AWS_ACCOUNT_ID_PROD }} QA_PYROSCOPE_INSTANCE: ${{ secrets.QA_PYROSCOPE_INSTANCE }} QA_PYROSCOPE_KEY: ${{ secrets.QA_PYROSCOPE_KEY }} - QA_KUBECONFIG: ${{ secrets.QA_KUBECONFIG }} GRAFANA_INTERNAL_TENANT_ID: ${{ secrets.GRAFANA_INTERNAL_TENANT_ID }} GRAFANA_INTERNAL_BASIC_AUTH: ${{ secrets.GRAFANA_INTERNAL_BASIC_AUTH }} GRAFANA_INTERNAL_HOST: ${{ secrets.GRAFANA_INTERNAL_HOST }} @@ -205,6 +204,8 @@ jobs: AWS_OIDC_IAM_ROLE_VALIDATION_PROD_ARN: ${{ secrets.AWS_OIDC_IAM_ROLE_VALIDATION_PROD_ARN }} AWS_API_GW_HOST_GRAFANA: ${{ secrets.AWS_API_GW_HOST_GRAFANA }} SLACK_BOT_TOKEN: ${{ secrets.QA_SLACK_API_KEY }} + MAIN_DNS_ZONE_PUBLIC_SDLC: ${{ secrets.MAIN_DNS_ZONE_PUBLIC_SDLC }} + AWS_K8S_CLUSTER_NAME_SDLC: ${{ secrets.AWS_K8S_CLUSTER_NAME_SDLC }} run-core-e2e-tests-for-merge-queue: name: Run Core E2E Tests For Merge Queue @@ -216,7 +217,7 @@ jobs: contents: read needs: [build-chainlink, changes] if: github.event_name == 'merge_group' && ( needs.changes.outputs.core_changes == 'true' || needs.changes.outputs.github_ci_changes == 'true') - uses: smartcontractkit/.github/.github/workflows/run-e2e-tests.yml@0632b5652dd5eb03bfa87e23a2b3e2911484fe59 + uses: smartcontractkit/.github/.github/workflows/run-e2e-tests.yml@fb79097de87a6391457ccc36f82387746d1cef55 with: workflow_name: Run Core E2E Tests For Merge Queue chainlink_version: ${{ inputs.evm-ref || github.sha }} @@ -237,7 +238,6 @@ jobs: PROD_AWS_ACCOUNT_NUMBER: ${{ secrets.AWS_ACCOUNT_ID_PROD }} QA_PYROSCOPE_INSTANCE: ${{ secrets.QA_PYROSCOPE_INSTANCE }} QA_PYROSCOPE_KEY: ${{ secrets.QA_PYROSCOPE_KEY }} - QA_KUBECONFIG: ${{ secrets.QA_KUBECONFIG }} GRAFANA_INTERNAL_TENANT_ID: ${{ secrets.GRAFANA_INTERNAL_TENANT_ID }} GRAFANA_INTERNAL_BASIC_AUTH: ${{ secrets.GRAFANA_INTERNAL_BASIC_AUTH }} GRAFANA_INTERNAL_HOST: ${{ secrets.GRAFANA_INTERNAL_HOST }} @@ -250,6 +250,8 @@ jobs: AWS_OIDC_IAM_ROLE_VALIDATION_PROD_ARN: ${{ secrets.AWS_OIDC_IAM_ROLE_VALIDATION_PROD_ARN }} AWS_API_GW_HOST_GRAFANA: ${{ secrets.AWS_API_GW_HOST_GRAFANA }} SLACK_BOT_TOKEN: ${{ secrets.QA_SLACK_API_KEY }} + MAIN_DNS_ZONE_PUBLIC_SDLC: ${{ secrets.MAIN_DNS_ZONE_PUBLIC_SDLC }} + AWS_K8S_CLUSTER_NAME_SDLC: ${{ secrets.AWS_K8S_CLUSTER_NAME_SDLC }} run-ccip-e2e-tests-for-pr: name: Run CCIP E2E Tests For PR @@ -261,7 +263,7 @@ jobs: contents: read needs: [build-chainlink, changes] if: github.event_name == 'pull_request' && (needs.changes.outputs.ccip_changes == 'true' || needs.changes.outputs.github_ci_changes == 'true') - uses: smartcontractkit/.github/.github/workflows/run-e2e-tests.yml@0632b5652dd5eb03bfa87e23a2b3e2911484fe59 + uses: smartcontractkit/.github/.github/workflows/run-e2e-tests.yml@fb79097de87a6391457ccc36f82387746d1cef55 with: workflow_name: Run CCIP E2E Tests For PR chainlink_version: ${{ inputs.evm-ref || github.sha }} @@ -279,7 +281,6 @@ jobs: PROD_AWS_ACCOUNT_NUMBER: ${{ secrets.AWS_ACCOUNT_ID_PROD }} QA_PYROSCOPE_INSTANCE: ${{ secrets.QA_PYROSCOPE_INSTANCE }} QA_PYROSCOPE_KEY: ${{ secrets.QA_PYROSCOPE_KEY }} - QA_KUBECONFIG: ${{ secrets.QA_KUBECONFIG }} GRAFANA_INTERNAL_TENANT_ID: ${{ secrets.GRAFANA_INTERNAL_TENANT_ID }} GRAFANA_INTERNAL_BASIC_AUTH: ${{ secrets.GRAFANA_INTERNAL_BASIC_AUTH }} GRAFANA_INTERNAL_HOST: ${{ secrets.GRAFANA_INTERNAL_HOST }} @@ -292,6 +293,8 @@ jobs: AWS_OIDC_IAM_ROLE_VALIDATION_PROD_ARN: ${{ secrets.AWS_OIDC_IAM_ROLE_VALIDATION_PROD_ARN }} AWS_API_GW_HOST_GRAFANA: ${{ secrets.AWS_API_GW_HOST_GRAFANA }} SLACK_BOT_TOKEN: ${{ secrets.QA_SLACK_API_KEY }} + MAIN_DNS_ZONE_PUBLIC_SDLC: ${{ secrets.MAIN_DNS_ZONE_PUBLIC_SDLC }} + AWS_K8S_CLUSTER_NAME_SDLC: ${{ secrets.AWS_K8S_CLUSTER_NAME_SDLC }} run-ccip-e2e-tests-for-merge-queue: name: Run CCIP E2E Tests For Merge Queue @@ -303,7 +306,7 @@ jobs: contents: read needs: [build-chainlink, changes] if: github.event_name == 'merge_group' && (needs.changes.outputs.ccip_changes == 'true' || needs.changes.outputs.github_ci_changes == 'true') - uses: smartcontractkit/.github/.github/workflows/run-e2e-tests.yml@0632b5652dd5eb03bfa87e23a2b3e2911484fe59 + uses: smartcontractkit/.github/.github/workflows/run-e2e-tests.yml@fb79097de87a6391457ccc36f82387746d1cef55 with: workflow_name: Run CCIP E2E Tests For Merge Queue chainlink_version: ${{ inputs.evm-ref || github.sha }} @@ -321,7 +324,6 @@ jobs: PROD_AWS_ACCOUNT_NUMBER: ${{ secrets.AWS_ACCOUNT_ID_PROD }} QA_PYROSCOPE_INSTANCE: ${{ secrets.QA_PYROSCOPE_INSTANCE }} QA_PYROSCOPE_KEY: ${{ secrets.QA_PYROSCOPE_KEY }} - QA_KUBECONFIG: ${{ secrets.QA_KUBECONFIG }} GRAFANA_INTERNAL_TENANT_ID: ${{ secrets.GRAFANA_INTERNAL_TENANT_ID }} GRAFANA_INTERNAL_BASIC_AUTH: ${{ secrets.GRAFANA_INTERNAL_BASIC_AUTH }} GRAFANA_INTERNAL_HOST: ${{ secrets.GRAFANA_INTERNAL_HOST }} @@ -334,6 +336,8 @@ jobs: AWS_OIDC_IAM_ROLE_VALIDATION_PROD_ARN: ${{ secrets.AWS_OIDC_IAM_ROLE_VALIDATION_PROD_ARN }} AWS_API_GW_HOST_GRAFANA: ${{ secrets.AWS_API_GW_HOST_GRAFANA }} SLACK_BOT_TOKEN: ${{ secrets.QA_SLACK_API_KEY }} + MAIN_DNS_ZONE_PUBLIC_SDLC: ${{ secrets.MAIN_DNS_ZONE_PUBLIC_SDLC }} + AWS_K8S_CLUSTER_NAME_SDLC: ${{ secrets.AWS_K8S_CLUSTER_NAME_SDLC }} check-e2e-test-results: if: always() diff --git a/.github/workflows/on-demand-vrfv2-performance-test.yml b/.github/workflows/on-demand-vrfv2-performance-test.yml index 2f3ea12cbe2..85ded7f1a58 100644 --- a/.github/workflows/on-demand-vrfv2-performance-test.yml +++ b/.github/workflows/on-demand-vrfv2-performance-test.yml @@ -18,16 +18,16 @@ on: test_config_override_path: description: Path to a test config file used to override the default test config required: false - type: string + type: string test_secrets_override_key: description: 'Key to run tests with custom test secrets' required: false - type: string + type: string notify_user_id_on_failure: description: 'Enter Slack user ID to notify on test failure' required: false - type: string - + type: string + jobs: set-tests-to-run: name: Set tests to run @@ -60,7 +60,7 @@ jobs: "test_cmd": $test_cmd, "test_config_override_path": $test_config_override_path, "test_env_vars": { - "TEST_TYPE": $TEST_TYPE + "TEST_TYPE": $TEST_TYPE } } ] @@ -71,13 +71,13 @@ jobs: run-e2e-tests-workflow: name: Run E2E Tests needs: set-tests-to-run - uses: smartcontractkit/.github/.github/workflows/run-e2e-tests.yml@0632b5652dd5eb03bfa87e23a2b3e2911484fe59 + uses: smartcontractkit/.github/.github/workflows/run-e2e-tests.yml@fb79097de87a6391457ccc36f82387746d1cef55 with: custom_test_list_json: ${{ needs.set-tests-to-run.outputs.test_list }} chainlink_version: ${{ inputs.chainlink_version }} slack_notification_after_tests: always slack_notification_after_tests_name: "VRF V2 Performance Tests with test config: ${{ inputs.test_config_override_path || 'default' }}" - slack_notification_after_tests_notify_user_id_on_failure: ${{ inputs.notify_user_id_on_failure }} + slack_notification_after_tests_notify_user_id_on_failure: ${{ inputs.notify_user_id_on_failure }} secrets: QA_AWS_REGION: ${{ secrets.QA_AWS_REGION }} QA_AWS_ROLE_TO_ASSUME: ${{ secrets.QA_AWS_ROLE_TO_ASSUME }} @@ -85,7 +85,6 @@ jobs: PROD_AWS_ACCOUNT_NUMBER: ${{ secrets.AWS_ACCOUNT_ID_PROD }} QA_PYROSCOPE_INSTANCE: ${{ secrets.QA_PYROSCOPE_INSTANCE }} QA_PYROSCOPE_KEY: ${{ secrets.QA_PYROSCOPE_KEY }} - QA_KUBECONFIG: ${{ secrets.QA_KUBECONFIG }} GRAFANA_INTERNAL_TENANT_ID: ${{ secrets.GRAFANA_INTERNAL_TENANT_ID }} GRAFANA_INTERNAL_BASIC_AUTH: ${{ secrets.GRAFANA_INTERNAL_BASIC_AUTH }} GRAFANA_INTERNAL_HOST: ${{ secrets.GRAFANA_INTERNAL_HOST }} @@ -93,11 +92,13 @@ jobs: LOKI_TENANT_ID: ${{ secrets.LOKI_TENANT_ID }} LOKI_URL: ${{ secrets.LOKI_URL }} LOKI_BASIC_AUTH: ${{ secrets.LOKI_BASIC_AUTH }} - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} AWS_REGION: ${{ secrets.QA_AWS_REGION }} AWS_OIDC_IAM_ROLE_VALIDATION_PROD_ARN: ${{ secrets.AWS_OIDC_IAM_ROLE_VALIDATION_PROD_ARN }} - AWS_API_GW_HOST_GRAFANA: ${{ secrets.AWS_API_GW_HOST_GRAFANA }} + AWS_API_GW_HOST_GRAFANA: ${{ secrets.AWS_API_GW_HOST_GRAFANA }} TEST_SECRETS_OVERRIDE_BASE64: ${{ secrets[inputs.test_secrets_override_key] }} SLACK_BOT_TOKEN: ${{ secrets.QA_SLACK_API_KEY }} SLACK_API_KEY: ${{ secrets.QA_SLACK_API_KEY }} - SLACK_CHANNEL: ${{ secrets.QA_VRF_SLACK_CHANNEL }} + SLACK_CHANNEL: ${{ secrets.QA_VRF_SLACK_CHANNEL }} + MAIN_DNS_ZONE_PUBLIC_SDLC: ${{ secrets.MAIN_DNS_ZONE_PUBLIC_SDLC }} + AWS_K8S_CLUSTER_NAME_SDLC: ${{ secrets.AWS_K8S_CLUSTER_NAME_SDLC }} diff --git a/.github/workflows/on-demand-vrfv2-smoke-tests.yml b/.github/workflows/on-demand-vrfv2-smoke-tests.yml index db242c1aae2..ddfdedca54d 100644 --- a/.github/workflows/on-demand-vrfv2-smoke-tests.yml +++ b/.github/workflows/on-demand-vrfv2-smoke-tests.yml @@ -17,7 +17,7 @@ on: test_config_override_path: description: Path to a test config file used to override the default test config required: false - type: string + type: string test_secrets_override_key: description: 'Key to run tests with custom test secrets' required: false @@ -31,7 +31,7 @@ on: description: 'Enter Slack user ID to notify on test failure' required: false type: string - + jobs: set-tests-to-run: name: Set tests to run @@ -74,7 +74,7 @@ jobs: run-e2e-tests-workflow: name: Run E2E Tests needs: set-tests-to-run - uses: smartcontractkit/.github/.github/workflows/run-e2e-tests.yml@0632b5652dd5eb03bfa87e23a2b3e2911484fe59 + uses: smartcontractkit/.github/.github/workflows/run-e2e-tests.yml@fb79097de87a6391457ccc36f82387746d1cef55 with: custom_test_list_json: ${{ needs.set-tests-to-run.outputs.test_list }} chainlink_version: ${{ inputs.chainlink_version }} @@ -88,7 +88,6 @@ jobs: PROD_AWS_ACCOUNT_NUMBER: ${{ secrets.AWS_ACCOUNT_ID_PROD }} QA_PYROSCOPE_INSTANCE: ${{ secrets.QA_PYROSCOPE_INSTANCE }} QA_PYROSCOPE_KEY: ${{ secrets.QA_PYROSCOPE_KEY }} - QA_KUBECONFIG: ${{ secrets.QA_KUBECONFIG }} GRAFANA_INTERNAL_TENANT_ID: ${{ secrets.GRAFANA_INTERNAL_TENANT_ID }} GRAFANA_INTERNAL_BASIC_AUTH: ${{ secrets.GRAFANA_INTERNAL_BASIC_AUTH }} GRAFANA_INTERNAL_HOST: ${{ secrets.GRAFANA_INTERNAL_HOST }} @@ -96,10 +95,12 @@ jobs: LOKI_TENANT_ID: ${{ secrets.LOKI_TENANT_ID }} LOKI_URL: ${{ secrets.LOKI_URL }} LOKI_BASIC_AUTH: ${{ secrets.LOKI_BASIC_AUTH }} - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} AWS_REGION: ${{ secrets.QA_AWS_REGION }} AWS_OIDC_IAM_ROLE_VALIDATION_PROD_ARN: ${{ secrets.AWS_OIDC_IAM_ROLE_VALIDATION_PROD_ARN }} - AWS_API_GW_HOST_GRAFANA: ${{ secrets.AWS_API_GW_HOST_GRAFANA }} + AWS_API_GW_HOST_GRAFANA: ${{ secrets.AWS_API_GW_HOST_GRAFANA }} TEST_SECRETS_OVERRIDE_BASE64: ${{ secrets[inputs.test_secrets_override_key] }} SLACK_BOT_TOKEN: ${{ secrets.QA_SLACK_API_KEY }} SLACK_NOTIFICATION_AFTER_TESTS_CHANNEL_ID: ${{ secrets.QA_VRF_SLACK_CHANNEL }} + MAIN_DNS_ZONE_PUBLIC_SDLC: ${{ secrets.MAIN_DNS_ZONE_PUBLIC_SDLC }} + AWS_K8S_CLUSTER_NAME_SDLC: ${{ secrets.AWS_K8S_CLUSTER_NAME_SDLC }} diff --git a/.github/workflows/on-demand-vrfv2plus-performance-test.yml b/.github/workflows/on-demand-vrfv2plus-performance-test.yml index 66878c552fd..fc9b9f7d8f3 100644 --- a/.github/workflows/on-demand-vrfv2plus-performance-test.yml +++ b/.github/workflows/on-demand-vrfv2plus-performance-test.yml @@ -13,11 +13,11 @@ on: test_config_override_path: description: Path to a test config file used to override the default test config required: false - type: string + type: string test_secrets_override_key: description: 'Key to run tests with custom test secrets' required: false - type: string + type: string chainlink_version: description: Chainlink image version to use default: develop @@ -26,7 +26,7 @@ on: notify_user_id_on_failure: description: 'Enter Slack user ID to notify on test failure' required: false - type: string + type: string jobs: set-tests-to-run: @@ -60,7 +60,7 @@ jobs: "test_cmd": $test_cmd, "test_config_override_path": $test_config_override_path, "test_env_vars": { - "TEST_TYPE": $TEST_TYPE + "TEST_TYPE": $TEST_TYPE } } ] @@ -71,7 +71,7 @@ jobs: run-e2e-tests-workflow: name: Run E2E Tests needs: set-tests-to-run - uses: smartcontractkit/.github/.github/workflows/run-e2e-tests.yml@0632b5652dd5eb03bfa87e23a2b3e2911484fe59 + uses: smartcontractkit/.github/.github/workflows/run-e2e-tests.yml@fb79097de87a6391457ccc36f82387746d1cef55 with: custom_test_list_json: ${{ needs.set-tests-to-run.outputs.test_list }} chainlink_version: ${{ inputs.chainlink_version }} @@ -85,7 +85,6 @@ jobs: PROD_AWS_ACCOUNT_NUMBER: ${{ secrets.AWS_ACCOUNT_ID_PROD }} QA_PYROSCOPE_INSTANCE: ${{ secrets.QA_PYROSCOPE_INSTANCE }} QA_PYROSCOPE_KEY: ${{ secrets.QA_PYROSCOPE_KEY }} - QA_KUBECONFIG: ${{ secrets.QA_KUBECONFIG }} GRAFANA_INTERNAL_TENANT_ID: ${{ secrets.GRAFANA_INTERNAL_TENANT_ID }} GRAFANA_INTERNAL_BASIC_AUTH: ${{ secrets.GRAFANA_INTERNAL_BASIC_AUTH }} GRAFANA_INTERNAL_HOST: ${{ secrets.GRAFANA_INTERNAL_HOST }} @@ -93,12 +92,14 @@ jobs: LOKI_TENANT_ID: ${{ secrets.LOKI_TENANT_ID }} LOKI_URL: ${{ secrets.LOKI_URL }} LOKI_BASIC_AUTH: ${{ secrets.LOKI_BASIC_AUTH }} - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} AWS_REGION: ${{ secrets.QA_AWS_REGION }} AWS_OIDC_IAM_ROLE_VALIDATION_PROD_ARN: ${{ secrets.AWS_OIDC_IAM_ROLE_VALIDATION_PROD_ARN }} - AWS_API_GW_HOST_GRAFANA: ${{ secrets.AWS_API_GW_HOST_GRAFANA }} + AWS_API_GW_HOST_GRAFANA: ${{ secrets.AWS_API_GW_HOST_GRAFANA }} TEST_SECRETS_OVERRIDE_BASE64: ${{ secrets[inputs.test_secrets_override_key] }} SLACK_BOT_TOKEN: ${{ secrets.QA_SLACK_API_KEY }} SLACK_NOTIFICATION_AFTER_TESTS_CHANNEL_ID: ${{ secrets.QA_VRF_SLACK_CHANNEL }} SLACK_API_KEY: ${{ secrets.QA_SLACK_API_KEY }} - SLACK_CHANNEL: ${{ secrets.QA_VRF_SLACK_CHANNEL }} + SLACK_CHANNEL: ${{ secrets.QA_VRF_SLACK_CHANNEL }} + MAIN_DNS_ZONE_PUBLIC_SDLC: ${{ secrets.MAIN_DNS_ZONE_PUBLIC_SDLC }} + AWS_K8S_CLUSTER_NAME_SDLC: ${{ secrets.AWS_K8S_CLUSTER_NAME_SDLC }} diff --git a/.github/workflows/on-demand-vrfv2plus-smoke-tests.yml b/.github/workflows/on-demand-vrfv2plus-smoke-tests.yml index 51c80af9bfa..b44a41fd137 100644 --- a/.github/workflows/on-demand-vrfv2plus-smoke-tests.yml +++ b/.github/workflows/on-demand-vrfv2plus-smoke-tests.yml @@ -17,7 +17,7 @@ on: test_config_override_path: description: Path to a test config file used to override the default test config required: false - type: string + type: string test_secrets_override_key: description: 'Key to run tests with custom test secrets' required: false @@ -31,7 +31,7 @@ on: description: 'Enter Slack user ID to notify on test failure' required: false type: string - + jobs: set-tests-to-run: name: Set tests to run @@ -74,7 +74,7 @@ jobs: run-e2e-tests-workflow: name: Run E2E Tests needs: set-tests-to-run - uses: smartcontractkit/.github/.github/workflows/run-e2e-tests.yml@0632b5652dd5eb03bfa87e23a2b3e2911484fe59 + uses: smartcontractkit/.github/.github/workflows/run-e2e-tests.yml@fb79097de87a6391457ccc36f82387746d1cef55 with: custom_test_list_json: ${{ needs.set-tests-to-run.outputs.test_list }} chainlink_version: ${{ inputs.chainlink_version }} @@ -88,7 +88,6 @@ jobs: PROD_AWS_ACCOUNT_NUMBER: ${{ secrets.AWS_ACCOUNT_ID_PROD }} QA_PYROSCOPE_INSTANCE: ${{ secrets.QA_PYROSCOPE_INSTANCE }} QA_PYROSCOPE_KEY: ${{ secrets.QA_PYROSCOPE_KEY }} - QA_KUBECONFIG: ${{ secrets.QA_KUBECONFIG }} GRAFANA_INTERNAL_TENANT_ID: ${{ secrets.GRAFANA_INTERNAL_TENANT_ID }} GRAFANA_INTERNAL_BASIC_AUTH: ${{ secrets.GRAFANA_INTERNAL_BASIC_AUTH }} GRAFANA_INTERNAL_HOST: ${{ secrets.GRAFANA_INTERNAL_HOST }} @@ -96,10 +95,12 @@ jobs: LOKI_TENANT_ID: ${{ secrets.LOKI_TENANT_ID }} LOKI_URL: ${{ secrets.LOKI_URL }} LOKI_BASIC_AUTH: ${{ secrets.LOKI_BASIC_AUTH }} - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} AWS_REGION: ${{ secrets.QA_AWS_REGION }} AWS_OIDC_IAM_ROLE_VALIDATION_PROD_ARN: ${{ secrets.AWS_OIDC_IAM_ROLE_VALIDATION_PROD_ARN }} - AWS_API_GW_HOST_GRAFANA: ${{ secrets.AWS_API_GW_HOST_GRAFANA }} + AWS_API_GW_HOST_GRAFANA: ${{ secrets.AWS_API_GW_HOST_GRAFANA }} TEST_SECRETS_OVERRIDE_BASE64: ${{ secrets[inputs.test_secrets_override_key] }} SLACK_BOT_TOKEN: ${{ secrets.QA_SLACK_API_KEY }} SLACK_NOTIFICATION_AFTER_TESTS_CHANNEL_ID: ${{ secrets.QA_VRF_SLACK_CHANNEL }} + MAIN_DNS_ZONE_PUBLIC_SDLC: ${{ secrets.MAIN_DNS_ZONE_PUBLIC_SDLC }} + AWS_K8S_CLUSTER_NAME_SDLC: ${{ secrets.AWS_K8S_CLUSTER_NAME_SDLC }} diff --git a/.github/workflows/run-nightly-e2e-tests.yml b/.github/workflows/run-nightly-e2e-tests.yml index 712fb088181..23b2f7ce7c1 100644 --- a/.github/workflows/run-nightly-e2e-tests.yml +++ b/.github/workflows/run-nightly-e2e-tests.yml @@ -20,7 +20,7 @@ on: jobs: call-run-e2e-tests-workflow: name: Run E2E Tests - uses: smartcontractkit/.github/.github/workflows/run-e2e-tests.yml@0632b5652dd5eb03bfa87e23a2b3e2911484fe59 + uses: smartcontractkit/.github/.github/workflows/run-e2e-tests.yml@fb79097de87a6391457ccc36f82387746d1cef55 with: chainlink_version: ${{ inputs.chainlink_version || 'develop' }} test_path: .github/e2e-tests.yml @@ -35,7 +35,6 @@ jobs: PROD_AWS_ACCOUNT_NUMBER: ${{ secrets.AWS_ACCOUNT_ID_PROD }} QA_PYROSCOPE_INSTANCE: ${{ secrets.QA_PYROSCOPE_INSTANCE }} QA_PYROSCOPE_KEY: ${{ secrets.QA_PYROSCOPE_KEY }} - QA_KUBECONFIG: ${{ secrets.QA_KUBECONFIG }} GRAFANA_INTERNAL_TENANT_ID: ${{ secrets.GRAFANA_INTERNAL_TENANT_ID }} GRAFANA_INTERNAL_BASIC_AUTH: ${{ secrets.GRAFANA_INTERNAL_BASIC_AUTH }} GRAFANA_INTERNAL_HOST: ${{ secrets.GRAFANA_INTERNAL_HOST }} @@ -43,8 +42,10 @@ jobs: LOKI_TENANT_ID: ${{ secrets.LOKI_TENANT_ID }} LOKI_URL: ${{ secrets.LOKI_URL }} LOKI_BASIC_AUTH: ${{ secrets.LOKI_BASIC_AUTH }} - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} AWS_REGION: ${{ secrets.QA_AWS_REGION }} AWS_OIDC_IAM_ROLE_VALIDATION_PROD_ARN: ${{ secrets.AWS_OIDC_IAM_ROLE_VALIDATION_PROD_ARN }} - AWS_API_GW_HOST_GRAFANA: ${{ secrets.AWS_API_GW_HOST_GRAFANA }} + AWS_API_GW_HOST_GRAFANA: ${{ secrets.AWS_API_GW_HOST_GRAFANA }} SLACK_BOT_TOKEN: ${{ secrets.QA_SLACK_API_KEY }} + MAIN_DNS_ZONE_PUBLIC_SDLC: ${{ secrets.MAIN_DNS_ZONE_PUBLIC_SDLC }} + AWS_K8S_CLUSTER_NAME_SDLC: ${{ secrets.AWS_K8S_CLUSTER_NAME_SDLC }} diff --git a/.github/workflows/run-selected-e2e-tests.yml b/.github/workflows/run-selected-e2e-tests.yml index e95ce1cef19..ba96c3daa54 100644 --- a/.github/workflows/run-selected-e2e-tests.yml +++ b/.github/workflows/run-selected-e2e-tests.yml @@ -15,7 +15,7 @@ on: test_secrets_override_key: description: 'Enter the secret key to override test secrets' required: false - type: string + type: string test_config_override_path: description: 'Path to a test config file used to override the default test config' required: false @@ -23,19 +23,19 @@ on: with_existing_remote_runner_version: description: 'Use the existing remote runner version for k8s tests. Example: "d3bf5044af33e08be788a2df31c4a745cf69d787"' required: false - type: string + type: string workflow_run_name: description: 'Enter the name of the workflow run' default: 'Run E2E Tests' required: false type: string - + run-name: ${{ inputs.workflow_run_name }} jobs: call-run-e2e-tests-workflow: name: Run E2E Tests - uses: smartcontractkit/.github/.github/workflows/run-e2e-tests.yml@0632b5652dd5eb03bfa87e23a2b3e2911484fe59 + uses: smartcontractkit/.github/.github/workflows/run-e2e-tests.yml@fb79097de87a6391457ccc36f82387746d1cef55 with: chainlink_version: ${{ github.event.inputs.chainlink_version }} test_path: .github/e2e-tests.yml @@ -49,7 +49,6 @@ jobs: PROD_AWS_ACCOUNT_NUMBER: ${{ secrets.AWS_ACCOUNT_ID_PROD }} QA_PYROSCOPE_INSTANCE: ${{ secrets.QA_PYROSCOPE_INSTANCE }} QA_PYROSCOPE_KEY: ${{ secrets.QA_PYROSCOPE_KEY }} - QA_KUBECONFIG: ${{ secrets.QA_KUBECONFIG }} GRAFANA_INTERNAL_TENANT_ID: ${{ secrets.GRAFANA_INTERNAL_TENANT_ID }} GRAFANA_INTERNAL_BASIC_AUTH: ${{ secrets.GRAFANA_INTERNAL_BASIC_AUTH }} GRAFANA_INTERNAL_HOST: ${{ secrets.GRAFANA_INTERNAL_HOST }} @@ -57,9 +56,11 @@ jobs: LOKI_TENANT_ID: ${{ secrets.LOKI_TENANT_ID }} LOKI_URL: ${{ secrets.LOKI_URL }} LOKI_BASIC_AUTH: ${{ secrets.LOKI_BASIC_AUTH }} - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} AWS_REGION: ${{ secrets.QA_AWS_REGION }} AWS_OIDC_IAM_ROLE_VALIDATION_PROD_ARN: ${{ secrets.AWS_OIDC_IAM_ROLE_VALIDATION_PROD_ARN }} AWS_API_GW_HOST_GRAFANA: ${{ secrets.AWS_API_GW_HOST_GRAFANA }} TEST_SECRETS_OVERRIDE_BASE64: ${{ secrets[inputs.test_secrets_override_key] }} SLACK_BOT_TOKEN: ${{ secrets.QA_SLACK_API_KEY }} + MAIN_DNS_ZONE_PUBLIC_SDLC: ${{ secrets.MAIN_DNS_ZONE_PUBLIC_SDLC }} + AWS_K8S_CLUSTER_NAME_SDLC: ${{ secrets.AWS_K8S_CLUSTER_NAME_SDLC }} diff --git a/contracts/.changeset/chilly-news-wink.md b/contracts/.changeset/chilly-news-wink.md new file mode 100644 index 00000000000..2ccdbb483ca --- /dev/null +++ b/contracts/.changeset/chilly-news-wink.md @@ -0,0 +1,10 @@ +--- +'@chainlink/contracts': minor +--- + +#feature Add two new pool types: Siloed-LockRelease and BurnToAddress and fix bug in HybridUSDCTokenPool for transferLiqudity #bugfix + + +PR issue: CCIP-4723 + +Solidity Review issue: CCIP-3966 \ No newline at end of file diff --git a/contracts/.changeset/poor-turtles-give.md b/contracts/.changeset/poor-turtles-give.md new file mode 100644 index 00000000000..7776bdd195e --- /dev/null +++ b/contracts/.changeset/poor-turtles-give.md @@ -0,0 +1,5 @@ +--- +'@chainlink/contracts': patch +--- + +DEVSVCS-958: fix automation v2.3 batching bug #bugfix diff --git a/contracts/gas-snapshots/ccip.gas-snapshot b/contracts/gas-snapshots/ccip.gas-snapshot index 842bfaeff5d..7a8979891e4 100644 --- a/contracts/gas-snapshots/ccip.gas-snapshot +++ b/contracts/gas-snapshots/ccip.gas-snapshot @@ -4,6 +4,9 @@ BurnMintTokenPool_lockOrBurn:test_PoolBurn() (gas: 236872) BurnMintTokenPool_lockOrBurn:test_Setup() (gas: 17819) BurnMintTokenPool_releaseOrMint:test_PoolMint() (gas: 102527) BurnMintWithLockReleaseFlagTokenPool_lockOrBurn:test_LockOrBurn_CorrectReturnData() (gas: 237292) +BurnToAddressMintTokenPool_lockOrBurn:test_LockOrBurn() (gas: 257956) +BurnToAddressMintTokenPool_releaseOrMint:test_releaseOrMint() (gas: 126048) +BurnToAddressMintTokenPool_setOutstandingokens:test_setOutstandingTokens() (gas: 37793) BurnWithFromMintTokenPool_lockOrBurn:test_PoolBurn() (gas: 239012) BurnWithFromMintTokenPool_lockOrBurn:test_Setup() (gas: 24169) CCIPClientExample_sanity:test_ImmutableExamples() (gas: 2078616) @@ -136,12 +139,11 @@ FeeQuoter_updateTokenPriceFeeds:test_SingleFeedUpdate() (gas: 53171) FeeQuoter_updateTokenPriceFeeds:test_ZeroFeeds() (gas: 12471) FeeQuoter_validateDestFamilyAddress:test_ValidEVMAddress() (gas: 6796) FeeQuoter_validateDestFamilyAddress:test_ValidSVMAddress() (gas: 6657) -HybridLockReleaseUSDCTokenPool_TransferLiquidity:test_transferLiquidity() (gas: 167013) -HybridLockReleaseUSDCTokenPool_lockOrBurn:test_PrimaryMechanism() (gas: 130356) -HybridLockReleaseUSDCTokenPool_lockOrBurn:test_onLockReleaseMechanism() (gas: 140104) +HybridLockReleaseUSDCTokenPool_lockOrBurn:test_PrimaryMechanism() (gas: 130339) +HybridLockReleaseUSDCTokenPool_lockOrBurn:test_onLockReleaseMechanism() (gas: 140169) HybridLockReleaseUSDCTokenPool_lockOrBurn:test_onLockReleaseMechanism_thenSwitchToPrimary() (gas: 202967) -HybridLockReleaseUSDCTokenPool_releaseOrMint:test_OnLockReleaseMechanism() (gas: 206218) -HybridLockReleaseUSDCTokenPool_releaseOrMint:test_incomingMessageWithPrimaryMechanism() (gas: 260387) +HybridLockReleaseUSDCTokenPool_releaseOrMint:test_OnLockReleaseMechanism() (gas: 206350) +HybridLockReleaseUSDCTokenPool_releaseOrMint:test_incomingMessageWithPrimaryMechanism() (gas: 260423) LockReleaseTokenPool_canAcceptLiquidity:test_CanAcceptLiquidity() (gas: 3222607) LockReleaseTokenPool_lockOrBurn:test_LockOrBurnWithAllowList() (gas: 72828) LockReleaseTokenPool_releaseOrMint:test_ReleaseOrMint() (gas: 217898) @@ -358,6 +360,22 @@ Router_recoverTokens:test_RecoverTokens() (gas: 52686) Router_routeMessage:test_routeMessage_AutoExec() (gas: 38071) Router_routeMessage:test_routeMessage_ExecutionEvent() (gas: 153593) Router_routeMessage:test_routeMessage_ManualExec() (gas: 31120) +SiloedLockReleaseTokenPool_lockOrBurn:test_lockOrBurn_SiloedFunds() (gas: 76874) +SiloedLockReleaseTokenPool_lockOrBurn:test_lockOrBurn_UnsiloedFunds() (gas: 76104) +SiloedLockReleaseTokenPool_provideLiqudity:test_ProvideLiquidity_LegacyProvideLiquiditySelector() (gas: 91873) +SiloedLockReleaseTokenPool_provideLiqudity:test_ProvideLiquidity_SiloedChain() (gas: 82416) +SiloedLockReleaseTokenPool_provideLiqudity:test_ProvideLiquidity_UnsiloedChain() (gas: 84036) +SiloedLockReleaseTokenPool_releaseOrMint:test_ReleaseOrMint_RevertsWhen_InsufficientLiquidity_SiloedChain() (gas: 110002) +SiloedLockReleaseTokenPool_releaseOrMint:test_ReleaseOrMint_RevertsWhen_InsufficientLiquidity_UnsiloedChain() (gas: 115718) +SiloedLockReleaseTokenPool_releaseOrMint:test_ReleaseOrMint_SiloedChain() (gas: 262340) +SiloedLockReleaseTokenPool_releaseOrMint:test_ReleaseOrMint_UnsiloedChain() (gas: 263392) +SiloedLockReleaseTokenPool_setRebalancer:test_setRebalancer_UnsiloedChains() (gas: 24429) +SiloedLockReleaseTokenPool_setRebalancer:test_setSiloRebalancer() (gas: 32165) +SiloedLockReleaseTokenPool_updateSiloDesignations:test_updateSiloDesignations() (gas: 105825) +SiloedLockReleaseTokenPool_withdrawLiqudity:test_withdrawLiquidity_RevertsWhen_LegacyFunctionSelectorUnauthorized() (gas: 18244) +SiloedLockReleaseTokenPool_withdrawLiqudity:test_withdrawLiquidity_SiloedFunds() (gas: 70948) +SiloedLockReleaseTokenPool_withdrawLiqudity:test_withdrawLiquidity_UnsiloedFunds_LegacyFunctionSelector() (gas: 76391) +SiloedLockReleaseTokenPool_withdrawLiqudity:test_withdrawSiloedLiquidity_UnsiloedFunds() (gas: 71945) TokenAdminRegistry_acceptAdminRole:test_acceptAdminRole() (gas: 44236) TokenAdminRegistry_addRegistryModule:test_addRegistryModule() (gas: 67093) TokenAdminRegistry_getAllConfiguredTokens:test_getAllConfiguredTokens_outOfBounds() (gas: 11363) @@ -397,22 +415,22 @@ TokenPool_parseRemoteDecimals:test_parseRemoteDecimals() (gas: 14030) TokenPool_parseRemoteDecimals:test_parseRemoteDecimals_NoDecimalsDefaultsToLocalDecimals() (gas: 9705) TokenPool_removeRemotePool:test_removeRemotePool() (gas: 188402) TokenPool_setRateLimitAdmin:test_SetRateLimitAdmin() (gas: 37630) -USDCBridgeMigrator_BurnLockedUSDC:test_PrimaryMechanism() (gas: 130520) -USDCBridgeMigrator_BurnLockedUSDC:test_lockOrBurn_then_BurnInCCTPMigration() (gas: 303986) -USDCBridgeMigrator_BurnLockedUSDC:test_onLockReleaseMechanism() (gas: 140171) +USDCBridgeMigrator_BurnLockedUSDC:test_PrimaryMechanism() (gas: 130502) +USDCBridgeMigrator_BurnLockedUSDC:test_lockOrBurn_then_BurnInCCTPMigration() (gas: 303967) +USDCBridgeMigrator_BurnLockedUSDC:test_onLockReleaseMechanism() (gas: 140236) USDCBridgeMigrator_BurnLockedUSDC:test_onLockReleaseMechanism_thenSwitchToPrimary() (gas: 203330) -USDCBridgeMigrator_cancelMigrationProposal:test_cancelExistingCCTPMigrationProposal() (gas: 56117) -USDCBridgeMigrator_provideLiquidity:test_PrimaryMechanism() (gas: 130538) -USDCBridgeMigrator_provideLiquidity:test_lockOrBurn_then_BurnInCCTPMigration() (gas: 303986) -USDCBridgeMigrator_provideLiquidity:test_onLockReleaseMechanism() (gas: 140260) +USDCBridgeMigrator_cancelMigrationProposal:test_cancelExistingCCTPMigrationProposal() (gas: 56100) +USDCBridgeMigrator_provideLiquidity:test_PrimaryMechanism() (gas: 130520) +USDCBridgeMigrator_provideLiquidity:test_lockOrBurn_then_BurnInCCTPMigration() (gas: 303967) +USDCBridgeMigrator_provideLiquidity:test_onLockReleaseMechanism() (gas: 140325) USDCBridgeMigrator_provideLiquidity:test_onLockReleaseMechanism_thenSwitchToPrimary() (gas: 203331) -USDCBridgeMigrator_releaseOrMint:test_OnLockReleaseMechanism() (gas: 206251) -USDCBridgeMigrator_releaseOrMint:test_incomingMessageWithPrimaryMechanism() (gas: 260440) -USDCBridgeMigrator_releaseOrMint:test_unstickManualTxAfterMigration_destChain() (gas: 142763) -USDCBridgeMigrator_releaseOrMint:test_unstickManualTxAfterMigration_homeChain() (gas: 505520) -USDCBridgeMigrator_updateChainSelectorMechanism:test_PrimaryMechanism() (gas: 130520) -USDCBridgeMigrator_updateChainSelectorMechanism:test_lockOrBurn_then_BurnInCCTPMigration() (gas: 303968) -USDCBridgeMigrator_updateChainSelectorMechanism:test_onLockReleaseMechanism() (gas: 140260) +USDCBridgeMigrator_releaseOrMint:test_OnLockReleaseMechanism() (gas: 206383) +USDCBridgeMigrator_releaseOrMint:test_incomingMessageWithPrimaryMechanism() (gas: 260476) +USDCBridgeMigrator_releaseOrMint:test_unstickManualTxAfterMigration_destChain() (gas: 142853) +USDCBridgeMigrator_releaseOrMint:test_unstickManualTxAfterMigration_homeChain() (gas: 505540) +USDCBridgeMigrator_updateChainSelectorMechanism:test_PrimaryMechanism() (gas: 130502) +USDCBridgeMigrator_updateChainSelectorMechanism:test_lockOrBurn_then_BurnInCCTPMigration() (gas: 303949) +USDCBridgeMigrator_updateChainSelectorMechanism:test_onLockReleaseMechanism() (gas: 140325) USDCBridgeMigrator_updateChainSelectorMechanism:test_onLockReleaseMechanism_thenSwitchToPrimary() (gas: 203312) USDCTokenPool_lockOrBurn:test_LockOrBurn() (gas: 128094) USDCTokenPool_releaseOrMint:test_ReleaseOrMintRealTx() (gas: 260189) diff --git a/contracts/src/v0.8/automation/test/v2_3/AutomationRegistry2_3.t.sol b/contracts/src/v0.8/automation/test/v2_3/AutomationRegistry2_3.t.sol index 41aabf1bbe2..e461060e27d 100644 --- a/contracts/src/v0.8/automation/test/v2_3/AutomationRegistry2_3.t.sol +++ b/contracts/src/v0.8/automation/test/v2_3/AutomationRegistry2_3.t.sol @@ -1653,6 +1653,140 @@ contract Transmit is SetUp { vm.stopPrank(); } + struct PaymentReceipt { + uint96 gasChargeInBillingToken; + uint96 premiumInBillingToken; + uint96 gasReimbursementInJuels; + uint96 premiumInJuels; + IERC20 billingToken; + uint96 linkUSD; + uint96 nativeUSD; + uint96 billingUSD; + } + event ReorgedUpkeepReport(uint256 indexed id, bytes trigger); + event UpkeepCharged(uint256 indexed id, PaymentReceipt receipt); + event UpkeepPerformed( + uint256 indexed id, + bool indexed success, + uint96 totalPayment, + uint256 gasUsed, + uint256 gasOverhead, + bytes trigger + ); + function test_whenFirstUpkeepFails_subsequentUpkeepsPerform() external { + // the first and second upkeeps use LINK as billing token and the third uses WETH + // the first upkeep fails the pre perform check due to incorrect block number in its trigger + // the second and third upkeep perform + // the first upkeep should not be charged and the second and third upkeep should be charged + uint256[] memory prevUpkeepBalances = new uint256[](3); + prevUpkeepBalances[0] = registry.getBalance(linkUpkeepID); + prevUpkeepBalances[1] = registry.getBalance(linkUpkeepID2); + prevUpkeepBalances[2] = registry.getBalance(nativeUpkeepID); + uint256[] memory prevTokenBalances = new uint256[](2); + prevTokenBalances[0] = linkToken.balanceOf(address(registry)); + prevTokenBalances[1] = weth.balanceOf(address(registry)); + uint256[] memory prevReserveBalances = new uint256[](2); + prevReserveBalances[0] = registry.getReserveAmount(address(linkToken)); + prevReserveBalances[1] = registry.getReserveAmount(address(weth)); + uint256[] memory upkeepIDs = new uint256[](3); + upkeepIDs[0] = linkUpkeepID; + upkeepIDs[1] = linkUpkeepID2; + upkeepIDs[2] = nativeUpkeepID; + + // do the transmit + vm.expectEmit(); + emit ReorgedUpkeepReport(linkUpkeepID, abi.encode(block.number, blockhash(block.number))); + vm.expectEmit(true, false, false, false); + emit UpkeepCharged(linkUpkeepID2, PaymentReceipt(0, 0, 0, 0, linkToken, 0, 0, 0)); + vm.expectEmit(true, true, false, false); + emit UpkeepPerformed(linkUpkeepID2, true, 0, 0, 0, bytes("")); + vm.expectEmit(true, false, false, false); + emit UpkeepCharged(nativeUpkeepID, PaymentReceipt(0, 0, 0, 0, linkToken, 0, 0, 0)); + vm.expectEmit(true, true, false, false); + emit UpkeepPerformed(nativeUpkeepID, true, 0, 0, 0, bytes("")); + bool[] memory goodTriggers = new bool[](3); + goodTriggers[0] = false; + goodTriggers[1] = true; + goodTriggers[2] = true; + _batchTransmitWithBadTriggers(upkeepIDs, goodTriggers, registry); + + // assert upkeep balances + // the first upkeep fails and the second and third upkeep succeeds + require(prevUpkeepBalances[0] == registry.getBalance(linkUpkeepID), "link upkeep balance should remain the same"); + require(prevUpkeepBalances[1] > registry.getBalance(linkUpkeepID2), "link upkeep 2 balance should have decreased"); + require(prevUpkeepBalances[2] > registry.getBalance(nativeUpkeepID), "native upkeep balance should have decreased"); + // assert token balances have not changed + assertEq(prevTokenBalances[0], linkToken.balanceOf(address(registry))); + assertEq(prevTokenBalances[1], weth.balanceOf(address(registry))); + // assert reserve amounts have adjusted accordingly + require( + prevReserveBalances[0] < registry.getReserveAmount(address(linkToken)), + "link reserve amount should have increased" + ); // link reserve amount increases in value equal to the decrease of the other reserve amounts + require( + prevReserveBalances[1] > registry.getReserveAmount(address(weth)), + "native reserve amount should have decreased" + ); + } + + function test_whenSecondUpkeepFails_FirstAndThirdUpkeepsPerform() external { + // the first upkeep uses WETH as billing token and the second and third use LINK + // the first upkeep succeeds + // the second upkeep fails pre perform check due to incorrect block number in its trigger + // the third upkeep succeeds + // the second upkeep should not be charged and the first and third upkeep should be charged + uint256[] memory prevUpkeepBalances = new uint256[](3); + prevUpkeepBalances[0] = registry.getBalance(nativeUpkeepID); + prevUpkeepBalances[1] = registry.getBalance(linkUpkeepID); + prevUpkeepBalances[2] = registry.getBalance(linkUpkeepID2); + uint256[] memory prevTokenBalances = new uint256[](2); + prevTokenBalances[0] = weth.balanceOf(address(registry)); + prevTokenBalances[1] = linkToken.balanceOf(address(registry)); + uint256[] memory prevReserveBalances = new uint256[](2); + prevReserveBalances[0] = registry.getReserveAmount(address(weth)); + prevReserveBalances[1] = registry.getReserveAmount(address(linkToken)); + uint256[] memory upkeepIDs = new uint256[](3); + upkeepIDs[0] = nativeUpkeepID; + upkeepIDs[1] = linkUpkeepID; + upkeepIDs[2] = linkUpkeepID2; + + // do the transmit + // expect this event first because all the upkeeps will be checked first before they are performed and charged + vm.expectEmit(); + emit ReorgedUpkeepReport(linkUpkeepID, abi.encode(block.number, blockhash(block.number))); + vm.expectEmit(true, false, false, false); + emit UpkeepCharged(nativeUpkeepID, PaymentReceipt(0, 0, 0, 0, linkToken, 0, 0, 0)); + vm.expectEmit(true, true, false, false); + emit UpkeepPerformed(nativeUpkeepID, true, 0, 0, 0, bytes("")); + vm.expectEmit(true, false, false, false); + emit UpkeepCharged(linkUpkeepID2, PaymentReceipt(0, 0, 0, 0, linkToken, 0, 0, 0)); + vm.expectEmit(true, true, false, false); + emit UpkeepPerformed(linkUpkeepID2, true, 0, 0, 0, bytes("")); + bool[] memory goodTriggers = new bool[](3); + goodTriggers[0] = true; + goodTriggers[1] = false; + goodTriggers[2] = true; + _batchTransmitWithBadTriggers(upkeepIDs, goodTriggers, registry); + + // assert upkeep balances + // the first upkeep fails and the second and third upkeep succeeds + require(prevUpkeepBalances[0] > registry.getBalance(nativeUpkeepID), "native upkeep balance should have decreased"); + require(prevUpkeepBalances[1] == registry.getBalance(linkUpkeepID), "link upkeep balance should remain the same"); + require(prevUpkeepBalances[2] > registry.getBalance(linkUpkeepID2), "link upkeep 2 balance should have decreased"); + // assert token balances have not changed + assertEq(prevTokenBalances[0], weth.balanceOf(address(registry))); + assertEq(prevTokenBalances[1], linkToken.balanceOf(address(registry))); + // assert reserve amounts have adjusted accordingly + require( + prevReserveBalances[0] > registry.getReserveAmount(address(weth)), + "native reserve amount should have decreased" + ); // link reserve amount increases in value equal to the decrease of the other reserve amounts + require( + prevReserveBalances[1] < registry.getReserveAmount(address(linkToken)), + "link reserve amount should have increased" + ); + } + function test_handlesMixedBatchOfBillingTokens() external { uint256[] memory prevUpkeepBalances = new uint256[](3); prevUpkeepBalances[0] = registry.getBalance(linkUpkeepID); @@ -1696,7 +1830,7 @@ contract Transmit is SetUp { // assert reserve amounts have adjusted accordingly require( prevReserveBalances[0] < registry.getReserveAmount(address(linkToken)), - "usd reserve amount should have increased" + "link reserve amount should have increased" ); // link reserve amount increases in value equal to the decrease of the other reserve amounts require( prevReserveBalances[1] > registry.getReserveAmount(address(usdToken18)), diff --git a/contracts/src/v0.8/automation/test/v2_3/BaseTest.t.sol b/contracts/src/v0.8/automation/test/v2_3/BaseTest.t.sol index f1086e7bfa4..44bb0f0ae60 100644 --- a/contracts/src/v0.8/automation/test/v2_3/BaseTest.t.sol +++ b/contracts/src/v0.8/automation/test/v2_3/BaseTest.t.sol @@ -367,6 +367,54 @@ contract BaseTest is Test { _handleTransmit(ids, registry, bytes4(0)); } + function _batchTransmitWithBadTriggers(uint256[] memory ids, bool[] memory goodTriggers, Registry registry) internal { + bytes memory reportBytes; + { + uint256[] memory upkeepIds = new uint256[](ids.length); + uint256[] memory gasLimits = new uint256[](ids.length); + bytes[] memory performDatas = new bytes[](ids.length); + bytes[] memory triggers = new bytes[](ids.length); + for (uint256 i = 0; i < ids.length; i++) { + upkeepIds[i] = ids[i]; + gasLimits[i] = registry.getUpkeep(ids[i]).performGas; + performDatas[i] = new bytes(0); + uint8 triggerType = registry.getTriggerType(ids[i]); + if (triggerType == 0) { + uint256 j = 0; + if (goodTriggers[i]) { + j = 1; + } + triggers[i] = _encodeConditionalTrigger( + AutoBase.ConditionalTrigger(uint32(block.number - j), blockhash(block.number - j)) + ); + } else { + revert("not implemented"); + } + } + + AutoBase.Report memory report = AutoBase.Report( + uint256(1000000000), + uint256(2000000000), + upkeepIds, + gasLimits, + triggers, + performDatas + ); + + reportBytes = _encodeReport(report); + } + (, , bytes32 configDigest) = registry.latestConfigDetails(); + bytes32[3] memory reportContext = [configDigest, configDigest, configDigest]; + uint256[] memory signerPKs = new uint256[](2); + signerPKs[0] = SIGNING_KEY0; + signerPKs[1] = SIGNING_KEY1; + (bytes32[] memory rs, bytes32[] memory ss, bytes32 vs) = _signReport(reportBytes, reportContext, signerPKs); + + vm.startPrank(TRANSMITTERS[0]); + registry.transmit(reportContext, reportBytes, rs, ss, vs); + vm.stopPrank(); + } + // tests single upkeep, expects revert function _transmitAndExpectRevert(uint256 id, Registry registry, bytes4 selector) internal { uint256[] memory ids = new uint256[](1); diff --git a/contracts/src/v0.8/automation/test/v2_3_zksync/BaseTest.t.sol b/contracts/src/v0.8/automation/test/v2_3_zksync/BaseTest.t.sol index dde8f5b3867..f33360aa9f6 100644 --- a/contracts/src/v0.8/automation/test/v2_3_zksync/BaseTest.t.sol +++ b/contracts/src/v0.8/automation/test/v2_3_zksync/BaseTest.t.sol @@ -419,6 +419,54 @@ contract BaseTest is Test { vm.stopPrank(); } + function _batchTransmitWithBadTriggers(uint256[] memory ids, bool[] memory goodTriggers, Registry registry) internal { + bytes memory reportBytes; + { + uint256[] memory upkeepIds = new uint256[](ids.length); + uint256[] memory gasLimits = new uint256[](ids.length); + bytes[] memory performDatas = new bytes[](ids.length); + bytes[] memory triggers = new bytes[](ids.length); + for (uint256 i = 0; i < ids.length; i++) { + upkeepIds[i] = ids[i]; + gasLimits[i] = registry.getUpkeep(ids[i]).performGas; + performDatas[i] = new bytes(0); + uint8 triggerType = registry.getTriggerType(ids[i]); + if (triggerType == 0) { + uint256 j = 0; + if (goodTriggers[i]) { + j = 1; + } + triggers[i] = _encodeConditionalTrigger( + ZKSyncAutoBase.ConditionalTrigger(uint32(block.number - j), blockhash(block.number - j)) + ); + } else { + revert("not implemented"); + } + } + + ZKSyncAutoBase.Report memory report = ZKSyncAutoBase.Report( + uint256(1000000000), + uint256(2000000000), + upkeepIds, + gasLimits, + triggers, + performDatas + ); + + reportBytes = _encodeReport(report); + } + (, , bytes32 configDigest) = registry.latestConfigDetails(); + bytes32[3] memory reportContext = [configDigest, configDigest, configDigest]; + uint256[] memory signerPKs = new uint256[](2); + signerPKs[0] = SIGNING_KEY0; + signerPKs[1] = SIGNING_KEY1; + (bytes32[] memory rs, bytes32[] memory ss, bytes32 vs) = _signReport(reportBytes, reportContext, signerPKs); + + vm.startPrank(TRANSMITTERS[0]); + registry.transmit(reportContext, reportBytes, rs, ss, vs); + vm.stopPrank(); + } + /// @notice Gather signatures on report data /// @param report - Report bytes generated from `_buildReport` /// @param reportContext - Report context bytes32 generated from `_buildReport` diff --git a/contracts/src/v0.8/automation/test/v2_3_zksync/ZKSyncAutomationRegistry2_3.t.sol b/contracts/src/v0.8/automation/test/v2_3_zksync/ZKSyncAutomationRegistry2_3.t.sol index 7098d9f38fa..2e3ca5b1584 100644 --- a/contracts/src/v0.8/automation/test/v2_3_zksync/ZKSyncAutomationRegistry2_3.t.sol +++ b/contracts/src/v0.8/automation/test/v2_3_zksync/ZKSyncAutomationRegistry2_3.t.sol @@ -1655,6 +1655,140 @@ contract Transmit is SetUp { vm.stopPrank(); } + struct PaymentReceipt { + uint96 gasChargeInBillingToken; + uint96 premiumInBillingToken; + uint96 gasReimbursementInJuels; + uint96 premiumInJuels; + IERC20 billingToken; + uint96 linkUSD; + uint96 nativeUSD; + uint96 billingUSD; + } + event ReorgedUpkeepReport(uint256 indexed id, bytes trigger); + event UpkeepCharged(uint256 indexed id, PaymentReceipt receipt); + event UpkeepPerformed( + uint256 indexed id, + bool indexed success, + uint96 totalPayment, + uint256 gasUsed, + uint256 gasOverhead, + bytes trigger + ); + function test_whenFirstUpkeepFails_subsequentUpkeepsPerformZK() external { + // the first and second upkeeps use LINK as billing token and the third uses WETH + // the first upkeep fails the pre perform check due to incorrect block number in its trigger + // the second and third upkeep perform + // the first upkeep should not be charged and the second and third upkeep should be charged + uint256[] memory prevUpkeepBalances = new uint256[](3); + prevUpkeepBalances[0] = registry.getBalance(linkUpkeepID); + prevUpkeepBalances[1] = registry.getBalance(linkUpkeepID2); + prevUpkeepBalances[2] = registry.getBalance(nativeUpkeepID); + uint256[] memory prevTokenBalances = new uint256[](2); + prevTokenBalances[0] = linkToken.balanceOf(address(registry)); + prevTokenBalances[1] = weth.balanceOf(address(registry)); + uint256[] memory prevReserveBalances = new uint256[](2); + prevReserveBalances[0] = registry.getReserveAmount(address(linkToken)); + prevReserveBalances[1] = registry.getReserveAmount(address(weth)); + uint256[] memory upkeepIDs = new uint256[](3); + upkeepIDs[0] = linkUpkeepID; + upkeepIDs[1] = linkUpkeepID2; + upkeepIDs[2] = nativeUpkeepID; + + // do the transmit + vm.expectEmit(); + emit ReorgedUpkeepReport(linkUpkeepID, abi.encode(block.number, blockhash(block.number))); + vm.expectEmit(true, false, false, false); + emit UpkeepCharged(linkUpkeepID2, PaymentReceipt(0, 0, 0, 0, linkToken, 0, 0, 0)); + vm.expectEmit(true, true, false, false); + emit UpkeepPerformed(linkUpkeepID2, true, 0, 0, 0, bytes("")); + vm.expectEmit(true, false, false, false); + emit UpkeepCharged(nativeUpkeepID, PaymentReceipt(0, 0, 0, 0, linkToken, 0, 0, 0)); + vm.expectEmit(true, true, false, false); + emit UpkeepPerformed(nativeUpkeepID, true, 0, 0, 0, bytes("")); + bool[] memory goodTriggers = new bool[](3); + goodTriggers[0] = false; + goodTriggers[1] = true; + goodTriggers[2] = true; + _batchTransmitWithBadTriggers(upkeepIDs, goodTriggers, registry); + + // assert upkeep balances + // the first upkeep fails and the second and third upkeep succeeds + require(prevUpkeepBalances[0] == registry.getBalance(linkUpkeepID), "link upkeep balance should remain the same"); + require(prevUpkeepBalances[1] > registry.getBalance(linkUpkeepID2), "link upkeep 2 balance should have decreased"); + require(prevUpkeepBalances[2] > registry.getBalance(nativeUpkeepID), "native upkeep balance should have decreased"); + // assert token balances have not changed + assertEq(prevTokenBalances[0], linkToken.balanceOf(address(registry))); + assertEq(prevTokenBalances[1], weth.balanceOf(address(registry))); + // assert reserve amounts have adjusted accordingly + require( + prevReserveBalances[0] < registry.getReserveAmount(address(linkToken)), + "link reserve amount should have increased" + ); // link reserve amount increases in value equal to the decrease of the other reserve amounts + require( + prevReserveBalances[1] > registry.getReserveAmount(address(weth)), + "native reserve amount should have decreased" + ); + } + + function test_whenSecondUpkeepFails_FirstAndThirdUpkeepsPerform() external { + // the first upkeep uses WETH as billing token and the second and third use LINK + // the first upkeep succeeds + // the second upkeep fails pre perform check due to incorrect block number in its trigger + // the third upkeep succeeds + // the second upkeep should not be charged and the first and third upkeep should be charged + uint256[] memory prevUpkeepBalances = new uint256[](3); + prevUpkeepBalances[0] = registry.getBalance(nativeUpkeepID); + prevUpkeepBalances[1] = registry.getBalance(linkUpkeepID); + prevUpkeepBalances[2] = registry.getBalance(linkUpkeepID2); + uint256[] memory prevTokenBalances = new uint256[](2); + prevTokenBalances[0] = weth.balanceOf(address(registry)); + prevTokenBalances[1] = linkToken.balanceOf(address(registry)); + uint256[] memory prevReserveBalances = new uint256[](2); + prevReserveBalances[0] = registry.getReserveAmount(address(weth)); + prevReserveBalances[1] = registry.getReserveAmount(address(linkToken)); + uint256[] memory upkeepIDs = new uint256[](3); + upkeepIDs[0] = nativeUpkeepID; + upkeepIDs[1] = linkUpkeepID; + upkeepIDs[2] = linkUpkeepID2; + + // do the transmit + // expect this event first because all the upkeeps will be checked first before they are performed and charged + vm.expectEmit(); + emit ReorgedUpkeepReport(linkUpkeepID, abi.encode(block.number, blockhash(block.number))); + vm.expectEmit(true, false, false, false); + emit UpkeepCharged(nativeUpkeepID, PaymentReceipt(0, 0, 0, 0, linkToken, 0, 0, 0)); + vm.expectEmit(true, true, false, false); + emit UpkeepPerformed(nativeUpkeepID, true, 0, 0, 0, bytes("")); + vm.expectEmit(true, false, false, false); + emit UpkeepCharged(linkUpkeepID2, PaymentReceipt(0, 0, 0, 0, linkToken, 0, 0, 0)); + vm.expectEmit(true, true, false, false); + emit UpkeepPerformed(linkUpkeepID2, true, 0, 0, 0, bytes("")); + bool[] memory goodTriggers = new bool[](3); + goodTriggers[0] = true; + goodTriggers[1] = false; + goodTriggers[2] = true; + _batchTransmitWithBadTriggers(upkeepIDs, goodTriggers, registry); + + // assert upkeep balances + // the first upkeep fails and the second and third upkeep succeeds + require(prevUpkeepBalances[0] > registry.getBalance(nativeUpkeepID), "native upkeep balance should have decreased"); + require(prevUpkeepBalances[1] == registry.getBalance(linkUpkeepID), "link upkeep balance should remain the same"); + require(prevUpkeepBalances[2] > registry.getBalance(linkUpkeepID2), "link upkeep 2 balance should have decreased"); + // assert token balances have not changed + assertEq(prevTokenBalances[0], weth.balanceOf(address(registry))); + assertEq(prevTokenBalances[1], linkToken.balanceOf(address(registry))); + // assert reserve amounts have adjusted accordingly + require( + prevReserveBalances[0] > registry.getReserveAmount(address(weth)), + "native reserve amount should have decreased" + ); // link reserve amount increases in value equal to the decrease of the other reserve amounts + require( + prevReserveBalances[1] < registry.getReserveAmount(address(linkToken)), + "link reserve amount should have increased" + ); + } + function test_handlesMixedBatchOfBillingTokens() external { uint256[] memory prevUpkeepBalances = new uint256[](3); prevUpkeepBalances[0] = registry.getBalance(linkUpkeepID); @@ -1698,7 +1832,7 @@ contract Transmit is SetUp { // assert reserve amounts have adjusted accordingly require( prevReserveBalances[0] < registry.getReserveAmount(address(linkToken)), - "usd reserve amount should have increased" + "link reserve amount should have increased" ); // link reserve amount increases in value equal to the decrease of the other reserve amounts require( prevReserveBalances[1] > registry.getReserveAmount(address(usdToken18)), diff --git a/contracts/src/v0.8/automation/v2_3/AutomationRegistry2_3.sol b/contracts/src/v0.8/automation/v2_3/AutomationRegistry2_3.sol index 031d7b5dfb8..fbf509772f0 100644 --- a/contracts/src/v0.8/automation/v2_3/AutomationRegistry2_3.sol +++ b/contracts/src/v0.8/automation/v2_3/AutomationRegistry2_3.sol @@ -192,9 +192,7 @@ contract AutomationRegistry2_3 is AutomationRegistryBase2_3, OCR2Abstract, Chain uint256 nativeUSD = _getNativeUSD(hotVars); for (uint256 i = 0; i < report.upkeepIds.length; i++) { if (upkeepTransmitInfo[i].earlyChecksPassed) { - if (i == 0 || upkeepTransmitInfo[i].upkeep.billingToken != upkeepTransmitInfo[i - 1].upkeep.billingToken) { - billingTokenParams = _getBillingTokenPaymentParams(hotVars, upkeepTransmitInfo[i].upkeep.billingToken); - } + billingTokenParams = _getBillingTokenPaymentParams(hotVars, upkeepTransmitInfo[i].upkeep.billingToken); PaymentReceipt memory receipt = _handlePayment( hotVars, PaymentParams({ diff --git a/contracts/src/v0.8/automation/v2_3/AutomationRegistryBase2_3.sol b/contracts/src/v0.8/automation/v2_3/AutomationRegistryBase2_3.sol index 354a6a9b475..bc9cc144424 100644 --- a/contracts/src/v0.8/automation/v2_3/AutomationRegistryBase2_3.sol +++ b/contracts/src/v0.8/automation/v2_3/AutomationRegistryBase2_3.sol @@ -59,8 +59,8 @@ abstract contract AutomationRegistryBase2_3 is ConfirmedOwner { // tx itself, but since payment processing itself takes gas, and it needs the overhead as input, we use fixed constants // to account for gas used in payment processing. These values are calibrated using hardhat tests which simulates various cases and verifies that // the variables result in accurate estimation - uint256 internal constant ACCOUNTING_FIXED_GAS_OVERHEAD = 51_200; // Fixed overhead per tx - uint256 internal constant ACCOUNTING_PER_UPKEEP_GAS_OVERHEAD = 14_200; // Overhead per upkeep performed in batch + uint256 internal constant ACCOUNTING_FIXED_GAS_OVERHEAD = 51_000; // Fixed overhead per tx + uint256 internal constant ACCOUNTING_PER_UPKEEP_GAS_OVERHEAD = 14_900; // Overhead per upkeep performed in batch LinkTokenInterface internal immutable i_link; AggregatorV3Interface internal immutable i_linkUSDFeed; diff --git a/contracts/src/v0.8/automation/v2_3_zksync/ZKSyncAutomationRegistry2_3.sol b/contracts/src/v0.8/automation/v2_3_zksync/ZKSyncAutomationRegistry2_3.sol index 5d5bf23aa26..b1b2feff83f 100644 --- a/contracts/src/v0.8/automation/v2_3_zksync/ZKSyncAutomationRegistry2_3.sol +++ b/contracts/src/v0.8/automation/v2_3_zksync/ZKSyncAutomationRegistry2_3.sol @@ -187,9 +187,7 @@ contract ZKSyncAutomationRegistry2_3 is ZKSyncAutomationRegistryBase2_3, OCR2Abs uint256 nativeUSD = _getNativeUSD(hotVars); for (uint256 i = 0; i < report.upkeepIds.length; i++) { if (upkeepTransmitInfo[i].earlyChecksPassed) { - if (i == 0 || upkeepTransmitInfo[i].upkeep.billingToken != upkeepTransmitInfo[i - 1].upkeep.billingToken) { - billingTokenParams = _getBillingTokenPaymentParams(hotVars, upkeepTransmitInfo[i].upkeep.billingToken); - } + billingTokenParams = _getBillingTokenPaymentParams(hotVars, upkeepTransmitInfo[i].upkeep.billingToken); PaymentReceipt memory receipt = _handlePayment( hotVars, PaymentParams({ diff --git a/contracts/src/v0.8/ccip/pools/BurnMintTokenPoolAbstract.sol b/contracts/src/v0.8/ccip/pools/BurnMintTokenPoolAbstract.sol index 91472a5f5c8..aba9852d639 100644 --- a/contracts/src/v0.8/ccip/pools/BurnMintTokenPoolAbstract.sol +++ b/contracts/src/v0.8/ccip/pools/BurnMintTokenPoolAbstract.sol @@ -35,7 +35,7 @@ abstract contract BurnMintTokenPoolAbstract is TokenPool { /// @dev The _validateReleaseOrMint check is an essential security check function releaseOrMint( Pool.ReleaseOrMintInV1 calldata releaseOrMintIn - ) external virtual override returns (Pool.ReleaseOrMintOutV1 memory) { + ) public virtual override returns (Pool.ReleaseOrMintOutV1 memory) { _validateReleaseOrMint(releaseOrMintIn); // Calculate the local amount diff --git a/contracts/src/v0.8/ccip/pools/BurnToAddressMintTokenPool.sol b/contracts/src/v0.8/ccip/pools/BurnToAddressMintTokenPool.sol new file mode 100644 index 00000000000..563375f099a --- /dev/null +++ b/contracts/src/v0.8/ccip/pools/BurnToAddressMintTokenPool.sol @@ -0,0 +1,103 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity ^0.8.24; + +import {ITypeAndVersion} from "../../shared/interfaces/ITypeAndVersion.sol"; +import {IBurnMintERC20} from "../../shared/token/ERC20/IBurnMintERC20.sol"; + +import {Pool} from "../libraries/Pool.sol"; +import {BurnMintTokenPoolAbstract} from "./BurnMintTokenPoolAbstract.sol"; +import {TokenPool} from "./TokenPool.sol"; + +import {IERC20} from "../../vendor/openzeppelin-solidity/v4.8.3/contracts/token/ERC20/IERC20.sol"; +import {SafeERC20} from "../../vendor/openzeppelin-solidity/v4.8.3/contracts/token/ERC20/utils/SafeERC20.sol"; + +/// @notice This pool mints and burns a 3rd-party token by sending tokens to an address which is unrecoverable. +/// @dev The pool is designed to have an immutable burn address. If the tokens at the burn address become recoverable, +/// for example, a quantum computer calculating a private key for the zero address, the pool will need to be replaced +/// with a new pool with a different burn address. +contract BurnToAddressMintTokenPool is BurnMintTokenPoolAbstract, ITypeAndVersion { + using SafeERC20 for IERC20; + + event OutstandingTokensSet(uint256 newMintedTokenAmount, uint256 oldMintedTokenAmount); + + error InsufficientOutstandingTokens(); + + string public constant override typeAndVersion = "BurnToAddressTokenPool 1.5.1"; + + /// @notice The address where tokens are sent during a call to lockOrBurn, functionally burning but without decreasing + /// total supply. This address is expected to have no ability to recover the tokens sent to it, and will thus be locked forever. + /// This can be either an EOA without a corresponding private key, or a contract which does not have the ability to transfer the tokens. + address public immutable i_burnAddress; + + /// @notice Minted Tokens is a safety mechanism to ensure that more tokens cannot be sent out of the bridge + /// than were originally sent in via CCIP. On incoming messages the value is increased, and on outgoing messages, + /// the value is decreased. For pools with existing tokens in circulation, the value may not be known at deployment + /// time, and thus should be set later using the setoutstandingTokens() function. + uint256 internal s_outstandingTokens; + + /// @dev Since burnAddress is expected to make the tokens unrecoverable, no check for the zero address needs to be + /// performed, as it is a valid input. + constructor( + IBurnMintERC20 token, + uint8 localTokenDecimals, + address[] memory allowlist, + address rmnProxy, + address router, + address burnAddress + ) TokenPool(token, localTokenDecimals, allowlist, rmnProxy, router) { + i_burnAddress = burnAddress; + } + + /// @notice Mint tokens from the pool to the recipient, updating the internal accounting for an outflow of tokens. + /// @dev If the amount of tokens to be + function releaseOrMint( + Pool.ReleaseOrMintInV1 calldata releaseOrMintIn + ) public virtual override returns (Pool.ReleaseOrMintOutV1 memory) { + // When minting tokens, the local outstanding supply increases. These tokens will be burned + // when they are sent back to the pool on an outgoing message. + s_outstandingTokens += releaseOrMintIn.amount; + + return super.releaseOrMint(releaseOrMintIn); + } + + /// @inheritdoc BurnMintTokenPoolAbstract + /// @notice Tokens are burned by sending to an address which can never transfer them, + /// making the tokens unrecoverable without reducing the total supply. + function _burn( + uint256 amount + ) internal virtual override { + if (amount > s_outstandingTokens) { + revert InsufficientOutstandingTokens(); + } + + // When tokens are burned, the amount outstanding decreases. This ensures that more tokens cannot be sent out + // of the bridge than were originally sent in via CCIP. + s_outstandingTokens -= amount; + + getToken().safeTransfer(i_burnAddress, amount); + } + + /// @notice Returns the address where tokens are sent during a call to lockOrBurn + /// @return burnAddress the address which receives the tokens. + function getBurnAddress() public view returns (address burnAddress) { + return i_burnAddress; + } + + /// @notice Return the amount of tokens which were minted by this contract and not yet burned. + /// @return outstandingTokens The amount of tokens which were minted by this token pool and not yet burned. + function getOutstandingTokens() public view returns (uint256 outstandingTokens) { + return s_outstandingTokens; + } + + /// @notice Set the amount of tokens which were minted by this contract and not yet burned. + /// @param amount The new amount of tokens which were minted by this token pool and not yet burned. + function setOutstandingTokens( + uint256 amount + ) external onlyOwner { + uint256 currentOutstandingTokens = s_outstandingTokens; + + s_outstandingTokens = amount; + + emit OutstandingTokensSet(amount, currentOutstandingTokens); + } +} diff --git a/contracts/src/v0.8/ccip/pools/SiloedLockReleaseTokenPool.sol b/contracts/src/v0.8/ccip/pools/SiloedLockReleaseTokenPool.sol new file mode 100644 index 00000000000..adb3a452957 --- /dev/null +++ b/contracts/src/v0.8/ccip/pools/SiloedLockReleaseTokenPool.sol @@ -0,0 +1,299 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity ^0.8.24; + +import {ITypeAndVersion} from "../../shared/interfaces/ITypeAndVersion.sol"; + +import {Pool} from "../libraries/Pool.sol"; +import {TokenPool} from "./TokenPool.sol"; + +import {IERC20} from "../../vendor/openzeppelin-solidity/v4.8.3/contracts/token/ERC20/IERC20.sol"; +import {SafeERC20} from "../../vendor/openzeppelin-solidity/v4.8.3/contracts/token/ERC20/utils/SafeERC20.sol"; + +/// @notice A variation on Lock Release token pools where liquidity is shared among some chains, and stored independently +/// for others. Chains which do not share liquidity are known as siloed chains. +contract SiloedLockReleaseTokenPool is TokenPool, ITypeAndVersion { + using SafeERC20 for IERC20; + + error InsufficientLiquidity(uint256 availableLiquidity, uint256 requestedAmount); + error ChainNotSiloed(uint64 remoteChainSelector); + error InvalidChainSelector(uint64 remoteChainSelector); + + event LiquidityAdded(uint64 remoteChainSelector, address indexed provider, uint256 amount); + event LiquidityRemoved(uint64 remoteChainSelector, address indexed provider, uint256 amount); + event ChainUnsiloed(uint64 remoteChainSelector, uint256 amountUnsiloed); + event ChainSiloed(uint64 remoteChainSelector, address rebalancer); + event SiloRebalancerSet(uint64 indexed remoteChainSelector, address oldRebalancer, address newRebalancer); + event UnsiloedRebalancerSet(address oldRebalancer, address newRebalancer); + + string public constant override typeAndVersion = "SiloedLockReleaseTokenPool 1.6.0-dev"; + + /// @notice The amount of tokens available for remote chains which are not siloed as an additional security precaution. + uint256 internal s_unsiloedTokenBalance; + + /// @notice The rebalancer for unsiloed chains, which can add liquidity to the shared pool. + address internal s_rebalancer; + + struct SiloConfigUpdate { + uint64 remoteChainSelector; + address rebalancer; + } + + struct SiloConfig { + uint256 tokenBalance; // The amount of tokens available for incoming messages, either locked or as liquidity. + address rebalancer; // ─╮ The address allowed to add liquidity for the given siloed chain. + bool isSiloed; // ──────╯ Whether funds should be isolated from all other chains or shared amongst all non-siloed chains. + } + + /// @notice The configuration for each chain that is siloed, or not. By default chains are not siloed. + mapping(uint64 remoteChainSelector => SiloConfig) internal s_chainConfigs; + + constructor( + IERC20 token, + uint8 localTokenDecimals, + address[] memory allowlist, + address rmnProxy, + address router + ) TokenPool(token, localTokenDecimals, allowlist, rmnProxy, router) {} + + /// @notice Locks the token in the pool + /// @dev The _validateLockOrBurn check is an essential security check + function lockOrBurn( + Pool.LockOrBurnInV1 calldata lockOrBurnIn + ) external virtual override returns (Pool.LockOrBurnOutV1 memory) { + _validateLockOrBurn(lockOrBurnIn); + + // If funds need to be siloed, update internal accounting; + if (s_chainConfigs[lockOrBurnIn.remoteChainSelector].isSiloed) { + s_chainConfigs[lockOrBurnIn.remoteChainSelector].tokenBalance += lockOrBurnIn.amount; + } + // If the messages is going to a chain without siloed funds, update state accounting accordingly. + else { + s_unsiloedTokenBalance += lockOrBurnIn.amount; + } + + emit Locked(msg.sender, lockOrBurnIn.amount); + + return Pool.LockOrBurnOutV1({ + destTokenAddress: getRemoteToken(lockOrBurnIn.remoteChainSelector), + destPoolData: _encodeLocalDecimals() + }); + } + + /// @notice Release tokens from the pool to the recipient + /// @dev The _validateReleaseOrMint check is an essential security check + /// @dev If the releaseOrMintIn amount is greater than available liquidity, the function will revert as a security + /// measure to prevent funds from a Silo being released by another chain. + function releaseOrMint( + Pool.ReleaseOrMintInV1 calldata releaseOrMintIn + ) external virtual override returns (Pool.ReleaseOrMintOutV1 memory) { + _validateReleaseOrMint(releaseOrMintIn); + + // Calculate the local amount + uint256 localAmount = + _calculateLocalAmount(releaseOrMintIn.amount, _parseRemoteDecimals(releaseOrMintIn.sourcePoolData)); + + // Save gas by using storage instead of memory as a value may need to be updated. + SiloConfig storage remoteConfig = s_chainConfigs[releaseOrMintIn.remoteChainSelector]; + + // Prevent A silent underflow by explicitly ensuring that enough funds are available to release + uint256 availableLiquidity = remoteConfig.isSiloed ? remoteConfig.tokenBalance : s_unsiloedTokenBalance; + if (localAmount > availableLiquidity) revert InsufficientLiquidity(availableLiquidity, localAmount); + + // Tracking balances independently by chain is a security measure to prevent liquidity for one chain from being + // released by another chain. + if (remoteConfig.isSiloed) { + remoteConfig.tokenBalance -= localAmount; + } else { + s_unsiloedTokenBalance -= localAmount; + } + + // Release to the recipient + getToken().safeTransfer(releaseOrMintIn.receiver, localAmount); + + emit Released(msg.sender, releaseOrMintIn.receiver, localAmount); + + return Pool.ReleaseOrMintOutV1({destinationAmount: localAmount}); + } + + /// @notice Returns whether the tokens locked for a given remote chain should be siloed independently + /// from all other remote chains. + /// @param remoteChainSelector the CCIP specific selector for the remote chain being interacted with. + /// @return isSiloed Whether the funds should be isolated from all the others. + function isSiloed( + uint64 remoteChainSelector + ) external view returns (bool) { + return s_chainConfigs[remoteChainSelector].isSiloed; + } + + /// @notice Returns the amount of tokens in the token pool that were siloed for a specific remote chain selector. + /// @param remoteChainSelector the CCIP specific selector for the remote chain being interacted with. + /// @return lockedTokens The tokens locked into this token pool for the given selector. If the chain is not siloed, + /// the amount will be the amount of liquidity shared among all unsiloed chains. + function getAvailableTokens( + uint64 remoteChainSelector + ) external view returns (uint256 lockedTokens) { + if (s_chainConfigs[remoteChainSelector].isSiloed) { + return s_chainConfigs[remoteChainSelector].tokenBalance; + } + + return s_unsiloedTokenBalance; + } + + /// @notice Returns the amount of tokens in the token pool that are shared among all unsiloed chains. + /// @return unsiloedTokens amount of tokens available to all unsiloed chains. + function getUnsiloedLiquidity() external view returns (uint256) { + return s_unsiloedTokenBalance; + } + + /// @notice Updates designations for chains on whether to mark funds as Siloed or not + /// @param removes A list of chain selectors to disable Siloing. Their funds will be moved into the unsiloed pool. + /// If a chain is not siloed, and attempted to be removed, the function will revert. + /// @param adds A list of chain selectors to enable Siloing. Adding a chain to siloing will not set the rebalancer. + /// The rebalancer will need to be set separately. + function updateSiloDesignations(uint64[] calldata removes, SiloConfigUpdate[] calldata adds) external onlyOwner { + for (uint256 i = 0; i < removes.length; ++i) { + if (!s_chainConfigs[removes[i]].isSiloed) revert ChainNotSiloed(removes[i]); + + // When a chain is removed from siloing, the funds are moved to the accounting pool shared by all unsiloed chain. + uint256 amountUnsiloed = s_chainConfigs[removes[i]].tokenBalance; + + s_unsiloedTokenBalance += amountUnsiloed; + + delete s_chainConfigs[removes[i]]; + + // Emit a removal event which includes the amount of funds moved to the general silo. + emit ChainUnsiloed(removes[i], amountUnsiloed); + } + + for (uint256 i = 0; i < adds.length; ++i) { + // Since the zero chain selector is used to designate unsiloed chains, it should never be used for siloed chains. + if (adds[i].remoteChainSelector == 0) { + revert InvalidChainSelector(0); + } + + SiloConfig memory newConfig = SiloConfig({tokenBalance: 0, rebalancer: adds[i].rebalancer, isSiloed: true}); + + s_chainConfigs[adds[i].remoteChainSelector] = newConfig; + + emit ChainSiloed(adds[i].remoteChainSelector, adds[i].rebalancer); + } + } + + /// @notice Gets the rebalancer able to provide liquidity for a remote chain selector + /// @param remoteChainSelector The CCIP specific selector for the remote chain being interacted with. + /// @return The current liquidity manager, contract owner if the chain's funds are not siloed. + function getSiloRebalancer( + uint64 remoteChainSelector + ) public view returns (address) { + SiloConfig memory remoteConfig = s_chainConfigs[remoteChainSelector]; + if (remoteConfig.isSiloed) { + return remoteConfig.rebalancer; + } + + return s_rebalancer; + } + + /// @notice Sets the Rebalancer address for a given remoteChainSelector. + /// @dev Only callable by the owner. + /// @param remoteChainSelector the remote chain to set. + /// @param newRebalancer the address allowed to add liquidity for the given siloed chain. + function setSiloRebalancer(uint64 remoteChainSelector, address newRebalancer) external onlyOwner { + SiloConfig memory remoteConfig = s_chainConfigs[remoteChainSelector]; + + if (!remoteConfig.isSiloed) revert ChainNotSiloed(remoteChainSelector); + + address oldRebalancer = remoteConfig.rebalancer; + + s_chainConfigs[remoteChainSelector].rebalancer = newRebalancer; + + emit SiloRebalancerSet(remoteChainSelector, newRebalancer, oldRebalancer); + } + + /// @notice Sets the Rebalancer address for unsiloed chains. + /// @dev Only callable by the owner. + /// @param newRebalancer the address allowed to add liquidity for the given siloed chain. + function setRebalancer( + address newRebalancer + ) external onlyOwner { + address oldRebalancer = s_rebalancer; + + s_rebalancer = newRebalancer; + + emit UnsiloedRebalancerSet(newRebalancer, oldRebalancer); + } + + /// @notice Adds liquidity to the pool. The tokens should be approved first. + /// @param remoteChainSelector the remote chain to set. If the chain is not siloed, the liquidity will be shared among all + /// non-siloed chains. + /// @param amount The amount of liquidity to provide. + /// @dev Only the rebalancer for the chain can add liquidity + function provideSiloedLiquidity(uint64 remoteChainSelector, uint256 amount) external { + _provideLiquidity(remoteChainSelector, amount); + } + + /// @notice Adds liquidity to the pool for unsiloed chains. Function is used to support legacy liquidity operations + /// by using a function selector available to previous L/R pools. + /// @dev Since the remoteChainSelector 0 should never be applied to a real chain, it is used to designate unsiloed chains. + /// @param amount The amount of liquidity to provide. + function provideLiquidity( + uint256 amount + ) external { + _provideLiquidity(0, amount); + } + + function _provideLiquidity(uint64 remoteChainSelector, uint256 amount) internal { + if (msg.sender != getSiloRebalancer(remoteChainSelector)) revert Unauthorized(msg.sender); + + // Storage is used instead of memory to save gas, as the state may need to be updated if the chain is siloed. + SiloConfig storage remoteConfig = s_chainConfigs[remoteChainSelector]; + + if (remoteConfig.isSiloed) { + remoteConfig.tokenBalance += amount; + } else { + s_unsiloedTokenBalance += amount; + } + + i_token.safeTransferFrom(msg.sender, address(this), amount); + emit LiquidityAdded(remoteChainSelector, msg.sender, amount); + } + + /// @notice Removes liquidity from the pool for unsiloed chains. Function is used to support legacy liquidity operations + /// by using a function selector available to previous L/R pools. + /// @dev Since the remoteChainSelector 0 should never be applied to a real chain, it is used to designate unsiloed chains. + /// @param amount The amount of liquidity to remove. + function withdrawLiquidity( + uint256 amount + ) external { + _withdrawLiquidity(0, amount); + } + + /// @notice Removed liquidity to the pool. The tokens will be sent to msg.sender. + /// @dev Only the rebalancer can remove liquidity from the contract, for both siloed and unsiloed chains. + /// @param remoteChainSelector the remote chain to set. If the chain is not siloed, then no accounting will be updated, + /// which can be considered the liquidity for all non-siloed chains sharing liquidity. + /// @param amount The amount of liquidity to remove. + function withdrawSiloedLiquidity(uint64 remoteChainSelector, uint256 amount) external { + _withdrawLiquidity(remoteChainSelector, amount); + } + + function _withdrawLiquidity(uint64 remoteChainSelector, uint256 amount) internal { + if (msg.sender != getSiloRebalancer(remoteChainSelector)) revert Unauthorized(msg.sender); + + // Save gas by using storage as multiple values may need to be read/written. + SiloConfig storage remoteConfig = s_chainConfigs[remoteChainSelector]; + + // Prevent A silent underflow by explicitly ensuring that enough funds are available to withdraw + uint256 availableLiquidity = remoteConfig.isSiloed ? remoteConfig.tokenBalance : s_unsiloedTokenBalance; + if (amount > availableLiquidity) revert InsufficientLiquidity(availableLiquidity, amount); + + // If funds are siloed by chain, prevent more than has been locked from being removed from the token pool. + if (remoteConfig.isSiloed) { + remoteConfig.tokenBalance -= amount; + } else { + s_unsiloedTokenBalance -= amount; + } + + i_token.safeTransfer(msg.sender, amount); + emit LiquidityRemoved(remoteChainSelector, msg.sender, amount); + } +} diff --git a/contracts/src/v0.8/ccip/pools/USDC/HybridLockReleaseUSDCTokenPool.sol b/contracts/src/v0.8/ccip/pools/USDC/HybridLockReleaseUSDCTokenPool.sol index 89e609fcc5e..3f94a1b719a 100644 --- a/contracts/src/v0.8/ccip/pools/USDC/HybridLockReleaseUSDCTokenPool.sol +++ b/contracts/src/v0.8/ccip/pools/USDC/HybridLockReleaseUSDCTokenPool.sol @@ -4,7 +4,6 @@ pragma solidity ^0.8.24; import {ILiquidityContainer} from "../../../liquiditymanager/interfaces/ILiquidityContainer.sol"; import {ITokenMessenger} from "../USDC/ITokenMessenger.sol"; -import {Ownable2StepMsgSender} from "../../../shared/access/Ownable2StepMsgSender.sol"; import {Pool} from "../../libraries/Pool.sol"; import {TokenPool} from "../TokenPool.sol"; import {USDCTokenPool} from "../USDC/USDCTokenPool.sol"; @@ -209,31 +208,6 @@ contract HybridLockReleaseUSDCTokenPool is USDCTokenPool, USDCBridgeMigrator { emit ILiquidityContainer.LiquidityRemoved(msg.sender, amount); } - /// @notice This function can be used to transfer liquidity from an older version of the pool to this pool. To do so - /// this pool must be the owner of the old pool. Since the pool uses two-step ownership transfer, the old pool must - /// first propose the ownership transfer, and then this pool must accept it. This function can only be called after - /// the ownership transfer has been proposed, as it will accept it and then make the call to withdrawLiquidity - /// @dev When upgrading a LockRelease pool, this function can be called at the same time as the pool is changed in the - /// TokenAdminRegistry. This allows for a smooth transition of both liquidity and transactions to the new pool. - /// Alternatively, when no multicall is available, a portion of the funds can be transferred to the new pool before - /// changing which pool CCIP uses, to ensure both pools can operate. Then the pool should be changed in the - /// TokenAdminRegistry, which will activate the new pool. All new transactions will use the new pool and its - /// liquidity. - /// @param from The address of the old pool. - /// @param remoteChainSelector The chain for which liquidity is being transferred. - function transferLiquidity(address from, uint64 remoteChainSelector) external onlyOwner { - Ownable2StepMsgSender(from).acceptOwnership(); - - // Withdraw all available liquidity from the old pool. No check is needed for pending migrations, as the old pool - // will revert if the migration has begun. - uint256 withdrawAmount = HybridLockReleaseUSDCTokenPool(from).getLockedTokensForChain(remoteChainSelector); - HybridLockReleaseUSDCTokenPool(from).withdrawLiquidity(remoteChainSelector, withdrawAmount); - - s_lockedTokensByChainSelector[remoteChainSelector] += withdrawAmount; - - emit LiquidityTransferred(from, remoteChainSelector, withdrawAmount); - } - // ================================================================ // │ Alt Mechanism Logic | // ================================================================ diff --git a/contracts/src/v0.8/ccip/test/helpers/MaybeRevertingBurnMintTokenPool.sol b/contracts/src/v0.8/ccip/test/helpers/MaybeRevertingBurnMintTokenPool.sol index 058398e4c08..2ec5219b36c 100644 --- a/contracts/src/v0.8/ccip/test/helpers/MaybeRevertingBurnMintTokenPool.sol +++ b/contracts/src/v0.8/ccip/test/helpers/MaybeRevertingBurnMintTokenPool.sol @@ -60,7 +60,7 @@ contract MaybeRevertingBurnMintTokenPool is BurnMintTokenPool { /// @notice Reverts depending on the value of `s_revertReason` function releaseOrMint( Pool.ReleaseOrMintInV1 calldata releaseOrMintIn - ) external virtual override returns (Pool.ReleaseOrMintOutV1 memory) { + ) public virtual override returns (Pool.ReleaseOrMintOutV1 memory) { _validateReleaseOrMint(releaseOrMintIn); bytes memory revertReason = s_revertReason; diff --git a/contracts/src/v0.8/ccip/test/pools/BurnToAddressMintTokenPool/BurnToAddressMintTokenPool.lockOrBurn.t.sol b/contracts/src/v0.8/ccip/test/pools/BurnToAddressMintTokenPool/BurnToAddressMintTokenPool.lockOrBurn.t.sol new file mode 100644 index 00000000000..c5e559b2d9e --- /dev/null +++ b/contracts/src/v0.8/ccip/test/pools/BurnToAddressMintTokenPool/BurnToAddressMintTokenPool.lockOrBurn.t.sol @@ -0,0 +1,63 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity ^0.8.24; + +import {Pool} from "../../../libraries/Pool.sol"; +import {BurnToAddressMintTokenPool} from "../../../pools/BurnToAddressMintTokenPool.sol"; +import {BurnToAddressMintTokenPoolSetup} from "./BurnToAddressMintTokenPoolSetup.t.sol"; + +import {IERC20} from "../../../../vendor/openzeppelin-solidity/v4.8.3/contracts/interfaces/IERC20.sol"; + +contract BurnToAddressMintTokenPool_lockOrBurn is BurnToAddressMintTokenPoolSetup { + uint256 public constant AMOUNT = 1e24; + + function test_LockOrBurn() public { + s_pool.setOutstandingTokens(AMOUNT); + + deal(address(s_burnMintERC20), address(s_pool), AMOUNT); + assertEq(s_burnMintERC20.balanceOf(address(s_pool)), AMOUNT); + + vm.startPrank(s_burnMintOnRamp); + + vm.expectEmit(); + emit IERC20.Transfer(address(s_pool), BURN_ADDRESS, AMOUNT); + + vm.expectCall(address(s_burnMintERC20), abi.encodeWithSelector(IERC20.transfer.selector, BURN_ADDRESS, AMOUNT)); + + s_pool.lockOrBurn( + Pool.LockOrBurnInV1({ + originalSender: OWNER, + receiver: bytes(""), + amount: AMOUNT, + remoteChainSelector: DEST_CHAIN_SELECTOR, + localToken: address(s_burnMintERC20) + }) + ); + + assertEq(s_burnMintERC20.balanceOf(s_pool.getBurnAddress()), AMOUNT); + assertEq(s_burnMintERC20.balanceOf(address(s_pool)), 0); + assertEq(s_pool.getOutstandingTokens(), 0); + } + + // Reverts + + function test_LockOrBurn_RevertWhen_InsufficientOutstandingTokens() public { + s_pool.setOutstandingTokens(AMOUNT - 1); + + deal(address(s_burnMintERC20), address(s_pool), AMOUNT); + assertEq(s_burnMintERC20.balanceOf(address(s_pool)), AMOUNT); + + vm.startPrank(s_burnMintOnRamp); + + vm.expectRevert(BurnToAddressMintTokenPool.InsufficientOutstandingTokens.selector); + + s_pool.lockOrBurn( + Pool.LockOrBurnInV1({ + originalSender: OWNER, + receiver: bytes(""), + amount: AMOUNT, + remoteChainSelector: DEST_CHAIN_SELECTOR, + localToken: address(s_burnMintERC20) + }) + ); + } +} diff --git a/contracts/src/v0.8/ccip/test/pools/BurnToAddressMintTokenPool/BurnToAddressMintTokenPool.releaseOrMint.t.sol b/contracts/src/v0.8/ccip/test/pools/BurnToAddressMintTokenPool/BurnToAddressMintTokenPool.releaseOrMint.t.sol new file mode 100644 index 00000000000..508ed6bb787 --- /dev/null +++ b/contracts/src/v0.8/ccip/test/pools/BurnToAddressMintTokenPool/BurnToAddressMintTokenPool.releaseOrMint.t.sol @@ -0,0 +1,35 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity ^0.8.24; + +import {Pool} from "../../../libraries/Pool.sol"; +import {BurnToAddressMintTokenPoolSetup} from "./BurnToAddressMintTokenPoolSetup.t.sol"; + +import {IERC20} from "../../../../vendor/openzeppelin-solidity/v4.8.3/contracts/interfaces/IERC20.sol"; + +contract BurnToAddressMintTokenPool_releaseOrMint is BurnToAddressMintTokenPoolSetup { + function test_releaseOrMint() public { + uint256 amount = 1e24; + address receiver = makeAddr("RECEIVER_ADDRESS"); + + vm.startPrank(s_burnMintOffRamp); + + vm.expectEmit(); + emit IERC20.Transfer(address(0), receiver, amount); + + s_pool.releaseOrMint( + Pool.ReleaseOrMintInV1({ + originalSender: bytes(""), + receiver: receiver, + amount: amount, + localToken: address(s_burnMintERC20), + remoteChainSelector: DEST_CHAIN_SELECTOR, + sourcePoolAddress: abi.encode(s_remoteBurnMintPool), + sourcePoolData: "", + offchainTokenData: "" + }) + ); + + assertEq(s_burnMintERC20.balanceOf(receiver), amount); + assertEq(s_pool.getOutstandingTokens(), amount); + } +} diff --git a/contracts/src/v0.8/ccip/test/pools/BurnToAddressMintTokenPool/BurnToAddressMintTokenPool.setMintedTokens.t.sol b/contracts/src/v0.8/ccip/test/pools/BurnToAddressMintTokenPool/BurnToAddressMintTokenPool.setMintedTokens.t.sol new file mode 100644 index 00000000000..11c615d8b2b --- /dev/null +++ b/contracts/src/v0.8/ccip/test/pools/BurnToAddressMintTokenPool/BurnToAddressMintTokenPool.setMintedTokens.t.sol @@ -0,0 +1,20 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity ^0.8.24; + +import {BurnToAddressMintTokenPool} from "../../../pools/BurnToAddressMintTokenPool.sol"; +import {BurnToAddressMintTokenPoolSetup} from "./BurnToAddressMintTokenPoolSetup.t.sol"; + +contract BurnToAddressMintTokenPool_setOutstandingokens is BurnToAddressMintTokenPoolSetup { + function test_setOutstandingTokens() public { + uint256 amount = 1e18; + + assertEq(s_pool.getOutstandingTokens(), 0); + + vm.expectEmit(); + emit BurnToAddressMintTokenPool.OutstandingTokensSet(amount, 0); + + s_pool.setOutstandingTokens(amount); + + assertEq(s_pool.getOutstandingTokens(), amount); + } +} diff --git a/contracts/src/v0.8/ccip/test/pools/BurnToAddressMintTokenPool/BurnToAddressMintTokenPoolSetup.t.sol b/contracts/src/v0.8/ccip/test/pools/BurnToAddressMintTokenPool/BurnToAddressMintTokenPoolSetup.t.sol new file mode 100644 index 00000000000..a27c0a0f8c4 --- /dev/null +++ b/contracts/src/v0.8/ccip/test/pools/BurnToAddressMintTokenPool/BurnToAddressMintTokenPoolSetup.t.sol @@ -0,0 +1,28 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity ^0.8.24; + +import {BurnToAddressMintTokenPool} from "../../../pools/BurnToAddressMintTokenPool.sol"; +import {BurnMintSetup} from "../BurnMintTokenPool/BurnMintSetup.t.sol"; + +contract BurnToAddressMintTokenPoolSetup is BurnMintSetup { + BurnToAddressMintTokenPool internal s_pool; + + address public constant BURN_ADDRESS = address(0xdead); + + function setUp() public virtual override { + BurnMintSetup.setUp(); + + s_pool = new BurnToAddressMintTokenPool( + s_burnMintERC20, + DEFAULT_TOKEN_DECIMALS, + new address[](0), + address(s_mockRMNRemote), + address(s_sourceRouter), + BURN_ADDRESS + ); + + s_burnMintERC20.grantMintAndBurnRoles(address(s_pool)); + + _applyChainUpdates(address(s_pool)); + } +} diff --git a/contracts/src/v0.8/ccip/test/pools/SiloedLockReleaseTokenPool/SiloedLockReleaseTokenPool.lockOrBurn.t.sol b/contracts/src/v0.8/ccip/test/pools/SiloedLockReleaseTokenPool/SiloedLockReleaseTokenPool.lockOrBurn.t.sol new file mode 100644 index 00000000000..2cf51a045e9 --- /dev/null +++ b/contracts/src/v0.8/ccip/test/pools/SiloedLockReleaseTokenPool/SiloedLockReleaseTokenPool.lockOrBurn.t.sol @@ -0,0 +1,57 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity ^0.8.24; + +import {Pool} from "../../../libraries/Pool.sol"; +import {RateLimiter} from "../../../libraries/RateLimiter.sol"; +import {TokenPool} from "../../../pools/TokenPool.sol"; +import {SiloedLockReleaseTokenPoolSetup} from "./SiloedLockReleaseTokenPoolSetup.t.sol"; + +contract SiloedLockReleaseTokenPool_lockOrBurn is SiloedLockReleaseTokenPoolSetup { + uint256 public constant AMOUNT = 10e18; + + function test_lockOrBurn_SiloedFunds() public { + assertTrue(s_siloedLockReleaseTokenPool.isSiloed(SILOED_CHAIN_SELECTOR)); + + vm.startPrank(s_allowedOnRamp); + + vm.expectEmit(); + emit RateLimiter.TokensConsumed(AMOUNT); + vm.expectEmit(); + emit TokenPool.Locked(s_allowedOnRamp, AMOUNT); + + s_siloedLockReleaseTokenPool.lockOrBurn( + Pool.LockOrBurnInV1({ + originalSender: STRANGER, + receiver: bytes(""), + amount: AMOUNT, + remoteChainSelector: SILOED_CHAIN_SELECTOR, + localToken: address(s_token) + }) + ); + + assertEq(s_siloedLockReleaseTokenPool.getAvailableTokens(SILOED_CHAIN_SELECTOR), AMOUNT); + } + + function test_lockOrBurn_UnsiloedFunds() public { + vm.startPrank(s_allowedOnRamp); + + assertFalse(s_siloedLockReleaseTokenPool.isSiloed(DEST_CHAIN_SELECTOR)); + + vm.expectEmit(); + emit RateLimiter.TokensConsumed(AMOUNT); + vm.expectEmit(); + emit TokenPool.Locked(s_allowedOnRamp, AMOUNT); + + s_siloedLockReleaseTokenPool.lockOrBurn( + Pool.LockOrBurnInV1({ + originalSender: STRANGER, + receiver: bytes(""), + amount: AMOUNT, + remoteChainSelector: DEST_CHAIN_SELECTOR, + localToken: address(s_token) + }) + ); + + assertEq(s_siloedLockReleaseTokenPool.getAvailableTokens(DEST_CHAIN_SELECTOR), AMOUNT); + } +} diff --git a/contracts/src/v0.8/ccip/test/pools/SiloedLockReleaseTokenPool/SiloedLockReleaseTokenPool.provideLiquidity.t.sol b/contracts/src/v0.8/ccip/test/pools/SiloedLockReleaseTokenPool/SiloedLockReleaseTokenPool.provideLiquidity.t.sol new file mode 100644 index 00000000000..6af10971018 --- /dev/null +++ b/contracts/src/v0.8/ccip/test/pools/SiloedLockReleaseTokenPool/SiloedLockReleaseTokenPool.provideLiquidity.t.sol @@ -0,0 +1,91 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity ^0.8.24; + +import {SiloedLockReleaseTokenPool} from "../../../pools/SiloedLockReleaseTokenPool.sol"; +import {TokenPool} from "../../../pools/TokenPool.sol"; +import {SiloedLockReleaseTokenPoolSetup} from "./SiloedLockReleaseTokenPoolSetup.t.sol"; + +contract SiloedLockReleaseTokenPool_provideLiqudity is SiloedLockReleaseTokenPoolSetup { + address public UNAUTHORIZED_ADDRESS = address(0xdeadbeef); + + function setUp() public override { + super.setUp(); + + s_siloedLockReleaseTokenPool.setSiloRebalancer(SILOED_CHAIN_SELECTOR, OWNER); + } + + function test_ProvideLiquidity_UnsiloedChain() public { + uint256 amount = 1e24; + + vm.expectEmit(); + emit SiloedLockReleaseTokenPool.LiquidityAdded(DEST_CHAIN_SELECTOR, OWNER, amount); + + s_siloedLockReleaseTokenPool.provideSiloedLiquidity(DEST_CHAIN_SELECTOR, amount); + + assertEq(s_token.balanceOf(address(s_siloedLockReleaseTokenPool)), amount); + + // Since the funds for the destination chain are not siloed, + // the locked token amount should not be increased + assertEq(s_siloedLockReleaseTokenPool.getAvailableTokens(DEST_CHAIN_SELECTOR), amount); + assertEq(s_siloedLockReleaseTokenPool.getUnsiloedLiquidity(), amount); + } + + function test_ProvideLiquidity_SiloedChain() public { + uint256 amount = 1e24; + + vm.expectEmit(); + emit SiloedLockReleaseTokenPool.LiquidityAdded(SILOED_CHAIN_SELECTOR, OWNER, amount); + + s_siloedLockReleaseTokenPool.provideSiloedLiquidity(SILOED_CHAIN_SELECTOR, amount); + + assertEq(s_token.balanceOf(address(s_siloedLockReleaseTokenPool)), amount); + + assertEq(s_siloedLockReleaseTokenPool.getAvailableTokens(SILOED_CHAIN_SELECTOR), amount); + + // Since the funds for the destination chain are not siloed, the locked token amount should not be increased + assertEq(s_siloedLockReleaseTokenPool.getUnsiloedLiquidity(), 0); + } + + function test_ProvideLiquidity_LegacyProvideLiquiditySelector() public { + uint256 amount = 1e24; + + vm.expectEmit(); + emit SiloedLockReleaseTokenPool.LiquidityAdded(0, OWNER, amount); + + s_siloedLockReleaseTokenPool.provideLiquidity(amount); + + assertEq(s_token.balanceOf(address(s_siloedLockReleaseTokenPool)), amount); + + // Since the funds for the destination chain are not siloed, + // the locked token amount should not be increased + assertEq(s_siloedLockReleaseTokenPool.getAvailableTokens(DEST_CHAIN_SELECTOR), amount); + assertEq(s_siloedLockReleaseTokenPool.getUnsiloedLiquidity(), amount); + assertEq(s_siloedLockReleaseTokenPool.getAvailableTokens(SILOED_CHAIN_SELECTOR), 0); + } + + // Reverts + + function test_ProvideLiquidity_RevertWhen_UnauthorizedForSiloedChain() public { + vm.startPrank(UNAUTHORIZED_ADDRESS); + + vm.expectRevert(abi.encodeWithSelector(TokenPool.Unauthorized.selector, UNAUTHORIZED_ADDRESS)); + + s_siloedLockReleaseTokenPool.provideSiloedLiquidity(SILOED_CHAIN_SELECTOR, 1); + } + + function test_ProvideLiquidity_RevertWhen_UnauthorizedForUnsiloedChain() public { + vm.startPrank(UNAUTHORIZED_ADDRESS); + + vm.expectRevert(abi.encodeWithSelector(TokenPool.Unauthorized.selector, UNAUTHORIZED_ADDRESS)); + + s_siloedLockReleaseTokenPool.provideSiloedLiquidity(DEST_CHAIN_SELECTOR, 1); + } + + function test_ProvideLiquidity_RevertWhen_LegacyFunctionSelector_Unauthorized() public { + vm.startPrank(UNAUTHORIZED_ADDRESS); + + vm.expectRevert(abi.encodeWithSelector(TokenPool.Unauthorized.selector, UNAUTHORIZED_ADDRESS)); + + s_siloedLockReleaseTokenPool.provideLiquidity(1); + } +} diff --git a/contracts/src/v0.8/ccip/test/pools/SiloedLockReleaseTokenPool/SiloedLockReleaseTokenPool.releaseOrMint.t.sol b/contracts/src/v0.8/ccip/test/pools/SiloedLockReleaseTokenPool/SiloedLockReleaseTokenPool.releaseOrMint.t.sol new file mode 100644 index 00000000000..eec0503b716 --- /dev/null +++ b/contracts/src/v0.8/ccip/test/pools/SiloedLockReleaseTokenPool/SiloedLockReleaseTokenPool.releaseOrMint.t.sol @@ -0,0 +1,149 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity ^0.8.24; + +import {Pool} from "../../../libraries/Pool.sol"; +import {SiloedLockReleaseTokenPool} from "../../../pools/SiloedLockReleaseTokenPool.sol"; +import {SiloedLockReleaseTokenPoolSetup} from "./SiloedLockReleaseTokenPoolSetup.t.sol"; + +import {IERC20} from "../../../../vendor/openzeppelin-solidity/v4.8.3/contracts/interfaces/IERC20.sol"; + +contract SiloedLockReleaseTokenPool_releaseOrMint is SiloedLockReleaseTokenPoolSetup { + function test_ReleaseOrMint_SiloedChain() public { + uint256 amount = 10e18; + + deal(address(s_token), address(s_siloedLockReleaseTokenPool), amount); + vm.startPrank(s_allowedOnRamp); + + // Lock funds so that they can be released without underflowing the internal accounting + s_siloedLockReleaseTokenPool.lockOrBurn( + Pool.LockOrBurnInV1({ + originalSender: STRANGER, + receiver: bytes(""), + amount: amount, + remoteChainSelector: SILOED_CHAIN_SELECTOR, + localToken: address(s_token) + }) + ); + + assertEq(s_siloedLockReleaseTokenPool.getAvailableTokens(SILOED_CHAIN_SELECTOR), amount); + + vm.startPrank(s_allowedOffRamp); + + vm.expectEmit(); + emit IERC20.Transfer(address(s_siloedLockReleaseTokenPool), OWNER, amount); + + s_siloedLockReleaseTokenPool.releaseOrMint( + Pool.ReleaseOrMintInV1({ + originalSender: bytes(""), + receiver: OWNER, + amount: amount, + localToken: address(s_token), + remoteChainSelector: SILOED_CHAIN_SELECTOR, + sourcePoolAddress: abi.encode(s_siloedDestPoolAddress), + sourcePoolData: "", + offchainTokenData: "" + }) + ); + + assertEq(s_siloedLockReleaseTokenPool.getAvailableTokens(SILOED_CHAIN_SELECTOR), 0); + } + + function test_ReleaseOrMint_UnsiloedChain() public { + uint256 amount = 10e18; + + deal(address(s_token), address(s_siloedLockReleaseTokenPool), amount); + vm.startPrank(s_allowedOnRamp); + + // Lock funds for unsiloed chain so they can be released later + s_siloedLockReleaseTokenPool.lockOrBurn( + Pool.LockOrBurnInV1({ + originalSender: STRANGER, + receiver: bytes(""), + amount: amount, + remoteChainSelector: SOURCE_CHAIN_SELECTOR, + localToken: address(s_token) + }) + ); + + assertEq(s_siloedLockReleaseTokenPool.getAvailableTokens(SOURCE_CHAIN_SELECTOR), amount); + assertEq(s_siloedLockReleaseTokenPool.getUnsiloedLiquidity(), amount); + + vm.startPrank(s_allowedOffRamp); + + vm.expectEmit(); + emit IERC20.Transfer(address(s_siloedLockReleaseTokenPool), OWNER, amount); + + s_siloedLockReleaseTokenPool.releaseOrMint( + Pool.ReleaseOrMintInV1({ + originalSender: bytes(""), + receiver: OWNER, + amount: amount, + localToken: address(s_token), + remoteChainSelector: SOURCE_CHAIN_SELECTOR, + sourcePoolAddress: abi.encode(s_siloedDestPoolAddress), + sourcePoolData: "", + offchainTokenData: "" + }) + ); + + assertEq(s_siloedLockReleaseTokenPool.getAvailableTokens(SOURCE_CHAIN_SELECTOR), 0); + assertEq(s_siloedLockReleaseTokenPool.getUnsiloedLiquidity(), 0); + } + + // Reverts + + function test_ReleaseOrMint_RevertsWhen_InsufficientLiquidity_SiloedChain() public { + uint256 releaseAmount = 10e18; + uint256 liquidityAmount = releaseAmount - 1; + + s_siloedLockReleaseTokenPool.provideSiloedLiquidity(SILOED_CHAIN_SELECTOR, liquidityAmount); + + // Since amount to release is greater than provided liquidity, the function should revert + vm.expectRevert( + abi.encodeWithSelector(SiloedLockReleaseTokenPool.InsufficientLiquidity.selector, liquidityAmount, releaseAmount) + ); + + vm.startPrank(s_allowedOffRamp); + + s_siloedLockReleaseTokenPool.releaseOrMint( + Pool.ReleaseOrMintInV1({ + originalSender: bytes(""), + receiver: OWNER, + amount: releaseAmount, + localToken: address(s_token), + remoteChainSelector: SILOED_CHAIN_SELECTOR, + sourcePoolAddress: abi.encode(s_siloedDestPoolAddress), + sourcePoolData: "", + offchainTokenData: "" + }) + ); + } + + function test_ReleaseOrMint_RevertsWhen_InsufficientLiquidity_UnsiloedChain() public { + uint256 releaseAmount = 10e18; + uint256 liquidityAmount = releaseAmount - 1; + + // Call the provide liquidity function which provides to unsiloed chains. + s_siloedLockReleaseTokenPool.provideLiquidity(liquidityAmount); + + // Since amount to release is greater than provided liquidity, the function should revert + vm.expectRevert( + abi.encodeWithSelector(SiloedLockReleaseTokenPool.InsufficientLiquidity.selector, liquidityAmount, releaseAmount) + ); + + vm.startPrank(s_allowedOffRamp); + + s_siloedLockReleaseTokenPool.releaseOrMint( + Pool.ReleaseOrMintInV1({ + originalSender: bytes(""), + receiver: OWNER, + amount: releaseAmount, + localToken: address(s_token), + remoteChainSelector: SOURCE_CHAIN_SELECTOR, + sourcePoolAddress: abi.encode(s_siloedDestPoolAddress), + sourcePoolData: "", + offchainTokenData: "" + }) + ); + } +} diff --git a/contracts/src/v0.8/ccip/test/pools/SiloedLockReleaseTokenPool/SiloedLockReleaseTokenPool.setRebalancer.t.sol b/contracts/src/v0.8/ccip/test/pools/SiloedLockReleaseTokenPool/SiloedLockReleaseTokenPool.setRebalancer.t.sol new file mode 100644 index 00000000000..ea676d53015 --- /dev/null +++ b/contracts/src/v0.8/ccip/test/pools/SiloedLockReleaseTokenPool/SiloedLockReleaseTokenPool.setRebalancer.t.sol @@ -0,0 +1,36 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity ^0.8.24; + +import {SiloedLockReleaseTokenPool} from "../../../pools/SiloedLockReleaseTokenPool.sol"; +import {SiloedLockReleaseTokenPoolSetup} from "./SiloedLockReleaseTokenPoolSetup.t.sol"; + +contract SiloedLockReleaseTokenPool_setRebalancer is SiloedLockReleaseTokenPoolSetup { + address public constant REBALANCER_ADDRESS = address(0xdeadbeef); + + function test_setSiloRebalancer() public { + vm.expectEmit(); + emit SiloedLockReleaseTokenPool.SiloRebalancerSet(SILOED_CHAIN_SELECTOR, REBALANCER_ADDRESS, OWNER); + + s_siloedLockReleaseTokenPool.setSiloRebalancer(SILOED_CHAIN_SELECTOR, REBALANCER_ADDRESS); + + assertEq(s_siloedLockReleaseTokenPool.getSiloRebalancer(SILOED_CHAIN_SELECTOR), REBALANCER_ADDRESS); + assertEq(s_siloedLockReleaseTokenPool.getSiloRebalancer(DEST_CHAIN_SELECTOR), OWNER); + } + + function test_setRebalancer_UnsiloedChains() public { + vm.expectEmit(); + emit SiloedLockReleaseTokenPool.UnsiloedRebalancerSet(REBALANCER_ADDRESS, OWNER); + + s_siloedLockReleaseTokenPool.setRebalancer(REBALANCER_ADDRESS); + + assertEq(s_siloedLockReleaseTokenPool.getSiloRebalancer(DEST_CHAIN_SELECTOR), REBALANCER_ADDRESS); + } + + // Reverts + + function test_setSiloRebalancer_RevertWhen_ChainNotSiloed() public { + vm.expectRevert(abi.encodeWithSelector(SiloedLockReleaseTokenPool.ChainNotSiloed.selector, DEST_CHAIN_SELECTOR)); + + s_siloedLockReleaseTokenPool.setSiloRebalancer(DEST_CHAIN_SELECTOR, REBALANCER_ADDRESS); + } +} diff --git a/contracts/src/v0.8/ccip/test/pools/SiloedLockReleaseTokenPool/SiloedLockReleaseTokenPool.updateSiloDesignations.t.sol b/contracts/src/v0.8/ccip/test/pools/SiloedLockReleaseTokenPool/SiloedLockReleaseTokenPool.updateSiloDesignations.t.sol new file mode 100644 index 00000000000..506b1373ceb --- /dev/null +++ b/contracts/src/v0.8/ccip/test/pools/SiloedLockReleaseTokenPool/SiloedLockReleaseTokenPool.updateSiloDesignations.t.sol @@ -0,0 +1,73 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity ^0.8.24; + +import {SiloedLockReleaseTokenPool} from "../../../pools/SiloedLockReleaseTokenPool.sol"; +import {SiloedLockReleaseTokenPoolSetup} from "./SiloedLockReleaseTokenPoolSetup.t.sol"; + +contract SiloedLockReleaseTokenPool_updateSiloDesignations is SiloedLockReleaseTokenPoolSetup { + function test_updateSiloDesignations() public { + uint256 amount = 1e18; + + SiloedLockReleaseTokenPool.SiloConfigUpdate[] memory chainSelectors = + new SiloedLockReleaseTokenPool.SiloConfigUpdate[](1); + + chainSelectors[0] = + SiloedLockReleaseTokenPool.SiloConfigUpdate({remoteChainSelector: SILOED_CHAIN_SELECTOR, rebalancer: OWNER}); + + vm.expectEmit(); + emit SiloedLockReleaseTokenPool.ChainSiloed(SILOED_CHAIN_SELECTOR, OWNER); + + s_siloedLockReleaseTokenPool.updateSiloDesignations(new uint64[](0), chainSelectors); + + // Assert that the funds are siloed correctly + assertTrue(s_siloedLockReleaseTokenPool.isSiloed(SILOED_CHAIN_SELECTOR)); + assertEq(s_siloedLockReleaseTokenPool.getAvailableTokens(SILOED_CHAIN_SELECTOR), 0); + assertEq(s_siloedLockReleaseTokenPool.getSiloRebalancer(SILOED_CHAIN_SELECTOR), OWNER); + + // Provide some Liquidity so that we can then check that it gets removed. + s_siloedLockReleaseTokenPool.setSiloRebalancer(SILOED_CHAIN_SELECTOR, OWNER); + s_siloedLockReleaseTokenPool.provideSiloedLiquidity(SILOED_CHAIN_SELECTOR, amount); + assertEq(s_siloedLockReleaseTokenPool.getAvailableTokens(SILOED_CHAIN_SELECTOR), amount); + + vm.expectEmit(); + emit SiloedLockReleaseTokenPool.ChainUnsiloed(SILOED_CHAIN_SELECTOR, amount); + + assertEq(s_siloedLockReleaseTokenPool.getUnsiloedLiquidity(), 0); + + uint64[] memory removableChainSelectors = new uint64[](1); + removableChainSelectors[0] = SILOED_CHAIN_SELECTOR; + + s_siloedLockReleaseTokenPool.updateSiloDesignations( + removableChainSelectors, new SiloedLockReleaseTokenPool.SiloConfigUpdate[](0) + ); + + // Check that the locked funds accounting was cleared when the funds were un-siloed. + assertFalse(s_siloedLockReleaseTokenPool.isSiloed(SILOED_CHAIN_SELECTOR)); + assertEq(s_siloedLockReleaseTokenPool.getAvailableTokens(SILOED_CHAIN_SELECTOR), amount); + + // Assert that the available liquidity moved from being siloed to unsiloed. + assertEq(s_siloedLockReleaseTokenPool.getUnsiloedLiquidity(), amount); + } + + // Reverts + + function test_updateSiloDesignations_RevertWhen_ChainNotSiloed() public { + uint64[] memory removableChainSelectors = new uint64[](1); + removableChainSelectors[0] = DEST_CHAIN_SELECTOR; + + vm.expectRevert(abi.encodeWithSelector(SiloedLockReleaseTokenPool.ChainNotSiloed.selector, DEST_CHAIN_SELECTOR)); + + s_siloedLockReleaseTokenPool.updateSiloDesignations( + removableChainSelectors, new SiloedLockReleaseTokenPool.SiloConfigUpdate[](0) + ); + } + + function test_updateSiloDesignations_RevertWhen_InvalidChainSelector() public { + SiloedLockReleaseTokenPool.SiloConfigUpdate[] memory adds = new SiloedLockReleaseTokenPool.SiloConfigUpdate[](1); + adds[0] = SiloedLockReleaseTokenPool.SiloConfigUpdate({remoteChainSelector: 0, rebalancer: OWNER}); + + vm.expectRevert(abi.encodeWithSelector(SiloedLockReleaseTokenPool.InvalidChainSelector.selector, 0)); + + s_siloedLockReleaseTokenPool.updateSiloDesignations(new uint64[](0), adds); + } +} diff --git a/contracts/src/v0.8/ccip/test/pools/SiloedLockReleaseTokenPool/SiloedLockReleaseTokenPool.withdrawLiquidity.t.sol b/contracts/src/v0.8/ccip/test/pools/SiloedLockReleaseTokenPool/SiloedLockReleaseTokenPool.withdrawLiquidity.t.sol new file mode 100644 index 00000000000..7a82f0954a0 --- /dev/null +++ b/contracts/src/v0.8/ccip/test/pools/SiloedLockReleaseTokenPool/SiloedLockReleaseTokenPool.withdrawLiquidity.t.sol @@ -0,0 +1,126 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity ^0.8.24; + +import {SiloedLockReleaseTokenPool} from "../../../pools/SiloedLockReleaseTokenPool.sol"; +import {TokenPool} from "../../../pools/TokenPool.sol"; +import {SiloedLockReleaseTokenPoolSetup} from "./SiloedLockReleaseTokenPoolSetup.t.sol"; + +contract SiloedLockReleaseTokenPool_withdrawLiqudity is SiloedLockReleaseTokenPoolSetup { + address public UNAUTHORIZED_ADDRESS = address(0xdeadbeef); + + function setUp() public override { + super.setUp(); + + s_siloedLockReleaseTokenPool.setSiloRebalancer(SILOED_CHAIN_SELECTOR, OWNER); + } + + function test_withdrawLiquidity_SiloedFunds() public { + uint256 amount = 1e24; + + uint256 balanceBefore = s_token.balanceOf(OWNER); + + // Provide the Liquidity first + s_siloedLockReleaseTokenPool.provideSiloedLiquidity(SILOED_CHAIN_SELECTOR, amount); + + vm.expectEmit(); + emit SiloedLockReleaseTokenPool.LiquidityRemoved(SILOED_CHAIN_SELECTOR, OWNER, amount); + + // Remove the Liquidity + s_siloedLockReleaseTokenPool.withdrawSiloedLiquidity(SILOED_CHAIN_SELECTOR, amount); + + assertEq(s_token.balanceOf(OWNER), balanceBefore); + assertEq(s_token.balanceOf(address(s_siloedLockReleaseTokenPool)), 0); + assertEq(s_siloedLockReleaseTokenPool.getAvailableTokens(SILOED_CHAIN_SELECTOR), 0); + assertEq(s_siloedLockReleaseTokenPool.getUnsiloedLiquidity(), 0); + } + + function test_withdrawSiloedLiquidity_UnsiloedFunds() public { + uint256 amount = 1e24; + + uint256 balanceBefore = s_token.balanceOf(OWNER); + + // Provide the Liquidity first + s_siloedLockReleaseTokenPool.provideSiloedLiquidity(DEST_CHAIN_SELECTOR, amount); + + assertEq(s_siloedLockReleaseTokenPool.getUnsiloedLiquidity(), amount); + + vm.expectEmit(); + emit SiloedLockReleaseTokenPool.LiquidityRemoved(DEST_CHAIN_SELECTOR, OWNER, amount); + + // Remove the Liquidity + s_siloedLockReleaseTokenPool.withdrawSiloedLiquidity(DEST_CHAIN_SELECTOR, amount); + + assertEq(s_token.balanceOf(OWNER), balanceBefore); + assertEq(s_token.balanceOf(address(s_siloedLockReleaseTokenPool)), 0); + assertEq(s_siloedLockReleaseTokenPool.getUnsiloedLiquidity(), 0); + } + + function test_withdrawLiquidity_UnsiloedFunds_LegacyFunctionSelector() public { + uint256 amount = 1e24; + + uint256 balanceBefore = s_token.balanceOf(OWNER); + + // Provide the Liquidity first + s_siloedLockReleaseTokenPool.provideSiloedLiquidity(DEST_CHAIN_SELECTOR, amount); + + assertEq(s_siloedLockReleaseTokenPool.getUnsiloedLiquidity(), amount); + + vm.expectEmit(); + emit SiloedLockReleaseTokenPool.LiquidityRemoved(0, OWNER, amount); + + // Remove the Liquidity + s_siloedLockReleaseTokenPool.withdrawLiquidity(amount); + + assertEq(s_token.balanceOf(OWNER), balanceBefore); + assertEq(s_token.balanceOf(address(s_siloedLockReleaseTokenPool)), 0); + assertEq(s_siloedLockReleaseTokenPool.getUnsiloedLiquidity(), 0); + assertEq(s_siloedLockReleaseTokenPool.getAvailableTokens(DEST_CHAIN_SELECTOR), 0); + } + + // Reverts + + function test_withdrawLiquidity_RevertWhen_SiloedFunds_NotEnoughLiquidity() public { + uint256 liquidityAmount = 1e24; + uint256 withdrawAmount = liquidityAmount + 1; + + s_siloedLockReleaseTokenPool.provideSiloedLiquidity(SILOED_CHAIN_SELECTOR, liquidityAmount); + + // Call should revert due to underflow error due to trying to burn more tokens than are locked via CCIP. + vm.expectRevert( + abi.encodeWithSelector(SiloedLockReleaseTokenPool.InsufficientLiquidity.selector, liquidityAmount, withdrawAmount) + ); + + s_siloedLockReleaseTokenPool.withdrawSiloedLiquidity(SILOED_CHAIN_SELECTOR, withdrawAmount); + } + + function test_withdrawSiloedLiquidity_RevertWhen_UnsiloedFunds_NotEnoughLiquidity() public { + uint256 liquidityAmount = 1e24; + uint256 withdrawAmount = liquidityAmount + 1; + + s_siloedLockReleaseTokenPool.provideSiloedLiquidity(DEST_CHAIN_SELECTOR, liquidityAmount); + + // Call should revert due to underflow error due to trying to burn more tokens than are locked via CCIP. + vm.expectRevert( + abi.encodeWithSelector(SiloedLockReleaseTokenPool.InsufficientLiquidity.selector, liquidityAmount, withdrawAmount) + ); + + // Test withdrawing funds from unsiloed liquidity pool but underflow + s_siloedLockReleaseTokenPool.withdrawSiloedLiquidity(DEST_CHAIN_SELECTOR, withdrawAmount); + } + + function test_withdrawSiloedLiqudity_RevertWhen_UnauthorizedOnlyUnsiloedRebalancer() public { + vm.startPrank(UNAUTHORIZED_ADDRESS); + + vm.expectRevert(abi.encodeWithSelector(TokenPool.Unauthorized.selector, UNAUTHORIZED_ADDRESS)); + + s_siloedLockReleaseTokenPool.withdrawSiloedLiquidity(DEST_CHAIN_SELECTOR, 1); + } + + function test_withdrawLiquidity_RevertsWhen_LegacyFunctionSelectorUnauthorized() public { + vm.startPrank(UNAUTHORIZED_ADDRESS); + + vm.expectRevert(abi.encodeWithSelector(TokenPool.Unauthorized.selector, UNAUTHORIZED_ADDRESS)); + + s_siloedLockReleaseTokenPool.withdrawLiquidity(1); + } +} diff --git a/contracts/src/v0.8/ccip/test/pools/SiloedLockReleaseTokenPool/SiloedLockReleaseTokenPoolSetup.t.sol b/contracts/src/v0.8/ccip/test/pools/SiloedLockReleaseTokenPool/SiloedLockReleaseTokenPoolSetup.t.sol new file mode 100644 index 00000000000..e7724663e05 --- /dev/null +++ b/contracts/src/v0.8/ccip/test/pools/SiloedLockReleaseTokenPool/SiloedLockReleaseTokenPoolSetup.t.sol @@ -0,0 +1,96 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity ^0.8.24; + +import {BurnMintERC20} from "../../../../shared/token/ERC20/BurnMintERC20.sol"; +import {Router} from "../../../Router.sol"; +import {SiloedLockReleaseTokenPool} from "../../../pools/SiloedLockReleaseTokenPool.sol"; +import {TokenPool} from "../../../pools/TokenPool.sol"; +import {BaseTest} from "../../BaseTest.t.sol"; + +import {IERC20} from "../../../../vendor/openzeppelin-solidity/v4.8.3/contracts/token/ERC20/IERC20.sol"; + +contract SiloedLockReleaseTokenPoolSetup is BaseTest { + IERC20 internal s_token; + SiloedLockReleaseTokenPool internal s_siloedLockReleaseTokenPool; + address[] internal s_allowedList; + + address internal s_allowedOnRamp = address(123); + address internal s_allowedOffRamp = address(234); + + address internal s_destPoolAddress = address(2736782345); + address internal s_sourcePoolAddress = address(53852352095); + + address internal s_siloedDestPoolAddress = address(4245234524); + uint64 internal constant SILOED_CHAIN_SELECTOR = DEST_CHAIN_SELECTOR + 1; + + function setUp() public virtual override { + super.setUp(); + s_token = new BurnMintERC20("LINK", "LNK", 18, 0, 0); + deal(address(s_token), OWNER, type(uint256).max); + + s_siloedLockReleaseTokenPool = new SiloedLockReleaseTokenPool( + s_token, DEFAULT_TOKEN_DECIMALS, new address[](0), address(s_mockRMNRemote), address(s_sourceRouter) + ); + + s_siloedLockReleaseTokenPool.setRebalancer(OWNER); + + s_token.approve(address(s_siloedLockReleaseTokenPool), type(uint256).max); + + bytes[] memory remotePoolAddresses = new bytes[](2); + remotePoolAddresses[0] = abi.encode(s_destPoolAddress); + remotePoolAddresses[1] = abi.encode(s_siloedDestPoolAddress); + + TokenPool.ChainUpdate[] memory chainUpdates = new TokenPool.ChainUpdate[](3); + chainUpdates[0] = TokenPool.ChainUpdate({ + remoteChainSelector: DEST_CHAIN_SELECTOR, + remotePoolAddresses: remotePoolAddresses, + remoteTokenAddress: abi.encode(address(2)), + outboundRateLimiterConfig: _getOutboundRateLimiterConfig(), + inboundRateLimiterConfig: _getInboundRateLimiterConfig() + }); + + chainUpdates[1] = TokenPool.ChainUpdate({ + remoteChainSelector: SILOED_CHAIN_SELECTOR, + remotePoolAddresses: remotePoolAddresses, + remoteTokenAddress: abi.encode(address(2)), + outboundRateLimiterConfig: _getOutboundRateLimiterConfig(), + inboundRateLimiterConfig: _getInboundRateLimiterConfig() + }); + + chainUpdates[2] = TokenPool.ChainUpdate({ + remoteChainSelector: SOURCE_CHAIN_SELECTOR, + remotePoolAddresses: remotePoolAddresses, + remoteTokenAddress: abi.encode(address(2)), + outboundRateLimiterConfig: _getOutboundRateLimiterConfig(), + inboundRateLimiterConfig: _getInboundRateLimiterConfig() + }); + + s_siloedLockReleaseTokenPool.applyChainUpdates(new uint64[](0), chainUpdates); + + Router.OnRamp[] memory onRampUpdates = new Router.OnRamp[](3); + Router.OffRamp[] memory offRampUpdates = new Router.OffRamp[](2); + + onRampUpdates[0] = Router.OnRamp({destChainSelector: DEST_CHAIN_SELECTOR, onRamp: s_allowedOnRamp}); + offRampUpdates[0] = Router.OffRamp({sourceChainSelector: SOURCE_CHAIN_SELECTOR, offRamp: s_allowedOffRamp}); + + onRampUpdates[1] = Router.OnRamp({destChainSelector: SILOED_CHAIN_SELECTOR, onRamp: s_allowedOnRamp}); + offRampUpdates[1] = Router.OffRamp({sourceChainSelector: SILOED_CHAIN_SELECTOR, offRamp: s_allowedOffRamp}); + + onRampUpdates[2] = Router.OnRamp({destChainSelector: SOURCE_CHAIN_SELECTOR, onRamp: s_allowedOnRamp}); + + s_sourceRouter.applyRampUpdates(onRampUpdates, new Router.OffRamp[](0), offRampUpdates); + + // Apply Siloeing Rules + SiloedLockReleaseTokenPool.SiloConfigUpdate[] memory adds = new SiloedLockReleaseTokenPool.SiloConfigUpdate[](1); + + adds[0] = + SiloedLockReleaseTokenPool.SiloConfigUpdate({remoteChainSelector: SILOED_CHAIN_SELECTOR, rebalancer: OWNER}); + + s_siloedLockReleaseTokenPool.updateSiloDesignations(new uint64[](0), adds); + + assertTrue(s_siloedLockReleaseTokenPool.isSiloed(SILOED_CHAIN_SELECTOR)); + assertFalse(s_siloedLockReleaseTokenPool.isSiloed(DEST_CHAIN_SELECTOR)); + + s_siloedLockReleaseTokenPool.setSiloRebalancer(SILOED_CHAIN_SELECTOR, OWNER); + } +} diff --git a/contracts/src/v0.8/ccip/test/pools/USDC/HybridLockReleaseUSDCTokenPool/HybridLockReleaseUSDCTokenPool.transferLiquidity.t.sol b/contracts/src/v0.8/ccip/test/pools/USDC/HybridLockReleaseUSDCTokenPool/HybridLockReleaseUSDCTokenPool.transferLiquidity.t.sol deleted file mode 100644 index d0600d26b88..00000000000 --- a/contracts/src/v0.8/ccip/test/pools/USDC/HybridLockReleaseUSDCTokenPool/HybridLockReleaseUSDCTokenPool.transferLiquidity.t.sol +++ /dev/null @@ -1,95 +0,0 @@ -// SPDX-License-Identifier: BUSL-1.1 -pragma solidity ^0.8.24; - -import {ILiquidityContainer} from "../../../../../liquiditymanager/interfaces/ILiquidityContainer.sol"; - -import {HybridLockReleaseUSDCTokenPool} from "../../../../pools/USDC/HybridLockReleaseUSDCTokenPool.sol"; -import {HybridLockReleaseUSDCTokenPoolSetup} from "./HybridLockReleaseUSDCTokenPoolSetup.t.sol"; - -contract HybridLockReleaseUSDCTokenPool_TransferLiquidity is HybridLockReleaseUSDCTokenPoolSetup { - function test_transferLiquidity() public { - // Set as the OWNER so we can provide liquidity - vm.startPrank(OWNER); - - s_usdcTokenPool.setLiquidityProvider(DEST_CHAIN_SELECTOR, OWNER); - s_token.approve(address(s_usdcTokenPool), type(uint256).max); - - uint256 liquidityAmount = 1e9; - - // Provide some liquidity to the pool - s_usdcTokenPool.provideLiquidity(DEST_CHAIN_SELECTOR, liquidityAmount); - - // Set the new token pool as the rebalancer - s_usdcTokenPool.transferOwnership(address(s_usdcTokenPoolTransferLiquidity)); - - vm.expectEmit(); - emit ILiquidityContainer.LiquidityRemoved(address(s_usdcTokenPoolTransferLiquidity), liquidityAmount); - - vm.expectEmit(); - emit HybridLockReleaseUSDCTokenPool.LiquidityTransferred( - address(s_usdcTokenPool), DEST_CHAIN_SELECTOR, liquidityAmount - ); - - s_usdcTokenPoolTransferLiquidity.transferLiquidity(address(s_usdcTokenPool), DEST_CHAIN_SELECTOR); - - assertEq( - s_usdcTokenPool.owner(), - address(s_usdcTokenPoolTransferLiquidity), - "Ownership of the old pool should be transferred to the new pool" - ); - - assertEq( - s_usdcTokenPoolTransferLiquidity.getLockedTokensForChain(DEST_CHAIN_SELECTOR), - liquidityAmount, - "Tokens locked for dest chain doesn't match expected amount in storage" - ); - - assertEq( - s_usdcTokenPool.getLockedTokensForChain(DEST_CHAIN_SELECTOR), - 0, - "Tokens locked for dest chain in old token pool doesn't match expected amount in storage" - ); - - assertEq( - s_token.balanceOf(address(s_usdcTokenPoolTransferLiquidity)), - liquidityAmount, - "Liquidity amount of tokens should be new in new pool, but aren't" - ); - - assertEq( - s_token.balanceOf(address(s_usdcTokenPool)), - 0, - "Liquidity amount of tokens should be zero in old pool, but aren't" - ); - } - - function test_RevertWhen_cannotTransferLiquidityDuringPendingMigration() public { - // Set as the OWNER so we can provide liquidity - vm.startPrank(OWNER); - - // Mark the destination chain as supporting CCTP, so use L/R instead. - uint64[] memory destChainAdds = new uint64[](1); - destChainAdds[0] = DEST_CHAIN_SELECTOR; - - s_usdcTokenPool.updateChainSelectorMechanisms(new uint64[](0), destChainAdds); - - s_usdcTokenPool.setLiquidityProvider(DEST_CHAIN_SELECTOR, OWNER); - s_token.approve(address(s_usdcTokenPool), type(uint256).max); - - uint256 liquidityAmount = 1e9; - - // Provide some liquidity to the pool - s_usdcTokenPool.provideLiquidity(DEST_CHAIN_SELECTOR, liquidityAmount); - - // Set the new token pool as the rebalancer - s_usdcTokenPool.transferOwnership(address(s_usdcTokenPoolTransferLiquidity)); - - s_usdcTokenPool.proposeCCTPMigration(DEST_CHAIN_SELECTOR); - - vm.expectRevert( - abi.encodeWithSelector(HybridLockReleaseUSDCTokenPool.LanePausedForCCTPMigration.selector, DEST_CHAIN_SELECTOR) - ); - - s_usdcTokenPoolTransferLiquidity.transferLiquidity(address(s_usdcTokenPool), DEST_CHAIN_SELECTOR); - } -} diff --git a/contracts/test/v0.8/automation/AutomationRegistry2_3.test.ts b/contracts/test/v0.8/automation/AutomationRegistry2_3.test.ts index 48ec8469f9a..11282bdff94 100644 --- a/contracts/test/v0.8/automation/AutomationRegistry2_3.test.ts +++ b/contracts/test/v0.8/automation/AutomationRegistry2_3.test.ts @@ -117,7 +117,7 @@ const emptyBytes = '0x' const emptyBytes32 = '0x0000000000000000000000000000000000000000000000000000000000000000' -const transmitGasOverhead = 1_040_000 +const transmitGasOverhead = 1_080_000 const checkGasOverhead = 600_000 const stalenessSeconds = BigNumber.from(43820) @@ -165,7 +165,6 @@ let registry: IAutomationRegistry // default registry, used for most tests let arbRegistry: IAutomationRegistry // arbitrum registry let opRegistry: IAutomationRegistry // optimism registry let mgRegistry: IAutomationRegistry // "migrate registry" used in migration tests -let blankRegistry: IAutomationRegistry // used to test initial configurations let mockArbGasInfo: MockArbGasInfo let mockOVMGasPriceOracle: MockOVMGasPriceOracle let mock: UpkeepMock @@ -402,7 +401,6 @@ describe('AutomationRegistry2_3', () => { let afUpkeepId: BigNumber // auto funding upkeep let logUpkeepId: BigNumber // log trigger upkeepID let streamsLookupUpkeepId: BigNumber // streams lookup upkeep - const numUpkeeps = 4 // see above let keeperAddresses: string[] let payees: string[] let signers: Wallet[] @@ -1017,7 +1015,6 @@ describe('AutomationRegistry2_3', () => { arbRegistry = await deployRegistry23(...registryParams) opRegistry = await deployRegistry23(...registryParams) mgRegistry = await deployRegistry23(...registryParams) - blankRegistry = await deployRegistry23(...registryParams) registryConditionalOverhead = await registry.getConditionalGasOverhead() registryLogOverhead = await registry.getLogGasOverhead() diff --git a/contracts/test/v0.8/automation/ZKSyncAutomationRegistry2_3.test.ts b/contracts/test/v0.8/automation/ZKSyncAutomationRegistry2_3.test.ts index ffbde4464b9..21af6fcbf0a 100644 --- a/contracts/test/v0.8/automation/ZKSyncAutomationRegistry2_3.test.ts +++ b/contracts/test/v0.8/automation/ZKSyncAutomationRegistry2_3.test.ts @@ -84,9 +84,6 @@ type OnChainConfig = Parameters[3] let registryConditionalOverhead: BigNumber let registryLogOverhead: BigNumber let registryPerSignerGasOverhead: BigNumber -// let registryPerPerformByteGasOverhead: BigNumber -// let registryTransmitCalldataFixedBytesOverhead: BigNumber -// let registryTransmitCalldataPerSignerBytesOverhead: BigNumber let cancellationDelay: number // This is the margin for gas that we test for. Gas charged should always be greater @@ -1618,7 +1615,6 @@ describe('ZKSyncAutomationRegistry2_3', () => { BigNumber.from('1'), // Not the config multiplier, but the actual gas used paymentPremiumPPB, flatFeeMilliCents, - // pubdataGas.mul(gasPrice), ).total.toString(), totalPayment.toString(), ) @@ -1630,7 +1626,6 @@ describe('ZKSyncAutomationRegistry2_3', () => { BigNumber.from('1'), // Not the config multiplier, but the actual gas used paymentPremiumPPB, flatFeeMilliCents, - // pubdataGas.mul(gasPrice), ).premium.toString(), premium.toString(), ) @@ -1661,7 +1656,6 @@ describe('ZKSyncAutomationRegistry2_3', () => { gasCeilingMultiplier, // Should be same with exisitng multiplier paymentPremiumPPB, flatFeeMilliCents, - // pubdataGas.mul(gasPrice), ).total.toString(), totalPayment.toString(), ) diff --git a/core/gethwrappers/generated/automation_registry_wrapper_2_3/automation_registry_wrapper_2_3.go b/core/gethwrappers/generated/automation_registry_wrapper_2_3/automation_registry_wrapper_2_3.go index 97f0cfb113a..17cbd9a95a8 100644 --- a/core/gethwrappers/generated/automation_registry_wrapper_2_3/automation_registry_wrapper_2_3.go +++ b/core/gethwrappers/generated/automation_registry_wrapper_2_3/automation_registry_wrapper_2_3.go @@ -76,7 +76,7 @@ type AutomationRegistryBase23PaymentReceipt struct { var AutomationRegistryMetaData = &bind.MetaData{ ABI: "[{\"inputs\":[{\"internalType\":\"contractAutomationRegistryLogicA2_3\",\"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\":[{\"internalType\":\"uint256\",\"name\":\"available\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"requested\",\"type\":\"uint256\"}],\"name\":\"InsufficientBalance\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InsufficientLinkLiquidity\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidDataLength\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidFeed\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidPayee\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidRecipient\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidReport\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidSigner\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidToken\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidTransmitter\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidTrigger\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidTriggerType\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"MigrationNotPermitted\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"MustSettleOffchain\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"MustSettleOnchain\",\"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\":\"OnlyFinanceAdmin\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyPausedUpkeep\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlySimulatedBackend\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyUnpausedUpkeep\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ParameterLengthError\",\"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\":\"TransferFailed\",\"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\"},{\"inputs\":[],\"name\":\"ZeroAddressNotAllowed\",\"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\"},{\"components\":[{\"internalType\":\"uint32\",\"name\":\"gasFeePPB\",\"type\":\"uint32\"},{\"internalType\":\"uint24\",\"name\":\"flatFeeMilliCents\",\"type\":\"uint24\"}],\"indexed\":false,\"internalType\":\"structAutomationRegistryBase2_3.BillingOverrides\",\"name\":\"overrides\",\"type\":\"tuple\"}],\"name\":\"BillingConfigOverridden\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"name\":\"BillingConfigOverrideRemoved\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"contractIERC20Metadata\",\"name\":\"token\",\"type\":\"address\"},{\"components\":[{\"internalType\":\"uint32\",\"name\":\"gasFeePPB\",\"type\":\"uint32\"},{\"internalType\":\"uint24\",\"name\":\"flatFeeMilliCents\",\"type\":\"uint24\"},{\"internalType\":\"contractAggregatorV3Interface\",\"name\":\"priceFeed\",\"type\":\"address\"},{\"internalType\":\"uint8\",\"name\":\"decimals\",\"type\":\"uint8\"},{\"internalType\":\"uint256\",\"name\":\"fallbackPrice\",\"type\":\"uint256\"},{\"internalType\":\"uint96\",\"name\":\"minSpend\",\"type\":\"uint96\"}],\"indexed\":false,\"internalType\":\"structAutomationRegistryBase2_3.BillingConfig\",\"name\":\"config\",\"type\":\"tuple\"}],\"name\":\"BillingConfigSet\",\"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\":\"address\",\"name\":\"newModule\",\"type\":\"address\"}],\"name\":\"ChainSpecificModuleUpdated\",\"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\":\"address\",\"name\":\"assetAddress\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"FeesWithdrawn\",\"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\":\"address[]\",\"name\":\"payees\",\"type\":\"address[]\"},{\"indexed\":false,\"internalType\":\"uint256[]\",\"name\":\"payments\",\"type\":\"uint256[]\"}],\"name\":\"NOPsSettledOffchain\",\"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\"},{\"components\":[{\"internalType\":\"uint96\",\"name\":\"gasChargeInBillingToken\",\"type\":\"uint96\"},{\"internalType\":\"uint96\",\"name\":\"premiumInBillingToken\",\"type\":\"uint96\"},{\"internalType\":\"uint96\",\"name\":\"gasReimbursementInJuels\",\"type\":\"uint96\"},{\"internalType\":\"uint96\",\"name\":\"premiumInJuels\",\"type\":\"uint96\"},{\"internalType\":\"contractIERC20Metadata\",\"name\":\"billingToken\",\"type\":\"address\"},{\"internalType\":\"uint96\",\"name\":\"linkUSD\",\"type\":\"uint96\"},{\"internalType\":\"uint96\",\"name\":\"nativeUSD\",\"type\":\"uint96\"},{\"internalType\":\"uint96\",\"name\":\"billingUSD\",\"type\":\"uint96\"}],\"indexed\":false,\"internalType\":\"structAutomationRegistryBase2_3.PaymentReceipt\",\"name\":\"receipt\",\"type\":\"tuple\"}],\"name\":\"UpkeepCharged\",\"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\":\"payable\",\"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\":[],\"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\":\"checkGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"maxPerformGas\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"maxCheckDataSize\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"transcoder\",\"type\":\"address\"},{\"internalType\":\"bool\",\"name\":\"reorgProtectionEnabled\",\"type\":\"bool\"},{\"internalType\":\"uint24\",\"name\":\"stalenessSeconds\",\"type\":\"uint24\"},{\"internalType\":\"uint32\",\"name\":\"maxPerformDataSize\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"maxRevertDataSize\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"upkeepPrivilegeManager\",\"type\":\"address\"},{\"internalType\":\"uint16\",\"name\":\"gasCeilingMultiplier\",\"type\":\"uint16\"},{\"internalType\":\"address\",\"name\":\"financeAdmin\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"fallbackGasPrice\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"fallbackLinkPrice\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"fallbackNativePrice\",\"type\":\"uint256\"},{\"internalType\":\"address[]\",\"name\":\"registrars\",\"type\":\"address[]\"},{\"internalType\":\"contractIChainModule\",\"name\":\"chainModule\",\"type\":\"address\"}],\"internalType\":\"structAutomationRegistryBase2_3.OnchainConfig\",\"name\":\"onchainConfig\",\"type\":\"tuple\"},{\"internalType\":\"uint64\",\"name\":\"offchainConfigVersion\",\"type\":\"uint64\"},{\"internalType\":\"bytes\",\"name\":\"offchainConfig\",\"type\":\"bytes\"},{\"internalType\":\"contractIERC20Metadata[]\",\"name\":\"billingTokens\",\"type\":\"address[]\"},{\"components\":[{\"internalType\":\"uint32\",\"name\":\"gasFeePPB\",\"type\":\"uint32\"},{\"internalType\":\"uint24\",\"name\":\"flatFeeMilliCents\",\"type\":\"uint24\"},{\"internalType\":\"contractAggregatorV3Interface\",\"name\":\"priceFeed\",\"type\":\"address\"},{\"internalType\":\"uint8\",\"name\":\"decimals\",\"type\":\"uint8\"},{\"internalType\":\"uint256\",\"name\":\"fallbackPrice\",\"type\":\"uint256\"},{\"internalType\":\"uint96\",\"name\":\"minSpend\",\"type\":\"uint96\"}],\"internalType\":\"structAutomationRegistryBase2_3.BillingConfig[]\",\"name\":\"billingConfigs\",\"type\":\"tuple[]\"}],\"name\":\"setConfigTypeSafe\",\"outputs\":[],\"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: "0x6101806040523480156200001257600080fd5b50604051620065423803806200654283398101604081905262000035916200062f565b80816001600160a01b031663ca30e6036040518163ffffffff1660e01b8152600401602060405180830381865afa15801562000075573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200009b91906200062f565b826001600160a01b031663226cf83c6040518163ffffffff1660e01b8152600401602060405180830381865afa158015620000da573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200010091906200062f565b836001600160a01b031663614486af6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156200013f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200016591906200062f565b846001600160a01b0316636709d0e56040518163ffffffff1660e01b8152600401602060405180830381865afa158015620001a4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620001ca91906200062f565b856001600160a01b0316635425d8ac6040518163ffffffff1660e01b8152600401602060405180830381865afa15801562000209573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200022f91906200062f565b866001600160a01b031663a08714c06040518163ffffffff1660e01b8152600401602060405180830381865afa1580156200026e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200029491906200062f565b876001600160a01b031663c5b964e06040518163ffffffff1660e01b8152600401602060405180830381865afa158015620002d3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620002f9919062000656565b886001600160a01b031663ac4dc59a6040518163ffffffff1660e01b8152600401602060405180830381865afa15801562000338573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200035e91906200062f565b3380600081620003b55760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b0384811691909117909155811615620003e857620003e8816200056b565b5050506001600160a01b0380891660805287811660a05286811660c05285811660e052848116610100528316610120526025805483919060ff19166001838181111562000439576200043962000679565b0217905550806001600160a01b0316610140816001600160a01b03168152505060c0516001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa1580156200049a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620004c091906200068f565b60ff1660a0516001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa15801562000504573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200052a91906200068f565b60ff16146200054c576040516301f86e1760e41b815260040160405180910390fd5b5050506001600160a01b039095166101605250620006b4945050505050565b336001600160a01b03821603620005c55760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c660000000000000000006044820152606401620003ac565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b6001600160a01b03811681146200062c57600080fd5b50565b6000602082840312156200064257600080fd5b81516200064f8162000616565b9392505050565b6000602082840312156200066957600080fd5b8151600281106200064f57600080fd5b634e487b7160e01b600052602160045260246000fd5b600060208284031215620006a257600080fd5b815160ff811681146200064f57600080fd5b60805160a05160c05160e05161010051610120516101405161016051615e2a620007186000396000818160b3015261018601526000505060005050600050506000505060006137bd015260005050600081816113710152612de60152615e2a6000f3fe6080604052600436106100b15760003560e01c80638da5cb5b11610069578063b1dc65a41161004e578063b1dc65a4146102cb578063e3d0e712146102eb578063f2fde38b1461030b576100b1565b80638da5cb5b1461025a578063afcb95d714610285576100b1565b8063349e8cca1161009a578063349e8cca1461017757806379ba5097146101cb57806381ff7048146101e0576100b1565b80630870d3a1146100f8578063181f5a7714610118575b7f00000000000000000000000000000000000000000000000000000000000000003660008037600080366000845af43d6000803e8080156100f1573d6000f35b3d6000fd5b005b34801561010457600080fd5b506100f6610113366004614b9e565b61032b565b34801561012457600080fd5b506101616040518060400160405280601881526020017f4175746f6d6174696f6e526567697374727920322e332e30000000000000000081525081565b60405161016e9190614d1a565b60405180910390f35b34801561018357600080fd5b507f00000000000000000000000000000000000000000000000000000000000000005b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200161016e565b3480156101d757600080fd5b506100f6610c0f565b3480156101ec57600080fd5b5061023760175460135463ffffffff74010000000000000000000000000000000000000000830481169378010000000000000000000000000000000000000000000000009093041691565b6040805163ffffffff94851681529390921660208401529082015260600161016e565b34801561026657600080fd5b5060005473ffffffffffffffffffffffffffffffffffffffff166101a6565b34801561029157600080fd5b50601354601454604080516000815260208101939093526c0100000000000000000000000090910463ffffffff169082015260600161016e565b3480156102d757600080fd5b506100f66102e6366004614d79565b610d11565b3480156102f757600080fd5b506100f6610306366004614e5e565b611051565b34801561031757600080fd5b506100f6610326366004614f2b565b61108b565b61033361109f565b601f8851111561036f576040517f25d0209c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8560ff166000036103ac576040517fe77dba5600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b865188511415806103cb57506103c3866003614f77565b60ff16885111155b15610402576040517f1d2d1c5800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b805182511461043d576040517fcf54c06a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6104478282611122565b610451888861175a565b604051806101200160405280601460000160009054906101000a90046bffffffffffffffffffffffff166bffffffffffffffffffffffff168152602001600063ffffffff1681526020018660a0015162ffffff16815260200186610120015161ffff1681526020018760ff168152602001601460000160169054906101000a900460ff1615158152602001601460000160179054906101000a900460ff1615158152602001866080015115158152602001866101e0015173ffffffffffffffffffffffffffffffffffffffff16815250601460008201518160000160006101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff160217905550602082015181600001600c6101000a81548163ffffffff021916908363ffffffff16021790555060408201518160000160106101000a81548162ffffff021916908362ffffff16021790555060608201518160000160136101000a81548161ffff021916908361ffff16021790555060808201518160000160156101000a81548160ff021916908360ff16021790555060a08201518160000160166101000a81548160ff02191690831515021790555060c08201518160000160176101000a81548160ff02191690831515021790555060e08201518160000160186101000a81548160ff0219169083151502179055506101008201518160010160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055509050506000601660010160189054906101000a900463ffffffff1690506000866101e0015173ffffffffffffffffffffffffffffffffffffffff166357e871e76040518163ffffffff1660e01b8152600401602060405180830381865afa158015610701573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107259190614f93565b6017549091506000906107579074010000000000000000000000000000000000000000900463ffffffff166001614fac565b9050604051806101600160405280896060015173ffffffffffffffffffffffffffffffffffffffff168152602001896000015163ffffffff168152602001896020015163ffffffff1681526020016016600001601c9054906101000a900463ffffffff1663ffffffff16815260200189610100015173ffffffffffffffffffffffffffffffffffffffff1681526020018263ffffffff1681526020018363ffffffff168152602001896040015163ffffffff16815260200189610140015173ffffffffffffffffffffffffffffffffffffffff1681526020018960c0015163ffffffff1681526020018960e0015163ffffffff16815250601660008201518160000160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060208201518160000160146101000a81548163ffffffff021916908363ffffffff16021790555060408201518160000160186101000a81548163ffffffff021916908363ffffffff160217905550606082015181600001601c6101000a81548163ffffffff021916908363ffffffff16021790555060808201518160010160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060a08201518160010160146101000a81548163ffffffff021916908363ffffffff16021790555060c08201518160010160186101000a81548163ffffffff021916908363ffffffff16021790555060e082015181600101601c6101000a81548163ffffffff021916908363ffffffff1602179055506101008201518160020160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506101208201518160020160146101000a81548163ffffffff021916908363ffffffff1602179055506101408201518160020160186101000a81548163ffffffff021916908363ffffffff160217905550905050876101600151601981905550876101800151601a81905550876101a00151601b81905550600088604051602001610a9a919061501a565b604080518083037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0018152919052601754909150610aff904690309074010000000000000000000000000000000000000000900463ffffffff168f8f8f878f8f611e19565b6013556000610b0e6009611ec3565b90505b8015610b4b57610b38610b30610b286001846151a0565b600990611ed3565b600990611ee6565b5080610b43816151b3565b915050610b11565b5060005b896101c0015151811015610ba257610b8f8a6101c001518281518110610b7757610b776151e8565b60200260200101516009611f0890919063ffffffff16565b5080610b9a81615217565b915050610b4f565b507f1591690b8638f5fb2dbec82ac741805ac5da8b45dc5263f4875b0496fdce4e0584601354601660010160149054906101000a900463ffffffff168f8f8f878f8f604051610bf99998979695949392919061524f565b60405180910390a1505050505050505050505050565b60015473ffffffffffffffffffffffffffffffffffffffff163314610c95576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e65720000000000000000000060448201526064015b60405180910390fd5b60008054337fffffffffffffffffffffffff00000000000000000000000000000000000000008083168217845560018054909116905560405173ffffffffffffffffffffffffffffffffffffffff90921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b60005a90506000610d238660406152e5565b610d2f896101446152fc565b610d3991906152fc565b9050368114610d74576040517fdfe9309000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60408051610120810182526014546bffffffffffffffffffffffff8116825263ffffffff6c01000000000000000000000000820416602083015262ffffff7001000000000000000000000000000000008204169282019290925261ffff730100000000000000000000000000000000000000830416606082015260ff75010000000000000000000000000000000000000000008304811660808301527601000000000000000000000000000000000000000000008304811615801560a08401527701000000000000000000000000000000000000000000000084048216151560c0840152780100000000000000000000000000000000000000000000000090930416151560e082015260155473ffffffffffffffffffffffffffffffffffffffff1661010082015290610ed3576040517f24522f3400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b336000908152600b602052604090205460ff16610f1c576040517f1099ed7500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6013548b3514610f58576040517fdfdcf8e700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6080810151610f6890600161530f565b60ff1687141580610f795750868514155b15610fb0576040517f0244f71a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610fc08b8b8b8b8b8b8b8b611f2a565b6000610fcc8b8b612193565b905060208c0135600881901c63ffffffff16610fe984848861224c565b836020015163ffffffff168163ffffffff16111561104157601480547fffffffffffffffffffffffffffffffff00000000ffffffffffffffffffffffff166c0100000000000000000000000063ffffffff8416021790555b5050505050505050505050505050565b60008060008580602001905181019061106a9190615495565b925092509250611080898989868989888861032b565b505050505050505050565b61109361109f565b61109c81612e5c565b50565b60005473ffffffffffffffffffffffffffffffffffffffff163314611120576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e6572000000000000000000006044820152606401610c8c565b565b60005b6024548110156111e0576022600060248381548110611146576111466151e8565b600091825260208083209091015473ffffffffffffffffffffffffffffffffffffffff168352820192909252604001812080547fffffffff00000000000000000000000000000000000000000000000000000000168155600181019190915560020180547fffffffffffffffffffffffffffffffffffffffff000000000000000000000000169055806111d881615217565b915050611125565b506111ed602460006145f2565b60255460ff1660005b8351811015611754576000848281518110611213576112136151e8565b602002602001015190506000848381518110611231576112316151e8565b602002602001015190508173ffffffffffffffffffffffffffffffffffffffff1663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015611286573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112aa9190615640565b60ff16816060015160ff161415806113385750806040015173ffffffffffffffffffffffffffffffffffffffff1663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa15801561130c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113309190615640565b60ff16600814155b1561136f576040517fc1ab6dc100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff161480156113db575060018460018111156113d9576113d961565d565b145b15611412576040517fc1ab6dc100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff8216158061144d5750604081015173ffffffffffffffffffffffffffffffffffffffff16155b15611484576040517f8579befe00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff828116600090815260226020526040902054670100000000000000900416156114ee576040517f357d0cc400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6024805460018181019092557f7cd332d19b93bcabe3cce7ca0c18a052f57e5fd03b4758a09f30f5ddc4b22ec401805473ffffffffffffffffffffffffffffffffffffffff8086167fffffffffffffffffffffffff0000000000000000000000000000000000000000909216821790925560008181526022602090815260409182902086518154928801518489015160608a015160ff167b01000000000000000000000000000000000000000000000000000000027fffffffff00ffffffffffffffffffffffffffffffffffffffffffffffffffffff9190981667010000000000000002167fffffffff000000000000000000000000000000000000000000ffffffffffffff62ffffff909216640100000000027fffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000090951663ffffffff9093169290921793909317929092169190911793909317835560808501519383019390935560a0840151600290920180546bffffffffffffffffffffffff9093167fffffffffffffffffffffffffffffffffffffffff0000000000000000000000009093169290921790915590517fca93cbe727c73163ec538f71be6c0a64877d7f1f6dd35d5ca7cbaef3a3e34ba390611737908490600060c08201905063ffffffff835116825262ffffff602084015116602083015273ffffffffffffffffffffffffffffffffffffffff604084015116604083015260ff6060840151166060830152608083015160808301526bffffffffffffffffffffffff60a08401511660a083015292915050565b60405180910390a25050808061174c90615217565b9150506111f6565b50505050565b600e546014546bffffffffffffffffffffffff1660005b600e548110156117cd576117ba600e8281548110611791576117916151e8565b60009182526020909120015473ffffffffffffffffffffffffffffffffffffffff168385612f51565b50806117c581615217565b915050611771565b5060255460009060ff16815b600e5481101561193e57600e81815481106117f6576117f66151e8565b6000918252602082200154600d805473ffffffffffffffffffffffffffffffffffffffff9092169550600c929184908110611833576118336151e8565b600091825260208083209091015473ffffffffffffffffffffffffffffffffffffffff9081168452838201949094526040928301822080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00001690559286168152600b909252902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016905560018260018111156118d5576118d561565d565b14801561191a575073ffffffffffffffffffffffffffffffffffffffff83166000908152600b60205260409020546201000090046bffffffffffffffffffffffff1615155b1561192c5761192a600f84611f08565b505b8061193681615217565b9150506117d9565b5061194b600d60006145f2565b611957600e60006145f2565b6040805160808101825260008082526020820181905291810182905260608101829052905b8751811015611de757600c600089838151811061199b5761199b6151e8565b60209081029190910181015173ffffffffffffffffffffffffffffffffffffffff1682528101919091526040016000205460ff1615611a06576040517f77cea0fa00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff16888281518110611a3057611a306151e8565b602002602001015173ffffffffffffffffffffffffffffffffffffffff1603611a85576040517f815e1d6400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60405180604001604052806001151581526020018260ff16815250600c60008a8481518110611ab657611ab66151e8565b60209081029190910181015173ffffffffffffffffffffffffffffffffffffffff1682528181019290925260400160002082518154939092015160ff16610100027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff921515929092167fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000909316929092171790558651879082908110611b5e57611b5e6151e8565b60200260200101519350600073ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff1603611bce576040517f58a70a0a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff84166000908152600b60209081526040918290208251608081018452905460ff80821615801584526101008304909116938301939093526bffffffffffffffffffffffff6201000082048116948301949094526e01000000000000000000000000000090049092166060830152909250611c89576040517f6a7281ad00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600180835260ff80831660208086019182526014546bffffffffffffffffffffffff9081166060880190815273ffffffffffffffffffffffffffffffffffffffff8a166000908152600b909352604092839020885181549551948a0151925184166e010000000000000000000000000000027fffffffffffff000000000000000000000000ffffffffffffffffffffffffffff939094166201000002929092167fffffffffffff000000000000000000000000000000000000000000000000ffff94909616610100027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff921515929092167fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000090951694909417179190911692909217919091179055836001811115611dc357611dc361565d565b03611dd557611dd3600f85611ee6565b505b80611ddf81615217565b91505061197c565b508651611dfb90600d9060208a0190614610565b508551611e0f90600e906020890190614610565b5050505050505050565b6000808a8a8a8a8a8a8a8a8a604051602001611e3d9998979695949392919061568c565b604080518083037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe001815291905280516020909101207dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff167e01000000000000000000000000000000000000000000000000000000000000179b9a5050505050505050505050565b6000611ecd825490565b92915050565b6000611edf8383613159565b9392505050565b6000611edf8373ffffffffffffffffffffffffffffffffffffffff8416613183565b6000611edf8373ffffffffffffffffffffffffffffffffffffffff841661327d565b60008787604051611f3c929190615721565b604051908190038120611f53918b90602001615731565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081840301815282825280516020918201208383019092526000808452908301819052909250906000805b8881101561212a57600185878360208110611fbf57611fbf6151e8565b611fcc91901a601b61530f565b8c8c85818110611fde57611fde6151e8565b905060200201358b8b86818110611ff757611ff76151e8565b9050602002013560405160008152602001604052604051612034949392919093845260ff9290921660208401526040830152606082015260800190565b6020604051602081039080840390855afa158015612056573d6000803e3d6000fd5b5050604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081015173ffffffffffffffffffffffffffffffffffffffff81166000908152600c602090815290849020838501909452925460ff8082161515808552610100909204169383019390935290955093509050612104576040517f0f4c073700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b826020015160080260ff166001901b84019350808061212290615217565b915050611fa2565b50827e01010101010101010101010101010101010101010101010101010101010101841614612185576040517fc103be2e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b505050505050505050505050565b6121cc6040518060c001604052806000815260200160008152602001606081526020016060815260200160608152602001606081525090565b60006121da83850185615822565b60408101515160608201515191925090811415806121fd57508082608001515114155b8061220d5750808260a001515114155b15612244576040517fb55ac75400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b509392505050565b600082604001515167ffffffffffffffff81111561226c5761226c6146a7565b60405190808252806020026020018201604052801561233857816020015b6040805161020081018252600060e08201818152610100830182905261012083018290526101408301829052610160830182905261018083018290526101a083018290526101c083018290526101e0830182905282526020808301829052928201819052606082018190526080820181905260a0820181905260c082015282527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff90920191018161228a5790505b50905060006040518060800160405280600061ffff16815260200160006bffffffffffffffffffffffff16815260200160006bffffffffffffffffffffffff16815260200160008152509050600085610100015173ffffffffffffffffffffffffffffffffffffffff166357e871e76040518163ffffffff1660e01b8152600401602060405180830381865afa1580156123d6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123fa9190614f93565b6101008701516040517f7810d12a00000000000000000000000000000000000000000000000000000000815236600482015291925060009173ffffffffffffffffffffffffffffffffffffffff90911690637810d12a90602401602060405180830381865afa158015612471573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906124959190614f93565b905060005b8660400151518110156129255760046000886040015183815181106124c1576124c16151e8565b6020908102919091018101518252818101929092526040908101600020815161012081018352815460ff8082161515835261010080830490911615159583019590955263ffffffff620100008204811694830194909452660100000000000081048416606083015273ffffffffffffffffffffffffffffffffffffffff6a01000000000000000000009091048116608083015260018301546fffffffffffffffffffffffffffffffff811660a08401526bffffffffffffffffffffffff70010000000000000000000000000000000082041660c08401527c0100000000000000000000000000000000000000000000000000000000900490931660e08201526002909101549091169181019190915285518690839081106125e4576125e46151e8565b6020026020010151600001819052506126198760400151828151811061260c5761260c6151e8565b60200260200101516132cc565b85828151811061262b5761262b6151e8565b60200260200101516060019060018111156126485761264861565d565b9081600181111561265b5761265b61565d565b815250506126bf87604001518281518110612678576126786151e8565b60200260200101518489608001518481518110612697576126976151e8565b60200260200101518885815181106126b1576126b16151e8565b60200260200101518c613377565b8683815181106126d1576126d16151e8565b60200260200101516020018784815181106126ee576126ee6151e8565b602002602001015160c0018281525082151515158152505050848181518110612719576127196151e8565b602002602001015160200151156127495760018460000181815161273d919061590f565b61ffff1690525061274e565b612913565b6127b4858281518110612763576127636151e8565b6020026020010151600001516080015188606001518381518110612789576127896151e8565b60200260200101518960a0015184815181106127a7576127a76151e8565b6020026020010151613496565b8683815181106127c6576127c66151e8565b60200260200101516040018784815181106127e3576127e36151e8565b602002602001015160800182815250821515151581525050508760800151600161280d919061530f565b61281b9060ff1660406152e5565b6103a48860a001518381518110612834576128346151e8565b60200260200101515161284791906152fc565b61285191906152fc565b858281518110612863576128636151e8565b602002602001015160a0018181525050848181518110612885576128856151e8565b602002602001015160a00151846060018181516128a291906152fc565b90525084518590829081106128b9576128b96151e8565b602002602001015160800151866128d091906151a0565b9550612913876040015182815181106128eb576128eb6151e8565b602002602001015184878481518110612906576129066151e8565b60200260200101516136b1565b8061291d81615217565b91505061249a565b50825161ffff1660000361293c5750505050505050565b61c80061294a3660106152e5565b5a61295590886151a0565b61295f91906152fc565b61296991906152fc565b8351909550613778906129809061ffff1687615959565b61298a91906152fc565b60408051608081018252600080825260208201819052918101829052606081018290529196506129b9896137b6565b905060005b886040015151811015612cf5578681815181106129dd576129dd6151e8565b60200260200101516020015115612ce357801580612a75575086612a026001836151a0565b81518110612a1257612a126151e8565b602002602001015160000151610100015173ffffffffffffffffffffffffffffffffffffffff16878281518110612a4b57612a4b6151e8565b602002602001015160000151610100015173ffffffffffffffffffffffffffffffffffffffff1614155b15612aa957612aa68a888381518110612a9057612a906151e8565b60200260200101516000015161010001516138a0565b92505b6000612bc78b6040518061012001604052808b8681518110612acd57612acd6151e8565b60200260200101516080015181526020018c81526020018a606001518c8781518110612afb57612afb6151e8565b602002602001015160a001518a612b1291906152e5565b612b1c9190615959565b81526020018d6000015181526020018d6020015181526020018681526020018b8681518110612b4d57612b4d6151e8565b602002602001015160000151610100015173ffffffffffffffffffffffffffffffffffffffff168152602001878152602001600115158152508c604001518581518110612b9c57612b9c6151e8565b60200260200101518b8681518110612bb657612bb66151e8565b602002602001015160000151613a1c565b9050806060015187604001818151612bdf919061596d565b6bffffffffffffffffffffffff169052506040810151602088018051612c0690839061596d565b6bffffffffffffffffffffffff169052508751889083908110612c2b57612c2b6151e8565b60200260200101516040015115158a604001518381518110612c4f57612c4f6151e8565b60200260200101517fad8cc9579b21dfe2c2f6ea35ba15b656e46b4f5b0cb424f52739b8ce5cac9c5b83602001518460000151612c8c919061596d565b8b8681518110612c9e57612c9e6151e8565b6020026020010151608001518d8f608001518881518110612cc157612cc16151e8565b6020026020010151604051612cd99493929190615992565b60405180910390a3505b80612ced81615217565b9150506129be565b505050602083810151336000908152600b90925260409091208054600290612d329084906201000090046bffffffffffffffffffffffff1661596d565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff1602179055508260400151601460000160008282829054906101000a90046bffffffffffffffffffffffff16612d90919061596d565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff16021790555082604001518360200151612dd2919061596d565b6bffffffffffffffffffffffff16602160007f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000828254612e4e91906152fc565b909155505050505050505050565b3373ffffffffffffffffffffffffffffffffffffffff821603612edb576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c660000000000000000006044820152606401610c8c565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b73ffffffffffffffffffffffffffffffffffffffff83166000908152600b602090815260408083208151608081018352905460ff80821615801584526101008304909116948301949094526bffffffffffffffffffffffff6201000082048116938301939093526e010000000000000000000000000000900490911660608201529061314d576000816060015185612fe991906159cf565b90506000612ff785836159f4565b9050808360400181815161300b919061596d565b6bffffffffffffffffffffffff169052506130268582615a1f565b83606001818151613037919061596d565b6bffffffffffffffffffffffff90811690915273ffffffffffffffffffffffffffffffffffffffff89166000908152600b602090815260409182902087518154928901519389015160608a015186166e010000000000000000000000000000027fffffffffffff000000000000000000000000ffffffffffffffffffffffffffff919096166201000002167fffffffffffff000000000000000000000000000000000000000000000000ffff60ff95909516610100027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff921515929092167fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000909416939093171792909216179190911790555050505b60400151949350505050565b6000826000018281548110613170576131706151e8565b9060005260206000200154905092915050565b6000818152600183016020526040812054801561326c5760006131a76001836151a0565b85549091506000906131bb906001906151a0565b90508181146132205760008660000182815481106131db576131db6151e8565b90600052602060002001549050808760000184815481106131fe576131fe6151e8565b6000918252602080832090910192909255918252600188019052604090208390555b855486908061323157613231615a4f565b600190038181906000526020600020016000905590558560010160008681526020019081526020016000206000905560019350505050611ecd565b6000915050611ecd565b5092915050565b60008181526001830160205260408120546132c457508154600181810184556000848152602080822090930184905584548482528286019093526040902091909155611ecd565b506000611ecd565b6000818160045b600f811015613359577fff000000000000000000000000000000000000000000000000000000000000008216838260208110613311576133116151e8565b1a60f81b7effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff19161461334757506000949350505050565b8061335181615217565b9150506132d3565b5081600f1a600181111561336f5761336f61565d565b949350505050565b6000808080856060015160018111156133925761339261565d565b036133b8576133a48888888888613e8b565b6133b35760009250905061348c565b613430565b6001856060015160018111156133d0576133d061565d565b036133fe5760006133e389898988614015565b92509050806133f8575060009250905061348c565b50613430565b6040517ff2b2d41200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b84516060015163ffffffff16871061348557877fc3237c8807c467c1b39b8d0395eff077313e691bf0a7388106792564ebfd5636876040516134729190614d1a565b60405180910390a260009250905061348c565b6001925090505b9550959350505050565b601454600090819077010000000000000000000000000000000000000000000000900460ff16156134f3576040517f37ed32e800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b601480547fffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffffffff16770100000000000000000000000000000000000000000000001790556040517f4585e33b0000000000000000000000000000000000000000000000000000000090613568908590602401614d1a565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff000000000000000000000000000000000000000000000000000000009094169390931790925290517f79188d1600000000000000000000000000000000000000000000000000000000815290935073ffffffffffffffffffffffffffffffffffffffff8616906379188d169061363b9087908790600401615a7e565b60408051808303816000875af1158015613659573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061367d9190615a97565b601480547fffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffffffff16905590969095509350505050565b6000816060015160018111156136c9576136c961565d565b0361372d57600083815260046020526040902060010180547bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167c010000000000000000000000000000000000000000000000000000000063ffffffff851602179055505050565b6001816060015160018111156137455761374561565d565b036137b15760c08101805160009081526008602052604080822080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055915191517fa4a4e334c0e330143f9437484fe516c13bc560b86b5b0daf58e7084aaac228f29190a25b505050565b60008060007f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663feaf968c6040518163ffffffff1660e01b815260040160a060405180830381865afa158015613826573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061384a9190615adf565b5093505092505060008213158061386057508042105b8061389057506000846040015162ffffff16118015613890575061388481426151a0565b846040015162ffffff16105b15613276575050601b5492915050565b60408051608081018252600080825260208083018281528385018381526060850184905273ffffffffffffffffffffffffffffffffffffffff878116855260229093528584208054640100000000810462ffffff1690925263ffffffff82169092527b01000000000000000000000000000000000000000000000000000000810460ff16855285517ffeaf968c00000000000000000000000000000000000000000000000000000000815295519495919484936701000000000000009092049091169163feaf968c9160048083019260a09291908290030181865afa15801561398d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906139b19190615adf565b509350509250506000821315806139c757508042105b806139f757506000866040015162ffffff161180156139f757506139eb81426151a0565b866040015162ffffff16105b15613a0b5760018301546060850152613a13565b606084018290525b50505092915050565b604080516101008101825260008082526020808301829052928201819052606082018190526080820181905260a0820181905260c0820181905260e08201529082015115613ab25760008381526023602090815260409182902082518084018452905463ffffffff811680835262ffffff640100000000909204821692840192835260e089018051909401529051915191169101525b6000613abe8686614222565b60c0840151602082015182519293509091600091613adb9161596d565b60e08801515190915060ff16600060128210613af8576001613b0e565b613b038260126151a0565b613b0e90600a615c4f565b9050600060128311613b21576001613b37565b613b2c6012846151a0565b613b3790600a615c4f565b905085600001516bffffffffffffffffffffffff16856bffffffffffffffffffffffff161015613bdf57849350613bb3818b60800151613b7791906152e5565b838c60e0015160600151886bffffffffffffffffffffffff16613b9a91906152e5565b613ba491906152e5565b613bae9190615959565b614550565b6bffffffffffffffffffffffff9081166040880152600060608801819052602088015285168652613d05565b836bffffffffffffffffffffffff16856bffffffffffffffffffffffff161015613d0557849350613c6d86604001516bffffffffffffffffffffffff16828c60800151613c2c91906152e5565b848d60e0015160600151896bffffffffffffffffffffffff16613c4f91906152e5565b613c5991906152e5565b613c639190615959565b613bae91906151a0565b6bffffffffffffffffffffffff1660608088019190915260e08b01510151613cf190613c9a9084906152e5565b6001848d60e0015160600151613cb091906152e5565b613cba91906151a0565b838d608001518a606001516bffffffffffffffffffffffff16613cdd91906152e5565b613ce791906152e5565b613ba491906152fc565b6bffffffffffffffffffffffff1660208701525b60008981526004602052604090206001018054859190601090613d4b90849070010000000000000000000000000000000090046bffffffffffffffffffffffff166159cf565b82546101009290920a6bffffffffffffffffffffffff81810219909316918316021790915560008b81526004602052604081206001018054928816935091613da69084906fffffffffffffffffffffffffffffffff16615c5b565b92506101000a8154816fffffffffffffffffffffffffffffffff02191690836fffffffffffffffffffffffffffffffff160217905550836bffffffffffffffffffffffff16602160008c60c0015173ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000828254613e3d91906151a0565b92505081905550887f801ba6ed51146ffe3e99d1dbd9dd0f4de6292e78a9a34c39c0183de17b3f40fc87604051613e749190615c84565b60405180910390a250939998505050505050505050565b60008084806020019051810190613ea29190615d44565b845160e00151815191925063ffffffff90811691161015613eff57867f405288ea7be309e16cfdf481367f90a413e1d4634fcdaf8966546db9b93012e886604051613eed9190614d1a565b60405180910390a2600091505061400c565b8260e001518015613fbf5750602081015115801590613fbf5750602081015161010084015182516040517f85df51fd00000000000000000000000000000000000000000000000000000000815263ffffffff909116600482015273ffffffffffffffffffffffffffffffffffffffff909116906385df51fd90602401602060405180830381865afa158015613f98573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613fbc9190614f93565b14155b80613fd15750805163ffffffff168611155b1561400657867f6aa7f60c176da7af894b384daea2249497448137f5943c1237ada8bc92bdc30186604051613eed9190614d1a565b60019150505b95945050505050565b60008060008480602001905181019061402e9190615d9c565b905060008782600001518360200151846040015160405160200161409094939291909384526020840192909252604083015260e01b7fffffffff0000000000000000000000000000000000000000000000000000000016606082015260640190565b6040516020818303038152906040528051906020012090508460e00151801561416b575060808201511580159061416b5750608082015161010086015160608401516040517f85df51fd00000000000000000000000000000000000000000000000000000000815263ffffffff909116600482015273ffffffffffffffffffffffffffffffffffffffff909116906385df51fd90602401602060405180830381865afa158015614144573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906141689190614f93565b14155b80614180575086826060015163ffffffff1610155b156141ca57877f6aa7f60c176da7af894b384daea2249497448137f5943c1237ada8bc92bdc301876040516141b59190614d1a565b60405180910390a26000935091506142199050565b60008181526008602052604090205460ff161561421157877f405288ea7be309e16cfdf481367f90a413e1d4634fcdaf8966546db9b93012e8876040516141b59190614d1a565b600193509150505b94509492505050565b6040805161010081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e081019190915260008260e001516000015160ff1690506000846060015161ffff16846060015161428d91906152e5565b905083610100015180156142a05750803a105b156142a857503a5b6000601283116142b95760016142cf565b6142c46012846151a0565b6142cf90600a615c4f565b90506000601284106142e25760016142f8565b6142ed8460126151a0565b6142f890600a615c4f565b905060008660a0015187604001518860200151896000015161431a91906152fc565b61432490876152e5565b61432e91906152fc565b61433891906152e5565b905061437b828860e001516060015161435191906152e5565b6001848a60e001516060015161436791906152e5565b61437191906151a0565b613ce786856152e5565b6bffffffffffffffffffffffff168652608087015161439e90613bae9083615959565b6bffffffffffffffffffffffff1660408088019190915260e088015101516000906143d79062ffffff16683635c9adc5dea000006152e5565b9050600081633b9aca008a60a001518b60e001516020015163ffffffff168c604001518d600001518b61440a91906152e5565b61441491906152fc565b61441e91906152e5565b61442891906152e5565b6144329190615959565b61443c91906152fc565b905061447f848a60e001516060015161445591906152e5565b6001868c60e001516060015161446b91906152e5565b61447591906151a0565b613ce788856152e5565b6bffffffffffffffffffffffff16602089015260808901516144a590613bae9083615959565b6bffffffffffffffffffffffff16606089015260c089015173ffffffffffffffffffffffffffffffffffffffff166080808a01919091528901516144e890614550565b6bffffffffffffffffffffffff1660a0808a019190915289015161450b90614550565b6bffffffffffffffffffffffff1660c089015260e08901516060015161453090614550565b6bffffffffffffffffffffffff1660e08901525050505050505092915050565b60006bffffffffffffffffffffffff8211156145ee576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f53616665436173743a2076616c756520646f65736e27742066697420696e203960448201527f36206269747300000000000000000000000000000000000000000000000000006064820152608401610c8c565b5090565b508054600082559060005260206000209081019061109c9190614692565b82805482825590600052602060002090810192821561468a579160200282015b8281111561468a57825182547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff909116178255602090920191600190910190614630565b506145ee9291505b5b808211156145ee5760008155600101614693565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051610200810167ffffffffffffffff811182821017156146fa576146fa6146a7565b60405290565b60405160c0810167ffffffffffffffff811182821017156146fa576146fa6146a7565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff8111828210171561476a5761476a6146a7565b604052919050565b600067ffffffffffffffff82111561478c5761478c6146a7565b5060051b60200190565b73ffffffffffffffffffffffffffffffffffffffff8116811461109c57600080fd5b80356147c381614796565b919050565b600082601f8301126147d957600080fd5b813560206147ee6147e983614772565b614723565b82815260059290921b8401810191818101908684111561480d57600080fd5b8286015b8481101561483157803561482481614796565b8352918301918301614811565b509695505050505050565b60ff8116811461109c57600080fd5b80356147c38161483c565b63ffffffff8116811461109c57600080fd5b80356147c381614856565b801515811461109c57600080fd5b80356147c381614873565b62ffffff8116811461109c57600080fd5b80356147c38161488c565b61ffff8116811461109c57600080fd5b80356147c3816148a8565b600061020082840312156148d657600080fd5b6148de6146d6565b90506148e982614868565b81526148f760208301614868565b602082015261490860408301614868565b6040820152614919606083016147b8565b606082015261492a60808301614881565b608082015261493b60a0830161489d565b60a082015261494c60c08301614868565b60c082015261495d60e08301614868565b60e08201526101006149708184016147b8565b908201526101206149828382016148b8565b908201526101406149948382016147b8565b90820152610160828101359082015261018080830135908201526101a080830135908201526101c08083013567ffffffffffffffff8111156149d557600080fd5b6149e1858286016147c8565b8284015250506101e06149f58184016147b8565b9082015292915050565b803567ffffffffffffffff811681146147c357600080fd5b600082601f830112614a2857600080fd5b813567ffffffffffffffff811115614a4257614a426146a7565b614a7360207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f84011601614723565b818152846020838601011115614a8857600080fd5b816020850160208301376000918101602001919091529392505050565b6bffffffffffffffffffffffff8116811461109c57600080fd5b600082601f830112614ad057600080fd5b81356020614ae06147e983614772565b82815260c09283028501820192828201919087851115614aff57600080fd5b8387015b85811015614b915781818a031215614b1b5760008081fd5b614b23614700565b8135614b2e81614856565b815281860135614b3d8161488c565b81870152604082810135614b5081614796565b90820152606082810135614b638161483c565b908201526080828101359082015260a080830135614b8081614aa5565b908201528452928401928101614b03565b5090979650505050505050565b600080600080600080600080610100898b031215614bbb57600080fd5b883567ffffffffffffffff80821115614bd357600080fd5b614bdf8c838d016147c8565b995060208b0135915080821115614bf557600080fd5b614c018c838d016147c8565b9850614c0f60408c0161484b565b975060608b0135915080821115614c2557600080fd5b614c318c838d016148c3565b9650614c3f60808c016149ff565b955060a08b0135915080821115614c5557600080fd5b614c618c838d01614a17565b945060c08b0135915080821115614c7757600080fd5b614c838c838d016147c8565b935060e08b0135915080821115614c9957600080fd5b50614ca68b828c01614abf565b9150509295985092959890939650565b6000815180845260005b81811015614cdc57602081850181015186830182015201614cc0565b5060006020828601015260207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f83011685010191505092915050565b602081526000611edf6020830184614cb6565b60008083601f840112614d3f57600080fd5b50813567ffffffffffffffff811115614d5757600080fd5b6020830191508360208260051b8501011115614d7257600080fd5b9250929050565b60008060008060008060008060e0898b031215614d9557600080fd5b606089018a811115614da657600080fd5b8998503567ffffffffffffffff80821115614dc057600080fd5b818b0191508b601f830112614dd457600080fd5b813581811115614de357600080fd5b8c6020828501011115614df557600080fd5b6020830199508098505060808b0135915080821115614e1357600080fd5b614e1f8c838d01614d2d565b909750955060a08b0135915080821115614e3857600080fd5b50614e458b828c01614d2d565b999c989b50969995989497949560c00135949350505050565b60008060008060008060c08789031215614e7757600080fd5b863567ffffffffffffffff80821115614e8f57600080fd5b614e9b8a838b016147c8565b97506020890135915080821115614eb157600080fd5b614ebd8a838b016147c8565b9650614ecb60408a0161484b565b95506060890135915080821115614ee157600080fd5b614eed8a838b01614a17565b9450614efb60808a016149ff565b935060a0890135915080821115614f1157600080fd5b50614f1e89828a01614a17565b9150509295509295509295565b600060208284031215614f3d57600080fd5b8135611edf81614796565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60ff818116838216029081169081811461327657613276614f48565b600060208284031215614fa557600080fd5b5051919050565b63ffffffff81811683821601908082111561327657613276614f48565b600081518084526020808501945080840160005b8381101561500f57815173ffffffffffffffffffffffffffffffffffffffff1687529582019590820190600101614fdd565b509495945050505050565b6020815261503160208201835163ffffffff169052565b6000602083015161504a604084018263ffffffff169052565b50604083015163ffffffff8116606084015250606083015173ffffffffffffffffffffffffffffffffffffffff8116608084015250608083015180151560a08401525060a083015162ffffff811660c08401525060c083015163ffffffff811660e08401525060e08301516101006150c98185018363ffffffff169052565b84015190506101206150f28482018373ffffffffffffffffffffffffffffffffffffffff169052565b84015190506101406151098482018361ffff169052565b84015190506101606151328482018373ffffffffffffffffffffffffffffffffffffffff169052565b840151610180848101919091528401516101a0808501919091528401516101c0808501919091528401516102006101e08086018290529192509061517a610220860184614fc9565b95015173ffffffffffffffffffffffffffffffffffffffff169301929092525090919050565b81810381811115611ecd57611ecd614f48565b6000816151c2576151c2614f48565b507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0190565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff820361524857615248614f48565b5060010190565b600061012063ffffffff808d1684528b6020850152808b1660408501525080606084015261527f8184018a614fc9565b905082810360808401526152938189614fc9565b905060ff871660a084015282810360c08401526152b08187614cb6565b905067ffffffffffffffff851660e08401528281036101008401526152d58185614cb6565b9c9b505050505050505050505050565b8082028115828204841417611ecd57611ecd614f48565b80820180821115611ecd57611ecd614f48565b60ff8181168382160190811115611ecd57611ecd614f48565b80516147c381614856565b80516147c381614796565b80516147c381614873565b80516147c38161488c565b80516147c3816148a8565b600082601f83011261537057600080fd5b815160206153806147e983614772565b82815260059290921b8401810191818101908684111561539f57600080fd5b8286015b848110156148315780516153b681614796565b83529183019183016153a3565b600082601f8301126153d457600080fd5b815160206153e46147e983614772565b82815260c0928302850182019282820191908785111561540357600080fd5b8387015b85811015614b915781818a03121561541f5760008081fd5b615427614700565b815161543281614856565b8152818601516154418161488c565b8187015260408281015161545481614796565b908201526060828101516154678161483c565b908201526080828101519082015260a08083015161548481614aa5565b908201528452928401928101615407565b6000806000606084860312156154aa57600080fd5b835167ffffffffffffffff808211156154c257600080fd5b9085019061020082880312156154d757600080fd5b6154df6146d6565b6154e883615328565b81526154f660208401615328565b602082015261550760408401615328565b604082015261551860608401615333565b60608201526155296080840161533e565b608082015261553a60a08401615349565b60a082015261554b60c08401615328565b60c082015261555c60e08401615328565b60e082015261010061556f818501615333565b90820152610120615581848201615354565b90820152610140615593848201615333565b90820152610160838101519082015261018080840151908201526101a080840151908201526101c080840151838111156155cc57600080fd5b6155d88a82870161535f565b8284015250506101e06155ec818501615333565b90820152602087015190955091508082111561560757600080fd5b6156138783880161535f565b9350604086015191508082111561562957600080fd5b50615636868287016153c3565b9150509250925092565b60006020828403121561565257600080fd5b8151611edf8161483c565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b60006101208b835273ffffffffffffffffffffffffffffffffffffffff8b16602084015267ffffffffffffffff808b1660408501528160608501526156d38285018b614fc9565b915083820360808501526156e7828a614fc9565b915060ff881660a085015283820360c08501526157048288614cb6565b90861660e085015283810361010085015290506152d58185614cb6565b8183823760009101908152919050565b8281526080810160608360208401379392505050565b600082601f83011261575857600080fd5b813560206157686147e983614772565b82815260059290921b8401810191818101908684111561578757600080fd5b8286015b84811015614831578035835291830191830161578b565b600082601f8301126157b357600080fd5b813560206157c36147e983614772565b82815260059290921b840181019181810190868411156157e257600080fd5b8286015b8481101561483157803567ffffffffffffffff8111156158065760008081fd5b6158148986838b0101614a17565b8452509183019183016157e6565b60006020828403121561583457600080fd5b813567ffffffffffffffff8082111561584c57600080fd5b9083019060c0828603121561586057600080fd5b615868614700565b823581526020830135602082015260408301358281111561588857600080fd5b61589487828601615747565b6040830152506060830135828111156158ac57600080fd5b6158b887828601615747565b6060830152506080830135828111156158d057600080fd5b6158dc878286016157a2565b60808301525060a0830135828111156158f457600080fd5b615900878286016157a2565b60a08301525095945050505050565b61ffff81811683821601908082111561327657613276614f48565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b6000826159685761596861592a565b500490565b6bffffffffffffffffffffffff81811683821601908082111561327657613276614f48565b6bffffffffffffffffffffffff851681528360208201528260408201526080606082015260006159c56080830184614cb6565b9695505050505050565b6bffffffffffffffffffffffff82811682821603908082111561327657613276614f48565b60006bffffffffffffffffffffffff80841680615a1357615a1361592a565b92169190910492915050565b6bffffffffffffffffffffffff818116838216028082169190828114615a4757615a47614f48565b505092915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fd5b82815260406020820152600061336f6040830184614cb6565b60008060408385031215615aaa57600080fd5b8251615ab581614873565b6020939093015192949293505050565b805169ffffffffffffffffffff811681146147c357600080fd5b600080600080600060a08688031215615af757600080fd5b615b0086615ac5565b9450602086015193506040860151925060608601519150615b2360808701615ac5565b90509295509295909350565b600181815b80851115615b8857817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff04821115615b6e57615b6e614f48565b80851615615b7b57918102915b93841c9390800290615b34565b509250929050565b600082615b9f57506001611ecd565b81615bac57506000611ecd565b8160018114615bc25760028114615bcc57615be8565b6001915050611ecd565b60ff841115615bdd57615bdd614f48565b50506001821b611ecd565b5060208310610133831016604e8410600b8410161715615c0b575081810a611ecd565b615c158383615b2f565b807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff04821115615c4757615c47614f48565b029392505050565b6000611edf8383615b90565b6fffffffffffffffffffffffffffffffff81811683821601908082111561327657613276614f48565b6000610100820190506bffffffffffffffffffffffff8084511683528060208501511660208401528060408501511660408401528060608501511660608401525073ffffffffffffffffffffffffffffffffffffffff608084015116608083015260a0830151615d0460a08401826bffffffffffffffffffffffff169052565b5060c0830151615d2460c08401826bffffffffffffffffffffffff169052565b5060e083015161327660e08401826bffffffffffffffffffffffff169052565b600060408284031215615d5657600080fd5b6040516040810181811067ffffffffffffffff82111715615d7957615d796146a7565b6040528251615d8781614856565b81526020928301519281019290925250919050565b600060a08284031215615dae57600080fd5b60405160a0810181811067ffffffffffffffff82111715615dd157615dd16146a7565b806040525082518152602083015160208201526040830151615df281614856565b60408201526060830151615e0581614856565b6060820152608092830151928101929092525091905056fea164736f6c6343000813000a", + Bin: "0x6101806040523480156200001257600080fd5b50604051620064b5380380620064b583398101604081905262000035916200062f565b80816001600160a01b031663ca30e6036040518163ffffffff1660e01b8152600401602060405180830381865afa15801562000075573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200009b91906200062f565b826001600160a01b031663226cf83c6040518163ffffffff1660e01b8152600401602060405180830381865afa158015620000da573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200010091906200062f565b836001600160a01b031663614486af6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156200013f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200016591906200062f565b846001600160a01b0316636709d0e56040518163ffffffff1660e01b8152600401602060405180830381865afa158015620001a4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620001ca91906200062f565b856001600160a01b0316635425d8ac6040518163ffffffff1660e01b8152600401602060405180830381865afa15801562000209573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200022f91906200062f565b866001600160a01b031663a08714c06040518163ffffffff1660e01b8152600401602060405180830381865afa1580156200026e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200029491906200062f565b876001600160a01b031663c5b964e06040518163ffffffff1660e01b8152600401602060405180830381865afa158015620002d3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620002f9919062000656565b886001600160a01b031663ac4dc59a6040518163ffffffff1660e01b8152600401602060405180830381865afa15801562000338573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200035e91906200062f565b3380600081620003b55760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b0384811691909117909155811615620003e857620003e8816200056b565b5050506001600160a01b0380891660805287811660a05286811660c05285811660e052848116610100528316610120526025805483919060ff19166001838181111562000439576200043962000679565b0217905550806001600160a01b0316610140816001600160a01b03168152505060c0516001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa1580156200049a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620004c091906200068f565b60ff1660a0516001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa15801562000504573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200052a91906200068f565b60ff16146200054c576040516301f86e1760e41b815260040160405180910390fd5b5050506001600160a01b039095166101605250620006b4945050505050565b336001600160a01b03821603620005c55760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c660000000000000000006044820152606401620003ac565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b6001600160a01b03811681146200062c57600080fd5b50565b6000602082840312156200064257600080fd5b81516200064f8162000616565b9392505050565b6000602082840312156200066957600080fd5b8151600281106200064f57600080fd5b634e487b7160e01b600052602160045260246000fd5b600060208284031215620006a257600080fd5b815160ff811681146200064f57600080fd5b60805160a05160c05160e05161010051610120516101405161016051615d9d620007186000396000818160b301526101860152600050506000505060005050600050506000613730015260005050600081816113710152612d590152615d9d6000f3fe6080604052600436106100b15760003560e01c80638da5cb5b11610069578063b1dc65a41161004e578063b1dc65a4146102cb578063e3d0e712146102eb578063f2fde38b1461030b576100b1565b80638da5cb5b1461025a578063afcb95d714610285576100b1565b8063349e8cca1161009a578063349e8cca1461017757806379ba5097146101cb57806381ff7048146101e0576100b1565b80630870d3a1146100f8578063181f5a7714610118575b7f00000000000000000000000000000000000000000000000000000000000000003660008037600080366000845af43d6000803e8080156100f1573d6000f35b3d6000fd5b005b34801561010457600080fd5b506100f6610113366004614b11565b61032b565b34801561012457600080fd5b506101616040518060400160405280601881526020017f4175746f6d6174696f6e526567697374727920322e332e30000000000000000081525081565b60405161016e9190614c8d565b60405180910390f35b34801561018357600080fd5b507f00000000000000000000000000000000000000000000000000000000000000005b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200161016e565b3480156101d757600080fd5b506100f6610c0f565b3480156101ec57600080fd5b5061023760175460135463ffffffff74010000000000000000000000000000000000000000830481169378010000000000000000000000000000000000000000000000009093041691565b6040805163ffffffff94851681529390921660208401529082015260600161016e565b34801561026657600080fd5b5060005473ffffffffffffffffffffffffffffffffffffffff166101a6565b34801561029157600080fd5b50601354601454604080516000815260208101939093526c0100000000000000000000000090910463ffffffff169082015260600161016e565b3480156102d757600080fd5b506100f66102e6366004614cec565b610d11565b3480156102f757600080fd5b506100f6610306366004614dd1565b611051565b34801561031757600080fd5b506100f6610326366004614e9e565b61108b565b61033361109f565b601f8851111561036f576040517f25d0209c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8560ff166000036103ac576040517fe77dba5600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b865188511415806103cb57506103c3866003614eea565b60ff16885111155b15610402576040517f1d2d1c5800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b805182511461043d576040517fcf54c06a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6104478282611122565b610451888861175a565b604051806101200160405280601460000160009054906101000a90046bffffffffffffffffffffffff166bffffffffffffffffffffffff168152602001600063ffffffff1681526020018660a0015162ffffff16815260200186610120015161ffff1681526020018760ff168152602001601460000160169054906101000a900460ff1615158152602001601460000160179054906101000a900460ff1615158152602001866080015115158152602001866101e0015173ffffffffffffffffffffffffffffffffffffffff16815250601460008201518160000160006101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff160217905550602082015181600001600c6101000a81548163ffffffff021916908363ffffffff16021790555060408201518160000160106101000a81548162ffffff021916908362ffffff16021790555060608201518160000160136101000a81548161ffff021916908361ffff16021790555060808201518160000160156101000a81548160ff021916908360ff16021790555060a08201518160000160166101000a81548160ff02191690831515021790555060c08201518160000160176101000a81548160ff02191690831515021790555060e08201518160000160186101000a81548160ff0219169083151502179055506101008201518160010160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055509050506000601660010160189054906101000a900463ffffffff1690506000866101e0015173ffffffffffffffffffffffffffffffffffffffff166357e871e76040518163ffffffff1660e01b8152600401602060405180830381865afa158015610701573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107259190614f06565b6017549091506000906107579074010000000000000000000000000000000000000000900463ffffffff166001614f1f565b9050604051806101600160405280896060015173ffffffffffffffffffffffffffffffffffffffff168152602001896000015163ffffffff168152602001896020015163ffffffff1681526020016016600001601c9054906101000a900463ffffffff1663ffffffff16815260200189610100015173ffffffffffffffffffffffffffffffffffffffff1681526020018263ffffffff1681526020018363ffffffff168152602001896040015163ffffffff16815260200189610140015173ffffffffffffffffffffffffffffffffffffffff1681526020018960c0015163ffffffff1681526020018960e0015163ffffffff16815250601660008201518160000160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060208201518160000160146101000a81548163ffffffff021916908363ffffffff16021790555060408201518160000160186101000a81548163ffffffff021916908363ffffffff160217905550606082015181600001601c6101000a81548163ffffffff021916908363ffffffff16021790555060808201518160010160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060a08201518160010160146101000a81548163ffffffff021916908363ffffffff16021790555060c08201518160010160186101000a81548163ffffffff021916908363ffffffff16021790555060e082015181600101601c6101000a81548163ffffffff021916908363ffffffff1602179055506101008201518160020160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506101208201518160020160146101000a81548163ffffffff021916908363ffffffff1602179055506101408201518160020160186101000a81548163ffffffff021916908363ffffffff160217905550905050876101600151601981905550876101800151601a81905550876101a00151601b81905550600088604051602001610a9a9190614f8d565b604080518083037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0018152919052601754909150610aff904690309074010000000000000000000000000000000000000000900463ffffffff168f8f8f878f8f611e19565b6013556000610b0e6009611ec3565b90505b8015610b4b57610b38610b30610b28600184615113565b600990611ed3565b600990611ee6565b5080610b4381615126565b915050610b11565b5060005b896101c0015151811015610ba257610b8f8a6101c001518281518110610b7757610b7761515b565b60200260200101516009611f0890919063ffffffff16565b5080610b9a8161518a565b915050610b4f565b507f1591690b8638f5fb2dbec82ac741805ac5da8b45dc5263f4875b0496fdce4e0584601354601660010160149054906101000a900463ffffffff168f8f8f878f8f604051610bf9999897969594939291906151c2565b60405180910390a1505050505050505050505050565b60015473ffffffffffffffffffffffffffffffffffffffff163314610c95576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e65720000000000000000000060448201526064015b60405180910390fd5b60008054337fffffffffffffffffffffffff00000000000000000000000000000000000000008083168217845560018054909116905560405173ffffffffffffffffffffffffffffffffffffffff90921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b60005a90506000610d23866040615258565b610d2f8961014461526f565b610d39919061526f565b9050368114610d74576040517fdfe9309000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60408051610120810182526014546bffffffffffffffffffffffff8116825263ffffffff6c01000000000000000000000000820416602083015262ffffff7001000000000000000000000000000000008204169282019290925261ffff730100000000000000000000000000000000000000830416606082015260ff75010000000000000000000000000000000000000000008304811660808301527601000000000000000000000000000000000000000000008304811615801560a08401527701000000000000000000000000000000000000000000000084048216151560c0840152780100000000000000000000000000000000000000000000000090930416151560e082015260155473ffffffffffffffffffffffffffffffffffffffff1661010082015290610ed3576040517f24522f3400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b336000908152600b602052604090205460ff16610f1c576040517f1099ed7500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6013548b3514610f58576040517fdfdcf8e700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6080810151610f68906001615282565b60ff1687141580610f795750868514155b15610fb0576040517f0244f71a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610fc08b8b8b8b8b8b8b8b611f2a565b6000610fcc8b8b612193565b905060208c0135600881901c63ffffffff16610fe984848861224c565b836020015163ffffffff168163ffffffff16111561104157601480547fffffffffffffffffffffffffffffffff00000000ffffffffffffffffffffffff166c0100000000000000000000000063ffffffff8416021790555b5050505050505050505050505050565b60008060008580602001905181019061106a9190615408565b925092509250611080898989868989888861032b565b505050505050505050565b61109361109f565b61109c81612dcf565b50565b60005473ffffffffffffffffffffffffffffffffffffffff163314611120576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e6572000000000000000000006044820152606401610c8c565b565b60005b6024548110156111e05760226000602483815481106111465761114661515b565b600091825260208083209091015473ffffffffffffffffffffffffffffffffffffffff168352820192909252604001812080547fffffffff00000000000000000000000000000000000000000000000000000000168155600181019190915560020180547fffffffffffffffffffffffffffffffffffffffff000000000000000000000000169055806111d88161518a565b915050611125565b506111ed60246000614565565b60255460ff1660005b83518110156117545760008482815181106112135761121361515b565b6020026020010151905060008483815181106112315761123161515b565b602002602001015190508173ffffffffffffffffffffffffffffffffffffffff1663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015611286573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112aa91906155b3565b60ff16816060015160ff161415806113385750806040015173ffffffffffffffffffffffffffffffffffffffff1663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa15801561130c573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061133091906155b3565b60ff16600814155b1561136f576040517fc1ab6dc100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff161480156113db575060018460018111156113d9576113d96155d0565b145b15611412576040517fc1ab6dc100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff8216158061144d5750604081015173ffffffffffffffffffffffffffffffffffffffff16155b15611484576040517f8579befe00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff828116600090815260226020526040902054670100000000000000900416156114ee576040517f357d0cc400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6024805460018181019092557f7cd332d19b93bcabe3cce7ca0c18a052f57e5fd03b4758a09f30f5ddc4b22ec401805473ffffffffffffffffffffffffffffffffffffffff8086167fffffffffffffffffffffffff0000000000000000000000000000000000000000909216821790925560008181526022602090815260409182902086518154928801518489015160608a015160ff167b01000000000000000000000000000000000000000000000000000000027fffffffff00ffffffffffffffffffffffffffffffffffffffffffffffffffffff9190981667010000000000000002167fffffffff000000000000000000000000000000000000000000ffffffffffffff62ffffff909216640100000000027fffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000090951663ffffffff9093169290921793909317929092169190911793909317835560808501519383019390935560a0840151600290920180546bffffffffffffffffffffffff9093167fffffffffffffffffffffffffffffffffffffffff0000000000000000000000009093169290921790915590517fca93cbe727c73163ec538f71be6c0a64877d7f1f6dd35d5ca7cbaef3a3e34ba390611737908490600060c08201905063ffffffff835116825262ffffff602084015116602083015273ffffffffffffffffffffffffffffffffffffffff604084015116604083015260ff6060840151166060830152608083015160808301526bffffffffffffffffffffffff60a08401511660a083015292915050565b60405180910390a25050808061174c9061518a565b9150506111f6565b50505050565b600e546014546bffffffffffffffffffffffff1660005b600e548110156117cd576117ba600e82815481106117915761179161515b565b60009182526020909120015473ffffffffffffffffffffffffffffffffffffffff168385612ec4565b50806117c58161518a565b915050611771565b5060255460009060ff16815b600e5481101561193e57600e81815481106117f6576117f661515b565b6000918252602082200154600d805473ffffffffffffffffffffffffffffffffffffffff9092169550600c9291849081106118335761183361515b565b600091825260208083209091015473ffffffffffffffffffffffffffffffffffffffff9081168452838201949094526040928301822080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00001690559286168152600b909252902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016905560018260018111156118d5576118d56155d0565b14801561191a575073ffffffffffffffffffffffffffffffffffffffff83166000908152600b60205260409020546201000090046bffffffffffffffffffffffff1615155b1561192c5761192a600f84611f08565b505b806119368161518a565b9150506117d9565b5061194b600d6000614565565b611957600e6000614565565b6040805160808101825260008082526020820181905291810182905260608101829052905b8751811015611de757600c600089838151811061199b5761199b61515b565b60209081029190910181015173ffffffffffffffffffffffffffffffffffffffff1682528101919091526040016000205460ff1615611a06576040517f77cea0fa00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff16888281518110611a3057611a3061515b565b602002602001015173ffffffffffffffffffffffffffffffffffffffff1603611a85576040517f815e1d6400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60405180604001604052806001151581526020018260ff16815250600c60008a8481518110611ab657611ab661515b565b60209081029190910181015173ffffffffffffffffffffffffffffffffffffffff1682528181019290925260400160002082518154939092015160ff16610100027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff921515929092167fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000909316929092171790558651879082908110611b5e57611b5e61515b565b60200260200101519350600073ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff1603611bce576040517f58a70a0a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff84166000908152600b60209081526040918290208251608081018452905460ff80821615801584526101008304909116938301939093526bffffffffffffffffffffffff6201000082048116948301949094526e01000000000000000000000000000090049092166060830152909250611c89576040517f6a7281ad00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600180835260ff80831660208086019182526014546bffffffffffffffffffffffff9081166060880190815273ffffffffffffffffffffffffffffffffffffffff8a166000908152600b909352604092839020885181549551948a0151925184166e010000000000000000000000000000027fffffffffffff000000000000000000000000ffffffffffffffffffffffffffff939094166201000002929092167fffffffffffff000000000000000000000000000000000000000000000000ffff94909616610100027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff921515929092167fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000090951694909417179190911692909217919091179055836001811115611dc357611dc36155d0565b03611dd557611dd3600f85611ee6565b505b80611ddf8161518a565b91505061197c565b508651611dfb90600d9060208a0190614583565b508551611e0f90600e906020890190614583565b5050505050505050565b6000808a8a8a8a8a8a8a8a8a604051602001611e3d999897969594939291906155ff565b604080518083037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe001815291905280516020909101207dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff167e01000000000000000000000000000000000000000000000000000000000000179b9a5050505050505050505050565b6000611ecd825490565b92915050565b6000611edf83836130cc565b9392505050565b6000611edf8373ffffffffffffffffffffffffffffffffffffffff84166130f6565b6000611edf8373ffffffffffffffffffffffffffffffffffffffff84166131f0565b60008787604051611f3c929190615694565b604051908190038120611f53918b906020016156a4565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081840301815282825280516020918201208383019092526000808452908301819052909250906000805b8881101561212a57600185878360208110611fbf57611fbf61515b565b611fcc91901a601b615282565b8c8c85818110611fde57611fde61515b565b905060200201358b8b86818110611ff757611ff761515b565b9050602002013560405160008152602001604052604051612034949392919093845260ff9290921660208401526040830152606082015260800190565b6020604051602081039080840390855afa158015612056573d6000803e3d6000fd5b5050604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081015173ffffffffffffffffffffffffffffffffffffffff81166000908152600c602090815290849020838501909452925460ff8082161515808552610100909204169383019390935290955093509050612104576040517f0f4c073700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b826020015160080260ff166001901b8401935080806121229061518a565b915050611fa2565b50827e01010101010101010101010101010101010101010101010101010101010101841614612185576040517fc103be2e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b505050505050505050505050565b6121cc6040518060c001604052806000815260200160008152602001606081526020016060815260200160608152602001606081525090565b60006121da83850185615795565b60408101515160608201515191925090811415806121fd57508082608001515114155b8061220d5750808260a001515114155b15612244576040517fb55ac75400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b509392505050565b600082604001515167ffffffffffffffff81111561226c5761226c61461a565b60405190808252806020026020018201604052801561233857816020015b6040805161020081018252600060e08201818152610100830182905261012083018290526101408301829052610160830182905261018083018290526101a083018290526101c083018290526101e0830182905282526020808301829052928201819052606082018190526080820181905260a0820181905260c082015282527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff90920191018161228a5790505b50905060006040518060800160405280600061ffff16815260200160006bffffffffffffffffffffffff16815260200160006bffffffffffffffffffffffff16815260200160008152509050600085610100015173ffffffffffffffffffffffffffffffffffffffff166357e871e76040518163ffffffff1660e01b8152600401602060405180830381865afa1580156123d6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123fa9190614f06565b6101008701516040517f7810d12a00000000000000000000000000000000000000000000000000000000815236600482015291925060009173ffffffffffffffffffffffffffffffffffffffff90911690637810d12a90602401602060405180830381865afa158015612471573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906124959190614f06565b905060005b8660400151518110156129255760046000886040015183815181106124c1576124c161515b565b6020908102919091018101518252818101929092526040908101600020815161012081018352815460ff8082161515835261010080830490911615159583019590955263ffffffff620100008204811694830194909452660100000000000081048416606083015273ffffffffffffffffffffffffffffffffffffffff6a01000000000000000000009091048116608083015260018301546fffffffffffffffffffffffffffffffff811660a08401526bffffffffffffffffffffffff70010000000000000000000000000000000082041660c08401527c0100000000000000000000000000000000000000000000000000000000900490931660e08201526002909101549091169181019190915285518690839081106125e4576125e461515b565b6020026020010151600001819052506126198760400151828151811061260c5761260c61515b565b602002602001015161323f565b85828151811061262b5761262b61515b565b6020026020010151606001906001811115612648576126486155d0565b9081600181111561265b5761265b6155d0565b815250506126bf876040015182815181106126785761267861515b565b602002602001015184896080015184815181106126975761269761515b565b60200260200101518885815181106126b1576126b161515b565b60200260200101518c6132ea565b8683815181106126d1576126d161515b565b60200260200101516020018784815181106126ee576126ee61515b565b602002602001015160c00182815250821515151581525050508481815181106127195761271961515b565b602002602001015160200151156127495760018460000181815161273d9190615882565b61ffff1690525061274e565b612913565b6127b48582815181106127635761276361515b565b60200260200101516000015160800151886060015183815181106127895761278961515b565b60200260200101518960a0015184815181106127a7576127a761515b565b6020026020010151613409565b8683815181106127c6576127c661515b565b60200260200101516040018784815181106127e3576127e361515b565b602002602001015160800182815250821515151581525050508760800151600161280d9190615282565b61281b9060ff166040615258565b6103a48860a0015183815181106128345761283461515b565b602002602001015151612847919061526f565b612851919061526f565b8582815181106128635761286361515b565b602002602001015160a00181815250508481815181106128855761288561515b565b602002602001015160a00151846060018181516128a2919061526f565b90525084518590829081106128b9576128b961515b565b602002602001015160800151866128d09190615113565b9550612913876040015182815181106128eb576128eb61515b565b6020026020010151848784815181106129065761290661515b565b6020026020010151613624565b8061291d8161518a565b91505061249a565b50825161ffff1660000361293c5750505050505050565b61c73861294a366010615258565b5a6129559088615113565b61295f919061526f565b612969919061526f565b8351909550613a34906129809061ffff16876158cc565b61298a919061526f565b60408051608081018252600080825260208201819052918101829052606081018290529196506129b989613729565b905060005b886040015151811015612c68578681815181106129dd576129dd61515b565b60200260200101516020015115612c5657612a1a8a888381518110612a0457612a0461515b565b6020026020010151600001516101000151613813565b92506000612b3a8b6040518061012001604052808b8681518110612a4057612a4061515b565b60200260200101516080015181526020018c81526020018a606001518c8781518110612a6e57612a6e61515b565b602002602001015160a001518a612a859190615258565b612a8f91906158cc565b81526020018d6000015181526020018d6020015181526020018681526020018b8681518110612ac057612ac061515b565b602002602001015160000151610100015173ffffffffffffffffffffffffffffffffffffffff168152602001878152602001600115158152508c604001518581518110612b0f57612b0f61515b565b60200260200101518b8681518110612b2957612b2961515b565b60200260200101516000015161398f565b9050806060015187604001818151612b5291906158e0565b6bffffffffffffffffffffffff169052506040810151602088018051612b799083906158e0565b6bffffffffffffffffffffffff169052508751889083908110612b9e57612b9e61515b565b60200260200101516040015115158a604001518381518110612bc257612bc261515b565b60200260200101517fad8cc9579b21dfe2c2f6ea35ba15b656e46b4f5b0cb424f52739b8ce5cac9c5b83602001518460000151612bff91906158e0565b8b8681518110612c1157612c1161515b565b6020026020010151608001518d8f608001518881518110612c3457612c3461515b565b6020026020010151604051612c4c9493929190615905565b60405180910390a3505b80612c608161518a565b9150506129be565b505050602083810151336000908152600b90925260409091208054600290612ca59084906201000090046bffffffffffffffffffffffff166158e0565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff1602179055508260400151601460000160008282829054906101000a90046bffffffffffffffffffffffff16612d0391906158e0565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff16021790555082604001518360200151612d4591906158e0565b6bffffffffffffffffffffffff16602160007f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000828254612dc1919061526f565b909155505050505050505050565b3373ffffffffffffffffffffffffffffffffffffffff821603612e4e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c660000000000000000006044820152606401610c8c565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b73ffffffffffffffffffffffffffffffffffffffff83166000908152600b602090815260408083208151608081018352905460ff80821615801584526101008304909116948301949094526bffffffffffffffffffffffff6201000082048116938301939093526e01000000000000000000000000000090049091166060820152906130c0576000816060015185612f5c9190615942565b90506000612f6a8583615967565b90508083604001818151612f7e91906158e0565b6bffffffffffffffffffffffff16905250612f998582615992565b83606001818151612faa91906158e0565b6bffffffffffffffffffffffff90811690915273ffffffffffffffffffffffffffffffffffffffff89166000908152600b602090815260409182902087518154928901519389015160608a015186166e010000000000000000000000000000027fffffffffffff000000000000000000000000ffffffffffffffffffffffffffff919096166201000002167fffffffffffff000000000000000000000000000000000000000000000000ffff60ff95909516610100027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff921515929092167fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000909416939093171792909216179190911790555050505b60400151949350505050565b60008260000182815481106130e3576130e361515b565b9060005260206000200154905092915050565b600081815260018301602052604081205480156131df57600061311a600183615113565b855490915060009061312e90600190615113565b905081811461319357600086600001828154811061314e5761314e61515b565b90600052602060002001549050808760000184815481106131715761317161515b565b6000918252602080832090910192909255918252600188019052604090208390555b85548690806131a4576131a46159c2565b600190038181906000526020600020016000905590558560010160008681526020019081526020016000206000905560019350505050611ecd565b6000915050611ecd565b5092915050565b600081815260018301602052604081205461323757508154600181810184556000848152602080822090930184905584548482528286019093526040902091909155611ecd565b506000611ecd565b6000818160045b600f8110156132cc577fff0000000000000000000000000000000000000000000000000000000000000082168382602081106132845761328461515b565b1a60f81b7effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916146132ba57506000949350505050565b806132c48161518a565b915050613246565b5081600f1a60018111156132e2576132e26155d0565b949350505050565b600080808085606001516001811115613305576133056155d0565b0361332b576133178888888888613dfe565b613326576000925090506133ff565b6133a3565b600185606001516001811115613343576133436155d0565b0361337157600061335689898988613f88565b925090508061336b57506000925090506133ff565b506133a3565b6040517ff2b2d41200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b84516060015163ffffffff1687106133f857877fc3237c8807c467c1b39b8d0395eff077313e691bf0a7388106792564ebfd5636876040516133e59190614c8d565b60405180910390a26000925090506133ff565b6001925090505b9550959350505050565b601454600090819077010000000000000000000000000000000000000000000000900460ff1615613466576040517f37ed32e800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b601480547fffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffffffff16770100000000000000000000000000000000000000000000001790556040517f4585e33b00000000000000000000000000000000000000000000000000000000906134db908590602401614c8d565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff000000000000000000000000000000000000000000000000000000009094169390931790925290517f79188d1600000000000000000000000000000000000000000000000000000000815290935073ffffffffffffffffffffffffffffffffffffffff8616906379188d16906135ae90879087906004016159f1565b60408051808303816000875af11580156135cc573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906135f09190615a0a565b601480547fffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffffffff16905590969095509350505050565b60008160600151600181111561363c5761363c6155d0565b036136a057600083815260046020526040902060010180547bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167c010000000000000000000000000000000000000000000000000000000063ffffffff851602179055505050565b6001816060015160018111156136b8576136b86155d0565b036137245760c08101805160009081526008602052604080822080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055915191517fa4a4e334c0e330143f9437484fe516c13bc560b86b5b0daf58e7084aaac228f29190a25b505050565b60008060007f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663feaf968c6040518163ffffffff1660e01b815260040160a060405180830381865afa158015613799573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906137bd9190615a52565b509350509250506000821315806137d357508042105b8061380357506000846040015162ffffff1611801561380357506137f78142615113565b846040015162ffffff16105b156131e9575050601b5492915050565b60408051608081018252600080825260208083018281528385018381526060850184905273ffffffffffffffffffffffffffffffffffffffff878116855260229093528584208054640100000000810462ffffff1690925263ffffffff82169092527b01000000000000000000000000000000000000000000000000000000810460ff16855285517ffeaf968c00000000000000000000000000000000000000000000000000000000815295519495919484936701000000000000009092049091169163feaf968c9160048083019260a09291908290030181865afa158015613900573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906139249190615a52565b5093505092505060008213158061393a57508042105b8061396a57506000866040015162ffffff1611801561396a575061395e8142615113565b866040015162ffffff16105b1561397e5760018301546060850152613986565b606084018290525b50505092915050565b604080516101008101825260008082526020808301829052928201819052606082018190526080820181905260a0820181905260c0820181905260e08201529082015115613a255760008381526023602090815260409182902082518084018452905463ffffffff811680835262ffffff640100000000909204821692840192835260e089018051909401529051915191169101525b6000613a318686614195565b60c0840151602082015182519293509091600091613a4e916158e0565b60e08801515190915060ff16600060128210613a6b576001613a81565b613a76826012615113565b613a8190600a615bc2565b9050600060128311613a94576001613aaa565b613a9f601284615113565b613aaa90600a615bc2565b905085600001516bffffffffffffffffffffffff16856bffffffffffffffffffffffff161015613b5257849350613b26818b60800151613aea9190615258565b838c60e0015160600151886bffffffffffffffffffffffff16613b0d9190615258565b613b179190615258565b613b2191906158cc565b6144c3565b6bffffffffffffffffffffffff9081166040880152600060608801819052602088015285168652613c78565b836bffffffffffffffffffffffff16856bffffffffffffffffffffffff161015613c7857849350613be086604001516bffffffffffffffffffffffff16828c60800151613b9f9190615258565b848d60e0015160600151896bffffffffffffffffffffffff16613bc29190615258565b613bcc9190615258565b613bd691906158cc565b613b219190615113565b6bffffffffffffffffffffffff1660608088019190915260e08b01510151613c6490613c0d908490615258565b6001848d60e0015160600151613c239190615258565b613c2d9190615113565b838d608001518a606001516bffffffffffffffffffffffff16613c509190615258565b613c5a9190615258565b613b17919061526f565b6bffffffffffffffffffffffff1660208701525b60008981526004602052604090206001018054859190601090613cbe90849070010000000000000000000000000000000090046bffffffffffffffffffffffff16615942565b82546101009290920a6bffffffffffffffffffffffff81810219909316918316021790915560008b81526004602052604081206001018054928816935091613d199084906fffffffffffffffffffffffffffffffff16615bce565b92506101000a8154816fffffffffffffffffffffffffffffffff02191690836fffffffffffffffffffffffffffffffff160217905550836bffffffffffffffffffffffff16602160008c60c0015173ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000828254613db09190615113565b92505081905550887f801ba6ed51146ffe3e99d1dbd9dd0f4de6292e78a9a34c39c0183de17b3f40fc87604051613de79190615bf7565b60405180910390a250939998505050505050505050565b60008084806020019051810190613e159190615cb7565b845160e00151815191925063ffffffff90811691161015613e7257867f405288ea7be309e16cfdf481367f90a413e1d4634fcdaf8966546db9b93012e886604051613e609190614c8d565b60405180910390a26000915050613f7f565b8260e001518015613f325750602081015115801590613f325750602081015161010084015182516040517f85df51fd00000000000000000000000000000000000000000000000000000000815263ffffffff909116600482015273ffffffffffffffffffffffffffffffffffffffff909116906385df51fd90602401602060405180830381865afa158015613f0b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613f2f9190614f06565b14155b80613f445750805163ffffffff168611155b15613f7957867f6aa7f60c176da7af894b384daea2249497448137f5943c1237ada8bc92bdc30186604051613e609190614c8d565b60019150505b95945050505050565b600080600084806020019051810190613fa19190615d0f565b905060008782600001518360200151846040015160405160200161400394939291909384526020840192909252604083015260e01b7fffffffff0000000000000000000000000000000000000000000000000000000016606082015260640190565b6040516020818303038152906040528051906020012090508460e0015180156140de57506080820151158015906140de5750608082015161010086015160608401516040517f85df51fd00000000000000000000000000000000000000000000000000000000815263ffffffff909116600482015273ffffffffffffffffffffffffffffffffffffffff909116906385df51fd90602401602060405180830381865afa1580156140b7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906140db9190614f06565b14155b806140f3575086826060015163ffffffff1610155b1561413d57877f6aa7f60c176da7af894b384daea2249497448137f5943c1237ada8bc92bdc301876040516141289190614c8d565b60405180910390a260009350915061418c9050565b60008181526008602052604090205460ff161561418457877f405288ea7be309e16cfdf481367f90a413e1d4634fcdaf8966546db9b93012e8876040516141289190614c8d565b600193509150505b94509492505050565b6040805161010081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e081019190915260008260e001516000015160ff1690506000846060015161ffff1684606001516142009190615258565b905083610100015180156142135750803a105b1561421b57503a5b60006012831161422c576001614242565b614237601284615113565b61424290600a615bc2565b905060006012841061425557600161426b565b614260846012615113565b61426b90600a615bc2565b905060008660a0015187604001518860200151896000015161428d919061526f565b6142979087615258565b6142a1919061526f565b6142ab9190615258565b90506142ee828860e00151606001516142c49190615258565b6001848a60e00151606001516142da9190615258565b6142e49190615113565b613c5a8685615258565b6bffffffffffffffffffffffff168652608087015161431190613b2190836158cc565b6bffffffffffffffffffffffff1660408088019190915260e0880151015160009061434a9062ffffff16683635c9adc5dea00000615258565b9050600081633b9aca008a60a001518b60e001516020015163ffffffff168c604001518d600001518b61437d9190615258565b614387919061526f565b6143919190615258565b61439b9190615258565b6143a591906158cc565b6143af919061526f565b90506143f2848a60e00151606001516143c89190615258565b6001868c60e00151606001516143de9190615258565b6143e89190615113565b613c5a8885615258565b6bffffffffffffffffffffffff166020890152608089015161441890613b2190836158cc565b6bffffffffffffffffffffffff16606089015260c089015173ffffffffffffffffffffffffffffffffffffffff166080808a019190915289015161445b906144c3565b6bffffffffffffffffffffffff1660a0808a019190915289015161447e906144c3565b6bffffffffffffffffffffffff1660c089015260e0890151606001516144a3906144c3565b6bffffffffffffffffffffffff1660e08901525050505050505092915050565b60006bffffffffffffffffffffffff821115614561576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f53616665436173743a2076616c756520646f65736e27742066697420696e203960448201527f36206269747300000000000000000000000000000000000000000000000000006064820152608401610c8c565b5090565b508054600082559060005260206000209081019061109c9190614605565b8280548282559060005260206000209081019282156145fd579160200282015b828111156145fd57825182547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff9091161782556020909201916001909101906145a3565b506145619291505b5b808211156145615760008155600101614606565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051610200810167ffffffffffffffff8111828210171561466d5761466d61461a565b60405290565b60405160c0810167ffffffffffffffff8111828210171561466d5761466d61461a565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff811182821017156146dd576146dd61461a565b604052919050565b600067ffffffffffffffff8211156146ff576146ff61461a565b5060051b60200190565b73ffffffffffffffffffffffffffffffffffffffff8116811461109c57600080fd5b803561473681614709565b919050565b600082601f83011261474c57600080fd5b8135602061476161475c836146e5565b614696565b82815260059290921b8401810191818101908684111561478057600080fd5b8286015b848110156147a457803561479781614709565b8352918301918301614784565b509695505050505050565b60ff8116811461109c57600080fd5b8035614736816147af565b63ffffffff8116811461109c57600080fd5b8035614736816147c9565b801515811461109c57600080fd5b8035614736816147e6565b62ffffff8116811461109c57600080fd5b8035614736816147ff565b61ffff8116811461109c57600080fd5b80356147368161481b565b6000610200828403121561484957600080fd5b614851614649565b905061485c826147db565b815261486a602083016147db565b602082015261487b604083016147db565b604082015261488c6060830161472b565b606082015261489d608083016147f4565b60808201526148ae60a08301614810565b60a08201526148bf60c083016147db565b60c08201526148d060e083016147db565b60e08201526101006148e381840161472b565b908201526101206148f583820161482b565b9082015261014061490783820161472b565b90820152610160828101359082015261018080830135908201526101a080830135908201526101c08083013567ffffffffffffffff81111561494857600080fd5b6149548582860161473b565b8284015250506101e061496881840161472b565b9082015292915050565b803567ffffffffffffffff8116811461473657600080fd5b600082601f83011261499b57600080fd5b813567ffffffffffffffff8111156149b5576149b561461a565b6149e660207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f84011601614696565b8181528460208386010111156149fb57600080fd5b816020850160208301376000918101602001919091529392505050565b6bffffffffffffffffffffffff8116811461109c57600080fd5b600082601f830112614a4357600080fd5b81356020614a5361475c836146e5565b82815260c09283028501820192828201919087851115614a7257600080fd5b8387015b85811015614b045781818a031215614a8e5760008081fd5b614a96614673565b8135614aa1816147c9565b815281860135614ab0816147ff565b81870152604082810135614ac381614709565b90820152606082810135614ad6816147af565b908201526080828101359082015260a080830135614af381614a18565b908201528452928401928101614a76565b5090979650505050505050565b600080600080600080600080610100898b031215614b2e57600080fd5b883567ffffffffffffffff80821115614b4657600080fd5b614b528c838d0161473b565b995060208b0135915080821115614b6857600080fd5b614b748c838d0161473b565b9850614b8260408c016147be565b975060608b0135915080821115614b9857600080fd5b614ba48c838d01614836565b9650614bb260808c01614972565b955060a08b0135915080821115614bc857600080fd5b614bd48c838d0161498a565b945060c08b0135915080821115614bea57600080fd5b614bf68c838d0161473b565b935060e08b0135915080821115614c0c57600080fd5b50614c198b828c01614a32565b9150509295985092959890939650565b6000815180845260005b81811015614c4f57602081850181015186830182015201614c33565b5060006020828601015260207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f83011685010191505092915050565b602081526000611edf6020830184614c29565b60008083601f840112614cb257600080fd5b50813567ffffffffffffffff811115614cca57600080fd5b6020830191508360208260051b8501011115614ce557600080fd5b9250929050565b60008060008060008060008060e0898b031215614d0857600080fd5b606089018a811115614d1957600080fd5b8998503567ffffffffffffffff80821115614d3357600080fd5b818b0191508b601f830112614d4757600080fd5b813581811115614d5657600080fd5b8c6020828501011115614d6857600080fd5b6020830199508098505060808b0135915080821115614d8657600080fd5b614d928c838d01614ca0565b909750955060a08b0135915080821115614dab57600080fd5b50614db88b828c01614ca0565b999c989b50969995989497949560c00135949350505050565b60008060008060008060c08789031215614dea57600080fd5b863567ffffffffffffffff80821115614e0257600080fd5b614e0e8a838b0161473b565b97506020890135915080821115614e2457600080fd5b614e308a838b0161473b565b9650614e3e60408a016147be565b95506060890135915080821115614e5457600080fd5b614e608a838b0161498a565b9450614e6e60808a01614972565b935060a0890135915080821115614e8457600080fd5b50614e9189828a0161498a565b9150509295509295509295565b600060208284031215614eb057600080fd5b8135611edf81614709565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60ff81811683821602908116908181146131e9576131e9614ebb565b600060208284031215614f1857600080fd5b5051919050565b63ffffffff8181168382160190808211156131e9576131e9614ebb565b600081518084526020808501945080840160005b83811015614f8257815173ffffffffffffffffffffffffffffffffffffffff1687529582019590820190600101614f50565b509495945050505050565b60208152614fa460208201835163ffffffff169052565b60006020830151614fbd604084018263ffffffff169052565b50604083015163ffffffff8116606084015250606083015173ffffffffffffffffffffffffffffffffffffffff8116608084015250608083015180151560a08401525060a083015162ffffff811660c08401525060c083015163ffffffff811660e08401525060e083015161010061503c8185018363ffffffff169052565b84015190506101206150658482018373ffffffffffffffffffffffffffffffffffffffff169052565b840151905061014061507c8482018361ffff169052565b84015190506101606150a58482018373ffffffffffffffffffffffffffffffffffffffff169052565b840151610180848101919091528401516101a0808501919091528401516101c0808501919091528401516102006101e0808601829052919250906150ed610220860184614f3c565b95015173ffffffffffffffffffffffffffffffffffffffff169301929092525090919050565b81810381811115611ecd57611ecd614ebb565b60008161513557615135614ebb565b507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0190565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82036151bb576151bb614ebb565b5060010190565b600061012063ffffffff808d1684528b6020850152808b166040850152508060608401526151f28184018a614f3c565b905082810360808401526152068189614f3c565b905060ff871660a084015282810360c08401526152238187614c29565b905067ffffffffffffffff851660e08401528281036101008401526152488185614c29565b9c9b505050505050505050505050565b8082028115828204841417611ecd57611ecd614ebb565b80820180821115611ecd57611ecd614ebb565b60ff8181168382160190811115611ecd57611ecd614ebb565b8051614736816147c9565b805161473681614709565b8051614736816147e6565b8051614736816147ff565b80516147368161481b565b600082601f8301126152e357600080fd5b815160206152f361475c836146e5565b82815260059290921b8401810191818101908684111561531257600080fd5b8286015b848110156147a457805161532981614709565b8352918301918301615316565b600082601f83011261534757600080fd5b8151602061535761475c836146e5565b82815260c0928302850182019282820191908785111561537657600080fd5b8387015b85811015614b045781818a0312156153925760008081fd5b61539a614673565b81516153a5816147c9565b8152818601516153b4816147ff565b818701526040828101516153c781614709565b908201526060828101516153da816147af565b908201526080828101519082015260a0808301516153f781614a18565b90820152845292840192810161537a565b60008060006060848603121561541d57600080fd5b835167ffffffffffffffff8082111561543557600080fd5b90850190610200828803121561544a57600080fd5b615452614649565b61545b8361529b565b81526154696020840161529b565b602082015261547a6040840161529b565b604082015261548b606084016152a6565b606082015261549c608084016152b1565b60808201526154ad60a084016152bc565b60a08201526154be60c0840161529b565b60c08201526154cf60e0840161529b565b60e08201526101006154e28185016152a6565b908201526101206154f48482016152c7565b908201526101406155068482016152a6565b90820152610160838101519082015261018080840151908201526101a080840151908201526101c0808401518381111561553f57600080fd5b61554b8a8287016152d2565b8284015250506101e061555f8185016152a6565b90820152602087015190955091508082111561557a57600080fd5b615586878388016152d2565b9350604086015191508082111561559c57600080fd5b506155a986828701615336565b9150509250925092565b6000602082840312156155c557600080fd5b8151611edf816147af565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b60006101208b835273ffffffffffffffffffffffffffffffffffffffff8b16602084015267ffffffffffffffff808b1660408501528160608501526156468285018b614f3c565b9150838203608085015261565a828a614f3c565b915060ff881660a085015283820360c08501526156778288614c29565b90861660e085015283810361010085015290506152488185614c29565b8183823760009101908152919050565b8281526080810160608360208401379392505050565b600082601f8301126156cb57600080fd5b813560206156db61475c836146e5565b82815260059290921b840181019181810190868411156156fa57600080fd5b8286015b848110156147a457803583529183019183016156fe565b600082601f83011261572657600080fd5b8135602061573661475c836146e5565b82815260059290921b8401810191818101908684111561575557600080fd5b8286015b848110156147a457803567ffffffffffffffff8111156157795760008081fd5b6157878986838b010161498a565b845250918301918301615759565b6000602082840312156157a757600080fd5b813567ffffffffffffffff808211156157bf57600080fd5b9083019060c082860312156157d357600080fd5b6157db614673565b82358152602083013560208201526040830135828111156157fb57600080fd5b615807878286016156ba565b60408301525060608301358281111561581f57600080fd5b61582b878286016156ba565b60608301525060808301358281111561584357600080fd5b61584f87828601615715565b60808301525060a08301358281111561586757600080fd5b61587387828601615715565b60a08301525095945050505050565b61ffff8181168382160190808211156131e9576131e9614ebb565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b6000826158db576158db61589d565b500490565b6bffffffffffffffffffffffff8181168382160190808211156131e9576131e9614ebb565b6bffffffffffffffffffffffff851681528360208201528260408201526080606082015260006159386080830184614c29565b9695505050505050565b6bffffffffffffffffffffffff8281168282160390808211156131e9576131e9614ebb565b60006bffffffffffffffffffffffff808416806159865761598661589d565b92169190910492915050565b6bffffffffffffffffffffffff8181168382160280821691908281146159ba576159ba614ebb565b505092915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fd5b8281526040602082015260006132e26040830184614c29565b60008060408385031215615a1d57600080fd5b8251615a28816147e6565b6020939093015192949293505050565b805169ffffffffffffffffffff8116811461473657600080fd5b600080600080600060a08688031215615a6a57600080fd5b615a7386615a38565b9450602086015193506040860151925060608601519150615a9660808701615a38565b90509295509295909350565b600181815b80851115615afb57817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff04821115615ae157615ae1614ebb565b80851615615aee57918102915b93841c9390800290615aa7565b509250929050565b600082615b1257506001611ecd565b81615b1f57506000611ecd565b8160018114615b355760028114615b3f57615b5b565b6001915050611ecd565b60ff841115615b5057615b50614ebb565b50506001821b611ecd565b5060208310610133831016604e8410600b8410161715615b7e575081810a611ecd565b615b888383615aa2565b807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff04821115615bba57615bba614ebb565b029392505050565b6000611edf8383615b03565b6fffffffffffffffffffffffffffffffff8181168382160190808211156131e9576131e9614ebb565b6000610100820190506bffffffffffffffffffffffff8084511683528060208501511660208401528060408501511660408401528060608501511660608401525073ffffffffffffffffffffffffffffffffffffffff608084015116608083015260a0830151615c7760a08401826bffffffffffffffffffffffff169052565b5060c0830151615c9760c08401826bffffffffffffffffffffffff169052565b5060e08301516131e960e08401826bffffffffffffffffffffffff169052565b600060408284031215615cc957600080fd5b6040516040810181811067ffffffffffffffff82111715615cec57615cec61461a565b6040528251615cfa816147c9565b81526020928301519281019290925250919050565b600060a08284031215615d2157600080fd5b60405160a0810181811067ffffffffffffffff82111715615d4457615d4461461a565b806040525082518152602083015160208201526040830151615d65816147c9565b60408201526060830151615d78816147c9565b6060820152608092830151928101929092525091905056fea164736f6c6343000813000a", } var AutomationRegistryABI = AutomationRegistryMetaData.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 b10ad89f930..03ebf78995e 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 @@ -13,7 +13,7 @@ automation_registry_logic_b_wrapper_2_2: ../../contracts/solc/v0.8.19/Automation automation_registry_logic_b_wrapper_2_3: ../../contracts/solc/v0.8.19/AutomationRegistryLogicB2_3/AutomationRegistryLogicB2_3.abi ../../contracts/solc/v0.8.19/AutomationRegistryLogicB2_3/AutomationRegistryLogicB2_3.bin e628b4ba1ca8bf45c2b08c6b80f0b14efbd2dff13b85e5a9ebf643df32335ed2 automation_registry_logic_c_wrapper_2_3: ../../contracts/solc/v0.8.19/AutomationRegistryLogicC2_3/AutomationRegistryLogicC2_3.abi ../../contracts/solc/v0.8.19/AutomationRegistryLogicC2_3/AutomationRegistryLogicC2_3.bin 19d59318e42f28777756eff60d5c5e52563a2fffb8e3f0f0b07b6d36d82b2c55 automation_registry_wrapper_2_2: ../../contracts/solc/v0.8.19/AutomationRegistry2_2/AutomationRegistry2_2.abi ../../contracts/solc/v0.8.19/AutomationRegistry2_2/AutomationRegistry2_2.bin 7072ba90159d84572f427ec816e78aa032cf907b39bf228185e0c446842f7c11 -automation_registry_wrapper_2_3: ../../contracts/solc/v0.8.19/AutomationRegistry2_3/AutomationRegistry2_3.abi ../../contracts/solc/v0.8.19/AutomationRegistry2_3/AutomationRegistry2_3.bin b6163402434b84e3b66bc078f6efac121c1e1240dca0e8ea89c43db46b4e308b +automation_registry_wrapper_2_3: ../../contracts/solc/v0.8.19/AutomationRegistry2_3/AutomationRegistry2_3.abi ../../contracts/solc/v0.8.19/AutomationRegistry2_3/AutomationRegistry2_3.bin 77ed34165d8623c4998dfdfb2ee74dcb395bbaa916e011a78ed1cbc98b24819e automation_utils_2_1: ../../contracts/solc/v0.8.16/AutomationUtils2_1/AutomationUtils2_1.abi ../../contracts/solc/v0.8.16/AutomationUtils2_1/AutomationUtils2_1.bin 815b17b63f15d26a0274b962eefad98cdee4ec897ead58688bbb8e2470e585f5 automation_utils_2_2: ../../contracts/solc/v0.8.19/AutomationUtils2_2/AutomationUtils2_2.abi ../../contracts/solc/v0.8.19/AutomationUtils2_2/AutomationUtils2_2.bin 8743f6231aaefa3f2a0b2d484258070d506e2d0860690e66890dccc3949edb2e automation_utils_2_3: ../../contracts/solc/v0.8.19/AutomationUtils2_3/AutomationUtils2_3.abi ../../contracts/solc/v0.8.19/AutomationUtils2_3/AutomationUtils2_3.bin 11e2b481dc9a4d936e3443345d45d2cc571164459d214917b42a8054b295393b diff --git a/core/scripts/common/helpers.go b/core/scripts/common/helpers.go index 97ca2dd4929..f852c88de5b 100644 --- a/core/scripts/common/helpers.go +++ b/core/scripts/common/helpers.go @@ -298,6 +298,11 @@ func TenderlySimLink(simID string) string { // ConfirmTXMined confirms that the given transaction is mined and prints useful execution information. func ConfirmTXMined(context context.Context, client *ethclient.Client, transaction *types.Transaction, chainID int64, txInfo ...string) (receipt *types.Receipt) { + if transaction == nil { + fmt.Println("No transaction to confirm") + return + } + fmt.Println("Executing TX", ExplorerLink(chainID, transaction.Hash()), txInfo) receipt, err := bind.WaitMined(context, client, transaction) PanicErr(err) diff --git a/core/scripts/go.mod b/core/scripts/go.mod index db32d617615..e312d6df955 100644 --- a/core/scripts/go.mod +++ b/core/scripts/go.mod @@ -315,7 +315,7 @@ require ( github.com/smartcontractkit/chainlink-ccip/chains/solana v0.0.0-20250103152858-8973fd0c912b // indirect github.com/smartcontractkit/chainlink-cosmos v0.5.2-0.20241202195413-82468150ac1e // indirect github.com/smartcontractkit/chainlink-feeds v0.1.1 // indirect - github.com/smartcontractkit/chainlink-framework/multinode v0.0.0-20241220173418-09e17ddbeb20 // indirect + github.com/smartcontractkit/chainlink-framework/multinode v0.0.0-20250115203616-a2ea5e50b260 // indirect github.com/smartcontractkit/chainlink-protos/job-distributor v0.6.0 // indirect github.com/smartcontractkit/chainlink-protos/orchestrator v0.4.0 // indirect github.com/smartcontractkit/chainlink-solana v1.1.1-0.20250110142550-e2a9566d39f3 // indirect diff --git a/core/scripts/go.sum b/core/scripts/go.sum index f5c0b058cfc..097005e9dc5 100644 --- a/core/scripts/go.sum +++ b/core/scripts/go.sum @@ -1172,8 +1172,8 @@ github.com/smartcontractkit/chainlink-data-streams v0.1.1-0.20250115135646-ac859 github.com/smartcontractkit/chainlink-data-streams v0.1.1-0.20250115135646-ac859d85e7e3/go.mod h1:pDZagSGjs9U+l4YIFhveDznMHqxuuz+5vRxvVgpbdr8= github.com/smartcontractkit/chainlink-feeds v0.1.1 h1:JzvUOM/OgGQA1sOqTXXl52R6AnNt+Wg64sVG+XSA49c= github.com/smartcontractkit/chainlink-feeds v0.1.1/go.mod h1:55EZ94HlKCfAsUiKUTNI7QlE/3d3IwTlsU3YNa/nBb4= -github.com/smartcontractkit/chainlink-framework/multinode v0.0.0-20241220173418-09e17ddbeb20 h1:p/gzWpEf8alodCXm2Gtx2kWI/O9ZLdWZOdNnv5ZGO6c= -github.com/smartcontractkit/chainlink-framework/multinode v0.0.0-20241220173418-09e17ddbeb20/go.mod h1:4JqpgFy01LaqG1yM2iFTzwX3ZgcAvW9WdstBZQgPHzU= +github.com/smartcontractkit/chainlink-framework/multinode v0.0.0-20250115203616-a2ea5e50b260 h1:See2isL6KdrTJDlVKWv8qiyYqWhYUcubU2e5yKXV1oY= +github.com/smartcontractkit/chainlink-framework/multinode v0.0.0-20250115203616-a2ea5e50b260/go.mod h1:4JqpgFy01LaqG1yM2iFTzwX3ZgcAvW9WdstBZQgPHzU= github.com/smartcontractkit/chainlink-protos/job-distributor v0.6.0 h1:0ewLMbAz3rZrovdRUCgd028yOXX8KigB4FndAUdI2kM= github.com/smartcontractkit/chainlink-protos/job-distributor v0.6.0/go.mod h1:/dVVLXrsp+V0AbcYGJo3XMzKg3CkELsweA/TTopCsKE= github.com/smartcontractkit/chainlink-protos/orchestrator v0.4.0 h1:ZBat8EBvE2LpSQR9U1gEbRV6PfAkiFdINmQ8nVnXIAQ= diff --git a/core/scripts/keystone/main.go b/core/scripts/keystone/main.go index 4bd8dea0e5f..3f14540e22c 100644 --- a/core/scripts/keystone/main.go +++ b/core/scripts/keystone/main.go @@ -18,6 +18,7 @@ func main() { src.NewProvisionKeystoneCommand(), src.NewDeployAndInitializeCapabilitiesRegistryCommand(), src.NewToolkit(), + src.NewGenerateLocalOCR3ConfigCommand(), } commandsList := func(commands []command) string { diff --git a/core/scripts/keystone/src/88_capabilities_registry_helpers.go b/core/scripts/keystone/src/88_capabilities_registry_helpers.go index 5494375aa4f..b75b2fb48af 100644 --- a/core/scripts/keystone/src/88_capabilities_registry_helpers.go +++ b/core/scripts/keystone/src/88_capabilities_registry_helpers.go @@ -554,13 +554,23 @@ func peerToNode(nopID uint32, p peer) (kcr.CapabilitiesRegistryNodeParams, error return kcr.CapabilitiesRegistryNodeParams{}, fmt.Errorf("failed to convert signer: %w", err) } + epk := strings.TrimPrefix(p.EncryptionPublicKey, "0x") + epkB, err := hex.DecodeString(epk) + if err != nil { + return kcr.CapabilitiesRegistryNodeParams{}, fmt.Errorf("failed to convert encryptionPublicKey: %w", err) + } + + var epkb [32]byte + copy(epkb[:], epkB) + var sigb [32]byte copy(sigb[:], signerB) return kcr.CapabilitiesRegistryNodeParams{ - NodeOperatorId: nopID, - P2pId: peerIDB, - Signer: sigb, + NodeOperatorId: nopID, + P2pId: peerIDB, + Signer: sigb, + EncryptionPublicKey: epkb, }, nil } diff --git a/core/scripts/keystone/src/generate_local_ocr3_config.go b/core/scripts/keystone/src/generate_local_ocr3_config.go new file mode 100644 index 00000000000..c171c7f097d --- /dev/null +++ b/core/scripts/keystone/src/generate_local_ocr3_config.go @@ -0,0 +1,119 @@ +package src + +import ( + "encoding/json" + "os" + + "github.com/smartcontractkit/chainlink/deployment" + "github.com/smartcontractkit/chainlink/deployment/keystone" + ksdeploy "github.com/smartcontractkit/chainlink/deployment/keystone" +) + +type generateLocalOCR3Config struct{} + +func NewGenerateLocalOCR3ConfigCommand() *generateLocalOCR3Config { + return &generateLocalOCR3Config{} +} + +func (g *generateLocalOCR3Config) Name() string { + return "generate-local-ocr3-config" +} + +func (g *generateLocalOCR3Config) Run(args []string) { + publicKeys := []byte(`[ + { + "EthAddress": "0xF4e7e516146c8567F8E8be0ED1f1A92798628d35", + "P2PPeerID": "12D3KooWNmhKZL1XW4Vv3rNjLXzJ6mqcVerihdijjGYuexPrFUFZ", + "OCR2BundleID": "2f92c96da20fbe39c89e59516e3a7473254523316887394e406527c72071d3db", + "OCR2OnchainPublicKey": "a2402db8e549f094ea31e1c0edd77623f4ca5b12", + "OCR2OffchainPublicKey": "3ca9918cd2787de8f9aff91f220f30a5cc54c394f73e173b12c93368bd7072ad", + "OCR2ConfigPublicKey": "19904debd03994fe9ea411cda7a6b2f01f20a3fe803df0fed67aaf00cc99113f", + "CSAPublicKey": "csa_dbae6965bad0b0fa95ecc34a602eee1c0c570ddc29b56502e400d18574b8c3df" + }, + { + "EthAddress": "0x8B60FDcc9CAC8ea476b31d17011CB204471431d9", + "P2PPeerID": "12D3KooWFUjV73ZYkAMhS2cVwte3kXDWD8Ybyx3u9CEDHNoeEhBH", + "OCR2BundleID": "b3df4d8748b67731a1112e8b45a764941974f5590c93672eebbc4f3504dd10ed", + "OCR2OnchainPublicKey": "4af19c802b244d1d085492c3946391c965e10519", + "OCR2OffchainPublicKey": "365b9e1c3c945fc3f51afb25772f0a5a1f1547935a4b5dc89c012f590709fefe", + "OCR2ConfigPublicKey": "15ff12569d11b8ff9f17f8999ea928d03a439f3fb116661cbc4669a0a3192775", + "CSAPublicKey": "csa_c5cc655a9c19b69626519c4a72c44a94a3675daeba9c16cc23e010a7a6dac1be" + }, + { + "EthAddress": "0x6620F516F29979B214e2451498a057FDd3a0A85d", + "P2PPeerID": "12D3KooWRTtH2WWrztD87Do1kXePSmGjyU4r7mZVWThmqTGgdbUC", + "OCR2BundleID": "38459ae37f29f2c1fde0f25972a973322be8cada82acf43f464756836725be97", + "OCR2OnchainPublicKey": "61925685d2b80b121537341d063c4e57b2f9323c", + "OCR2OffchainPublicKey": "7fe2dbd9f9fb96f7dbbe0410e32d435ad67dae6c91410189fe5664cf3057ef10", + "OCR2ConfigPublicKey": "2f02fd80b362e1c7acf91680fd48c062718233acd595a6ae7cbe434e118e6a4f", + "CSAPublicKey": "csa_7407fc90c70895c0fb2bdf385e2e4918364bec1f7a74bad7fdf696bffafbcab8" + }, + { + "EthAddress": "0xFeB61E22FCf4F9740c9D96b05199F195bd61A7c2", + "P2PPeerID": "12D3KooWMTZnZtcVK4EJsjkKsV9qXNoNRSjT62CZi3tKkXGaCsGh", + "OCR2BundleID": "b5dbc4c9da983cddde2e3226b85807eb7beaf818694a22576af4d80f352702ed", + "OCR2OnchainPublicKey": "fd97efd53fc20acc098fcd746c04d8d7540d97e0", + "OCR2OffchainPublicKey": "91b393bb5e6bd6fd9de23845bcd0e0d9b0dd28a1d65d3cfb1fce9f91bd3d8c19", + "OCR2ConfigPublicKey": "09eb53924ff8b33a08b4eae2f3819015314ce6e8864ac4f86e97caafd4181506", + "CSAPublicKey": "csa_ef55caf17eefc2a9d547b5a3978d396bd237c73af99cd849a4758701122e3cba" + }, + { + "EthAddress": "0x882Fd04D78A7e7D386Dd5b550f19479E5494B0B2", + "P2PPeerID": "12D3KooWRsM9yordRQDhLgbErH8WMMGz1bC1J4hR5gAGvMWu8goN", + "OCR2BundleID": "260d5c1a618cdf5324509d7db95f5a117511864ebb9e1f709e8969339eb225af", + "OCR2OnchainPublicKey": "a0b67dc5345a71d02b396147ae2cb75dda63cbe9", + "OCR2OffchainPublicKey": "4f42ef42e5cc351dbbd79c29ef33af25c0250cac84837c1ff997bc111199d07e", + "OCR2ConfigPublicKey": "3b90249731beb9e4f598371f0b96c3babf47bcc62121ebc9c195e3c33e4fd708", + "CSAPublicKey": "csa_1b874ac2d54b966cec5a8358678ca6f030261aabf3372ce9dbea2d4eb9cdab3d" + }]`) + + var pubKeys []ksdeploy.NodeKeys + err := json.Unmarshal(publicKeys, &pubKeys) + if err != nil { + panic(err) + } + + config := []byte(`{ + "MaxQueryLengthBytes": 1000000, + "MaxObservationLengthBytes": 1000000, + "MaxReportLengthBytes": 1000000, + "MaxRequestBatchSize": 1000, + "UniqueReports": true, + "DeltaProgressMillis": 5000, + "DeltaResendMillis": 5000, + "DeltaInitialMillis": 5000, + "DeltaRoundMillis": 2000, + "DeltaGraceMillis": 500, + "DeltaCertifiedCommitRequestMillis": 1000, + "DeltaStageMillis": 30000, + "MaxRoundsPerEpoch": 10, + "TransmissionSchedule": [4], + "MaxDurationQueryMillis": 1000, + "MaxDurationObservationMillis": 1000, + "MaxDurationReportMillis": 1000, + "MaxDurationAcceptMillis": 1000, + "MaxDurationTransmitMillis": 1000, + "MaxFaultyOracles": 1}`) + var cfg keystone.OracleConfig + err = json.Unmarshal(config, &cfg) + if err != nil { + panic(err) + } + + ocrConfig, err := ksdeploy.GenerateOCR3Config(cfg, pubKeys, deployment.XXXGenerateTestOCRSecrets()) + if err != nil { + panic(err) + } + + // Convert to JSON + jsonData, err := json.MarshalIndent(ocrConfig, "", " ") + if err != nil { + panic(err) + } + + // Generate a json file in `./OCR3Config.json` + err = os.WriteFile("./OCR3LocalConfig.json", jsonData, 0600) + if err != nil { + panic(err) + } +} diff --git a/core/services/gateway/handlers/capabilities/webapi.go b/core/services/gateway/handlers/capabilities/webapi.go index a0213eb8f42..f4a324420c0 100644 --- a/core/services/gateway/handlers/capabilities/webapi.go +++ b/core/services/gateway/handlers/capabilities/webapi.go @@ -1,5 +1,7 @@ package capabilities +import "errors" + type Request struct { URL string `json:"url"` // URL to query, only http and https protocols are supported. Method string `json:"method,omitempty"` // HTTP verb, defaults to GET. @@ -16,6 +18,25 @@ type Response struct { Body []byte `json:"body,omitempty"` // HTTP response body } +// Validate ensures the Response struct is consistent. +func (r Response) Validate() error { + if r.ExecutionError { + if r.ErrorMessage == "" { + return errors.New("executionError is true but errorMessage is empty") + } + if r.StatusCode != 0 || len(r.Headers) > 0 || len(r.Body) > 0 { + return errors.New("executionError is true but response details (statusCode, headers, body) are populated") + } + return nil + } + + if r.StatusCode < 100 || r.StatusCode > 599 { + return errors.New("statusCode must be a valid HTTP status code (100-599)") + } + + return nil +} + type TriggerResponsePayload struct { ErrorMessage string `json:"error_message,omitempty"` // ERROR, ACCEPTED, PENDING, COMPLETED diff --git a/core/services/gateway/handlers/capabilities/webapi_test.go b/core/services/gateway/handlers/capabilities/webapi_test.go new file mode 100644 index 00000000000..2030c898053 --- /dev/null +++ b/core/services/gateway/handlers/capabilities/webapi_test.go @@ -0,0 +1,54 @@ +package capabilities + +import ( + "testing" + + "github.com/stretchr/testify/require" +) + +func TestResponseValidate(t *testing.T) { + tt := []struct { + name string + response Response + expectError string + }{ + { + name: "valid Response with ExecutionError", + response: Response{ExecutionError: true, ErrorMessage: "Some error"}, + }, + { + name: "invalid Response with ExecutionError but no ErrorMessage", + response: Response{ExecutionError: true}, + expectError: "executionError is true but errorMessage is empty", + }, + { + name: "valid HTTP Response", + response: Response{StatusCode: 200}, + }, + { + name: "invalid status code", + response: Response{ + Body: []byte("body"), + }, + expectError: "statusCode must be set when executionError is false", + }, + { + name: "invalid HTTP Response with bad StatusCode", + response: Response{StatusCode: 700}, + expectError: "statusCode must be a valid HTTP status code (100-599)", + }, + } + + for _, tc := range tt { + t.Run(tc.name, func(t *testing.T) { + err := tc.response.Validate() + + if tc.expectError != "" { + require.Error(t, err) + return + } + + require.NoError(t, err) + }) + } +} diff --git a/core/services/workflows/syncer/fetcher.go b/core/services/workflows/syncer/fetcher.go index 5c8856d58c1..2e4fbd51354 100644 --- a/core/services/workflows/syncer/fetcher.go +++ b/core/services/workflows/syncer/fetcher.go @@ -93,13 +93,21 @@ func (s *FetcherService) Fetch(ctx context.Context, url string) ([]byte, error) return nil, err } - s.lggr.Debugw("received gateway response") + if err = resp.Validate(); err != nil { + return nil, fmt.Errorf("invalid response from gateway: %w", err) + } + + s.lggr.Debugw("received gateway response", "donID", resp.Body.DonId, "msgID", resp.Body.MessageId) + var payload ghcapabilities.Response - err = json.Unmarshal(resp.Body.Payload, &payload) - if err != nil { + if err = json.Unmarshal(resp.Body.Payload, &payload); err != nil { return nil, err } + if err = payload.Validate(); err != nil { + return nil, fmt.Errorf("invalid payload received from gateway message: %w", err) + } + if payload.ExecutionError { return nil, fmt.Errorf("execution error from gateway: %s", payload.ErrorMessage) } diff --git a/core/services/workflows/syncer/fetcher_test.go b/core/services/workflows/syncer/fetcher_test.go index 017b052f8ab..600cde5c577 100644 --- a/core/services/workflows/syncer/fetcher_test.go +++ b/core/services/workflows/syncer/fetcher_test.go @@ -2,6 +2,7 @@ package syncer import ( "context" + "crypto/ecdsa" "encoding/json" "strings" "testing" @@ -11,10 +12,12 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/gateway/api" + "github.com/smartcontractkit/chainlink/v2/core/services/gateway/common" "github.com/smartcontractkit/chainlink/v2/core/services/gateway/connector" gcmocks "github.com/smartcontractkit/chainlink/v2/core/services/gateway/connector/mocks" "github.com/smartcontractkit/chainlink/v2/core/services/gateway/handlers/capabilities" ghcapabilities "github.com/smartcontractkit/chainlink/v2/core/services/gateway/handlers/capabilities" + "github.com/smartcontractkit/chainlink/v2/core/utils" "github.com/smartcontractkit/chainlink/v2/core/utils/matches" ) @@ -33,9 +36,11 @@ func TestNewFetcherService(t *testing.T) { connector := gcmocks.NewGatewayConnector(t) wrapper := &wrapper{c: connector} - url := "http://example.com" - - msgID := strings.Join([]string{ghcapabilities.MethodWorkflowSyncer, hash(url)}, "/") + var ( + url = "http://example.com" + msgID = strings.Join([]string{ghcapabilities.MethodWorkflowSyncer, hash(url)}, "/") + donID = "don-id" + ) t.Run("OK-valid_request", func(t *testing.T) { connector.EXPECT().AddHandler([]string{capabilities.MethodWorkflowSyncer}, mock.Anything).Return(nil) @@ -44,11 +49,11 @@ func TestNewFetcherService(t *testing.T) { require.NoError(t, fetcher.Start(ctx)) defer fetcher.Close() - gatewayResp := gatewayResponse(t, msgID) + gatewayResp := signGatewayResponse(t, gatewayResponse(t, msgID, donID)) connector.EXPECT().SignAndSendToGateway(mock.Anything, "gateway1", mock.Anything).Run(func(ctx context.Context, gatewayID string, msg *api.MessageBody) { fetcher.och.HandleGatewayMessage(ctx, "gateway1", gatewayResp) }).Return(nil).Times(1) - connector.EXPECT().DonID().Return("don-id") + connector.EXPECT().DonID().Return(donID) connector.EXPECT().AwaitConnection(matches.AnyContext, "gateway1").Return(nil) connector.EXPECT().GatewayIDs().Return([]string{"gateway1", "gateway2"}) @@ -59,13 +64,51 @@ func TestNewFetcherService(t *testing.T) { require.Equal(t, expectedPayload, payload) }) + t.Run("fails with invalid payload response", func(t *testing.T) { + connector.EXPECT().AddHandler([]string{capabilities.MethodWorkflowSyncer}, mock.Anything).Return(nil) + + fetcher := NewFetcherService(lggr, wrapper) + require.NoError(t, fetcher.Start(ctx)) + defer fetcher.Close() + + gatewayResp := signGatewayResponse(t, inconsistentPayload(t, msgID, donID)) + connector.EXPECT().SignAndSendToGateway(mock.Anything, "gateway1", mock.Anything).Run(func(ctx context.Context, gatewayID string, msg *api.MessageBody) { + fetcher.och.HandleGatewayMessage(ctx, "gateway1", gatewayResp) + }).Return(nil).Times(1) + connector.EXPECT().DonID().Return(donID) + connector.EXPECT().AwaitConnection(matches.AnyContext, "gateway1").Return(nil) + connector.EXPECT().GatewayIDs().Return([]string{"gateway1", "gateway2"}) + + _, err := fetcher.Fetch(ctx, url) + require.Error(t, err) + }) + + t.Run("fails due to invalid gateway response", func(t *testing.T) { + connector.EXPECT().AddHandler([]string{capabilities.MethodWorkflowSyncer}, mock.Anything).Return(nil) + + fetcher := NewFetcherService(lggr, wrapper) + require.NoError(t, fetcher.Start(ctx)) + defer fetcher.Close() + + gatewayResp := gatewayResponse(t, msgID, donID) // gateway response that is not signed + connector.EXPECT().SignAndSendToGateway(mock.Anything, "gateway1", mock.Anything).Run(func(ctx context.Context, gatewayID string, msg *api.MessageBody) { + fetcher.och.HandleGatewayMessage(ctx, "gateway1", gatewayResp) + }).Return(nil).Times(1) + connector.EXPECT().DonID().Return(donID) + connector.EXPECT().AwaitConnection(matches.AnyContext, "gateway1").Return(nil) + connector.EXPECT().GatewayIDs().Return([]string{"gateway1", "gateway2"}) + + _, err := fetcher.Fetch(ctx, url) + require.Error(t, err) + require.ErrorContains(t, err, "invalid response from gateway") + }) + t.Run("NOK-response_payload_too_large", func(t *testing.T) { headers := map[string]string{"Content-Type": "application/json"} responsePayload, err := json.Marshal(ghcapabilities.Response{ - StatusCode: 400, - Headers: headers, - ErrorMessage: "http: request body too large", - ExecutionError: true, + StatusCode: 400, + Headers: headers, + ErrorMessage: "http: request body too large", }) require.NoError(t, err) gatewayResponse := &api.Message{ @@ -85,7 +128,7 @@ func TestNewFetcherService(t *testing.T) { connector.EXPECT().SignAndSendToGateway(mock.Anything, "gateway1", mock.Anything).Run(func(ctx context.Context, gatewayID string, msg *api.MessageBody) { fetcher.och.HandleGatewayMessage(ctx, "gateway1", gatewayResponse) }).Return(nil).Times(1) - connector.EXPECT().DonID().Return("don-id") + connector.EXPECT().DonID().Return(donID) connector.EXPECT().AwaitConnection(matches.AnyContext, "gateway1").Return(nil) connector.EXPECT().GatewayIDs().Return([]string{"gateway1", "gateway2"}) @@ -94,21 +137,63 @@ func TestNewFetcherService(t *testing.T) { }) } -func gatewayResponse(t *testing.T, msgID string) *api.Message { +// gatewayResponse creates an unsigned gateway response with a status code of 200 and a response body. +func gatewayResponse(t *testing.T, msgID string, donID string) *api.Message { headers := map[string]string{"Content-Type": "application/json"} body := []byte("response body") responsePayload, err := json.Marshal(ghcapabilities.Response{ - StatusCode: 200, - Headers: headers, - Body: body, - ExecutionError: false, + StatusCode: 200, + Headers: headers, + Body: body, }) require.NoError(t, err) return &api.Message{ Body: api.MessageBody{ MessageId: msgID, + DonId: donID, Method: ghcapabilities.MethodWebAPITarget, Payload: responsePayload, }, } } + +// inconsistentPayload creates an unsigned gateway response with an inconsistent payload. The +// ExecutionError is true, but there is no ErrorMessage, so it is invalid. +func inconsistentPayload(t *testing.T, msgID string, donID string) *api.Message { + responsePayload, err := json.Marshal(ghcapabilities.Response{ + ExecutionError: true, + }) + require.NoError(t, err) + return &api.Message{ + Body: api.MessageBody{ + MessageId: msgID, + DonId: donID, + Method: ghcapabilities.MethodWebAPITarget, + Payload: responsePayload, + }, + } +} + +// signGatewayResponse signs the gateway response with a private key and arbitrarily sets the receiver +// to the signer's address. A signature and receiver are required for a valid gateway response. +func signGatewayResponse(t *testing.T, msg *api.Message) *api.Message { + nodeKeys := common.NewTestNodes(t, 1) + s := &signer{pk: nodeKeys[0].PrivateKey} + signature, err := s.Sign(api.GetRawMessageBody(&msg.Body)...) + require.NoError(t, err) + msg.Signature = utils.StringToHex(string(signature)) + + signerBytes, err := msg.ExtractSigner() + require.NoError(t, err) + + msg.Body.Receiver = utils.StringToHex(string(signerBytes)) + return msg +} + +type signer struct { + pk *ecdsa.PrivateKey +} + +func (s *signer) Sign(data ...[]byte) ([]byte, error) { + return common.SignData(s.pk, data...) +} diff --git a/core/services/workflows/syncer/handler.go b/core/services/workflows/syncer/handler.go index 6d0ee7073e9..c8dbf94846d 100644 --- a/core/services/workflows/syncer/handler.go +++ b/core/services/workflows/syncer/handler.go @@ -495,34 +495,35 @@ func (h *eventHandler) getWorkflowArtifacts( ctx context.Context, payload WorkflowRegistryWorkflowRegisteredV1, ) ([]byte, []byte, error) { - spec, err := h.orm.GetWorkflowSpecByID(ctx, hex.EncodeToString(payload.WorkflowID[:])) - if err != nil { - binary, err2 := h.fetcher(ctx, payload.BinaryURL) - if err2 != nil { - return nil, nil, fmt.Errorf("failed to fetch binary from %s : %w", payload.BinaryURL, err2) + // Check if the workflow spec is already stored in the database + if spec, err := h.orm.GetWorkflowSpecByID(ctx, hex.EncodeToString(payload.WorkflowID[:])); err == nil { + // there is no update in the BinaryURL or ConfigURL, lets decode the stored artifacts + decodedBinary, err := hex.DecodeString(spec.Workflow) + if err != nil { + return nil, nil, fmt.Errorf("failed to decode stored workflow spec: %w", err) } + return decodedBinary, []byte(spec.Config), nil + } - decodedBinary, err2 := base64.StdEncoding.DecodeString(string(binary)) - if err2 != nil { - return nil, nil, fmt.Errorf("failed to decode binary: %w", err2) - } + // Fetch the binary and config files from the specified URLs. + var ( + binary, decodedBinary, config []byte + err error + ) + if binary, err = h.fetcher(ctx, payload.BinaryURL); err != nil { + return nil, nil, fmt.Errorf("failed to fetch binary from %s : %w", payload.BinaryURL, err) + } - var config []byte - if payload.ConfigURL != "" { - config, err2 = h.fetcher(ctx, payload.ConfigURL) - if err2 != nil { - return nil, nil, fmt.Errorf("failed to fetch config from %s : %w", payload.ConfigURL, err2) - } - } - return decodedBinary, config, nil + if decodedBinary, err = base64.StdEncoding.DecodeString(string(binary)); err != nil { + return nil, nil, fmt.Errorf("failed to decode binary: %w", err) } - // there is no update in the BinaryURL or ConfigURL, lets decode the stored artifacts - decodedBinary, err := hex.DecodeString(spec.Workflow) - if err != nil { - return nil, nil, fmt.Errorf("failed to decode stored workflow spec: %w", err) + if payload.ConfigURL != "" { + if config, err = h.fetcher(ctx, payload.ConfigURL); err != nil { + return nil, nil, fmt.Errorf("failed to fetch config from %s : %w", payload.ConfigURL, err) + } } - return decodedBinary, []byte(spec.Config), nil + return decodedBinary, config, nil } func (h *eventHandler) engineFactoryFn(ctx context.Context, id string, owner string, name string, config []byte, binary []byte) (services.Service, error) { diff --git a/deployment/ccip/changeset/accept_ownership_test.go b/deployment/ccip/changeset/accept_ownership_test.go index dc3b0ba33b3..264be42cce1 100644 --- a/deployment/ccip/changeset/accept_ownership_test.go +++ b/deployment/ccip/changeset/accept_ownership_test.go @@ -1,21 +1,21 @@ -package changeset +package changeset_test import ( "testing" - "github.com/ethereum/go-ethereum/common" - "github.com/stretchr/testify/require" "golang.org/x/exp/maps" + "github.com/smartcontractkit/chainlink/deployment/ccip/changeset" + "github.com/smartcontractkit/chainlink/deployment/ccip/changeset/testhelpers" commonchangeset "github.com/smartcontractkit/chainlink/deployment/common/changeset" "github.com/smartcontractkit/chainlink/deployment/common/proposalutils" ) func Test_NewAcceptOwnershipChangeset(t *testing.T) { t.Parallel() - e, _ := NewMemoryEnvironment(t) - state, err := LoadOnchainState(e.Env) + e, _ := testhelpers.NewMemoryEnvironment(t) + state, err := changeset.LoadOnchainState(e.Env) require.NoError(t, err) allChains := maps.Keys(e.Env.Chains) @@ -35,7 +35,7 @@ func Test_NewAcceptOwnershipChangeset(t *testing.T) { // at this point we have the initial deploys done, now we need to transfer ownership // to the timelock contract - state, err = LoadOnchainState(e.Env) + state, err = changeset.LoadOnchainState(e.Env) require.NoError(t, err) // compose the transfer ownership and accept ownership changesets @@ -43,84 +43,10 @@ func Test_NewAcceptOwnershipChangeset(t *testing.T) { // note this doesn't have proposals. { Changeset: commonchangeset.WrapChangeSet(commonchangeset.TransferToMCMSWithTimelock), - Config: genTestTransferOwnershipConfig(e, allChains, state), + Config: testhelpers.GenTestTransferOwnershipConfig(e, allChains, state), }, }) require.NoError(t, err) - assertTimelockOwnership(t, e, allChains, state) -} - -func genTestTransferOwnershipConfig( - e DeployedEnv, - chains []uint64, - state CCIPOnChainState, -) commonchangeset.TransferToMCMSWithTimelockConfig { - var ( - timelocksPerChain = make(map[uint64]common.Address) - contracts = make(map[uint64][]common.Address) - ) - - // chain contracts - for _, chain := range chains { - timelocksPerChain[chain] = state.Chains[chain].Timelock.Address() - contracts[chain] = []common.Address{ - state.Chains[chain].OnRamp.Address(), - state.Chains[chain].OffRamp.Address(), - state.Chains[chain].FeeQuoter.Address(), - state.Chains[chain].NonceManager.Address(), - state.Chains[chain].RMNRemote.Address(), - state.Chains[chain].TestRouter.Address(), - state.Chains[chain].Router.Address(), - } - } - - // home chain - homeChainTimelockAddress := state.Chains[e.HomeChainSel].Timelock.Address() - timelocksPerChain[e.HomeChainSel] = homeChainTimelockAddress - contracts[e.HomeChainSel] = append(contracts[e.HomeChainSel], - state.Chains[e.HomeChainSel].CapabilityRegistry.Address(), - state.Chains[e.HomeChainSel].CCIPHome.Address(), - state.Chains[e.HomeChainSel].RMNHome.Address(), - ) - - return commonchangeset.TransferToMCMSWithTimelockConfig{ - ContractsByChain: contracts, - } -} - -// assertTimelockOwnership asserts that the ownership of the contracts has been transferred -// to the appropriate timelock contract on each chain. -func assertTimelockOwnership( - t *testing.T, - e DeployedEnv, - chains []uint64, - state CCIPOnChainState, -) { - // check that the ownership has been transferred correctly - for _, chain := range chains { - for _, contract := range []common.Address{ - state.Chains[chain].OnRamp.Address(), - state.Chains[chain].OffRamp.Address(), - state.Chains[chain].FeeQuoter.Address(), - state.Chains[chain].NonceManager.Address(), - state.Chains[chain].RMNRemote.Address(), - } { - owner, _, err := commonchangeset.LoadOwnableContract(contract, e.Env.Chains[chain].Client) - require.NoError(t, err) - require.Equal(t, state.Chains[chain].Timelock.Address(), owner) - } - } - - // check home chain contracts ownership - homeChainTimelockAddress := state.Chains[e.HomeChainSel].Timelock.Address() - for _, contract := range []common.Address{ - state.Chains[e.HomeChainSel].CapabilityRegistry.Address(), - state.Chains[e.HomeChainSel].CCIPHome.Address(), - state.Chains[e.HomeChainSel].RMNHome.Address(), - } { - owner, _, err := commonchangeset.LoadOwnableContract(contract, e.Env.Chains[e.HomeChainSel].Client) - require.NoError(t, err) - require.Equal(t, homeChainTimelockAddress, owner) - } + testhelpers.AssertTimelockOwnership(t, e, allChains, state) } diff --git a/deployment/ccip/changeset/cs_active_candidate_test.go b/deployment/ccip/changeset/cs_active_candidate_test.go index 7c50fbc77d0..a3a0505b950 100644 --- a/deployment/ccip/changeset/cs_active_candidate_test.go +++ b/deployment/ccip/changeset/cs_active_candidate_test.go @@ -1,4 +1,4 @@ -package changeset +package changeset_test import ( "math/big" @@ -10,7 +10,9 @@ import ( "github.com/smartcontractkit/chainlink-testing-framework/lib/utils/testcontext" + "github.com/smartcontractkit/chainlink/deployment/ccip/changeset" "github.com/smartcontractkit/chainlink/deployment/ccip/changeset/internal" + "github.com/smartcontractkit/chainlink/deployment/ccip/changeset/testhelpers" commonchangeset "github.com/smartcontractkit/chainlink/deployment/common/changeset" "github.com/stretchr/testify/require" @@ -26,10 +28,10 @@ func Test_ActiveCandidate(t *testing.T) { // We want to have the active instance execute a few messages // and then setup a candidate instance. The candidate instance // should not be able to transmit anything until we make it active. - tenv, _ := NewMemoryEnvironment(t, - WithChains(2), - WithNodes(4)) - state, err := LoadOnchainState(tenv.Env) + tenv, _ := testhelpers.NewMemoryEnvironment(t, + testhelpers.WithNumOfChains(2), + testhelpers.WithNumOfNodes(4)) + state, err := changeset.LoadOnchainState(tenv.Env) require.NoError(t, err) // Deploy to all chains. @@ -41,9 +43,9 @@ func Test_ActiveCandidate(t *testing.T) { sourceState := state.Chains[source] tenv.Env, err = commonchangeset.ApplyChangesets(t, tenv.Env, tenv.TimelockContracts(t), []commonchangeset.ChangesetApplication{ { - Changeset: commonchangeset.WrapChangeSet(UpdateOnRampsDests), - Config: UpdateOnRampDestsConfig{ - UpdatesByChain: map[uint64]map[uint64]OnRampDestinationUpdate{ + Changeset: commonchangeset.WrapChangeSet(changeset.UpdateOnRampsDestsChangeset), + Config: changeset.UpdateOnRampDestsConfig{ + UpdatesByChain: map[uint64]map[uint64]changeset.OnRampDestinationUpdate{ source: { dest: { IsEnabled: true, @@ -54,35 +56,35 @@ func Test_ActiveCandidate(t *testing.T) { }, }, { - Changeset: commonchangeset.WrapChangeSet(UpdateFeeQuoterPricesCS), - Config: UpdateFeeQuoterPricesConfig{ - PricesByChain: map[uint64]FeeQuoterPriceUpdatePerSource{ + Changeset: commonchangeset.WrapChangeSet(changeset.UpdateFeeQuoterPricesChangeset), + Config: changeset.UpdateFeeQuoterPricesConfig{ + PricesByChain: map[uint64]changeset.FeeQuoterPriceUpdatePerSource{ source: { TokenPrices: map[common.Address]*big.Int{ - sourceState.LinkToken.Address(): DefaultLinkPrice, - sourceState.Weth9.Address(): DefaultWethPrice, + sourceState.LinkToken.Address(): testhelpers.DefaultLinkPrice, + sourceState.Weth9.Address(): testhelpers.DefaultWethPrice, }, GasPrices: map[uint64]*big.Int{ - dest: DefaultGasPrice, + dest: testhelpers.DefaultGasPrice, }, }, }, }, }, { - Changeset: commonchangeset.WrapChangeSet(UpdateFeeQuoterDests), - Config: UpdateFeeQuoterDestsConfig{ + Changeset: commonchangeset.WrapChangeSet(changeset.UpdateFeeQuoterDestsChangeset), + Config: changeset.UpdateFeeQuoterDestsConfig{ UpdatesByChain: map[uint64]map[uint64]fee_quoter.FeeQuoterDestChainConfig{ source: { - dest: DefaultFeeQuoterDestChainConfig(), + dest: changeset.DefaultFeeQuoterDestChainConfig(), }, }, }, }, { - Changeset: commonchangeset.WrapChangeSet(UpdateOffRampSources), - Config: UpdateOffRampSourcesConfig{ - UpdatesByChain: map[uint64]map[uint64]OffRampSourceUpdate{ + Changeset: commonchangeset.WrapChangeSet(changeset.UpdateOffRampSourcesChangeset), + Config: changeset.UpdateOffRampSourcesConfig{ + UpdatesByChain: map[uint64]map[uint64]changeset.OffRampSourceUpdate{ dest: { source: { IsEnabled: true, @@ -92,9 +94,9 @@ func Test_ActiveCandidate(t *testing.T) { }, }, { - Changeset: commonchangeset.WrapChangeSet(UpdateRouterRamps), - Config: UpdateRouterRampsConfig{ - UpdatesByChain: map[uint64]RouterUpdates{ + Changeset: commonchangeset.WrapChangeSet(changeset.UpdateRouterRampsChangeset), + Config: changeset.UpdateRouterRampsConfig{ + UpdatesByChain: map[uint64]changeset.RouterUpdates{ // onRamp update on source chain source: { OnRampUpdates: map[uint64]bool{ @@ -125,17 +127,17 @@ func Test_ActiveCandidate(t *testing.T) { _, err = commonchangeset.ApplyChangesets(t, tenv.Env, tenv.TimelockContracts(t), []commonchangeset.ChangesetApplication{ { Changeset: commonchangeset.WrapChangeSet(commonchangeset.TransferToMCMSWithTimelock), - Config: genTestTransferOwnershipConfig(tenv, allChains, state), + Config: testhelpers.GenTestTransferOwnershipConfig(tenv, allChains, state), }, }) require.NoError(t, err) - assertTimelockOwnership(t, tenv, allChains, state) + testhelpers.AssertTimelockOwnership(t, tenv, allChains, state) sendMsg := func() { latesthdr, err := tenv.Env.Chains[dest].Client.HeaderByNumber(testcontext.Get(t), nil) require.NoError(t, err) block := latesthdr.Number.Uint64() - msgSentEvent := TestSendRequest(t, tenv.Env, state, source, dest, false, router.ClientEVM2AnyMessage{ + msgSentEvent := testhelpers.TestSendRequest(t, tenv.Env, state, source, dest, false, router.ClientEVM2AnyMessage{ Receiver: common.LeftPadBytes(state.Chains[dest].Receiver.Address().Bytes(), 32), Data: []byte("hello world"), TokenAmounts: nil, @@ -147,13 +149,13 @@ func Test_ActiveCandidate(t *testing.T) { startBlocks = map[uint64]*uint64{ dest: &block, } - expectedSeqNum = map[SourceDestPair]uint64{ + expectedSeqNum = map[testhelpers.SourceDestPair]uint64{ { SourceChainSelector: source, DestChainSelector: dest, }: msgSentEvent.SequenceNumber, } - expectedSeqNumExec = map[SourceDestPair][]uint64{ + expectedSeqNumExec = map[testhelpers.SourceDestPair][]uint64{ { SourceChainSelector: source, DestChainSelector: dest, @@ -162,8 +164,8 @@ func Test_ActiveCandidate(t *testing.T) { ) // Confirm execution of the message - ConfirmCommitForAllWithExpectedSeqNums(t, tenv.Env, state, expectedSeqNum, startBlocks) - ConfirmExecWithSeqNrsForAll(t, tenv.Env, state, expectedSeqNumExec, startBlocks) + testhelpers.ConfirmCommitForAllWithExpectedSeqNums(t, tenv.Env, state, expectedSeqNum, startBlocks) + testhelpers.ConfirmExecWithSeqNrsForAll(t, tenv.Env, state, expectedSeqNumExec, startBlocks) } // send a message from source to dest and ensure that it gets executed @@ -188,30 +190,34 @@ func Test_ActiveCandidate(t *testing.T) { // Now we can add a candidate config, send another request, and observe behavior. // The candidate config should not be able to execute messages. - tokenConfig := NewTestTokenConfig(state.Chains[tenv.FeedChainSel].USDFeeds) + tokenConfig := changeset.NewTestTokenConfig(state.Chains[tenv.FeedChainSel].USDFeeds) _, err = commonchangeset.ApplyChangesets(t, tenv.Env, tenv.TimelockContracts(t), []commonchangeset.ChangesetApplication{ { - Changeset: commonchangeset.WrapChangeSet(SetCandidateChangeset), - Config: SetCandidateChangesetConfig{ - SetCandidateConfigBase: SetCandidateConfigBase{ + Changeset: commonchangeset.WrapChangeSet(changeset.SetCandidateChangeset), + Config: changeset.SetCandidateChangesetConfig{ + SetCandidateConfigBase: changeset.SetCandidateConfigBase{ HomeChainSelector: tenv.HomeChainSel, FeedChainSelector: tenv.FeedChainSel, - MCMS: &MCMSConfig{ + MCMS: &changeset.MCMSConfig{ MinDelay: 0, }, }, - PluginInfo: []SetCandidatePluginInfo{ + PluginInfo: []changeset.SetCandidatePluginInfo{ { // NOTE: this is technically not a new chain, but needed for validation. - OCRConfigPerRemoteChainSelector: map[uint64]CCIPOCRParams{ - dest: DefaultOCRParams(tenv.FeedChainSel, tokenConfig.GetTokenInfo(logger.TestLogger(t), state.Chains[dest].LinkToken, state.Chains[dest].Weth9), nil, true, false), + OCRConfigPerRemoteChainSelector: map[uint64]changeset.CCIPOCRParams{ + dest: changeset.DeriveCCIPOCRParams( + changeset.WithDefaultCommitOffChainConfig(tenv.FeedChainSel, tokenConfig.GetTokenInfo(logger.TestLogger(t), state.Chains[dest].LinkToken, state.Chains[dest].Weth9)), + ), }, PluginType: types.PluginTypeCCIPCommit, }, { // NOTE: this is technically not a new chain, but needed for validation. - OCRConfigPerRemoteChainSelector: map[uint64]CCIPOCRParams{ - dest: DefaultOCRParams(tenv.FeedChainSel, tokenConfig.GetTokenInfo(logger.TestLogger(t), state.Chains[dest].LinkToken, state.Chains[dest].Weth9), nil, false, true), + OCRConfigPerRemoteChainSelector: map[uint64]changeset.CCIPOCRParams{ + dest: changeset.DeriveCCIPOCRParams( + changeset.WithDefaultExecuteOffChainConfig(nil), + ), }, PluginType: types.PluginTypeCCIPExec, }, diff --git a/deployment/ccip/changeset/cs_add_lane_test.go b/deployment/ccip/changeset/cs_add_lane_test.go index 4b9f1f8641f..18f86d98a68 100644 --- a/deployment/ccip/changeset/cs_add_lane_test.go +++ b/deployment/ccip/changeset/cs_add_lane_test.go @@ -1,4 +1,4 @@ -package changeset +package changeset_test import ( "testing" @@ -8,37 +8,39 @@ import ( "github.com/smartcontractkit/chainlink-testing-framework/lib/utils/testcontext" + "github.com/smartcontractkit/chainlink/deployment/ccip/changeset" + "github.com/smartcontractkit/chainlink/deployment/ccip/changeset/testhelpers" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/router" ) func TestAddLanesWithTestRouter(t *testing.T) { t.Parallel() - e, _ := NewMemoryEnvironment(t) + e, _ := testhelpers.NewMemoryEnvironment(t) // Here we have CR + nodes set up, but no CCIP contracts deployed. - state, err := LoadOnchainState(e.Env) + state, err := changeset.LoadOnchainState(e.Env) require.NoError(t, err) selectors := e.Env.AllChainSelectors() chain1, chain2 := selectors[0], selectors[1] - AddLaneWithDefaultPricesAndFeeQuoterConfig(t, &e, state, chain1, chain2, true) + testhelpers.AddLaneWithDefaultPricesAndFeeQuoterConfig(t, &e, state, chain1, chain2, true) // Need to keep track of the block number for each chain so that event subscription can be done from that block. startBlocks := make(map[uint64]*uint64) // Send a message from each chain to every other chain. - expectedSeqNumExec := make(map[SourceDestPair][]uint64) + expectedSeqNumExec := make(map[testhelpers.SourceDestPair][]uint64) latesthdr, err := e.Env.Chains[chain2].Client.HeaderByNumber(testcontext.Get(t), nil) require.NoError(t, err) block := latesthdr.Number.Uint64() startBlocks[chain2] = &block - msgSentEvent := TestSendRequest(t, e.Env, state, chain1, chain2, true, router.ClientEVM2AnyMessage{ + msgSentEvent := testhelpers.TestSendRequest(t, e.Env, state, chain1, chain2, true, router.ClientEVM2AnyMessage{ Receiver: common.LeftPadBytes(state.Chains[chain2].Receiver.Address().Bytes(), 32), Data: []byte("hello"), TokenAmounts: nil, FeeToken: common.HexToAddress("0x0"), ExtraArgs: nil, }) - expectedSeqNumExec[SourceDestPair{ + expectedSeqNumExec[testhelpers.SourceDestPair{ SourceChainSelector: chain1, DestChainSelector: chain2, }] = []uint64{msgSentEvent.SequenceNumber} - ConfirmExecWithSeqNrsForAll(t, e.Env, state, expectedSeqNumExec, startBlocks) + testhelpers.ConfirmExecWithSeqNrsForAll(t, e.Env, state, expectedSeqNumExec, startBlocks) } diff --git a/deployment/ccip/changeset/cs_ccip_home.go b/deployment/ccip/changeset/cs_ccip_home.go index 12f488d1cfd..ef173e5ed07 100644 --- a/deployment/ccip/changeset/cs_ccip_home.go +++ b/deployment/ccip/changeset/cs_ccip_home.go @@ -39,7 +39,7 @@ var ( _ deployment.ChangeSet[PromoteCandidateChangesetConfig] = PromoteCandidateChangeset _ deployment.ChangeSet[SetCandidateChangesetConfig] = SetCandidateChangeset _ deployment.ChangeSet[RevokeCandidateChangesetConfig] = RevokeCandidateChangeset - _ deployment.ChangeSet[UpdateChainConfigConfig] = UpdateChainConfig + _ deployment.ChangeSet[UpdateChainConfigConfig] = UpdateChainConfigChangeset ) type tokenInfo interface { @@ -171,14 +171,66 @@ func (c CCIPOCRParams) Validate(selector uint64, feedChainSel uint64, state CCIP return nil } -// DefaultOCRParams returns the default OCR parameters for a chain, -// except for a few values which must be parameterized (passed as arguments). -func DefaultOCRParams( - feedChainSel uint64, - tokenInfo map[ccipocr3.UnknownEncodedAddress]pluginconfig.TokenInfo, - tokenDataObservers []pluginconfig.TokenDataObserverConfig, - commit bool, - exec bool, +type CCIPOCROpts func(params *CCIPOCRParams) + +// WithOCRParamOverride can be used if you want to override the default OCR parameters with your custom function. +func WithOCRParamOverride(override func(params *CCIPOCRParams)) CCIPOCROpts { + return func(params *CCIPOCRParams) { + if override != nil { + override(params) + } + } +} + +// WithDefaultCommitOffChainConfig can be used to add token info to the existing commit off-chain config. If no commit off-chain config is set, it will be created with default values. +func WithDefaultCommitOffChainConfig(feedChainSel uint64, tokenInfo map[ccipocr3.UnknownEncodedAddress]pluginconfig.TokenInfo) CCIPOCROpts { + return func(params *CCIPOCRParams) { + if params.CommitOffChainConfig == nil { + params.CommitOffChainConfig = &pluginconfig.CommitOffchainConfig{ + RemoteGasPriceBatchWriteFrequency: *config.MustNewDuration(internal.RemoteGasPriceBatchWriteFrequency), + TokenPriceBatchWriteFrequency: *config.MustNewDuration(internal.TokenPriceBatchWriteFrequency), + TokenInfo: tokenInfo, + PriceFeedChainSelector: ccipocr3.ChainSelector(feedChainSel), + NewMsgScanBatchSize: merklemulti.MaxNumberTreeLeaves, + MaxReportTransmissionCheckAttempts: 5, + RMNEnabled: os.Getenv("ENABLE_RMN") == "true", // only enabled in manual test + RMNSignaturesTimeout: 30 * time.Minute, + MaxMerkleTreeSize: merklemulti.MaxNumberTreeLeaves, + SignObservationPrefix: "chainlink ccip 1.6 rmn observation", + } + } else { + if params.CommitOffChainConfig.TokenInfo == nil { + params.CommitOffChainConfig.TokenInfo = make(map[ccipocr3.UnknownEncodedAddress]pluginconfig.TokenInfo) + } + for k, v := range tokenInfo { + params.CommitOffChainConfig.TokenInfo[k] = v + } + } + } +} + +// WithDefaultExecuteOffChainConfig can be used to add token data observers to the execute off-chain config. If no execute off-chain config is set, it will be created with default values. +func WithDefaultExecuteOffChainConfig(tokenDataObservers []pluginconfig.TokenDataObserverConfig) CCIPOCROpts { + return func(params *CCIPOCRParams) { + if params.ExecuteOffChainConfig == nil { + params.ExecuteOffChainConfig = &pluginconfig.ExecuteOffchainConfig{ + BatchGasLimit: internal.BatchGasLimit, + RelativeBoostPerWaitHour: internal.RelativeBoostPerWaitHour, + InflightCacheExpiry: *config.MustNewDuration(internal.InflightCacheExpiry), + RootSnoozeTime: *config.MustNewDuration(internal.RootSnoozeTime), + MessageVisibilityInterval: *config.MustNewDuration(internal.FirstBlockAge), + BatchingStrategyID: internal.BatchingStrategyID, + TokenDataObservers: tokenDataObservers, + } + } else if tokenDataObservers != nil { + params.ExecuteOffChainConfig.TokenDataObservers = append(params.ExecuteOffChainConfig.TokenDataObservers, tokenDataObservers...) + } + } +} + +// DeriveCCIPOCRParams derives the default OCR parameters for a chain, with the option to override them. +func DeriveCCIPOCRParams( + opts ...CCIPOCROpts, ) CCIPOCRParams { params := CCIPOCRParams{ OCRParameters: commontypes.OCRParameters{ @@ -196,30 +248,8 @@ func DefaultOCRParams( MaxDurationShouldTransmitAcceptedReport: internal.MaxDurationShouldTransmitAcceptedReport, }, } - if exec { - params.ExecuteOffChainConfig = &pluginconfig.ExecuteOffchainConfig{ - BatchGasLimit: internal.BatchGasLimit, - RelativeBoostPerWaitHour: internal.RelativeBoostPerWaitHour, - InflightCacheExpiry: *config.MustNewDuration(internal.InflightCacheExpiry), - RootSnoozeTime: *config.MustNewDuration(internal.RootSnoozeTime), - MessageVisibilityInterval: *config.MustNewDuration(internal.FirstBlockAge), - BatchingStrategyID: internal.BatchingStrategyID, - TokenDataObservers: tokenDataObservers, - } - } - if commit { - params.CommitOffChainConfig = &pluginconfig.CommitOffchainConfig{ - RemoteGasPriceBatchWriteFrequency: *config.MustNewDuration(internal.RemoteGasPriceBatchWriteFrequency), - TokenPriceBatchWriteFrequency: *config.MustNewDuration(internal.TokenPriceBatchWriteFrequency), - TokenInfo: tokenInfo, - PriceFeedChainSelector: ccipocr3.ChainSelector(feedChainSel), - NewMsgScanBatchSize: merklemulti.MaxNumberTreeLeaves, - MaxReportTransmissionCheckAttempts: 5, - RMNEnabled: os.Getenv("ENABLE_RMN") == "true", // only enabled in manual test - RMNSignaturesTimeout: 30 * time.Minute, - MaxMerkleTreeSize: merklemulti.MaxNumberTreeLeaves, - SignObservationPrefix: "chainlink ccip 1.6 rmn observation", - } + for _, opt := range opts { + opt(¶ms) } return params } @@ -1217,7 +1247,7 @@ func (c UpdateChainConfigConfig) Validate(e deployment.Environment) error { return nil } -func UpdateChainConfig(e deployment.Environment, cfg UpdateChainConfigConfig) (deployment.ChangesetOutput, error) { +func UpdateChainConfigChangeset(e deployment.Environment, cfg UpdateChainConfigConfig) (deployment.ChangesetOutput, error) { if err := cfg.Validate(e); err != nil { return deployment.ChangesetOutput{}, fmt.Errorf("%w: %w", deployment.ErrInvalidConfig, err) } diff --git a/deployment/ccip/changeset/cs_ccip_home_test.go b/deployment/ccip/changeset/cs_ccip_home_test.go index 96220477384..73fd921d503 100644 --- a/deployment/ccip/changeset/cs_ccip_home_test.go +++ b/deployment/ccip/changeset/cs_ccip_home_test.go @@ -1,4 +1,4 @@ -package changeset +package changeset_test import ( "math/big" @@ -15,7 +15,9 @@ import ( "github.com/smartcontractkit/chainlink-testing-framework/lib/utils/testcontext" "github.com/smartcontractkit/chainlink/deployment" + "github.com/smartcontractkit/chainlink/deployment/ccip/changeset" "github.com/smartcontractkit/chainlink/deployment/ccip/changeset/internal" + "github.com/smartcontractkit/chainlink/deployment/ccip/changeset/testhelpers" "github.com/smartcontractkit/chainlink/v2/core/capabilities/ccip/types" "github.com/smartcontractkit/chainlink/v2/core/logger" @@ -26,8 +28,8 @@ import ( ) func TestInvalidOCR3Params(t *testing.T) { - e, _ := NewMemoryEnvironment(t, - WithPrerequisiteDeployment(nil)) + e, _ := testhelpers.NewMemoryEnvironment(t, + testhelpers.WithPrerequisiteDeploymentOnly(nil)) chain1 := e.Env.AllChainSelectors()[0] envNodes, err := deployment.NodeInfo(e.Env.NodeIDs, e.Env.Offchain) require.NoError(t, err) @@ -35,20 +37,20 @@ func TestInvalidOCR3Params(t *testing.T) { // no proposals to be made, timelock can be passed as nil here e.Env, err = commonchangeset.ApplyChangesets(t, e.Env, nil, []commonchangeset.ChangesetApplication{ { - Changeset: commonchangeset.WrapChangeSet(DeployHomeChain), - Config: DeployHomeChainConfig{ + Changeset: commonchangeset.WrapChangeSet(changeset.DeployHomeChainChangeset), + Config: changeset.DeployHomeChainConfig{ HomeChainSel: e.HomeChainSel, - RMNDynamicConfig: NewTestRMNDynamicConfig(), - RMNStaticConfig: NewTestRMNStaticConfig(), - NodeOperators: NewTestNodeOperator(e.Env.Chains[e.HomeChainSel].DeployerKey.From), + RMNDynamicConfig: testhelpers.NewTestRMNDynamicConfig(), + RMNStaticConfig: testhelpers.NewTestRMNStaticConfig(), + NodeOperators: testhelpers.NewTestNodeOperator(e.Env.Chains[e.HomeChainSel].DeployerKey.From), NodeP2PIDsPerNodeOpAdmin: map[string][][32]byte{ - TestNodeOperator: envNodes.NonBootstraps().PeerIDs(), + testhelpers.TestNodeOperator: envNodes.NonBootstraps().PeerIDs(), }, }, }, { - Changeset: commonchangeset.WrapChangeSet(DeployChainContracts), - Config: DeployChainContractsConfig{ + Changeset: commonchangeset.WrapChangeSet(changeset.DeployChainContractsChangeset), + Config: changeset.DeployChainContractsConfig{ ChainSelectors: []uint64{chain1}, HomeChainSelector: e.HomeChainSel, }, @@ -56,11 +58,14 @@ func TestInvalidOCR3Params(t *testing.T) { }) require.NoError(t, err) - state, err := LoadOnchainState(e.Env) + state, err := changeset.LoadOnchainState(e.Env) require.NoError(t, err) nodes, err := deployment.NodeInfo(e.Env.NodeIDs, e.Env.Offchain) require.NoError(t, err) - params := DefaultOCRParams(e.FeedChainSel, nil, nil, true, true) + params := changeset.DeriveCCIPOCRParams( + changeset.WithDefaultCommitOffChainConfig(e.FeedChainSel, nil), + changeset.WithDefaultExecuteOffChainConfig(nil), + ) // tweak params to have invalid config // make DeltaRound greater than DeltaProgress params.OCRParameters.DeltaRound = params.OCRParameters.DeltaProgress + time.Duration(1) @@ -97,10 +102,10 @@ func Test_PromoteCandidate(t *testing.T) { } { t.Run(tc.name, func(t *testing.T) { ctx := testcontext.Get(t) - tenv, _ := NewMemoryEnvironment(t, - WithChains(2), - WithNodes(4)) - state, err := LoadOnchainState(tenv.Env) + tenv, _ := testhelpers.NewMemoryEnvironment(t, + testhelpers.WithNumOfChains(2), + testhelpers.WithNumOfNodes(4)) + state, err := changeset.LoadOnchainState(tenv.Env) require.NoError(t, err) // Deploy to all chains. @@ -132,9 +137,9 @@ func Test_PromoteCandidate(t *testing.T) { require.NoError(t, err) require.NotEqual(t, [32]byte{}, ActiveDigestExecBefore) - var mcmsConfig *MCMSConfig + var mcmsConfig *changeset.MCMSConfig if tc.mcmsEnabled { - mcmsConfig = &MCMSConfig{ + mcmsConfig = &changeset.MCMSConfig{ MinDelay: 0, } } @@ -146,10 +151,10 @@ func Test_PromoteCandidate(t *testing.T) { }, }, []commonchangeset.ChangesetApplication{ { - Changeset: commonchangeset.WrapChangeSet(PromoteCandidateChangeset), - Config: PromoteCandidateChangesetConfig{ + Changeset: commonchangeset.WrapChangeSet(changeset.PromoteCandidateChangeset), + Config: changeset.PromoteCandidateChangesetConfig{ HomeChainSelector: tenv.HomeChainSel, - PluginInfo: []PromoteCandidatePluginInfo{ + PluginInfo: []changeset.PromoteCandidatePluginInfo{ { RemoteChainSelectors: []uint64{dest}, PluginType: types.PluginTypeCCIPCommit, @@ -193,10 +198,10 @@ func Test_SetCandidate(t *testing.T) { } { t.Run(tc.name, func(t *testing.T) { ctx := testcontext.Get(t) - tenv, _ := NewMemoryEnvironment(t, - WithChains(2), - WithNodes(4)) - state, err := LoadOnchainState(tenv.Env) + tenv, _ := testhelpers.NewMemoryEnvironment(t, + testhelpers.WithNumOfChains(2), + testhelpers.WithNumOfNodes(4)) + state, err := changeset.LoadOnchainState(tenv.Env) require.NoError(t, err) // Deploy to all chains. @@ -227,13 +232,13 @@ func Test_SetCandidate(t *testing.T) { require.NoError(t, err) require.Equal(t, [32]byte{}, candidateDigestExecBefore) - var mcmsConfig *MCMSConfig + var mcmsConfig *changeset.MCMSConfig if tc.mcmsEnabled { - mcmsConfig = &MCMSConfig{ + mcmsConfig = &changeset.MCMSConfig{ MinDelay: 0, } } - tokenConfig := NewTestTokenConfig(state.Chains[tenv.FeedChainSel].USDFeeds) + tokenConfig := changeset.NewTestTokenConfig(state.Chains[tenv.FeedChainSel].USDFeeds) _, err = commonchangeset.ApplyChangesets(t, tenv.Env, map[uint64]*proposalutils.TimelockExecutionContracts{ tenv.HomeChainSel: { Timelock: state.Chains[tenv.HomeChainSel].Timelock, @@ -241,23 +246,27 @@ func Test_SetCandidate(t *testing.T) { }, }, []commonchangeset.ChangesetApplication{ { - Changeset: commonchangeset.WrapChangeSet(SetCandidateChangeset), - Config: SetCandidateChangesetConfig{ - SetCandidateConfigBase: SetCandidateConfigBase{ + Changeset: commonchangeset.WrapChangeSet(changeset.SetCandidateChangeset), + Config: changeset.SetCandidateChangesetConfig{ + SetCandidateConfigBase: changeset.SetCandidateConfigBase{ HomeChainSelector: tenv.HomeChainSel, FeedChainSelector: tenv.FeedChainSel, MCMS: mcmsConfig, }, - PluginInfo: []SetCandidatePluginInfo{ + PluginInfo: []changeset.SetCandidatePluginInfo{ { - OCRConfigPerRemoteChainSelector: map[uint64]CCIPOCRParams{ - dest: DefaultOCRParams(tenv.FeedChainSel, tokenConfig.GetTokenInfo(logger.TestLogger(t), state.Chains[dest].LinkToken, state.Chains[dest].Weth9), nil, true, false), + OCRConfigPerRemoteChainSelector: map[uint64]changeset.CCIPOCRParams{ + dest: changeset.DeriveCCIPOCRParams( + changeset.WithDefaultCommitOffChainConfig(tenv.FeedChainSel, tokenConfig.GetTokenInfo(logger.TestLogger(t), state.Chains[dest].LinkToken, state.Chains[dest].Weth9)), + ), }, PluginType: types.PluginTypeCCIPCommit, }, { - OCRConfigPerRemoteChainSelector: map[uint64]CCIPOCRParams{ - dest: DefaultOCRParams(tenv.FeedChainSel, tokenConfig.GetTokenInfo(logger.TestLogger(t), state.Chains[dest].LinkToken, state.Chains[dest].Weth9), nil, false, true), + OCRConfigPerRemoteChainSelector: map[uint64]changeset.CCIPOCRParams{ + dest: changeset.DeriveCCIPOCRParams( + changeset.WithDefaultExecuteOffChainConfig(nil), + ), }, PluginType: types.PluginTypeCCIPExec, }, @@ -302,10 +311,10 @@ func Test_RevokeCandidate(t *testing.T) { } { t.Run(tc.name, func(t *testing.T) { ctx := testcontext.Get(t) - tenv, _ := NewMemoryEnvironment(t, - WithChains(2), - WithNodes(4)) - state, err := LoadOnchainState(tenv.Env) + tenv, _ := testhelpers.NewMemoryEnvironment(t, + testhelpers.WithNumOfChains(2), + testhelpers.WithNumOfNodes(4)) + state, err := changeset.LoadOnchainState(tenv.Env) require.NoError(t, err) // Deploy to all chains. @@ -336,13 +345,13 @@ func Test_RevokeCandidate(t *testing.T) { require.NoError(t, err) require.Equal(t, [32]byte{}, candidateDigestExecBefore) - var mcmsConfig *MCMSConfig + var mcmsConfig *changeset.MCMSConfig if tc.mcmsEnabled { - mcmsConfig = &MCMSConfig{ + mcmsConfig = &changeset.MCMSConfig{ MinDelay: 0, } } - tokenConfig := NewTestTokenConfig(state.Chains[tenv.FeedChainSel].USDFeeds) + tokenConfig := changeset.NewTestTokenConfig(state.Chains[tenv.FeedChainSel].USDFeeds) _, err = commonchangeset.ApplyChangesets(t, tenv.Env, map[uint64]*proposalutils.TimelockExecutionContracts{ tenv.HomeChainSel: { Timelock: state.Chains[tenv.HomeChainSel].Timelock, @@ -350,23 +359,27 @@ func Test_RevokeCandidate(t *testing.T) { }, }, []commonchangeset.ChangesetApplication{ { - Changeset: commonchangeset.WrapChangeSet(SetCandidateChangeset), - Config: SetCandidateChangesetConfig{ - SetCandidateConfigBase: SetCandidateConfigBase{ + Changeset: commonchangeset.WrapChangeSet(changeset.SetCandidateChangeset), + Config: changeset.SetCandidateChangesetConfig{ + SetCandidateConfigBase: changeset.SetCandidateConfigBase{ HomeChainSelector: tenv.HomeChainSel, FeedChainSelector: tenv.FeedChainSel, MCMS: mcmsConfig, }, - PluginInfo: []SetCandidatePluginInfo{ + PluginInfo: []changeset.SetCandidatePluginInfo{ { - OCRConfigPerRemoteChainSelector: map[uint64]CCIPOCRParams{ - dest: DefaultOCRParams(tenv.FeedChainSel, tokenConfig.GetTokenInfo(logger.TestLogger(t), state.Chains[dest].LinkToken, state.Chains[dest].Weth9), nil, true, true), + OCRConfigPerRemoteChainSelector: map[uint64]changeset.CCIPOCRParams{ + dest: changeset.DeriveCCIPOCRParams( + changeset.WithDefaultCommitOffChainConfig(tenv.FeedChainSel, tokenConfig.GetTokenInfo(logger.TestLogger(t), state.Chains[dest].LinkToken, state.Chains[dest].Weth9)), + ), }, PluginType: types.PluginTypeCCIPCommit, }, { - OCRConfigPerRemoteChainSelector: map[uint64]CCIPOCRParams{ - dest: DefaultOCRParams(tenv.FeedChainSel, tokenConfig.GetTokenInfo(logger.TestLogger(t), state.Chains[dest].LinkToken, state.Chains[dest].Weth9), nil, true, true), + OCRConfigPerRemoteChainSelector: map[uint64]changeset.CCIPOCRParams{ + dest: changeset.DeriveCCIPOCRParams( + changeset.WithDefaultExecuteOffChainConfig(nil), + ), }, PluginType: types.PluginTypeCCIPExec, }, @@ -400,8 +413,8 @@ func Test_RevokeCandidate(t *testing.T) { }, }, []commonchangeset.ChangesetApplication{ { - Changeset: commonchangeset.WrapChangeSet(RevokeCandidateChangeset), - Config: RevokeCandidateChangesetConfig{ + Changeset: commonchangeset.WrapChangeSet(changeset.RevokeCandidateChangeset), + Config: changeset.RevokeCandidateChangesetConfig{ HomeChainSelector: tenv.HomeChainSel, RemoteChainSelector: dest, PluginType: types.PluginTypeCCIPCommit, @@ -409,8 +422,8 @@ func Test_RevokeCandidate(t *testing.T) { }, }, { - Changeset: commonchangeset.WrapChangeSet(RevokeCandidateChangeset), - Config: RevokeCandidateChangesetConfig{ + Changeset: commonchangeset.WrapChangeSet(changeset.RevokeCandidateChangeset), + Config: changeset.RevokeCandidateChangesetConfig{ HomeChainSelector: tenv.HomeChainSel, RemoteChainSelector: dest, PluginType: types.PluginTypeCCIPExec, @@ -438,8 +451,8 @@ func Test_RevokeCandidate(t *testing.T) { func transferToTimelock( t *testing.T, - tenv DeployedEnv, - state CCIPOnChainState, + tenv testhelpers.DeployedEnv, + state changeset.CCIPOnChainState, source, dest uint64) { // Transfer ownership to timelock so that we can promote the zero digest later down the line. @@ -459,11 +472,11 @@ func transferToTimelock( }, []commonchangeset.ChangesetApplication{ { Changeset: commonchangeset.WrapChangeSet(commonchangeset.TransferToMCMSWithTimelock), - Config: genTestTransferOwnershipConfig(tenv, []uint64{source, dest}, state), + Config: testhelpers.GenTestTransferOwnershipConfig(tenv, []uint64{source, dest}, state), }, }) require.NoError(t, err) - assertTimelockOwnership(t, tenv, []uint64{source, dest}, state) + testhelpers.AssertTimelockOwnership(t, tenv, []uint64{source, dest}, state) } func Test_UpdateChainConfigs(t *testing.T) { @@ -481,8 +494,8 @@ func Test_UpdateChainConfigs(t *testing.T) { }, } { t.Run(tc.name, func(t *testing.T) { - tenv, _ := NewMemoryEnvironment(t, WithChains(3)) - state, err := LoadOnchainState(tenv.Env) + tenv, _ := testhelpers.NewMemoryEnvironment(t, testhelpers.WithNumOfChains(3)) + state, err := changeset.LoadOnchainState(tenv.Env) require.NoError(t, err) allChains := maps.Keys(tenv.Env.Chains) @@ -500,9 +513,9 @@ func Test_UpdateChainConfigs(t *testing.T) { require.NoError(t, err) assert.NotZero(t, otherChainConfig.FChain) - var mcmsConfig *MCMSConfig + var mcmsConfig *changeset.MCMSConfig if tc.mcmsEnabled { - mcmsConfig = &MCMSConfig{ + mcmsConfig = &changeset.MCMSConfig{ MinDelay: 0, } } @@ -513,11 +526,11 @@ func Test_UpdateChainConfigs(t *testing.T) { }, }, []commonchangeset.ChangesetApplication{ { - Changeset: commonchangeset.WrapChangeSet(UpdateChainConfig), - Config: UpdateChainConfigConfig{ + Changeset: commonchangeset.WrapChangeSet(changeset.UpdateChainConfigChangeset), + Config: changeset.UpdateChainConfigConfig{ HomeChainSelector: tenv.HomeChainSel, RemoteChainRemoves: []uint64{otherChain}, - RemoteChainAdds: make(map[uint64]ChainConfig), + RemoteChainAdds: make(map[uint64]changeset.ChainConfig), MCMS: mcmsConfig, }, }, @@ -537,11 +550,11 @@ func Test_UpdateChainConfigs(t *testing.T) { }, }, []commonchangeset.ChangesetApplication{ { - Changeset: commonchangeset.WrapChangeSet(UpdateChainConfig), - Config: UpdateChainConfigConfig{ + Changeset: commonchangeset.WrapChangeSet(changeset.UpdateChainConfigChangeset), + Config: changeset.UpdateChainConfigConfig{ HomeChainSelector: tenv.HomeChainSel, RemoteChainRemoves: []uint64{}, - RemoteChainAdds: map[uint64]ChainConfig{ + RemoteChainAdds: map[uint64]changeset.ChainConfig{ otherChain: { EncodableChainConfig: chainconfig.ChainConfig{ GasPriceDeviationPPB: cciptypes.BigInt{Int: big.NewInt(internal.GasPriceDeviationPPB)}, diff --git a/deployment/ccip/changeset/cs_chain_contracts.go b/deployment/ccip/changeset/cs_chain_contracts.go index 8b50aa2fd3c..64e7ca295d7 100644 --- a/deployment/ccip/changeset/cs_chain_contracts.go +++ b/deployment/ccip/changeset/cs_chain_contracts.go @@ -31,13 +31,13 @@ import ( ) var ( - _ deployment.ChangeSet[UpdateOnRampDestsConfig] = UpdateOnRampsDests - _ deployment.ChangeSet[UpdateOffRampSourcesConfig] = UpdateOffRampSources - _ deployment.ChangeSet[UpdateRouterRampsConfig] = UpdateRouterRamps - _ deployment.ChangeSet[UpdateFeeQuoterDestsConfig] = UpdateFeeQuoterDests - _ deployment.ChangeSet[SetOCR3OffRampConfig] = SetOCR3OffRamp - _ deployment.ChangeSet[UpdateFeeQuoterPricesConfig] = UpdateFeeQuoterPricesCS - _ deployment.ChangeSet[UpdateNonceManagerConfig] = UpdateNonceManagersCS + _ deployment.ChangeSet[UpdateOnRampDestsConfig] = UpdateOnRampsDestsChangeset + _ deployment.ChangeSet[UpdateOffRampSourcesConfig] = UpdateOffRampSourcesChangeset + _ deployment.ChangeSet[UpdateRouterRampsConfig] = UpdateRouterRampsChangeset + _ deployment.ChangeSet[UpdateFeeQuoterDestsConfig] = UpdateFeeQuoterDestsChangeset + _ deployment.ChangeSet[SetOCR3OffRampConfig] = SetOCR3OffRampChangeset + _ deployment.ChangeSet[UpdateFeeQuoterPricesConfig] = UpdateFeeQuoterPricesChangeset + _ deployment.ChangeSet[UpdateNonceManagerConfig] = UpdateNonceManagersChangeset ) type UpdateNonceManagerConfig struct { @@ -107,7 +107,7 @@ func (cfg UpdateNonceManagerConfig) Validate(e deployment.Environment) error { return nil } -func UpdateNonceManagersCS(e deployment.Environment, cfg UpdateNonceManagerConfig) (deployment.ChangesetOutput, error) { +func UpdateNonceManagersChangeset(e deployment.Environment, cfg UpdateNonceManagerConfig) (deployment.ChangesetOutput, error) { if err := cfg.Validate(e); err != nil { return deployment.ChangesetOutput{}, err } @@ -272,10 +272,10 @@ func (cfg UpdateOnRampDestsConfig) Validate(e deployment.Environment) error { return nil } -// UpdateOnRampsDests updates the onramp destinations for each onramp +// UpdateOnRampsDestsChangeset updates the onramp destinations for each onramp // in the chains specified. Multichain support is important - consider when we add a new chain // and need to update the onramp destinations for all chains to support the new chain. -func UpdateOnRampsDests(e deployment.Environment, cfg UpdateOnRampDestsConfig) (deployment.ChangesetOutput, error) { +func UpdateOnRampsDestsChangeset(e deployment.Environment, cfg UpdateOnRampDestsConfig) (deployment.ChangesetOutput, error) { if err := cfg.Validate(e); err != nil { return deployment.ChangesetOutput{}, err } @@ -437,7 +437,7 @@ func (cfg UpdateFeeQuoterPricesConfig) Validate(e deployment.Environment) error return nil } -func UpdateFeeQuoterPricesCS(e deployment.Environment, cfg UpdateFeeQuoterPricesConfig) (deployment.ChangesetOutput, error) { +func UpdateFeeQuoterPricesChangeset(e deployment.Environment, cfg UpdateFeeQuoterPricesConfig) (deployment.ChangesetOutput, error) { if err := cfg.Validate(e); err != nil { return deployment.ChangesetOutput{}, err } @@ -559,7 +559,7 @@ func (cfg UpdateFeeQuoterDestsConfig) Validate(e deployment.Environment) error { return nil } -func UpdateFeeQuoterDests(e deployment.Environment, cfg UpdateFeeQuoterDestsConfig) (deployment.ChangesetOutput, error) { +func UpdateFeeQuoterDestsChangeset(e deployment.Environment, cfg UpdateFeeQuoterDestsConfig) (deployment.ChangesetOutput, error) { if err := cfg.Validate(e); err != nil { return deployment.ChangesetOutput{}, err } @@ -680,8 +680,8 @@ func (cfg UpdateOffRampSourcesConfig) Validate(e deployment.Environment) error { return nil } -// UpdateOffRampSources updates the offramp sources for each offramp. -func UpdateOffRampSources(e deployment.Environment, cfg UpdateOffRampSourcesConfig) (deployment.ChangesetOutput, error) { +// UpdateOffRampSourcesChangeset updates the offramp sources for each offramp. +func UpdateOffRampSourcesChangeset(e deployment.Environment, cfg UpdateOffRampSourcesConfig) (deployment.ChangesetOutput, error) { if err := cfg.Validate(e); err != nil { return deployment.ChangesetOutput{}, err } @@ -834,14 +834,14 @@ func (cfg UpdateRouterRampsConfig) Validate(e deployment.Environment) error { return nil } -// UpdateRouterRamps updates the on/offramps +// UpdateRouterRampsChangeset updates the on/offramps // in either the router or test router for a series of chains. Use cases include: // - Ramp upgrade. After deploying new ramps you can enable them on the test router and // ensure it works e2e. Then enable the ramps on the real router. // - New chain support. When adding a new chain, you can enable the new destination // on all chains to support the new chain through the test router first. Once tested, // Enable the new destination on the real router. -func UpdateRouterRamps(e deployment.Environment, cfg UpdateRouterRampsConfig) (deployment.ChangesetOutput, error) { +func UpdateRouterRampsChangeset(e deployment.Environment, cfg UpdateRouterRampsConfig) (deployment.ChangesetOutput, error) { if err := cfg.Validate(e); err != nil { return deployment.ChangesetOutput{}, err } @@ -964,13 +964,13 @@ func (c SetOCR3OffRampConfig) Validate(e deployment.Environment) error { return nil } -// SetOCR3OffRamp will set the OCR3 offramp for the given chain. +// SetOCR3OffRampChangeset will set the OCR3 offramp for the given chain. // to the active configuration on CCIPHome. This // is used to complete the candidate->active promotion cycle, it's // run after the candidate is confirmed to be working correctly. // Multichain is especially helpful for NOP rotations where we have // to touch all the chain to change signers. -func SetOCR3OffRamp(e deployment.Environment, cfg SetOCR3OffRampConfig) (deployment.ChangesetOutput, error) { +func SetOCR3OffRampChangeset(e deployment.Environment, cfg SetOCR3OffRampConfig) (deployment.ChangesetOutput, error) { if err := cfg.Validate(e); err != nil { return deployment.ChangesetOutput{}, err } diff --git a/deployment/ccip/changeset/cs_chain_contracts_test.go b/deployment/ccip/changeset/cs_chain_contracts_test.go index 544362a1b1e..7b7f420e531 100644 --- a/deployment/ccip/changeset/cs_chain_contracts_test.go +++ b/deployment/ccip/changeset/cs_chain_contracts_test.go @@ -1,4 +1,4 @@ -package changeset +package changeset_test import ( "testing" @@ -10,6 +10,8 @@ import ( "github.com/smartcontractkit/chainlink-testing-framework/lib/utils/testcontext" + "github.com/smartcontractkit/chainlink/deployment/ccip/changeset" + "github.com/smartcontractkit/chainlink/deployment/ccip/changeset/testhelpers" commonchangeset "github.com/smartcontractkit/chainlink/deployment/common/changeset" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/fee_quoter" ) @@ -32,8 +34,8 @@ func TestUpdateOnRampsDests(t *testing.T) { ctx := testcontext.Get(t) // Default env just has 2 chains with all contracts // deployed but no lanes. - tenv, _ := NewMemoryEnvironment(t) - state, err := LoadOnchainState(tenv.Env) + tenv, _ := testhelpers.NewMemoryEnvironment(t) + state, err := changeset.LoadOnchainState(tenv.Env) require.NoError(t, err) allChains := maps.Keys(tenv.Env.Chains) @@ -45,17 +47,17 @@ func TestUpdateOnRampsDests(t *testing.T) { transferToTimelock(t, tenv, state, source, dest) } - var mcmsConfig *MCMSConfig + var mcmsConfig *changeset.MCMSConfig if tc.mcmsEnabled { - mcmsConfig = &MCMSConfig{ + mcmsConfig = &changeset.MCMSConfig{ MinDelay: 0, } } _, err = commonchangeset.ApplyChangesets(t, tenv.Env, tenv.TimelockContracts(t), []commonchangeset.ChangesetApplication{ { - Changeset: commonchangeset.WrapChangeSet(UpdateOnRampsDests), - Config: UpdateOnRampDestsConfig{ - UpdatesByChain: map[uint64]map[uint64]OnRampDestinationUpdate{ + Changeset: commonchangeset.WrapChangeSet(changeset.UpdateOnRampsDestsChangeset), + Config: changeset.UpdateOnRampDestsConfig{ + UpdatesByChain: map[uint64]map[uint64]changeset.OnRampDestinationUpdate{ source: { dest: { IsEnabled: true, @@ -106,8 +108,8 @@ func TestUpdateOffRampsSources(t *testing.T) { } { t.Run(tc.name, func(t *testing.T) { ctx := testcontext.Get(t) - tenv, _ := NewMemoryEnvironment(t) - state, err := LoadOnchainState(tenv.Env) + tenv, _ := testhelpers.NewMemoryEnvironment(t) + state, err := changeset.LoadOnchainState(tenv.Env) require.NoError(t, err) allChains := maps.Keys(tenv.Env.Chains) @@ -119,17 +121,17 @@ func TestUpdateOffRampsSources(t *testing.T) { transferToTimelock(t, tenv, state, source, dest) } - var mcmsConfig *MCMSConfig + var mcmsConfig *changeset.MCMSConfig if tc.mcmsEnabled { - mcmsConfig = &MCMSConfig{ + mcmsConfig = &changeset.MCMSConfig{ MinDelay: 0, } } _, err = commonchangeset.ApplyChangesets(t, tenv.Env, tenv.TimelockContracts(t), []commonchangeset.ChangesetApplication{ { - Changeset: commonchangeset.WrapChangeSet(UpdateOffRampSources), - Config: UpdateOffRampSourcesConfig{ - UpdatesByChain: map[uint64]map[uint64]OffRampSourceUpdate{ + Changeset: commonchangeset.WrapChangeSet(changeset.UpdateOffRampSourcesChangeset), + Config: changeset.UpdateOffRampSourcesConfig{ + UpdatesByChain: map[uint64]map[uint64]changeset.OffRampSourceUpdate{ source: { dest: { IsEnabled: true, @@ -176,8 +178,8 @@ func TestUpdateFQDests(t *testing.T) { } { t.Run(tc.name, func(t *testing.T) { ctx := testcontext.Get(t) - tenv, _ := NewMemoryEnvironment(t) - state, err := LoadOnchainState(tenv.Env) + tenv, _ := testhelpers.NewMemoryEnvironment(t) + state, err := changeset.LoadOnchainState(tenv.Env) require.NoError(t, err) allChains := maps.Keys(tenv.Env.Chains) @@ -189,20 +191,20 @@ func TestUpdateFQDests(t *testing.T) { transferToTimelock(t, tenv, state, source, dest) } - var mcmsConfig *MCMSConfig + var mcmsConfig *changeset.MCMSConfig if tc.mcmsEnabled { - mcmsConfig = &MCMSConfig{ + mcmsConfig = &changeset.MCMSConfig{ MinDelay: 0, } } - fqCfg1 := DefaultFeeQuoterDestChainConfig() - fqCfg2 := DefaultFeeQuoterDestChainConfig() + fqCfg1 := changeset.DefaultFeeQuoterDestChainConfig() + fqCfg2 := changeset.DefaultFeeQuoterDestChainConfig() fqCfg2.DestGasOverhead = 1000 _, err = commonchangeset.ApplyChangesets(t, tenv.Env, tenv.TimelockContracts(t), []commonchangeset.ChangesetApplication{ { - Changeset: commonchangeset.WrapChangeSet(UpdateFeeQuoterDests), - Config: UpdateFeeQuoterDestsConfig{ + Changeset: commonchangeset.WrapChangeSet(changeset.UpdateFeeQuoterDestsChangeset), + Config: changeset.UpdateFeeQuoterDestsConfig{ UpdatesByChain: map[uint64]map[uint64]fee_quoter.FeeQuoterDestChainConfig{ source: { dest: fqCfg1, @@ -220,10 +222,10 @@ func TestUpdateFQDests(t *testing.T) { // Assert the fq configuration is as we expect. source2destCfg, err := state.Chains[source].FeeQuoter.GetDestChainConfig(&bind.CallOpts{Context: ctx}, dest) require.NoError(t, err) - AssertEqualFeeConfig(t, fqCfg1, source2destCfg) + testhelpers.AssertEqualFeeConfig(t, fqCfg1, source2destCfg) dest2sourceCfg, err := state.Chains[dest].FeeQuoter.GetDestChainConfig(&bind.CallOpts{Context: ctx}, source) require.NoError(t, err) - AssertEqualFeeConfig(t, fqCfg2, dest2sourceCfg) + testhelpers.AssertEqualFeeConfig(t, fqCfg2, dest2sourceCfg) }) } } @@ -244,8 +246,8 @@ func TestUpdateRouterRamps(t *testing.T) { } { t.Run(tc.name, func(t *testing.T) { ctx := testcontext.Get(t) - tenv, _ := NewMemoryEnvironment(t) - state, err := LoadOnchainState(tenv.Env) + tenv, _ := testhelpers.NewMemoryEnvironment(t) + state, err := changeset.LoadOnchainState(tenv.Env) require.NoError(t, err) allChains := maps.Keys(tenv.Env.Chains) @@ -257,9 +259,9 @@ func TestUpdateRouterRamps(t *testing.T) { transferToTimelock(t, tenv, state, source, dest) } - var mcmsConfig *MCMSConfig + var mcmsConfig *changeset.MCMSConfig if tc.mcmsEnabled { - mcmsConfig = &MCMSConfig{ + mcmsConfig = &changeset.MCMSConfig{ MinDelay: 0, } } @@ -267,10 +269,10 @@ func TestUpdateRouterRamps(t *testing.T) { // Updates test router. _, err = commonchangeset.ApplyChangesets(t, tenv.Env, tenv.TimelockContracts(t), []commonchangeset.ChangesetApplication{ { - Changeset: commonchangeset.WrapChangeSet(UpdateRouterRamps), - Config: UpdateRouterRampsConfig{ + Changeset: commonchangeset.WrapChangeSet(changeset.UpdateRouterRampsChangeset), + Config: changeset.UpdateRouterRampsConfig{ TestRouter: true, - UpdatesByChain: map[uint64]RouterUpdates{ + UpdatesByChain: map[uint64]changeset.RouterUpdates{ source: { OffRampUpdates: map[uint64]bool{ dest: true, @@ -320,8 +322,8 @@ func TestUpdateNonceManagersCS(t *testing.T) { }, } { t.Run(tc.name, func(t *testing.T) { - tenv, _ := NewMemoryEnvironment(t) - state, err := LoadOnchainState(tenv.Env) + tenv, _ := testhelpers.NewMemoryEnvironment(t) + state, err := changeset.LoadOnchainState(tenv.Env) require.NoError(t, err) allChains := maps.Keys(tenv.Env.Chains) @@ -333,18 +335,18 @@ func TestUpdateNonceManagersCS(t *testing.T) { transferToTimelock(t, tenv, state, source, dest) } - var mcmsConfig *MCMSConfig + var mcmsConfig *changeset.MCMSConfig if tc.mcmsEnabled { - mcmsConfig = &MCMSConfig{ + mcmsConfig = &changeset.MCMSConfig{ MinDelay: 0, } } _, err = commonchangeset.ApplyChangesets(t, tenv.Env, tenv.TimelockContracts(t), []commonchangeset.ChangesetApplication{ { - Changeset: commonchangeset.WrapChangeSet(UpdateNonceManagersCS), - Config: UpdateNonceManagerConfig{ - UpdatesByChain: map[uint64]NonceManagerUpdate{ + Changeset: commonchangeset.WrapChangeSet(changeset.UpdateNonceManagersChangeset), + Config: changeset.UpdateNonceManagerConfig{ + UpdatesByChain: map[uint64]changeset.NonceManagerUpdate{ source: { RemovedAuthCallers: []common.Address{state.Chains[source].OnRamp.Address()}, }, diff --git a/deployment/ccip/changeset/cs_deploy_chain.go b/deployment/ccip/changeset/cs_deploy_chain.go index 175498ba2cf..0cdc2327ca3 100644 --- a/deployment/ccip/changeset/cs_deploy_chain.go +++ b/deployment/ccip/changeset/cs_deploy_chain.go @@ -23,18 +23,18 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/router" ) -var _ deployment.ChangeSet[DeployChainContractsConfig] = DeployChainContracts +var _ deployment.ChangeSet[DeployChainContractsConfig] = DeployChainContractsChangeset -// DeployChainContracts deploys all new CCIP v1.6 or later contracts for the given chains. +// DeployChainContractsChangeset deploys all new CCIP v1.6 or later contracts for the given chains. // It returns the new addresses for the contracts. -// DeployChainContracts is idempotent. If there is an error, it will return the successfully deployed addresses and the error so that the caller can call the +// DeployChainContractsChangeset is idempotent. If there is an error, it will return the successfully deployed addresses and the error so that the caller can call the // changeset again with the same input to retry the failed deployment. // Caller should update the environment's address book with the returned addresses. // Points to note : // In case of migrating from legacy ccip to 1.6, the previous RMN address should be set while deploying RMNRemote. // if there is no existing RMN address found, RMNRemote will be deployed with 0x0 address for previous RMN address // which will set RMN to 0x0 address immutably in RMNRemote. -func DeployChainContracts(env deployment.Environment, c DeployChainContractsConfig) (deployment.ChangesetOutput, error) { +func DeployChainContractsChangeset(env deployment.Environment, c DeployChainContractsConfig) (deployment.ChangesetOutput, error) { if err := c.Validate(); err != nil { return deployment.ChangesetOutput{}, fmt.Errorf("invalid DeployChainContractsConfig: %w", err) } diff --git a/deployment/ccip/changeset/cs_deploy_chain_test.go b/deployment/ccip/changeset/cs_deploy_chain_test.go index 1f77be3ca5a..c579b075b70 100644 --- a/deployment/ccip/changeset/cs_deploy_chain_test.go +++ b/deployment/ccip/changeset/cs_deploy_chain_test.go @@ -1,4 +1,4 @@ -package changeset +package changeset_test import ( "encoding/json" @@ -9,6 +9,8 @@ import ( "go.uber.org/zap/zapcore" "github.com/smartcontractkit/chainlink/deployment" + "github.com/smartcontractkit/chainlink/deployment/ccip/changeset" + "github.com/smartcontractkit/chainlink/deployment/ccip/changeset/testhelpers" commonchangeset "github.com/smartcontractkit/chainlink/deployment/common/changeset" "github.com/smartcontractkit/chainlink/deployment/common/proposalutils" commontypes "github.com/smartcontractkit/chainlink/deployment/common/types" @@ -33,20 +35,20 @@ func TestDeployChainContractsChangeset(t *testing.T) { for _, chain := range e.AllChainSelectors() { cfg[chain] = proposalutils.SingleGroupTimelockConfig(t) } - var prereqCfg []DeployPrerequisiteConfigPerChain + prereqCfg := make([]changeset.DeployPrerequisiteConfigPerChain, 0) for _, chain := range e.AllChainSelectors() { - prereqCfg = append(prereqCfg, DeployPrerequisiteConfigPerChain{ + prereqCfg = append(prereqCfg, changeset.DeployPrerequisiteConfigPerChain{ ChainSelector: chain, }) } e, err = commonchangeset.ApplyChangesets(t, e, nil, []commonchangeset.ChangesetApplication{ { - Changeset: commonchangeset.WrapChangeSet(DeployHomeChain), - Config: DeployHomeChainConfig{ + Changeset: commonchangeset.WrapChangeSet(changeset.DeployHomeChainChangeset), + Config: changeset.DeployHomeChainConfig{ HomeChainSel: homeChainSel, - RMNStaticConfig: NewTestRMNStaticConfig(), - RMNDynamicConfig: NewTestRMNDynamicConfig(), - NodeOperators: NewTestNodeOperator(e.Chains[homeChainSel].DeployerKey.From), + RMNStaticConfig: testhelpers.NewTestRMNStaticConfig(), + RMNDynamicConfig: testhelpers.NewTestRMNDynamicConfig(), + NodeOperators: testhelpers.NewTestNodeOperator(e.Chains[homeChainSel].DeployerKey.From), NodeP2PIDsPerNodeOpAdmin: map[string][][32]byte{ "NodeOperator": p2pIds, }, @@ -61,14 +63,14 @@ func TestDeployChainContractsChangeset(t *testing.T) { Config: cfg, }, { - Changeset: commonchangeset.WrapChangeSet(DeployPrerequisites), - Config: DeployPrerequisiteConfig{ + Changeset: commonchangeset.WrapChangeSet(changeset.DeployPrerequisitesChangeset), + Config: changeset.DeployPrerequisiteConfig{ Configs: prereqCfg, }, }, { - Changeset: commonchangeset.WrapChangeSet(DeployChainContracts), - Config: DeployChainContractsConfig{ + Changeset: commonchangeset.WrapChangeSet(changeset.DeployChainContractsChangeset), + Config: changeset.DeployChainContractsConfig{ ChainSelectors: selectors, HomeChainSelector: homeChainSel, }, @@ -77,7 +79,7 @@ func TestDeployChainContractsChangeset(t *testing.T) { require.NoError(t, err) // load onchain state - state, err := LoadOnchainState(e) + state, err := changeset.LoadOnchainState(e) require.NoError(t, err) // verify all contracts populated @@ -101,9 +103,9 @@ func TestDeployChainContractsChangeset(t *testing.T) { func TestDeployCCIPContracts(t *testing.T) { t.Parallel() - e, _ := NewMemoryEnvironment(t) + e, _ := testhelpers.NewMemoryEnvironment(t) // Deploy all the CCIP contracts. - state, err := LoadOnchainState(e.Env) + state, err := changeset.LoadOnchainState(e.Env) require.NoError(t, err) snap, err := state.View(e.Env.AllChainSelectors()) require.NoError(t, err) diff --git a/deployment/ccip/changeset/cs_home_chain.go b/deployment/ccip/changeset/cs_home_chain.go index 3b985f5c526..cc234a45e49 100644 --- a/deployment/ccip/changeset/cs_home_chain.go +++ b/deployment/ccip/changeset/cs_home_chain.go @@ -16,6 +16,7 @@ import ( "golang.org/x/exp/maps" "github.com/smartcontractkit/chainlink-common/pkg/logger" + "github.com/smartcontractkit/chainlink/deployment/common/proposalutils" "github.com/smartcontractkit/chainlink/deployment" @@ -26,10 +27,10 @@ import ( p2ptypes "github.com/smartcontractkit/chainlink/v2/core/services/p2p/types" ) -var _ deployment.ChangeSet[DeployHomeChainConfig] = DeployHomeChain +var _ deployment.ChangeSet[DeployHomeChainConfig] = DeployHomeChainChangeset -// DeployHomeChain is a separate changeset because it is a standalone deployment performed once in home chain for the entire CCIP deployment. -func DeployHomeChain(env deployment.Environment, cfg DeployHomeChainConfig) (deployment.ChangesetOutput, error) { +// DeployHomeChainChangeset is a separate changeset because it is a standalone deployment performed once in home chain for the entire CCIP deployment. +func DeployHomeChainChangeset(env deployment.Environment, cfg DeployHomeChainConfig) (deployment.ChangesetOutput, error) { err := cfg.Validate() if err != nil { return deployment.ChangesetOutput{}, errors.Wrapf(deployment.ErrInvalidConfig, "%v", err) diff --git a/deployment/ccip/changeset/cs_home_chain_test.go b/deployment/ccip/changeset/cs_home_chain_test.go index 135e60f4eb1..0dbdb866d9b 100644 --- a/deployment/ccip/changeset/cs_home_chain_test.go +++ b/deployment/ccip/changeset/cs_home_chain_test.go @@ -1,4 +1,4 @@ -package changeset +package changeset_test import ( "testing" @@ -8,6 +8,8 @@ import ( "go.uber.org/zap/zapcore" "github.com/smartcontractkit/chainlink/deployment" + "github.com/smartcontractkit/chainlink/deployment/ccip/changeset" + "github.com/smartcontractkit/chainlink/deployment/ccip/changeset/testhelpers" commoncs "github.com/smartcontractkit/chainlink/deployment/common/changeset" "github.com/smartcontractkit/chainlink/deployment/common/proposalutils" "github.com/smartcontractkit/chainlink/deployment/common/view/v1_0" @@ -27,19 +29,19 @@ func TestDeployHomeChain(t *testing.T) { nodes, err := deployment.NodeInfo(e.NodeIDs, e.Offchain) require.NoError(t, err) p2pIds := nodes.NonBootstraps().PeerIDs() - homeChainCfg := DeployHomeChainConfig{ + homeChainCfg := changeset.DeployHomeChainConfig{ HomeChainSel: homeChainSel, - RMNStaticConfig: NewTestRMNStaticConfig(), - RMNDynamicConfig: NewTestRMNDynamicConfig(), - NodeOperators: NewTestNodeOperator(e.Chains[homeChainSel].DeployerKey.From), + RMNStaticConfig: testhelpers.NewTestRMNStaticConfig(), + RMNDynamicConfig: testhelpers.NewTestRMNDynamicConfig(), + NodeOperators: testhelpers.NewTestNodeOperator(e.Chains[homeChainSel].DeployerKey.From), NodeP2PIDsPerNodeOpAdmin: map[string][][32]byte{ "NodeOperator": p2pIds, }, } - output, err := DeployHomeChain(e, homeChainCfg) + output, err := changeset.DeployHomeChainChangeset(e, homeChainCfg) require.NoError(t, err) require.NoError(t, e.ExistingAddresses.Merge(output.AddressBook)) - state, err := LoadOnchainState(e) + state, err := changeset.LoadOnchainState(e) require.NoError(t, err) require.NotNil(t, state.Chains[homeChainSel].CapabilityRegistry) require.NotNil(t, state.Chains[homeChainSel].CCIPHome) @@ -62,18 +64,18 @@ func TestDeployHomeChain(t *testing.T) { } func TestRemoveDonsValidate(t *testing.T) { - e, _ := NewMemoryEnvironment(t) - s, err := LoadOnchainState(e.Env) + e, _ := testhelpers.NewMemoryEnvironment(t) + s, err := changeset.LoadOnchainState(e.Env) require.NoError(t, err) homeChain := s.Chains[e.HomeChainSel] var tt = []struct { name string - config RemoveDONsConfig + config changeset.RemoveDONsConfig expectErr bool }{ { name: "invalid home", - config: RemoveDONsConfig{ + config: changeset.RemoveDONsConfig{ HomeChainSel: 0, DonIDs: []uint32{1}, }, @@ -81,7 +83,7 @@ func TestRemoveDonsValidate(t *testing.T) { }, { name: "invalid dons", - config: RemoveDONsConfig{ + config: changeset.RemoveDONsConfig{ HomeChainSel: e.HomeChainSel, DonIDs: []uint32{1377}, }, @@ -89,7 +91,7 @@ func TestRemoveDonsValidate(t *testing.T) { }, { name: "no dons", - config: RemoveDONsConfig{ + config: changeset.RemoveDONsConfig{ HomeChainSel: e.HomeChainSel, DonIDs: []uint32{}, }, @@ -97,7 +99,7 @@ func TestRemoveDonsValidate(t *testing.T) { }, { name: "success", - config: RemoveDONsConfig{ + config: changeset.RemoveDONsConfig{ HomeChainSel: e.HomeChainSel, DonIDs: []uint32{1}, }, @@ -117,8 +119,8 @@ func TestRemoveDonsValidate(t *testing.T) { } func TestRemoveDons(t *testing.T) { - e, _ := NewMemoryEnvironment(t) - s, err := LoadOnchainState(e.Env) + e, _ := testhelpers.NewMemoryEnvironment(t) + s, err := changeset.LoadOnchainState(e.Env) require.NoError(t, err) homeChain := s.Chains[e.HomeChainSel] @@ -127,8 +129,8 @@ func TestRemoveDons(t *testing.T) { require.NoError(t, err) e.Env, err = commoncs.ApplyChangesets(t, e.Env, nil, []commoncs.ChangesetApplication{ { - Changeset: commoncs.WrapChangeSet(RemoveDONs), - Config: RemoveDONsConfig{ + Changeset: commoncs.WrapChangeSet(changeset.RemoveDONs), + Config: changeset.RemoveDONsConfig{ HomeChainSel: e.HomeChainSel, DonIDs: []uint32{donsBefore[0].Id}, }, @@ -158,11 +160,11 @@ func TestRemoveDons(t *testing.T) { }, }, { - Changeset: commoncs.WrapChangeSet(RemoveDONs), - Config: RemoveDONsConfig{ + Changeset: commoncs.WrapChangeSet(changeset.RemoveDONs), + Config: changeset.RemoveDONsConfig{ HomeChainSel: e.HomeChainSel, DonIDs: []uint32{donsBefore[0].Id}, - MCMS: &MCMSConfig{MinDelay: 0}, + MCMS: &changeset.MCMSConfig{MinDelay: 0}, }, }, }) diff --git a/deployment/ccip/changeset/cs_jobspec.go b/deployment/ccip/changeset/cs_jobspec.go index 2551f193f47..e29578a516a 100644 --- a/deployment/ccip/changeset/cs_jobspec.go +++ b/deployment/ccip/changeset/cs_jobspec.go @@ -9,11 +9,11 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/services/relay" ) -var _ deployment.ChangeSet[any] = CCIPCapabilityJobspec +var _ deployment.ChangeSet[any] = CCIPCapabilityJobspecChangeset -// CCIPCapabilityJobspec returns the job specs for the CCIP capability. +// CCIPCapabilityJobspecChangeset returns the job specs for the CCIP capability. // The caller needs to propose these job specs to the offchain system. -func CCIPCapabilityJobspec(env deployment.Environment, _ any) (deployment.ChangesetOutput, error) { +func CCIPCapabilityJobspecChangeset(env deployment.Environment, _ any) (deployment.ChangesetOutput, error) { nodes, err := deployment.NodeInfo(env.NodeIDs, env.Offchain) if err != nil { return deployment.ChangesetOutput{}, err diff --git a/deployment/ccip/changeset/cs_jobspec_test.go b/deployment/ccip/changeset/cs_jobspec_test.go index a0445b0d5ee..b79dfc47387 100644 --- a/deployment/ccip/changeset/cs_jobspec_test.go +++ b/deployment/ccip/changeset/cs_jobspec_test.go @@ -1,4 +1,4 @@ -package changeset +package changeset_test import ( "testing" @@ -7,6 +7,7 @@ import ( "go.uber.org/zap/zapcore" "github.com/smartcontractkit/chainlink/deployment" + "github.com/smartcontractkit/chainlink/deployment/ccip/changeset" "github.com/smartcontractkit/chainlink/deployment/environment/memory" ccip "github.com/smartcontractkit/chainlink/v2/core/capabilities/ccip/validate" "github.com/smartcontractkit/chainlink/v2/core/logger" @@ -19,7 +20,7 @@ func TestJobSpecChangeset(t *testing.T) { Chains: 1, Nodes: 4, }) - output, err := CCIPCapabilityJobspec(e, nil) + output, err := changeset.CCIPCapabilityJobspecChangeset(e, nil) require.NoError(t, err) require.NotNil(t, output.JobSpecs) nodes, err := deployment.NodeInfo(e.NodeIDs, e.Offchain) diff --git a/deployment/ccip/changeset/cs_prerequisites.go b/deployment/ccip/changeset/cs_prerequisites.go index 33db57cdc91..da4f59c3eb6 100644 --- a/deployment/ccip/changeset/cs_prerequisites.go +++ b/deployment/ccip/changeset/cs_prerequisites.go @@ -2,34 +2,41 @@ package changeset import ( "fmt" + "math/big" "github.com/ethereum/go-ethereum/common" "github.com/pkg/errors" "github.com/smartcontractkit/ccip-owner-contracts/pkg/proposal/timelock" + "github.com/smartcontractkit/chainlink-ccip/pkg/reader" + "github.com/smartcontractkit/chainlink-common/pkg/logger" "golang.org/x/sync/errgroup" "github.com/smartcontractkit/chainlink/deployment" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/maybe_revert_message_receiver" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/mock_rmn_contract" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/mock_usdc_token_messenger" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/mock_usdc_token_transmitter" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/price_registry_1_2_0" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/registry_module_owner_custom" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/rmn_contract" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/rmn_proxy_contract" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/router" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/token_admin_registry" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/usdc_token_pool" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/weth9" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/shared/generated/burn_mint_erc677" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/shared/generated/multicall3" ) var ( - _ deployment.ChangeSet[DeployPrerequisiteConfig] = DeployPrerequisites + _ deployment.ChangeSet[DeployPrerequisiteConfig] = DeployPrerequisitesChangeset ) -// DeployPrerequisites deploys the pre-requisite contracts for CCIP +// DeployPrerequisitesChangeset deploys the pre-requisite contracts for CCIP // pre-requisite contracts are the contracts which can be reused from previous versions of CCIP // Or the contracts which are already deployed on the chain ( for example, tokens, feeds, etc) // Caller should update the environment's address book with the returned addresses. -func DeployPrerequisites(env deployment.Environment, cfg DeployPrerequisiteConfig) (deployment.ChangesetOutput, error) { +func DeployPrerequisitesChangeset(env deployment.Environment, cfg DeployPrerequisiteConfig) (deployment.ChangesetOutput, error) { err := cfg.Validate() if err != nil { return deployment.ChangesetOutput{}, errors.Wrapf(deployment.ErrInvalidConfig, "%v", err) @@ -236,7 +243,7 @@ func deployPrerequisiteContracts(e deployment.Environment, ab deployment.Address if rmnOwner != chain.DeployerKey.From { lggr.Warnw( "RMNProxy is not owned by the deployer and RMNProxy is not pointing to the correct RMN contract, "+ - "run SetRMNRemoteOnRMNProxy to update RMN with a proposal", + "run SetRMNRemoteOnRMNProxyChangeset to update RMN with a proposal", "chain", chain.String(), "owner", rmnOwner, "currentRMN", currentRMNAddr, "expectedRMN", rmnAddr) } else { tx, err := rmnProxy.SetARM(chain.DeployerKey, rmnAddr) @@ -373,7 +380,7 @@ func deployPrerequisiteContracts(e deployment.Environment, ab deployment.Address } } if deployOpts.USDCEnabled { - token, pool, messenger, transmitter, err1 := DeployUSDC(e.Logger, chain, ab, rmnProxy.Address(), r.Address()) + token, pool, messenger, transmitter, err1 := deployUSDC(e.Logger, chain, ab, rmnProxy.Address(), r.Address()) if err1 != nil { return err1 } @@ -435,3 +442,119 @@ func deployPrerequisiteContracts(e deployment.Environment, ab deployment.Address } return nil } + +func deployUSDC( + lggr logger.Logger, + chain deployment.Chain, + addresses deployment.AddressBook, + rmnProxy common.Address, + router common.Address, +) ( + *burn_mint_erc677.BurnMintERC677, + *usdc_token_pool.USDCTokenPool, + *mock_usdc_token_messenger.MockE2EUSDCTokenMessenger, + *mock_usdc_token_transmitter.MockE2EUSDCTransmitter, + error, +) { + token, err := deployment.DeployContract(lggr, chain, addresses, + func(chain deployment.Chain) deployment.ContractDeploy[*burn_mint_erc677.BurnMintERC677] { + tokenAddress, tx, tokenContract, err2 := burn_mint_erc677.DeployBurnMintERC677( + chain.DeployerKey, + chain.Client, + USDCName, + string(USDCSymbol), + UsdcDecimals, + big.NewInt(0), + ) + return deployment.ContractDeploy[*burn_mint_erc677.BurnMintERC677]{ + Address: tokenAddress, + Contract: tokenContract, + Tx: tx, + Tv: deployment.NewTypeAndVersion(USDCToken, deployment.Version1_0_0), + Err: err2, + } + }) + if err != nil { + lggr.Errorw("Failed to deploy USDC token", "chain", chain.String(), "err", err) + return nil, nil, nil, nil, err + } + + tx, err := token.Contract.GrantMintRole(chain.DeployerKey, chain.DeployerKey.From) + if err != nil { + lggr.Errorw("Failed to grant mint role", "chain", chain.String(), "token", token.Contract.Address(), "err", err) + return nil, nil, nil, nil, err + } + _, err = chain.Confirm(tx) + if err != nil { + return nil, nil, nil, nil, err + } + + transmitter, err := deployment.DeployContract(lggr, chain, addresses, + func(chain deployment.Chain) deployment.ContractDeploy[*mock_usdc_token_transmitter.MockE2EUSDCTransmitter] { + transmitterAddress, tx, transmitterContract, err2 := mock_usdc_token_transmitter.DeployMockE2EUSDCTransmitter( + chain.DeployerKey, + chain.Client, + 0, + reader.AllAvailableDomains()[chain.Selector], + token.Address, + ) + return deployment.ContractDeploy[*mock_usdc_token_transmitter.MockE2EUSDCTransmitter]{ + Address: transmitterAddress, + Contract: transmitterContract, + Tx: tx, + Tv: deployment.NewTypeAndVersion(USDCMockTransmitter, deployment.Version1_0_0), + Err: err2, + } + }) + if err != nil { + lggr.Errorw("Failed to deploy mock USDC transmitter", "chain", chain.String(), "err", err) + return nil, nil, nil, nil, err + } + + messenger, err := deployment.DeployContract(lggr, chain, addresses, + func(chain deployment.Chain) deployment.ContractDeploy[*mock_usdc_token_messenger.MockE2EUSDCTokenMessenger] { + messengerAddress, tx, messengerContract, err2 := mock_usdc_token_messenger.DeployMockE2EUSDCTokenMessenger( + chain.DeployerKey, + chain.Client, + 0, + transmitter.Address, + ) + return deployment.ContractDeploy[*mock_usdc_token_messenger.MockE2EUSDCTokenMessenger]{ + Address: messengerAddress, + Contract: messengerContract, + Tx: tx, + Tv: deployment.NewTypeAndVersion(USDCTokenMessenger, deployment.Version1_0_0), + Err: err2, + } + }) + if err != nil { + lggr.Errorw("Failed to deploy USDC token messenger", "chain", chain.String(), "err", err) + return nil, nil, nil, nil, err + } + + tokenPool, err := deployment.DeployContract(lggr, chain, addresses, + func(chain deployment.Chain) deployment.ContractDeploy[*usdc_token_pool.USDCTokenPool] { + tokenPoolAddress, tx, tokenPoolContract, err2 := usdc_token_pool.DeployUSDCTokenPool( + chain.DeployerKey, + chain.Client, + messenger.Address, + token.Address, + []common.Address{}, + rmnProxy, + router, + ) + return deployment.ContractDeploy[*usdc_token_pool.USDCTokenPool]{ + Address: tokenPoolAddress, + Contract: tokenPoolContract, + Tx: tx, + Tv: deployment.NewTypeAndVersion(USDCTokenPool, deployment.Version1_0_0), + Err: err2, + } + }) + if err != nil { + lggr.Errorw("Failed to deploy USDC token pool", "chain", chain.String(), "err", err) + return nil, nil, nil, nil, err + } + + return token.Contract, tokenPool.Contract, messenger.Contract, transmitter.Contract, nil +} diff --git a/deployment/ccip/changeset/cs_prerequisites_test.go b/deployment/ccip/changeset/cs_prerequisites_test.go index 5835bd41aa3..c9c20757e92 100644 --- a/deployment/ccip/changeset/cs_prerequisites_test.go +++ b/deployment/ccip/changeset/cs_prerequisites_test.go @@ -1,4 +1,4 @@ -package changeset +package changeset_test import ( "testing" @@ -6,6 +6,7 @@ import ( "github.com/stretchr/testify/require" "go.uber.org/zap/zapcore" + "github.com/smartcontractkit/chainlink/deployment/ccip/changeset" "github.com/smartcontractkit/chainlink/deployment/environment/memory" "github.com/smartcontractkit/chainlink/v2/core/logger" ) @@ -19,18 +20,18 @@ func TestDeployPrerequisites(t *testing.T) { Nodes: 4, }) newChain := e.AllChainSelectors()[0] - cfg := DeployPrerequisiteConfig{ - Configs: []DeployPrerequisiteConfigPerChain{ + cfg := changeset.DeployPrerequisiteConfig{ + Configs: []changeset.DeployPrerequisiteConfigPerChain{ { ChainSelector: newChain, }, }, } - output, err := DeployPrerequisites(e, cfg) + output, err := changeset.DeployPrerequisitesChangeset(e, cfg) require.NoError(t, err) err = e.ExistingAddresses.Merge(output.AddressBook) require.NoError(t, err) - state, err := LoadOnchainState(e) + state, err := changeset.LoadOnchainState(e) require.NoError(t, err) require.NotNil(t, state.Chains[newChain].Weth9) require.NotNil(t, state.Chains[newChain].TokenAdminRegistry) diff --git a/deployment/ccip/changeset/cs_rmn_curse_uncurse.go b/deployment/ccip/changeset/cs_rmn_curse_uncurse.go index 1f3222014e3..b6125638143 100644 --- a/deployment/ccip/changeset/cs_rmn_curse_uncurse.go +++ b/deployment/ccip/changeset/cs_rmn_curse_uncurse.go @@ -9,6 +9,11 @@ import ( commoncs "github.com/smartcontractkit/chainlink/deployment/common/changeset" ) +var ( + _ deployment.ChangeSet[RMNCurseConfig] = RMNCurseChangeset + _ deployment.ChangeSet[RMNCurseConfig] = RMNUncurseChangeset +) + // GlobalCurseSubject as defined here: https://github.com/smartcontractkit/chainlink/blob/new-rmn-curse-changeset/contracts/src/v0.8/ccip/rmn/RMNRemote.sol#L15 func GlobalCurseSubject() Subject { return Subject{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01} @@ -225,7 +230,7 @@ func RMNCurseChangeset(e deployment.Environment, cfg RMNCurseConfig) (deployment grouped := groupRMNSubjectBySelector(curseActions, true, true) // For each chain in the environment get the RMNRemote contract and call curse for selector, chain := range state.Chains { - deployer, err := deployerGroup.getDeployer(selector) + deployer, err := deployerGroup.GetDeployer(selector) if err != nil { return deployment.ChangesetOutput{}, fmt.Errorf("failed to get deployer for chain %d: %w", selector, err) } @@ -258,7 +263,7 @@ func RMNCurseChangeset(e deployment.Environment, cfg RMNCurseConfig) (deployment } } - return deployerGroup.enact("proposal to curse RMNs: " + cfg.Reason) + return deployerGroup.Enact("proposal to curse RMNs: " + cfg.Reason) } // RMNUncurseChangeset creates a new changeset for uncursing chains or lanes on RMNRemote contracts. @@ -296,7 +301,7 @@ func RMNUncurseChangeset(e deployment.Environment, cfg RMNCurseConfig) (deployme // For each chain in the environement get the RMNRemote contract and call uncurse for selector, chain := range state.Chains { - deployer, err := deployerGroup.getDeployer(selector) + deployer, err := deployerGroup.GetDeployer(selector) if err != nil { return deployment.ChangesetOutput{}, fmt.Errorf("failed to get deployer for chain %d: %w", selector, err) } @@ -330,5 +335,5 @@ func RMNUncurseChangeset(e deployment.Environment, cfg RMNCurseConfig) (deployme } } - return deployerGroup.enact("proposal to uncurse RMNs: %s" + cfg.Reason) + return deployerGroup.Enact("proposal to uncurse RMNs: %s" + cfg.Reason) } diff --git a/deployment/ccip/changeset/cs_rmn_curse_uncurse_test.go b/deployment/ccip/changeset/cs_rmn_curse_uncurse_test.go index 2b0a6c07a59..7a043b36645 100644 --- a/deployment/ccip/changeset/cs_rmn_curse_uncurse_test.go +++ b/deployment/ccip/changeset/cs_rmn_curse_uncurse_test.go @@ -1,4 +1,4 @@ -package changeset +package changeset_test import ( "testing" @@ -6,6 +6,8 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/stretchr/testify/require" + "github.com/smartcontractkit/chainlink/deployment/ccip/changeset" + "github.com/smartcontractkit/chainlink/deployment/ccip/changeset/testhelpers" commonchangeset "github.com/smartcontractkit/chainlink/deployment/common/changeset" "github.com/smartcontractkit/chainlink/deployment/common/proposalutils" ) @@ -19,7 +21,7 @@ type curseAssertion struct { type CurseTestCase struct { name string - curseActionsBuilder func(mapIDToSelectorFunc) []CurseAction + curseActionsBuilder func(mapIDToSelectorFunc) []changeset.CurseAction curseAssertions []curseAssertion } @@ -28,8 +30,8 @@ type mapIDToSelectorFunc func(uint64) uint64 var testCases = []CurseTestCase{ { name: "lane", - curseActionsBuilder: func(mapIDToSelector mapIDToSelectorFunc) []CurseAction { - return []CurseAction{CurseLaneBidirectionally(mapIDToSelector(0), mapIDToSelector(1))} + curseActionsBuilder: func(mapIDToSelector mapIDToSelectorFunc) []changeset.CurseAction { + return []changeset.CurseAction{changeset.CurseLaneBidirectionally(mapIDToSelector(0), mapIDToSelector(1))} }, curseAssertions: []curseAssertion{ {chainID: 0, subject: 1, cursed: true}, @@ -42,8 +44,10 @@ var testCases = []CurseTestCase{ }, { name: "lane duplicate", - curseActionsBuilder: func(mapIDToSelector mapIDToSelectorFunc) []CurseAction { - return []CurseAction{CurseLaneBidirectionally(mapIDToSelector(0), mapIDToSelector(1)), CurseLaneBidirectionally(mapIDToSelector(0), mapIDToSelector(1))} + curseActionsBuilder: func(mapIDToSelector mapIDToSelectorFunc) []changeset.CurseAction { + return []changeset.CurseAction{ + changeset.CurseLaneBidirectionally(mapIDToSelector(0), mapIDToSelector(1)), + changeset.CurseLaneBidirectionally(mapIDToSelector(0), mapIDToSelector(1))} }, curseAssertions: []curseAssertion{ {chainID: 0, subject: 1, cursed: true}, @@ -56,8 +60,8 @@ var testCases = []CurseTestCase{ }, { name: "chain", - curseActionsBuilder: func(mapIDToSelector mapIDToSelectorFunc) []CurseAction { - return []CurseAction{CurseChain(mapIDToSelector(0))} + curseActionsBuilder: func(mapIDToSelector mapIDToSelectorFunc) []changeset.CurseAction { + return []changeset.CurseAction{changeset.CurseChain(mapIDToSelector(0))} }, curseAssertions: []curseAssertion{ {chainID: 0, globalCurse: true, cursed: true}, @@ -69,8 +73,8 @@ var testCases = []CurseTestCase{ }, { name: "chain duplicate", - curseActionsBuilder: func(mapIDToSelector mapIDToSelectorFunc) []CurseAction { - return []CurseAction{CurseChain(mapIDToSelector(0)), CurseChain(mapIDToSelector(0))} + curseActionsBuilder: func(mapIDToSelector mapIDToSelectorFunc) []changeset.CurseAction { + return []changeset.CurseAction{changeset.CurseChain(mapIDToSelector(0)), changeset.CurseChain(mapIDToSelector(0))} }, curseAssertions: []curseAssertion{ {chainID: 0, globalCurse: true, cursed: true}, @@ -82,8 +86,8 @@ var testCases = []CurseTestCase{ }, { name: "chain and lanes", - curseActionsBuilder: func(mapIDToSelector mapIDToSelectorFunc) []CurseAction { - return []CurseAction{CurseChain(mapIDToSelector(0)), CurseLaneBidirectionally(mapIDToSelector(1), mapIDToSelector(2))} + curseActionsBuilder: func(mapIDToSelector mapIDToSelectorFunc) []changeset.CurseAction { + return []changeset.CurseAction{changeset.CurseChain(mapIDToSelector(0)), changeset.CurseLaneBidirectionally(mapIDToSelector(1), mapIDToSelector(2))} }, curseAssertions: []curseAssertion{ {chainID: 0, globalCurse: true, cursed: true}, @@ -142,7 +146,7 @@ func TestRMNCurseConfigValidate(t *testing.T) { } func runRmnUncurseTest(t *testing.T, tc CurseTestCase) { - e, _ := NewMemoryEnvironment(t, WithChains(3)) + e, _ := testhelpers.NewMemoryEnvironment(t, testhelpers.WithNumOfChains(3)) mapIDToSelector := func(id uint64) uint64 { return e.Env.AllChainSelectors()[id] @@ -150,23 +154,23 @@ func runRmnUncurseTest(t *testing.T, tc CurseTestCase) { verifyNoActiveCurseOnAllChains(t, &e) - config := RMNCurseConfig{ + config := changeset.RMNCurseConfig{ CurseActions: tc.curseActionsBuilder(mapIDToSelector), Reason: "test curse", } - _, err := RMNCurseChangeset(e.Env, config) + _, err := changeset.RMNCurseChangeset(e.Env, config) require.NoError(t, err) verifyTestCaseAssertions(t, &e, tc, mapIDToSelector) - _, err = RMNUncurseChangeset(e.Env, config) + _, err = changeset.RMNUncurseChangeset(e.Env, config) require.NoError(t, err) verifyNoActiveCurseOnAllChains(t, &e) } -func transferRMNContractToMCMS(t *testing.T, e *DeployedEnv, state CCIPOnChainState, timelocksPerChain map[uint64]*proposalutils.TimelockExecutionContracts) { +func transferRMNContractToMCMS(t *testing.T, e *testhelpers.DeployedEnv, state changeset.CCIPOnChainState, timelocksPerChain map[uint64]*proposalutils.TimelockExecutionContracts) { contractsByChain := make(map[uint64][]common.Address) rmnRemoteAddressesByChain := buildRMNRemoteAddressPerChain(e.Env, state) for chainSelector, rmnRemoteAddress := range rmnRemoteAddressesByChain { @@ -189,30 +193,30 @@ func transferRMNContractToMCMS(t *testing.T, e *DeployedEnv, state CCIPOnChainSt } func runRmnUncurseMCMSTest(t *testing.T, tc CurseTestCase) { - e, _ := NewMemoryEnvironment(t, WithChains(3)) + e, _ := testhelpers.NewMemoryEnvironment(t, testhelpers.WithNumOfChains(3)) mapIDToSelector := func(id uint64) uint64 { return e.Env.AllChainSelectors()[id] } - config := RMNCurseConfig{ + config := changeset.RMNCurseConfig{ CurseActions: tc.curseActionsBuilder(mapIDToSelector), Reason: "test curse", - MCMS: &MCMSConfig{MinDelay: 0}, + MCMS: &changeset.MCMSConfig{MinDelay: 0}, } - state, err := LoadOnchainState(e.Env) + state, err := changeset.LoadOnchainState(e.Env) require.NoError(t, err) verifyNoActiveCurseOnAllChains(t, &e) - timelocksPerChain := buildTimelockPerChain(e.Env, state) + timelocksPerChain := changeset.BuildTimelockPerChain(e.Env, state) transferRMNContractToMCMS(t, &e, state, timelocksPerChain) _, err = commonchangeset.ApplyChangesets(t, e.Env, timelocksPerChain, []commonchangeset.ChangesetApplication{ { - Changeset: commonchangeset.WrapChangeSet(RMNCurseChangeset), + Changeset: commonchangeset.WrapChangeSet(changeset.RMNCurseChangeset), Config: config, }, }) @@ -222,7 +226,7 @@ func runRmnUncurseMCMSTest(t *testing.T, tc CurseTestCase) { _, err = commonchangeset.ApplyChangesets(t, e.Env, timelocksPerChain, []commonchangeset.ChangesetApplication{ { - Changeset: commonchangeset.WrapChangeSet(RMNUncurseChangeset), + Changeset: commonchangeset.WrapChangeSet(changeset.RMNUncurseChangeset), Config: config, }, }) @@ -232,13 +236,13 @@ func runRmnUncurseMCMSTest(t *testing.T, tc CurseTestCase) { } func runRmnCurseConfigValidateTest(t *testing.T, tc CurseTestCase) { - e, _ := NewMemoryEnvironment(t, WithChains(3)) + e, _ := testhelpers.NewMemoryEnvironment(t, testhelpers.WithNumOfChains(3)) mapIDToSelector := func(id uint64) uint64 { return e.Env.AllChainSelectors()[id] } - config := RMNCurseConfig{ + config := changeset.RMNCurseConfig{ CurseActions: tc.curseActionsBuilder(mapIDToSelector), Reason: "test curse", } @@ -248,7 +252,7 @@ func runRmnCurseConfigValidateTest(t *testing.T, tc CurseTestCase) { } func runRmnCurseTest(t *testing.T, tc CurseTestCase) { - e, _ := NewMemoryEnvironment(t, WithChains(3)) + e, _ := testhelpers.NewMemoryEnvironment(t, testhelpers.WithNumOfChains(3)) mapIDToSelector := func(id uint64) uint64 { return e.Env.AllChainSelectors()[id] @@ -256,19 +260,19 @@ func runRmnCurseTest(t *testing.T, tc CurseTestCase) { verifyNoActiveCurseOnAllChains(t, &e) - config := RMNCurseConfig{ + config := changeset.RMNCurseConfig{ CurseActions: tc.curseActionsBuilder(mapIDToSelector), Reason: "test curse", } - _, err := RMNCurseChangeset(e.Env, config) + _, err := changeset.RMNCurseChangeset(e.Env, config) require.NoError(t, err) verifyTestCaseAssertions(t, &e, tc, mapIDToSelector) } func runRmnCurseIdempotentTest(t *testing.T, tc CurseTestCase) { - e, _ := NewMemoryEnvironment(t, WithChains(3)) + e, _ := testhelpers.NewMemoryEnvironment(t, testhelpers.WithNumOfChains(3)) mapIDToSelector := func(id uint64) uint64 { return e.Env.AllChainSelectors()[id] @@ -276,22 +280,22 @@ func runRmnCurseIdempotentTest(t *testing.T, tc CurseTestCase) { verifyNoActiveCurseOnAllChains(t, &e) - config := RMNCurseConfig{ + config := changeset.RMNCurseConfig{ CurseActions: tc.curseActionsBuilder(mapIDToSelector), Reason: "test curse", } - _, err := RMNCurseChangeset(e.Env, config) + _, err := changeset.RMNCurseChangeset(e.Env, config) require.NoError(t, err) - _, err = RMNCurseChangeset(e.Env, config) + _, err = changeset.RMNCurseChangeset(e.Env, config) require.NoError(t, err) verifyTestCaseAssertions(t, &e, tc, mapIDToSelector) } func runRmnUncurseIdempotentTest(t *testing.T, tc CurseTestCase) { - e, _ := NewMemoryEnvironment(t, WithChains(3)) + e, _ := testhelpers.NewMemoryEnvironment(t, testhelpers.WithNumOfChains(3)) mapIDToSelector := func(id uint64) uint64 { return e.Env.AllChainSelectors()[id] @@ -299,50 +303,50 @@ func runRmnUncurseIdempotentTest(t *testing.T, tc CurseTestCase) { verifyNoActiveCurseOnAllChains(t, &e) - config := RMNCurseConfig{ + config := changeset.RMNCurseConfig{ CurseActions: tc.curseActionsBuilder(mapIDToSelector), Reason: "test curse", } - _, err := RMNCurseChangeset(e.Env, config) + _, err := changeset.RMNCurseChangeset(e.Env, config) require.NoError(t, err) verifyTestCaseAssertions(t, &e, tc, mapIDToSelector) - _, err = RMNUncurseChangeset(e.Env, config) + _, err = changeset.RMNUncurseChangeset(e.Env, config) require.NoError(t, err) - _, err = RMNUncurseChangeset(e.Env, config) + _, err = changeset.RMNUncurseChangeset(e.Env, config) require.NoError(t, err) verifyNoActiveCurseOnAllChains(t, &e) } func runRmnCurseMCMSTest(t *testing.T, tc CurseTestCase) { - e, _ := NewMemoryEnvironment(t, WithChains(3)) + e, _ := testhelpers.NewMemoryEnvironment(t, testhelpers.WithNumOfChains(3)) mapIDToSelector := func(id uint64) uint64 { return e.Env.AllChainSelectors()[id] } - config := RMNCurseConfig{ + config := changeset.RMNCurseConfig{ CurseActions: tc.curseActionsBuilder(mapIDToSelector), Reason: "test curse", - MCMS: &MCMSConfig{MinDelay: 0}, + MCMS: &changeset.MCMSConfig{MinDelay: 0}, } - state, err := LoadOnchainState(e.Env) + state, err := changeset.LoadOnchainState(e.Env) require.NoError(t, err) verifyNoActiveCurseOnAllChains(t, &e) - timelocksPerChain := buildTimelockPerChain(e.Env, state) + timelocksPerChain := changeset.BuildTimelockPerChain(e.Env, state) transferRMNContractToMCMS(t, &e, state, timelocksPerChain) _, err = commonchangeset.ApplyChangesets(t, e.Env, timelocksPerChain, []commonchangeset.ChangesetApplication{ { - Changeset: commonchangeset.WrapChangeSet(RMNCurseChangeset), + Changeset: commonchangeset.WrapChangeSet(changeset.RMNCurseChangeset), Config: config, }, }) @@ -351,14 +355,14 @@ func runRmnCurseMCMSTest(t *testing.T, tc CurseTestCase) { verifyTestCaseAssertions(t, &e, tc, mapIDToSelector) } -func verifyTestCaseAssertions(t *testing.T, e *DeployedEnv, tc CurseTestCase, mapIDToSelector mapIDToSelectorFunc) { - state, err := LoadOnchainState(e.Env) +func verifyTestCaseAssertions(t *testing.T, e *testhelpers.DeployedEnv, tc CurseTestCase, mapIDToSelector mapIDToSelectorFunc) { + state, err := changeset.LoadOnchainState(e.Env) require.NoError(t, err) for _, assertion := range tc.curseAssertions { - cursedSubject := SelectorToSubject(mapIDToSelector(assertion.subject)) + cursedSubject := changeset.SelectorToSubject(mapIDToSelector(assertion.subject)) if assertion.globalCurse { - cursedSubject = GlobalCurseSubject() + cursedSubject = changeset.GlobalCurseSubject() } isCursed, err := state.Chains[mapIDToSelector(assertion.chainID)].RMNRemote.IsCursed(nil, cursedSubject) @@ -367,8 +371,8 @@ func verifyTestCaseAssertions(t *testing.T, e *DeployedEnv, tc CurseTestCase, ma } } -func verifyNoActiveCurseOnAllChains(t *testing.T, e *DeployedEnv) { - state, err := LoadOnchainState(e.Env) +func verifyNoActiveCurseOnAllChains(t *testing.T, e *testhelpers.DeployedEnv) { + state, err := changeset.LoadOnchainState(e.Env) require.NoError(t, err) for _, chain := range e.Env.Chains { diff --git a/deployment/ccip/changeset/cs_update_rmn_config.go b/deployment/ccip/changeset/cs_update_rmn_config.go index 1797d588fca..e220ca50998 100644 --- a/deployment/ccip/changeset/cs_update_rmn_config.go +++ b/deployment/ccip/changeset/cs_update_rmn_config.go @@ -20,9 +20,9 @@ import ( ) var ( - _ deployment.ChangeSet[SetRMNRemoteOnRMNProxyConfig] = SetRMNRemoteOnRMNProxy + _ deployment.ChangeSet[SetRMNRemoteOnRMNProxyConfig] = SetRMNRemoteOnRMNProxyChangeset _ deployment.ChangeSet[SetRMNHomeCandidateConfig] = SetRMNHomeCandidateConfigChangeset - _ deployment.ChangeSet[PromoteRMNHomeCandidateConfig] = PromoteCandidateConfigChangeset + _ deployment.ChangeSet[PromoteRMNHomeCandidateConfig] = PromoteRMNHomeCandidateConfigChangeset _ deployment.ChangeSet[SetRMNRemoteConfig] = SetRMNRemoteConfigChangeset ) @@ -51,7 +51,7 @@ func (c SetRMNRemoteOnRMNProxyConfig) Validate(state CCIPOnChainState) error { return nil } -func SetRMNRemoteOnRMNProxy(e deployment.Environment, cfg SetRMNRemoteOnRMNProxyConfig) (deployment.ChangesetOutput, error) { +func SetRMNRemoteOnRMNProxyChangeset(e deployment.Environment, cfg SetRMNRemoteOnRMNProxyConfig) (deployment.ChangesetOutput, error) { state, err := LoadOnchainState(e) if err != nil { return deployment.ChangesetOutput{}, fmt.Errorf("failed to load onchain state: %w", err) @@ -314,9 +314,9 @@ func SetRMNHomeCandidateConfigChangeset(e deployment.Environment, config SetRMNH }, } - timelocksPerChain := buildTimelockAddressPerChain(e, state) + timelocksPerChain := BuildTimelockAddressPerChain(e, state) - proposerMCMSes := buildProposerPerChain(e, state) + proposerMCMSes := BuildProposerPerChain(e, state) prop, err := proposalutils.BuildProposalFromBatches( timelocksPerChain, @@ -331,7 +331,7 @@ func SetRMNHomeCandidateConfigChangeset(e deployment.Environment, config SetRMNH }, nil } -func PromoteCandidateConfigChangeset(e deployment.Environment, config PromoteRMNHomeCandidateConfig) (deployment.ChangesetOutput, error) { +func PromoteRMNHomeCandidateConfigChangeset(e deployment.Environment, config PromoteRMNHomeCandidateConfig) (deployment.ChangesetOutput, error) { state, err := LoadOnchainState(e) if err != nil { return deployment.ChangesetOutput{}, fmt.Errorf("failed to load onchain state: %w", err) @@ -393,9 +393,9 @@ func PromoteCandidateConfigChangeset(e deployment.Environment, config PromoteRMN }, } - timelocksPerChain := buildTimelockAddressPerChain(e, state) + timelocksPerChain := BuildTimelockAddressPerChain(e, state) - proposerMCMSes := buildProposerPerChain(e, state) + proposerMCMSes := BuildProposerPerChain(e, state) prop, err := proposalutils.BuildProposalFromBatches( timelocksPerChain, @@ -414,7 +414,7 @@ func PromoteCandidateConfigChangeset(e deployment.Environment, config PromoteRMN }, nil } -func buildRMNRemotePerChain(e deployment.Environment, state CCIPOnChainState) map[uint64]*rmn_remote.RMNRemote { +func BuildRMNRemotePerChain(e deployment.Environment, state CCIPOnChainState) map[uint64]*rmn_remote.RMNRemote { timelocksPerChain := make(map[uint64]*rmn_remote.RMNRemote) for _, chain := range e.Chains { timelocksPerChain[chain.Selector] = state.Chains[chain.Selector].RMNRemote @@ -488,7 +488,7 @@ func SetRMNRemoteConfigChangeset(e deployment.Environment, config SetRMNRemoteCo return deployment.ChangesetOutput{}, fmt.Errorf("failed to get RMNHome active digest for chain %s: %w", homeChain.String(), err) } - rmnRemotePerChain := buildRMNRemotePerChain(e, state) + rmnRemotePerChain := BuildRMNRemotePerChain(e, state) batches := make([]timelock.BatchChainOperation, 0) for chain, remoteConfig := range config.RMNRemoteConfigs { remote, ok := rmnRemotePerChain[chain] @@ -545,9 +545,9 @@ func SetRMNRemoteConfigChangeset(e deployment.Environment, config SetRMNRemoteCo return deployment.ChangesetOutput{}, nil } - timelocksPerChain := buildTimelockAddressPerChain(e, state) + timelocksPerChain := BuildTimelockAddressPerChain(e, state) - proposerMCMSes := buildProposerPerChain(e, state) + proposerMCMSes := BuildProposerPerChain(e, state) prop, err := proposalutils.BuildProposalFromBatches( timelocksPerChain, diff --git a/deployment/ccip/changeset/cs_update_rmn_config_test.go b/deployment/ccip/changeset/cs_update_rmn_config_test.go index fdccf36af07..1db80197b15 100644 --- a/deployment/ccip/changeset/cs_update_rmn_config_test.go +++ b/deployment/ccip/changeset/cs_update_rmn_config_test.go @@ -1,4 +1,4 @@ -package changeset +package changeset_test import ( "testing" @@ -7,6 +7,8 @@ import ( "github.com/stretchr/testify/require" "github.com/smartcontractkit/chainlink/deployment" + "github.com/smartcontractkit/chainlink/deployment/ccip/changeset" + "github.com/smartcontractkit/chainlink/deployment/ccip/changeset/testhelpers" commonchangeset "github.com/smartcontractkit/chainlink/deployment/common/changeset" "github.com/smartcontractkit/chainlink/deployment/common/proposalutils" commontypes "github.com/smartcontractkit/chainlink/deployment/common/types" @@ -15,19 +17,19 @@ import ( ) var ( - rmn_staging_1 = RMNNopConfig{ + rmnStaging1 = changeset.RMNNopConfig{ NodeIndex: 0, PeerId: deployment.MustPeerIDFromString("p2p_12D3KooWRXxZq3pd4a3ZGkKj7Nt1SQQrnB8CuvbPnnV9KVeMeWqg"), OffchainPublicKey: [32]byte(common.FromHex("0xb34944857a42444d1b285d7940d6e06682309e0781e43a69676ee9f85c73c2d1")), EVMOnChainPublicKey: common.HexToAddress("0x5af8ee32316a6427f169a45fdc1b3a91a85ac459e3c1cb91c69e1c51f0c1fc21"), } - rmn_staging_2 = RMNNopConfig{ + rmnStaging2 = changeset.RMNNopConfig{ NodeIndex: 1, PeerId: deployment.MustPeerIDFromString("p2p_12D3KooWEmdxYQFsRbD9aFczF32zA3CcUwuSiWCk2CrmACo4v9RL"), OffchainPublicKey: [32]byte(common.FromHex("0x68d9f3f274e3985528a923a9bace3d39c55dd778b187b4120b384cc48c892859")), EVMOnChainPublicKey: common.HexToAddress("0x858589216956f482a0f68b282a7050af4cd48ed2"), } - rmn_staging_3 = RMNNopConfig{ + rmnStaging3 = changeset.RMNNopConfig{ NodeIndex: 2, PeerId: deployment.MustPeerIDFromString("p2p_12D3KooWJS42cNXKJvj6DeZnxEX7aGxhEuap6uNFrz554AbUDw6Q"), OffchainPublicKey: [32]byte(common.FromHex("0x5af8ee32316a6427f169a45fdc1b3a91a85ac459e3c1cb91c69e1c51f0c1fc21")), @@ -38,7 +40,7 @@ var ( type updateRMNConfigTestCase struct { useMCMS bool name string - nops []RMNNopConfig + nops []changeset.RMNNopConfig } func TestUpdateRMNConfig(t *testing.T) { @@ -47,12 +49,12 @@ func TestUpdateRMNConfig(t *testing.T) { { useMCMS: true, name: "with MCMS", - nops: []RMNNopConfig{rmn_staging_1, rmn_staging_2, rmn_staging_3}, + nops: []changeset.RMNNopConfig{rmnStaging1, rmnStaging2, rmnStaging3}, }, { useMCMS: false, name: "without MCMS", - nops: []RMNNopConfig{rmn_staging_1, rmn_staging_2, rmn_staging_3}, + nops: []changeset.RMNNopConfig{rmnStaging1, rmnStaging2, rmnStaging3}, }, } @@ -65,9 +67,9 @@ func TestUpdateRMNConfig(t *testing.T) { } func updateRMNConfig(t *testing.T, tc updateRMNConfigTestCase) { - e, _ := NewMemoryEnvironment(t) + e, _ := testhelpers.NewMemoryEnvironment(t) - state, err := LoadOnchainState(e.Env) + state, err := changeset.LoadOnchainState(e.Env) require.NoError(t, err) contractsByChain := make(map[uint64][]common.Address) @@ -78,7 +80,7 @@ func updateRMNConfig(t *testing.T, tc updateRMNConfigTestCase) { contractsByChain[e.HomeChainSel] = append(contractsByChain[e.HomeChainSel], state.Chains[e.HomeChainSel].RMNHome.Address()) - timelocksPerChain := buildTimelockPerChain(e.Env, state) + timelocksPerChain := changeset.BuildTimelockPerChain(e.Env, state) if tc.useMCMS { // This is required because RMNHome is initially owned by the deployer _, err = commonchangeset.ApplyChangesets(t, e.Env, timelocksPerChain, []commonchangeset.ChangesetApplication{ @@ -99,10 +101,10 @@ func updateRMNConfig(t *testing.T, tc updateRMNConfigTestCase) { previousActiveDigest, err := rmnHome.GetActiveDigest(nil) require.NoError(t, err) - var mcmsConfig *MCMSConfig = nil + var mcmsConfig *changeset.MCMSConfig if tc.useMCMS { - mcmsConfig = &MCMSConfig{ + mcmsConfig = &changeset.MCMSConfig{ MinDelay: 0, } } @@ -112,7 +114,7 @@ func updateRMNConfig(t *testing.T, tc updateRMNConfigTestCase) { nodes = append(nodes, nop.ToRMNHomeNode()) } - setRMNHomeCandidateConfig := SetRMNHomeCandidateConfig{ + setRMNHomeCandidateConfig := changeset.SetRMNHomeCandidateConfig{ HomeChainSelector: e.HomeChainSel, RMNStaticConfig: rmn_home.RMNHomeStaticConfig{ Nodes: nodes, @@ -127,14 +129,14 @@ func updateRMNConfig(t *testing.T, tc updateRMNConfigTestCase) { _, err = commonchangeset.ApplyChangesets(t, e.Env, timelocksPerChain, []commonchangeset.ChangesetApplication{ { - Changeset: commonchangeset.WrapChangeSet(SetRMNHomeCandidateConfigChangeset), + Changeset: commonchangeset.WrapChangeSet(changeset.SetRMNHomeCandidateConfigChangeset), Config: setRMNHomeCandidateConfig, }, }) require.NoError(t, err) - state, err = LoadOnchainState(e.Env) + state, err = changeset.LoadOnchainState(e.Env) require.NoError(t, err) currentCandidateDigest, err := rmnHome.GetCandidateDigest(nil) @@ -145,7 +147,7 @@ func updateRMNConfig(t *testing.T, tc updateRMNConfigTestCase) { require.NotEqual(t, previousCandidateDigest, currentCandidateDigest) require.Equal(t, previousActiveDigest, currentActiveDigest) - promoteConfig := PromoteRMNHomeCandidateConfig{ + promoteConfig := changeset.PromoteRMNHomeCandidateConfig{ HomeChainSelector: e.HomeChainSel, DigestToPromote: currentCandidateDigest, MCMSConfig: mcmsConfig, @@ -153,7 +155,7 @@ func updateRMNConfig(t *testing.T, tc updateRMNConfigTestCase) { _, err = commonchangeset.ApplyChangesets(t, e.Env, timelocksPerChain, []commonchangeset.ChangesetApplication{ { - Changeset: commonchangeset.WrapChangeSet(PromoteCandidateConfigChangeset), + Changeset: commonchangeset.WrapChangeSet(changeset.PromoteRMNHomeCandidateConfigChangeset), Config: promoteConfig, }, }) @@ -169,9 +171,9 @@ func updateRMNConfig(t *testing.T, tc updateRMNConfigTestCase) { signers = append(signers, nop.ToRMNRemoteSigner()) } - remoteConfigs := make(map[uint64]RMNRemoteConfig, len(e.Env.Chains)) + remoteConfigs := make(map[uint64]changeset.RMNRemoteConfig, len(e.Env.Chains)) for _, chain := range e.Env.Chains { - remoteConfig := RMNRemoteConfig{ + remoteConfig := changeset.RMNRemoteConfig{ Signers: signers, F: 0, } @@ -179,7 +181,7 @@ func updateRMNConfig(t *testing.T, tc updateRMNConfigTestCase) { remoteConfigs[chain.Selector] = remoteConfig } - setRemoteConfig := SetRMNRemoteConfig{ + setRemoteConfig := changeset.SetRMNRemoteConfig{ HomeChainSelector: e.HomeChainSel, RMNRemoteConfigs: remoteConfigs, MCMSConfig: mcmsConfig, @@ -187,13 +189,13 @@ func updateRMNConfig(t *testing.T, tc updateRMNConfigTestCase) { _, err = commonchangeset.ApplyChangesets(t, e.Env, timelocksPerChain, []commonchangeset.ChangesetApplication{ { - Changeset: commonchangeset.WrapChangeSet(SetRMNRemoteConfigChangeset), + Changeset: commonchangeset.WrapChangeSet(changeset.SetRMNRemoteConfigChangeset), Config: setRemoteConfig, }, }) require.NoError(t, err) - rmnRemotePerChain := buildRMNRemotePerChain(e.Env, state) + rmnRemotePerChain := changeset.BuildRMNRemotePerChain(e.Env, state) for _, rmnRemote := range rmnRemotePerChain { remoteConfigSetEvents, err := rmnRemote.FilterConfigSet(nil, nil) require.NoError(t, err) @@ -206,8 +208,8 @@ func updateRMNConfig(t *testing.T, tc updateRMNConfigTestCase) { } } -func buildRMNRemoteAddressPerChain(e deployment.Environment, state CCIPOnChainState) map[uint64]common.Address { - rmnRemotePerChain := buildRMNRemotePerChain(e, state) +func buildRMNRemoteAddressPerChain(e deployment.Environment, state changeset.CCIPOnChainState) map[uint64]common.Address { + rmnRemotePerChain := changeset.BuildRMNRemotePerChain(e, state) rmnRemoteAddressPerChain := make(map[uint64]common.Address) for chain, remote := range rmnRemotePerChain { if remote == nil { @@ -220,14 +222,14 @@ func buildRMNRemoteAddressPerChain(e deployment.Environment, state CCIPOnChainSt func TestSetRMNRemoteOnRMNProxy(t *testing.T) { t.Parallel() - e, _ := NewMemoryEnvironment(t, WithNoJobsAndContracts()) + e, _ := testhelpers.NewMemoryEnvironment(t, testhelpers.WithNoJobsAndContracts()) allChains := e.Env.AllChainSelectors() mcmsCfg := make(map[uint64]commontypes.MCMSWithTimelockConfig) var err error - var prereqCfgs []DeployPrerequisiteConfigPerChain + prereqCfgs := make([]changeset.DeployPrerequisiteConfigPerChain, 0) for _, c := range e.Env.AllChainSelectors() { mcmsCfg[c] = proposalutils.SingleGroupTimelockConfig(t) - prereqCfgs = append(prereqCfgs, DeployPrerequisiteConfigPerChain{ + prereqCfgs = append(prereqCfgs, changeset.DeployPrerequisiteConfigPerChain{ ChainSelector: c, }) } @@ -239,8 +241,8 @@ func TestSetRMNRemoteOnRMNProxy(t *testing.T) { Config: allChains, }, { - Changeset: commonchangeset.WrapChangeSet(DeployPrerequisites), - Config: DeployPrerequisiteConfig{ + Changeset: commonchangeset.WrapChangeSet(changeset.DeployPrerequisitesChangeset), + Config: changeset.DeployPrerequisiteConfig{ Configs: prereqCfgs, }, }, @@ -251,7 +253,7 @@ func TestSetRMNRemoteOnRMNProxy(t *testing.T) { }) require.NoError(t, err) contractsByChain := make(map[uint64][]common.Address) - state, err := LoadOnchainState(e.Env) + state, err := changeset.LoadOnchainState(e.Env) require.NoError(t, err) for _, chain := range allChains { rmnProxy := state.Chains[chain].RMNProxy @@ -278,36 +280,36 @@ func TestSetRMNRemoteOnRMNProxy(t *testing.T) { }, { - Changeset: commonchangeset.WrapChangeSet(DeployHomeChain), - Config: DeployHomeChainConfig{ + Changeset: commonchangeset.WrapChangeSet(changeset.DeployHomeChainChangeset), + Config: changeset.DeployHomeChainConfig{ HomeChainSel: e.HomeChainSel, - RMNDynamicConfig: NewTestRMNDynamicConfig(), - RMNStaticConfig: NewTestRMNStaticConfig(), - NodeOperators: NewTestNodeOperator(e.Env.Chains[e.HomeChainSel].DeployerKey.From), + RMNDynamicConfig: testhelpers.NewTestRMNDynamicConfig(), + RMNStaticConfig: testhelpers.NewTestRMNStaticConfig(), + NodeOperators: testhelpers.NewTestNodeOperator(e.Env.Chains[e.HomeChainSel].DeployerKey.From), NodeP2PIDsPerNodeOpAdmin: map[string][][32]byte{ "NodeOperator": envNodes.NonBootstraps().PeerIDs(), }, }, }, { - Changeset: commonchangeset.WrapChangeSet(DeployChainContracts), - Config: DeployChainContractsConfig{ + Changeset: commonchangeset.WrapChangeSet(changeset.DeployChainContractsChangeset), + Config: changeset.DeployChainContractsConfig{ ChainSelectors: allChains, HomeChainSelector: e.HomeChainSel, }, }, { - Changeset: commonchangeset.WrapChangeSet(SetRMNRemoteOnRMNProxy), - Config: SetRMNRemoteOnRMNProxyConfig{ + Changeset: commonchangeset.WrapChangeSet(changeset.SetRMNRemoteOnRMNProxyChangeset), + Config: changeset.SetRMNRemoteOnRMNProxyConfig{ ChainSelectors: allChains, - MCMSConfig: &MCMSConfig{ + MCMSConfig: &changeset.MCMSConfig{ MinDelay: 0, }, }, }, }) require.NoError(t, err) - state, err = LoadOnchainState(e.Env) + state, err = changeset.LoadOnchainState(e.Env) require.NoError(t, err) for _, chain := range allChains { rmnProxy := state.Chains[chain].RMNProxy diff --git a/deployment/ccip/changeset/deployer_group.go b/deployment/ccip/changeset/deployer_group.go index 0c0ff1e5c8e..5f7c7e52da2 100644 --- a/deployment/ccip/changeset/deployer_group.go +++ b/deployment/ccip/changeset/deployer_group.go @@ -31,10 +31,10 @@ type DeployerGroup struct { // deployerGroup := NewDeployerGroup(e, state, mcmConfig) // selector := 0 // # Get the right deployer key for the chain -// deployer := deployerGroup.getDeployer(selector) +// deployer := deployerGroup.GetDeployer(selector) // state.Chains[selector].RMNRemote.Curse() // # Execute the transaction or create the proposal -// deployerGroup.enact("Curse RMNRemote") +// deployerGroup.Enact("Curse RMNRemote") func NewDeployerGroup(e deployment.Environment, state CCIPOnChainState, mcmConfig *MCMSConfig) *DeployerGroup { return &DeployerGroup{ e: e, @@ -44,7 +44,7 @@ func NewDeployerGroup(e deployment.Environment, state CCIPOnChainState, mcmConfi } } -func (d *DeployerGroup) getDeployer(chain uint64) (*bind.TransactOpts, error) { +func (d *DeployerGroup) GetDeployer(chain uint64) (*bind.TransactOpts, error) { txOpts := d.e.Chains[chain].DeployerKey if d.mcmConfig != nil { txOpts = deployment.SimTransactOpts() @@ -102,7 +102,7 @@ func (d *DeployerGroup) getDeployer(chain uint64) (*bind.TransactOpts, error) { return sim, nil } -func (d *DeployerGroup) enact(deploymentDescription string) (deployment.ChangesetOutput, error) { +func (d *DeployerGroup) Enact(deploymentDescription string) (deployment.ChangesetOutput, error) { if d.mcmConfig != nil { return d.enactMcms(deploymentDescription) } @@ -127,9 +127,9 @@ func (d *DeployerGroup) enactMcms(deploymentDescription string) (deployment.Chan }) } - timelocksPerChain := buildTimelockAddressPerChain(d.e, d.state) + timelocksPerChain := BuildTimelockAddressPerChain(d.e, d.state) - proposerMCMSes := buildProposerPerChain(d.e, d.state) + proposerMCMSes := BuildProposerPerChain(d.e, d.state) prop, err := proposalutils.BuildProposalFromBatches( timelocksPerChain, @@ -165,7 +165,7 @@ func (d *DeployerGroup) enactDeployer() (deployment.ChangesetOutput, error) { return deployment.ChangesetOutput{}, nil } -func buildTimelockPerChain(e deployment.Environment, state CCIPOnChainState) map[uint64]*proposalutils.TimelockExecutionContracts { +func BuildTimelockPerChain(e deployment.Environment, state CCIPOnChainState) map[uint64]*proposalutils.TimelockExecutionContracts { timelocksPerChain := make(map[uint64]*proposalutils.TimelockExecutionContracts) for _, chain := range e.Chains { timelocksPerChain[chain.Selector] = &proposalutils.TimelockExecutionContracts{ @@ -176,8 +176,8 @@ func buildTimelockPerChain(e deployment.Environment, state CCIPOnChainState) map return timelocksPerChain } -func buildTimelockAddressPerChain(e deployment.Environment, state CCIPOnChainState) map[uint64]common.Address { - timelocksPerChain := buildTimelockPerChain(e, state) +func BuildTimelockAddressPerChain(e deployment.Environment, state CCIPOnChainState) map[uint64]common.Address { + timelocksPerChain := BuildTimelockPerChain(e, state) timelockAddressPerChain := make(map[uint64]common.Address) for chain, timelock := range timelocksPerChain { timelockAddressPerChain[chain] = timelock.Timelock.Address() @@ -185,7 +185,7 @@ func buildTimelockAddressPerChain(e deployment.Environment, state CCIPOnChainSta return timelockAddressPerChain } -func buildProposerPerChain(e deployment.Environment, state CCIPOnChainState) map[uint64]*gethwrappers.ManyChainMultiSig { +func BuildProposerPerChain(e deployment.Environment, state CCIPOnChainState) map[uint64]*gethwrappers.ManyChainMultiSig { proposerPerChain := make(map[uint64]*gethwrappers.ManyChainMultiSig) for _, chain := range e.Chains { proposerPerChain[chain.Selector] = state.Chains[chain.Selector].ProposerMcm diff --git a/deployment/ccip/changeset/deployer_group_test.go b/deployment/ccip/changeset/deployer_group_test.go index 12dcaa9076b..ba598ec74e8 100644 --- a/deployment/ccip/changeset/deployer_group_test.go +++ b/deployment/ccip/changeset/deployer_group_test.go @@ -1,4 +1,4 @@ -package changeset +package changeset_test import ( "math/big" @@ -8,6 +8,8 @@ import ( "github.com/stretchr/testify/require" "github.com/smartcontractkit/chainlink/deployment" + "github.com/smartcontractkit/chainlink/deployment/ccip/changeset" + "github.com/smartcontractkit/chainlink/deployment/ccip/changeset/testhelpers" commonchangeset "github.com/smartcontractkit/chainlink/deployment/common/changeset" ) @@ -15,19 +17,19 @@ type dummyDeployerGroupChangesetConfig struct { selector uint64 address common.Address mints []*big.Int - MCMS *MCMSConfig + MCMS *changeset.MCMSConfig } func dummyDeployerGroupGrantMintChangeset(e deployment.Environment, cfg dummyDeployerGroupChangesetConfig) (deployment.ChangesetOutput, error) { - state, err := LoadOnchainState(e) + state, err := changeset.LoadOnchainState(e) if err != nil { return deployment.ChangesetOutput{}, err } token := state.Chains[cfg.selector].LinkToken - group := NewDeployerGroup(e, state, cfg.MCMS) - deployer, err := group.getDeployer(cfg.selector) + group := changeset.NewDeployerGroup(e, state, cfg.MCMS) + deployer, err := group.GetDeployer(cfg.selector) if err != nil { return deployment.ChangesetOutput{}, err } @@ -37,19 +39,19 @@ func dummyDeployerGroupGrantMintChangeset(e deployment.Environment, cfg dummyDep return deployment.ChangesetOutput{}, err } - return group.enact("Grant mint role") + return group.Enact("Grant mint role") } func dummyDeployerGroupMintChangeset(e deployment.Environment, cfg dummyDeployerGroupChangesetConfig) (deployment.ChangesetOutput, error) { - state, err := LoadOnchainState(e) + state, err := changeset.LoadOnchainState(e) if err != nil { return deployment.ChangesetOutput{}, err } token := state.Chains[cfg.selector].LinkToken - group := NewDeployerGroup(e, state, cfg.MCMS) - deployer, err := group.getDeployer(cfg.selector) + group := changeset.NewDeployerGroup(e, state, cfg.MCMS) + deployer, err := group.GetDeployer(cfg.selector) if err != nil { return deployment.ChangesetOutput{}, err } @@ -61,7 +63,7 @@ func dummyDeployerGroupMintChangeset(e deployment.Environment, cfg dummyDeployer } } - return group.enact("Mint tokens") + return group.Enact("Mint tokens") } type deployerGroupTestCase struct { @@ -91,7 +93,7 @@ var deployerGroupTestCases = []deployerGroupTestCase{ func TestDeployerGroup(t *testing.T) { for _, tc := range deployerGroupTestCases { t.Run(tc.name, func(t *testing.T) { - e, _ := NewMemoryEnvironment(t, WithChains(2)) + e, _ := testhelpers.NewMemoryEnvironment(t, testhelpers.WithNumOfChains(2)) tc.cfg.selector = e.HomeChainSel tc.cfg.MCMS = nil @@ -105,7 +107,7 @@ func TestDeployerGroup(t *testing.T) { } else { require.NoError(t, err) - state, err := LoadOnchainState(e.Env) + state, err := changeset.LoadOnchainState(e.Env) require.NoError(t, err) token := state.Chains[e.HomeChainSel].LinkToken @@ -131,16 +133,16 @@ func TestDeployerGroupMCMS(t *testing.T) { t.Skip("skipping test because it's not possible to verify error when using MCMS since we are explicitly failing the test in ApplyChangesets") } - e, _ := NewMemoryEnvironment(t, WithChains(2)) + e, _ := testhelpers.NewMemoryEnvironment(t, testhelpers.WithNumOfChains(2)) tc.cfg.selector = e.HomeChainSel - tc.cfg.MCMS = &MCMSConfig{ + tc.cfg.MCMS = &changeset.MCMSConfig{ MinDelay: 0, } - state, err := LoadOnchainState(e.Env) + state, err := changeset.LoadOnchainState(e.Env) require.NoError(t, err) - timelocksPerChain := buildTimelockPerChain(e.Env, state) + timelocksPerChain := changeset.BuildTimelockPerChain(e.Env, state) contractsByChain := make(map[uint64][]common.Address) contractsByChain[e.HomeChainSel] = []common.Address{state.Chains[e.HomeChainSel].LinkToken.Address()} @@ -172,7 +174,7 @@ func TestDeployerGroupMCMS(t *testing.T) { }) require.NoError(t, err) - state, err = LoadOnchainState(e.Env) + state, err = changeset.LoadOnchainState(e.Env) require.NoError(t, err) token := state.Chains[e.HomeChainSel].LinkToken diff --git a/deployment/ccip/changeset/save_existing_test.go b/deployment/ccip/changeset/save_existing_test.go index 080ed80481a..f575bc005f2 100644 --- a/deployment/ccip/changeset/save_existing_test.go +++ b/deployment/ccip/changeset/save_existing_test.go @@ -1,4 +1,4 @@ -package changeset +package changeset_test import ( "math/big" @@ -9,6 +9,7 @@ import ( "go.uber.org/zap/zapcore" "github.com/smartcontractkit/chainlink/deployment" + "github.com/smartcontractkit/chainlink/deployment/ccip/changeset" commonchangeset "github.com/smartcontractkit/chainlink/deployment/common/changeset" commontypes "github.com/smartcontractkit/chainlink/deployment/common/types" "github.com/smartcontractkit/chainlink/deployment/environment/memory" @@ -35,32 +36,32 @@ func TestSaveExistingCCIP(t *testing.T) { }, { Address: common.BigToAddress(big.NewInt(2)), - TypeAndVersion: deployment.NewTypeAndVersion(WETH9, deployment.Version1_0_0), + TypeAndVersion: deployment.NewTypeAndVersion(changeset.WETH9, deployment.Version1_0_0), ChainSelector: chain1, }, { Address: common.BigToAddress(big.NewInt(3)), - TypeAndVersion: deployment.NewTypeAndVersion(TokenAdminRegistry, deployment.Version1_5_0), + TypeAndVersion: deployment.NewTypeAndVersion(changeset.TokenAdminRegistry, deployment.Version1_5_0), ChainSelector: chain1, }, { Address: common.BigToAddress(big.NewInt(4)), - TypeAndVersion: deployment.NewTypeAndVersion(RegistryModule, deployment.Version1_5_0), + TypeAndVersion: deployment.NewTypeAndVersion(changeset.RegistryModule, deployment.Version1_5_0), ChainSelector: chain2, }, { Address: common.BigToAddress(big.NewInt(5)), - TypeAndVersion: deployment.NewTypeAndVersion(Router, deployment.Version1_2_0), + TypeAndVersion: deployment.NewTypeAndVersion(changeset.Router, deployment.Version1_2_0), ChainSelector: chain2, }, }, } - output, err := commonchangeset.SaveExistingContracts(e, cfg) + output, err := commonchangeset.SaveExistingContractsChangeset(e, cfg) require.NoError(t, err) err = e.ExistingAddresses.Merge(output.AddressBook) require.NoError(t, err) - state, err := LoadOnchainState(e) + state, err := changeset.LoadOnchainState(e) require.NoError(t, err) require.Equal(t, state.Chains[chain1].LinkToken.Address(), common.BigToAddress(big.NewInt(1))) require.Equal(t, state.Chains[chain1].Weth9.Address(), common.BigToAddress(big.NewInt(2))) diff --git a/deployment/ccip/changeset/state_test.go b/deployment/ccip/changeset/state_test.go index f7d06efa66d..c46df8b1dc7 100644 --- a/deployment/ccip/changeset/state_test.go +++ b/deployment/ccip/changeset/state_test.go @@ -1,14 +1,17 @@ -package changeset +package changeset_test import ( "testing" "github.com/stretchr/testify/require" + + "github.com/smartcontractkit/chainlink/deployment/ccip/changeset" + "github.com/smartcontractkit/chainlink/deployment/ccip/changeset/testhelpers" ) func TestSmokeState(t *testing.T) { - tenv, _ := NewMemoryEnvironment(t, WithChains(3)) - state, err := LoadOnchainState(tenv.Env) + tenv, _ := testhelpers.NewMemoryEnvironment(t, testhelpers.WithNumOfChains(3)) + state, err := changeset.LoadOnchainState(tenv.Env) require.NoError(t, err) _, err = state.View(tenv.Env.AllChainSelectors()) require.NoError(t, err) diff --git a/deployment/ccip/changeset/test_usdc_helpers.go b/deployment/ccip/changeset/test_usdc_helpers.go deleted file mode 100644 index c9dd87b866e..00000000000 --- a/deployment/ccip/changeset/test_usdc_helpers.go +++ /dev/null @@ -1,260 +0,0 @@ -package changeset - -import ( - "math/big" - - "golang.org/x/sync/errgroup" - - "github.com/ethereum/go-ethereum/common" - - "github.com/smartcontractkit/chainlink-ccip/pkg/reader" - "github.com/smartcontractkit/chainlink-common/pkg/logger" - - "github.com/smartcontractkit/chainlink/deployment" - "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/fee_quoter" - "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/mock_usdc_token_messenger" - "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/mock_usdc_token_transmitter" - "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/usdc_token_pool" - "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/shared/generated/burn_mint_erc677" -) - -func ConfigureUSDCTokenPools( - lggr logger.Logger, - chains map[uint64]deployment.Chain, - src, dst uint64, - state CCIPOnChainState, -) (*burn_mint_erc677.BurnMintERC677, *burn_mint_erc677.BurnMintERC677, error) { - srcToken := state.Chains[src].BurnMintTokens677[USDCSymbol] - dstToken := state.Chains[dst].BurnMintTokens677[USDCSymbol] - srcPool := state.Chains[src].USDCTokenPool - dstPool := state.Chains[dst].USDCTokenPool - - args := []struct { - sourceChain deployment.Chain - dstChainSel uint64 - state CCIPChainState - srcToken *burn_mint_erc677.BurnMintERC677 - srcPool *usdc_token_pool.USDCTokenPool - dstToken *burn_mint_erc677.BurnMintERC677 - dstPool *usdc_token_pool.USDCTokenPool - }{ - { - chains[src], - dst, - state.Chains[src], - srcToken, - srcPool, - dstToken, - dstPool, - }, - { - chains[dst], - src, - state.Chains[dst], - dstToken, - dstPool, - srcToken, - srcPool, - }, - } - - configurePoolGrp := errgroup.Group{} - for _, arg := range args { - configurePoolGrp.Go(configureSingleChain(lggr, arg.sourceChain, arg.dstChainSel, arg.state, arg.srcToken, arg.srcPool, arg.dstToken, arg.dstPool)) - } - if err := configurePoolGrp.Wait(); err != nil { - return nil, nil, err - } - return srcToken, dstToken, nil -} - -func configureSingleChain( - lggr logger.Logger, - sourceChain deployment.Chain, - dstChainSel uint64, - state CCIPChainState, - srcToken *burn_mint_erc677.BurnMintERC677, - srcPool *usdc_token_pool.USDCTokenPool, - dstToken *burn_mint_erc677.BurnMintERC677, - dstPool *usdc_token_pool.USDCTokenPool, -) func() error { - return func() error { - if err := attachTokenToTheRegistry(sourceChain, state, sourceChain.DeployerKey, srcToken.Address(), srcPool.Address()); err != nil { - lggr.Errorw("Failed to attach token to the registry", "err", err, "token", srcToken.Address(), "pool", srcPool.Address()) - return err - } - - if err := setUSDCTokenPoolCounterPart(sourceChain, srcPool, dstChainSel, sourceChain.DeployerKey, dstToken.Address(), dstPool.Address()); err != nil { - lggr.Errorw("Failed to set counter part", "err", err, "srcPool", srcPool.Address(), "dstPool", dstPool.Address()) - return err - } - - for _, addr := range []common.Address{ - srcPool.Address(), - state.MockUSDCTokenMessenger.Address(), - state.MockUSDCTransmitter.Address(), - } { - if err := grantMintBurnPermissions(lggr, sourceChain, srcToken, sourceChain.DeployerKey, addr); err != nil { - lggr.Errorw("Failed to grant mint/burn permissions", "err", err, "token", srcToken.Address(), "address", addr) - return err - } - } - return nil - } -} - -func UpdateFeeQuoterForUSDC( - lggr logger.Logger, - chain deployment.Chain, - state CCIPChainState, - dstChain uint64, - usdcToken *burn_mint_erc677.BurnMintERC677, -) error { - config := []fee_quoter.FeeQuoterTokenTransferFeeConfigArgs{ - { - DestChainSelector: dstChain, - TokenTransferFeeConfigs: []fee_quoter.FeeQuoterTokenTransferFeeConfigSingleTokenArgs{ - { - Token: usdcToken.Address(), - TokenTransferFeeConfig: fee_quoter.FeeQuoterTokenTransferFeeConfig{ - MinFeeUSDCents: 50, - MaxFeeUSDCents: 50_000, - DeciBps: 0, - DestGasOverhead: 180_000, - DestBytesOverhead: 640, - IsEnabled: true, - }, - }, - }, - }, - } - - tx, err := state.FeeQuoter.ApplyTokenTransferFeeConfigUpdates( - chain.DeployerKey, - config, - []fee_quoter.FeeQuoterTokenTransferFeeConfigRemoveArgs{}, - ) - if err != nil { - lggr.Errorw("Failed to apply token transfer fee config updates", "err", err, "config", config) - return err - } - - _, err = chain.Confirm(tx) - return err -} - -func DeployUSDC( - lggr logger.Logger, - chain deployment.Chain, - addresses deployment.AddressBook, - rmnProxy common.Address, - router common.Address, -) ( - *burn_mint_erc677.BurnMintERC677, - *usdc_token_pool.USDCTokenPool, - *mock_usdc_token_messenger.MockE2EUSDCTokenMessenger, - *mock_usdc_token_transmitter.MockE2EUSDCTransmitter, - error, -) { - token, err := deployment.DeployContract(lggr, chain, addresses, - func(chain deployment.Chain) deployment.ContractDeploy[*burn_mint_erc677.BurnMintERC677] { - tokenAddress, tx, tokenContract, err2 := burn_mint_erc677.DeployBurnMintERC677( - chain.DeployerKey, - chain.Client, - USDCName, - string(USDCSymbol), - UsdcDecimals, - big.NewInt(0), - ) - return deployment.ContractDeploy[*burn_mint_erc677.BurnMintERC677]{ - Address: tokenAddress, - Contract: tokenContract, - Tx: tx, - Tv: deployment.NewTypeAndVersion(USDCToken, deployment.Version1_0_0), - Err: err2, - } - }) - if err != nil { - lggr.Errorw("Failed to deploy USDC token", "chain", chain.String(), "err", err) - return nil, nil, nil, nil, err - } - - tx, err := token.Contract.GrantMintRole(chain.DeployerKey, chain.DeployerKey.From) - if err != nil { - lggr.Errorw("Failed to grant mint role", "chain", chain.String(), "token", token.Contract.Address(), "err", err) - return nil, nil, nil, nil, err - } - _, err = chain.Confirm(tx) - if err != nil { - return nil, nil, nil, nil, err - } - - transmitter, err := deployment.DeployContract(lggr, chain, addresses, - func(chain deployment.Chain) deployment.ContractDeploy[*mock_usdc_token_transmitter.MockE2EUSDCTransmitter] { - transmitterAddress, tx, transmitterContract, err2 := mock_usdc_token_transmitter.DeployMockE2EUSDCTransmitter( - chain.DeployerKey, - chain.Client, - 0, - reader.AllAvailableDomains()[chain.Selector], - token.Address, - ) - return deployment.ContractDeploy[*mock_usdc_token_transmitter.MockE2EUSDCTransmitter]{ - Address: transmitterAddress, - Contract: transmitterContract, - Tx: tx, - Tv: deployment.NewTypeAndVersion(USDCMockTransmitter, deployment.Version1_0_0), - Err: err2, - } - }) - if err != nil { - lggr.Errorw("Failed to deploy mock USDC transmitter", "chain", chain.String(), "err", err) - return nil, nil, nil, nil, err - } - - messenger, err := deployment.DeployContract(lggr, chain, addresses, - func(chain deployment.Chain) deployment.ContractDeploy[*mock_usdc_token_messenger.MockE2EUSDCTokenMessenger] { - messengerAddress, tx, messengerContract, err2 := mock_usdc_token_messenger.DeployMockE2EUSDCTokenMessenger( - chain.DeployerKey, - chain.Client, - 0, - transmitter.Address, - ) - return deployment.ContractDeploy[*mock_usdc_token_messenger.MockE2EUSDCTokenMessenger]{ - Address: messengerAddress, - Contract: messengerContract, - Tx: tx, - Tv: deployment.NewTypeAndVersion(USDCTokenMessenger, deployment.Version1_0_0), - Err: err2, - } - }) - if err != nil { - lggr.Errorw("Failed to deploy USDC token messenger", "chain", chain.String(), "err", err) - return nil, nil, nil, nil, err - } - - tokenPool, err := deployment.DeployContract(lggr, chain, addresses, - func(chain deployment.Chain) deployment.ContractDeploy[*usdc_token_pool.USDCTokenPool] { - tokenPoolAddress, tx, tokenPoolContract, err2 := usdc_token_pool.DeployUSDCTokenPool( - chain.DeployerKey, - chain.Client, - messenger.Address, - token.Address, - []common.Address{}, - rmnProxy, - router, - ) - return deployment.ContractDeploy[*usdc_token_pool.USDCTokenPool]{ - Address: tokenPoolAddress, - Contract: tokenPoolContract, - Tx: tx, - Tv: deployment.NewTypeAndVersion(USDCTokenPool, deployment.Version1_0_0), - Err: err2, - } - }) - if err != nil { - lggr.Errorw("Failed to deploy USDC token pool", "chain", chain.String(), "err", err) - return nil, nil, nil, nil, err - } - - return token.Contract, tokenPool.Contract, messenger.Contract, transmitter.Contract, nil -} diff --git a/deployment/ccip/changeset/test_assertions.go b/deployment/ccip/changeset/testhelpers/test_assertions.go similarity index 92% rename from deployment/ccip/changeset/test_assertions.go rename to deployment/ccip/changeset/testhelpers/test_assertions.go index ba1b5fa4a88..768788cef1a 100644 --- a/deployment/ccip/changeset/test_assertions.go +++ b/deployment/ccip/changeset/testhelpers/test_assertions.go @@ -1,4 +1,4 @@ -package changeset +package testhelpers import ( "context" @@ -19,6 +19,8 @@ import ( commonutils "github.com/smartcontractkit/chainlink-common/pkg/utils" "github.com/smartcontractkit/chainlink-common/pkg/utils/tests" + "github.com/smartcontractkit/chainlink/deployment/ccip/changeset" + commonchangeset "github.com/smartcontractkit/chainlink/deployment/common/changeset" "github.com/smartcontractkit/chainlink/deployment/environment/memory" "github.com/smartcontractkit/chainlink/deployment" @@ -29,7 +31,7 @@ import ( func ConfirmGasPriceUpdatedForAll( t *testing.T, e deployment.Environment, - state CCIPOnChainState, + state changeset.CCIPOnChainState, startBlocks map[uint64]*uint64, gasPrice *big.Int, ) { @@ -82,7 +84,7 @@ func ConfirmGasPriceUpdated( func ConfirmTokenPriceUpdatedForAll( t *testing.T, e deployment.Environment, - state CCIPOnChainState, + state changeset.CCIPOnChainState, startBlocks map[uint64]*uint64, linkPrice *big.Int, wethPrice *big.Int, @@ -167,7 +169,7 @@ type SourceDestPair struct { func ConfirmCommitForAllWithExpectedSeqNums( t *testing.T, e deployment.Environment, - state CCIPOnChainState, + state changeset.CCIPOnChainState, expectedSeqNums map[SourceDestPair]uint64, startBlocks map[uint64]*uint64, ) { @@ -267,7 +269,7 @@ func (c *commitReportTracker) allCommited(sourceChainSelector uint64) bool { func ConfirmMultipleCommits( t *testing.T, chains map[uint64]deployment.Chain, - state map[uint64]CCIPChainState, + state map[uint64]changeset.CCIPChainState, startBlocks map[uint64]*uint64, enforceSingleCommit bool, expectedSeqNums map[SourceDestPair]ccipocr3.SeqNumRange, @@ -413,7 +415,7 @@ func ConfirmCommitWithExpectedSeqNumRange( func ConfirmExecWithSeqNrsForAll( t *testing.T, e deployment.Environment, - state CCIPOnChainState, + state changeset.CCIPOnChainState, expectedSeqNums map[SourceDestPair][]uint64, startBlocks map[uint64]*uint64, ) (executionStates map[SourceDestPair]map[uint64]int) { @@ -656,3 +658,39 @@ func AssertEqualFeeConfig(t *testing.T, want, have fee_quoter.FeeQuoterDestChain assert.Equal(t, want.MaxNumberOfTokensPerMsg, have.MaxNumberOfTokensPerMsg) assert.Equal(t, want.MaxPerMsgGasLimit, have.MaxPerMsgGasLimit) } + +// AssertTimelockOwnership asserts that the ownership of the contracts has been transferred +// to the appropriate timelock contract on each chain. +func AssertTimelockOwnership( + t *testing.T, + e DeployedEnv, + chains []uint64, + state changeset.CCIPOnChainState, +) { + // check that the ownership has been transferred correctly + for _, chain := range chains { + for _, contract := range []common.Address{ + state.Chains[chain].OnRamp.Address(), + state.Chains[chain].OffRamp.Address(), + state.Chains[chain].FeeQuoter.Address(), + state.Chains[chain].NonceManager.Address(), + state.Chains[chain].RMNRemote.Address(), + } { + owner, _, err := commonchangeset.LoadOwnableContract(contract, e.Env.Chains[chain].Client) + require.NoError(t, err) + require.Equal(t, state.Chains[chain].Timelock.Address(), owner) + } + } + + // check home chain contracts ownership + homeChainTimelockAddress := state.Chains[e.HomeChainSel].Timelock.Address() + for _, contract := range []common.Address{ + state.Chains[e.HomeChainSel].CapabilityRegistry.Address(), + state.Chains[e.HomeChainSel].CCIPHome.Address(), + state.Chains[e.HomeChainSel].RMNHome.Address(), + } { + owner, _, err := commonchangeset.LoadOwnableContract(contract, e.Env.Chains[e.HomeChainSel].Client) + require.NoError(t, err) + require.Equal(t, homeChainTimelockAddress, owner) + } +} diff --git a/deployment/ccip/changeset/test_environment.go b/deployment/ccip/changeset/testhelpers/test_environment.go similarity index 82% rename from deployment/ccip/changeset/test_environment.go rename to deployment/ccip/changeset/testhelpers/test_environment.go index 16994211010..040dce9f17f 100644 --- a/deployment/ccip/changeset/test_environment.go +++ b/deployment/ccip/changeset/testhelpers/test_environment.go @@ -1,4 +1,4 @@ -package changeset +package testhelpers import ( "context" @@ -20,6 +20,7 @@ import ( jobv1 "github.com/smartcontractkit/chainlink-protos/job-distributor/v1/job" "github.com/smartcontractkit/chainlink-testing-framework/lib/utils/testcontext" + "github.com/smartcontractkit/chainlink/deployment/ccip/changeset" "github.com/smartcontractkit/chainlink/deployment/ccip/changeset/internal" "github.com/smartcontractkit/chainlink/v2/core/capabilities/ccip/types" @@ -44,7 +45,7 @@ type TestConfigs struct { // TODO: This should be CreateContracts so the booleans make sense? CreateJobAndContracts bool PrerequisiteDeploymentOnly bool - V1_5Cfg V1_5DeploymentConfig + V1_5Cfg changeset.V1_5DeploymentConfig Chains int // only used in memory mode, for docker mode, this is determined by the integration-test config toml input ChainIDs []uint64 // only used in memory mode, for docker mode, this is determined by the integration-test config toml input NumOfUsersPerChain int // only used in memory mode, for docker mode, this is determined by the integration-test config toml input @@ -53,7 +54,7 @@ type TestConfigs struct { IsUSDC bool IsUSDCAttestationMissing bool IsMultiCall3 bool - OCRConfigOverride func(CCIPOCRParams) CCIPOCRParams + OCRConfigOverride func(*changeset.CCIPOCRParams) RMNEnabled bool NumOfRMNNodes int LinkPrice *big.Int @@ -93,8 +94,8 @@ func DefaultTestConfigs() *TestConfigs { NumOfUsersPerChain: 1, Nodes: 4, Bootstraps: 1, - LinkPrice: MockLinkPrice, - WethPrice: MockWethPrice, + LinkPrice: changeset.MockLinkPrice, + WethPrice: changeset.MockWethPrice, CreateJobAndContracts: true, } } @@ -107,7 +108,7 @@ func WithMultiCall3() TestOps { } } -func WithPrerequisiteDeployment(v1_5Cfg *V1_5DeploymentConfig) TestOps { +func WithPrerequisiteDeploymentOnly(v1_5Cfg *changeset.V1_5DeploymentConfig) TestOps { return func(testCfg *TestConfigs) { testCfg.PrerequisiteDeploymentOnly = true if v1_5Cfg != nil { @@ -116,7 +117,7 @@ func WithPrerequisiteDeployment(v1_5Cfg *V1_5DeploymentConfig) TestOps { } } -func WithChainIds(chainIDs []uint64) TestOps { +func WithChainIDs(chainIDs []uint64) TestOps { return func(testCfg *TestConfigs) { testCfg.ChainIDs = chainIDs } @@ -143,7 +144,7 @@ func WithRMNEnabled(numOfNode int) TestOps { } } -func WithOCRConfigOverride(override func(CCIPOCRParams) CCIPOCRParams) TestOps { +func WithOCRConfigOverride(override func(*changeset.CCIPOCRParams)) TestOps { return func(testCfg *TestConfigs) { testCfg.OCRConfigOverride = override } @@ -161,25 +162,25 @@ func WithUSDC() TestOps { } } -func WithChains(numChains int) TestOps { +func WithNumOfChains(numChains int) TestOps { return func(testCfg *TestConfigs) { testCfg.Chains = numChains } } -func WithUsersPerChain(numUsers int) TestOps { +func WithNumOfUsersPerChain(numUsers int) TestOps { return func(testCfg *TestConfigs) { testCfg.NumOfUsersPerChain = numUsers } } -func WithNodes(numNodes int) TestOps { +func WithNumOfNodes(numNodes int) TestOps { return func(testCfg *TestConfigs) { testCfg.Nodes = numNodes } } -func WithBootstraps(numBootstraps int) TestOps { +func WithNumOfBootstrapNodes(numBootstraps int) TestOps { return func(testCfg *TestConfigs) { testCfg.Bootstraps = numBootstraps } @@ -205,7 +206,7 @@ type DeployedEnv struct { func (d *DeployedEnv) TimelockContracts(t *testing.T) map[uint64]*proposalutils.TimelockExecutionContracts { timelocks := make(map[uint64]*proposalutils.TimelockExecutionContracts) - state, err := LoadOnchainState(d.Env) + state, err := changeset.LoadOnchainState(d.Env) require.NoError(t, err) for chain, chainState := range state.Chains { timelocks[chain] = &proposalutils.TimelockExecutionContracts{ @@ -218,7 +219,7 @@ func (d *DeployedEnv) TimelockContracts(t *testing.T) map[uint64]*proposalutils. func (d *DeployedEnv) SetupJobs(t *testing.T) { ctx := testcontext.Get(t) - out, err := CCIPCapabilityJobspec(d.Env, struct{}{}) + out, err := changeset.CCIPCapabilityJobspecChangeset(d.Env, struct{}{}) require.NoError(t, err) for nodeID, jobs := range out.JobSpecs { for _, job := range jobs { @@ -354,21 +355,21 @@ func NewEnvironmentWithPrerequisitesContracts(t *testing.T, tEnv TestEnvironment for _, c := range e.Env.AllChainSelectors() { mcmsCfg[c] = proposalutils.SingleGroupTimelockConfig(t) } - var prereqCfg []DeployPrerequisiteConfigPerChain + prereqCfg := make([]changeset.DeployPrerequisiteConfigPerChain, 0) for _, chain := range allChains { - var opts []PrerequisiteOpt + var opts []changeset.PrerequisiteOpt if tc != nil { if tc.IsUSDC { - opts = append(opts, WithUSDCEnabled()) + opts = append(opts, changeset.WithUSDCEnabled()) } if tc.IsMultiCall3 { - opts = append(opts, WithMultiCall3Enabled()) + opts = append(opts, changeset.WithMultiCall3Enabled()) } } - if tc.V1_5Cfg != (V1_5DeploymentConfig{}) { - opts = append(opts, WithLegacyDeploymentEnabled(tc.V1_5Cfg)) + if tc.V1_5Cfg != (changeset.V1_5DeploymentConfig{}) { + opts = append(opts, changeset.WithLegacyDeploymentEnabled(tc.V1_5Cfg)) } - prereqCfg = append(prereqCfg, DeployPrerequisiteConfigPerChain{ + prereqCfg = append(prereqCfg, changeset.DeployPrerequisiteConfigPerChain{ ChainSelector: chain, Opts: opts, }) @@ -380,8 +381,8 @@ func NewEnvironmentWithPrerequisitesContracts(t *testing.T, tEnv TestEnvironment Config: allChains, }, { - Changeset: commonchangeset.WrapChangeSet(DeployPrerequisites), - Config: DeployPrerequisiteConfig{ + Changeset: commonchangeset.WrapChangeSet(changeset.DeployPrerequisitesChangeset), + Config: changeset.DeployPrerequisiteConfig{ Configs: prereqCfg, }, }, @@ -422,18 +423,18 @@ func NewEnvironmentWithJobsAndContracts(t *testing.T, tEnv TestEnvironment) Depl mcmsCfg[c] = proposalutils.SingleGroupTimelockConfig(t) } - var prereqCfg []DeployPrerequisiteConfigPerChain + prereqCfg := make([]changeset.DeployPrerequisiteConfigPerChain, 0) for _, chain := range allChains { - var opts []PrerequisiteOpt + var opts []changeset.PrerequisiteOpt if tc != nil { if tc.IsUSDC { - opts = append(opts, WithUSDCEnabled()) + opts = append(opts, changeset.WithUSDCEnabled()) } if tc.IsMultiCall3 { - opts = append(opts, WithMultiCall3Enabled()) + opts = append(opts, changeset.WithMultiCall3Enabled()) } } - prereqCfg = append(prereqCfg, DeployPrerequisiteConfigPerChain{ + prereqCfg = append(prereqCfg, changeset.DeployPrerequisiteConfigPerChain{ ChainSelector: chain, Opts: opts, }) @@ -446,8 +447,8 @@ func NewEnvironmentWithJobsAndContracts(t *testing.T, tEnv TestEnvironment) Depl Config: allChains, }, { - Changeset: commonchangeset.WrapChangeSet(DeployPrerequisites), - Config: DeployPrerequisiteConfig{ + Changeset: commonchangeset.WrapChangeSet(changeset.DeployPrerequisitesChangeset), + Config: changeset.DeployPrerequisiteConfig{ Configs: prereqCfg, }, }, @@ -462,8 +463,8 @@ func NewEnvironmentWithJobsAndContracts(t *testing.T, tEnv TestEnvironment) Depl // now we update RMNProxy to point to RMNRemote e.Env, err = commonchangeset.ApplyChangesets(t, e.Env, nil, []commonchangeset.ChangesetApplication{ { - Changeset: commonchangeset.WrapChangeSet(SetRMNRemoteOnRMNProxy), - Config: SetRMNRemoteOnRMNProxyConfig{ + Changeset: commonchangeset.WrapChangeSet(changeset.SetRMNRemoteOnRMNProxyChangeset), + Config: changeset.SetRMNRemoteOnRMNProxyConfig{ ChainSelectors: allChains, }, }, @@ -481,8 +482,8 @@ func AddCCIPContractsToEnvironment(t *testing.T, allChains []uint64, tEnv TestEn // no proposals to be made, timelock can be passed as nil here e.Env, err = commonchangeset.ApplyChangesets(t, e.Env, nil, []commonchangeset.ChangesetApplication{ { - Changeset: commonchangeset.WrapChangeSet(DeployHomeChain), - Config: DeployHomeChainConfig{ + Changeset: commonchangeset.WrapChangeSet(changeset.DeployHomeChainChangeset), + Config: changeset.DeployHomeChainConfig{ HomeChainSel: e.HomeChainSel, RMNDynamicConfig: NewTestRMNDynamicConfig(), RMNStaticConfig: NewTestRMNStaticConfig(), @@ -493,8 +494,8 @@ func AddCCIPContractsToEnvironment(t *testing.T, allChains []uint64, tEnv TestEn }, }, { - Changeset: commonchangeset.WrapChangeSet(DeployChainContracts), - Config: DeployChainContractsConfig{ + Changeset: commonchangeset.WrapChangeSet(changeset.DeployChainContractsChangeset), + Config: changeset.DeployChainContractsConfig{ ChainSelectors: allChains, HomeChainSelector: e.HomeChainSel, }, @@ -502,13 +503,13 @@ func AddCCIPContractsToEnvironment(t *testing.T, allChains []uint64, tEnv TestEn }) require.NoError(t, err) - state, err := LoadOnchainState(e.Env) + state, err := changeset.LoadOnchainState(e.Env) require.NoError(t, err) // Assert link present require.NotNil(t, state.Chains[e.FeedChainSel].LinkToken) require.NotNil(t, state.Chains[e.FeedChainSel].Weth9) - tokenConfig := NewTestTokenConfig(state.Chains[e.FeedChainSel].USDFeeds) + tokenConfig := changeset.NewTestTokenConfig(state.Chains[e.FeedChainSel].USDFeeds) var tokenDataProviders []pluginconfig.TokenDataObserverConfig if tc.IsUSDC { endpoint := tEnv.MockUSDCAttestationServer(t, tc.IsUSDCAttestationMissing) @@ -533,8 +534,8 @@ func AddCCIPContractsToEnvironment(t *testing.T, allChains []uint64, tEnv TestEn }}) } // Build the per chain config. - ocrConfigs := make(map[uint64]CCIPOCRParams) - chainConfigs := make(map[uint64]ChainConfig) + ocrConfigs := make(map[uint64]changeset.CCIPOCRParams) + chainConfigs := make(map[uint64]changeset.ChainConfig) timelockContractsPerChain := make(map[uint64]*proposalutils.TimelockExecutionContracts) nodeInfo, err := deployment.NodeInfo(e.Env.NodeIDs, e.Env.Offchain) require.NoError(t, err) @@ -544,12 +545,12 @@ func AddCCIPContractsToEnvironment(t *testing.T, allChains []uint64, tEnv TestEn CallProxy: state.Chains[chain].CallProxy, } tokenInfo := tokenConfig.GetTokenInfo(e.Env.Logger, state.Chains[chain].LinkToken, state.Chains[chain].Weth9) - ocrParams := DefaultOCRParams(e.FeedChainSel, tokenInfo, tokenDataProviders, true, true) - if tc.OCRConfigOverride != nil { - ocrParams = tc.OCRConfigOverride(ocrParams) - } + ocrParams := changeset.DeriveCCIPOCRParams(changeset.WithDefaultCommitOffChainConfig(e.FeedChainSel, tokenInfo), + changeset.WithDefaultExecuteOffChainConfig(tokenDataProviders), + changeset.WithOCRParamOverride(tc.OCRConfigOverride), + ) ocrConfigs[chain] = ocrParams - chainConfigs[chain] = ChainConfig{ + chainConfigs[chain] = changeset.ChainConfig{ Readers: nodeInfo.NonBootstraps().PeerIDs(), FChain: uint8(len(nodeInfo.NonBootstraps().PeerIDs()) / 3), EncodableChainConfig: chainconfig.ChainConfig{ @@ -563,21 +564,21 @@ func AddCCIPContractsToEnvironment(t *testing.T, allChains []uint64, tEnv TestEn e.Env, err = commonchangeset.ApplyChangesets(t, e.Env, timelockContractsPerChain, []commonchangeset.ChangesetApplication{ { // Add the chain configs for the new chains. - Changeset: commonchangeset.WrapChangeSet(UpdateChainConfig), - Config: UpdateChainConfigConfig{ + Changeset: commonchangeset.WrapChangeSet(changeset.UpdateChainConfigChangeset), + Config: changeset.UpdateChainConfigConfig{ HomeChainSelector: e.HomeChainSel, RemoteChainAdds: chainConfigs, }, }, { // Add the DONs and candidate commit OCR instances for the chain. - Changeset: commonchangeset.WrapChangeSet(AddDonAndSetCandidateChangeset), - Config: AddDonAndSetCandidateChangesetConfig{ - SetCandidateConfigBase: SetCandidateConfigBase{ + Changeset: commonchangeset.WrapChangeSet(changeset.AddDonAndSetCandidateChangeset), + Config: changeset.AddDonAndSetCandidateChangesetConfig{ + SetCandidateConfigBase: changeset.SetCandidateConfigBase{ HomeChainSelector: e.HomeChainSel, FeedChainSelector: e.FeedChainSel, }, - PluginInfo: SetCandidatePluginInfo{ + PluginInfo: changeset.SetCandidatePluginInfo{ OCRConfigPerRemoteChainSelector: ocrConfigs, PluginType: types.PluginTypeCCIPCommit, }, @@ -585,13 +586,13 @@ func AddCCIPContractsToEnvironment(t *testing.T, allChains []uint64, tEnv TestEn }, { // Add the exec OCR instances for the new chains. - Changeset: commonchangeset.WrapChangeSet(SetCandidateChangeset), - Config: SetCandidateChangesetConfig{ - SetCandidateConfigBase: SetCandidateConfigBase{ + Changeset: commonchangeset.WrapChangeSet(changeset.SetCandidateChangeset), + Config: changeset.SetCandidateChangesetConfig{ + SetCandidateConfigBase: changeset.SetCandidateConfigBase{ HomeChainSelector: e.HomeChainSel, FeedChainSelector: e.FeedChainSel, }, - PluginInfo: []SetCandidatePluginInfo{ + PluginInfo: []changeset.SetCandidatePluginInfo{ { OCRConfigPerRemoteChainSelector: ocrConfigs, PluginType: types.PluginTypeCCIPExec, @@ -601,10 +602,10 @@ func AddCCIPContractsToEnvironment(t *testing.T, allChains []uint64, tEnv TestEn }, { // Promote everything - Changeset: commonchangeset.WrapChangeSet(PromoteCandidateChangeset), - Config: PromoteCandidateChangesetConfig{ + Changeset: commonchangeset.WrapChangeSet(changeset.PromoteCandidateChangeset), + Config: changeset.PromoteCandidateChangesetConfig{ HomeChainSelector: e.HomeChainSel, - PluginInfo: []PromoteCandidatePluginInfo{ + PluginInfo: []changeset.PromoteCandidatePluginInfo{ { PluginType: types.PluginTypeCCIPCommit, RemoteChainSelectors: allChains, @@ -618,21 +619,21 @@ func AddCCIPContractsToEnvironment(t *testing.T, allChains []uint64, tEnv TestEn }, { // Enable the OCR config on the remote chains. - Changeset: commonchangeset.WrapChangeSet(SetOCR3OffRamp), - Config: SetOCR3OffRampConfig{ + Changeset: commonchangeset.WrapChangeSet(changeset.SetOCR3OffRampChangeset), + Config: changeset.SetOCR3OffRampConfig{ HomeChainSel: e.HomeChainSel, RemoteChainSels: allChains, }, }, { - Changeset: commonchangeset.WrapChangeSet(CCIPCapabilityJobspec), + Changeset: commonchangeset.WrapChangeSet(changeset.CCIPCapabilityJobspecChangeset), }, }) require.NoError(t, err) ReplayLogs(t, e.Env.Offchain, e.ReplayBlocks) - state, err = LoadOnchainState(e.Env) + state, err = changeset.LoadOnchainState(e.Env) require.NoError(t, err) require.NotNil(t, state.Chains[e.HomeChainSel].CapabilityRegistry) require.NotNil(t, state.Chains[e.HomeChainSel].CCIPHome) diff --git a/deployment/ccip/changeset/test_helpers.go b/deployment/ccip/changeset/testhelpers/test_helpers.go similarity index 89% rename from deployment/ccip/changeset/test_helpers.go rename to deployment/ccip/changeset/testhelpers/test_helpers.go index e0edbc93e12..fc08dc3c6b3 100644 --- a/deployment/ccip/changeset/test_helpers.go +++ b/deployment/ccip/changeset/testhelpers/test_helpers.go @@ -1,4 +1,4 @@ -package changeset +package testhelpers import ( "context" @@ -18,8 +18,10 @@ import ( "github.com/ethereum/go-ethereum/core/types" "github.com/pkg/errors" + "github.com/smartcontractkit/chainlink/deployment/ccip/changeset" commoncs "github.com/smartcontractkit/chainlink/deployment/common/changeset" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/fee_quoter" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/keystone/generated/capabilities_registry" "github.com/smartcontractkit/chainlink/v2/core/services/relay" "github.com/ethereum/go-ethereum/common" @@ -105,11 +107,16 @@ func DeployTestContracts(t *testing.T, linkPrice *big.Int, wethPrice *big.Int, ) deployment.CapabilityRegistryConfig { - capReg, err := deployCapReg(lggr, - // deploying cap reg for the first time on a blank chain state - CCIPOnChainState{ - Chains: make(map[uint64]CCIPChainState), - }, ab, chains[homeChainSel]) + capReg, err := deployment.DeployContract(lggr, chains[homeChainSel], ab, + func(chain deployment.Chain) deployment.ContractDeploy[*capabilities_registry.CapabilitiesRegistry] { + crAddr, tx, cr, err2 := capabilities_registry.DeployCapabilitiesRegistry( + chain.DeployerKey, + chain.Client, + ) + return deployment.ContractDeploy[*capabilities_registry.CapabilitiesRegistry]{ + Address: crAddr, Contract: cr, Tv: deployment.NewTypeAndVersion(changeset.CapabilitiesRegistry, deployment.Version1_0_0), Tx: tx, Err: err2, + } + }) require.NoError(t, err) _, err = DeployFeeds(lggr, ab, chains[feedChainSel], linkPrice, wethPrice) @@ -178,7 +185,7 @@ func mockAttestationResponse(isFaulty bool) *httptest.Server { func CCIPSendRequest( e deployment.Environment, - state CCIPOnChainState, + state changeset.CCIPOnChainState, cfg *CCIPSendReqConfig, ) (*types.Transaction, uint64, error) { msg := router.ClientEVM2AnyMessage{ @@ -266,7 +273,7 @@ func CCIPSendCalldata( func TestSendRequest( t *testing.T, e deployment.Environment, - state CCIPOnChainState, + state changeset.CCIPOnChainState, src, dest uint64, testRouter bool, evm2AnyMessage router.ClientEVM2AnyMessage, @@ -325,7 +332,7 @@ func WithDestChain(destChain uint64) SendReqOpts { func DoSendRequest( t *testing.T, e deployment.Environment, - state CCIPOnChainState, + state changeset.CCIPOnChainState, opts ...SendReqOpts, ) (*onramp.OnRampCCIPMessageSent, error) { cfg := &CCIPSendReqConfig{} @@ -394,9 +401,9 @@ func AddLane(t *testing.T, e *DeployedEnv, from, to uint64, isTestRouter bool, g var err error e.Env, err = commoncs.ApplyChangesets(t, e.Env, e.TimelockContracts(t), []commoncs.ChangesetApplication{ { - Changeset: commoncs.WrapChangeSet(UpdateOnRampsDests), - Config: UpdateOnRampDestsConfig{ - UpdatesByChain: map[uint64]map[uint64]OnRampDestinationUpdate{ + Changeset: commoncs.WrapChangeSet(changeset.UpdateOnRampsDestsChangeset), + Config: changeset.UpdateOnRampDestsConfig{ + UpdatesByChain: map[uint64]map[uint64]changeset.OnRampDestinationUpdate{ from: { to: { IsEnabled: true, @@ -408,9 +415,9 @@ func AddLane(t *testing.T, e *DeployedEnv, from, to uint64, isTestRouter bool, g }, }, { - Changeset: commoncs.WrapChangeSet(UpdateFeeQuoterPricesCS), - Config: UpdateFeeQuoterPricesConfig{ - PricesByChain: map[uint64]FeeQuoterPriceUpdatePerSource{ + Changeset: commoncs.WrapChangeSet(changeset.UpdateFeeQuoterPricesChangeset), + Config: changeset.UpdateFeeQuoterPricesConfig{ + PricesByChain: map[uint64]changeset.FeeQuoterPriceUpdatePerSource{ from: { TokenPrices: tokenPrices, GasPrices: gasprice, @@ -419,8 +426,8 @@ func AddLane(t *testing.T, e *DeployedEnv, from, to uint64, isTestRouter bool, g }, }, { - Changeset: commoncs.WrapChangeSet(UpdateFeeQuoterDests), - Config: UpdateFeeQuoterDestsConfig{ + Changeset: commoncs.WrapChangeSet(changeset.UpdateFeeQuoterDestsChangeset), + Config: changeset.UpdateFeeQuoterDestsConfig{ UpdatesByChain: map[uint64]map[uint64]fee_quoter.FeeQuoterDestChainConfig{ from: { to: fqCfg, @@ -429,9 +436,9 @@ func AddLane(t *testing.T, e *DeployedEnv, from, to uint64, isTestRouter bool, g }, }, { - Changeset: commoncs.WrapChangeSet(UpdateOffRampSources), - Config: UpdateOffRampSourcesConfig{ - UpdatesByChain: map[uint64]map[uint64]OffRampSourceUpdate{ + Changeset: commoncs.WrapChangeSet(changeset.UpdateOffRampSourcesChangeset), + Config: changeset.UpdateOffRampSourcesConfig{ + UpdatesByChain: map[uint64]map[uint64]changeset.OffRampSourceUpdate{ to: { from: { IsEnabled: true, @@ -442,10 +449,10 @@ func AddLane(t *testing.T, e *DeployedEnv, from, to uint64, isTestRouter bool, g }, }, { - Changeset: commoncs.WrapChangeSet(UpdateRouterRamps), - Config: UpdateRouterRampsConfig{ + Changeset: commoncs.WrapChangeSet(changeset.UpdateRouterRampsChangeset), + Config: changeset.UpdateRouterRampsConfig{ TestRouter: isTestRouter, - UpdatesByChain: map[uint64]RouterUpdates{ + UpdatesByChain: map[uint64]changeset.RouterUpdates{ // onRamp update on source chain from: { OnRampUpdates: map[uint64]bool{ @@ -465,7 +472,7 @@ func AddLane(t *testing.T, e *DeployedEnv, from, to uint64, isTestRouter bool, g require.NoError(t, err) } -func AddLaneWithDefaultPricesAndFeeQuoterConfig(t *testing.T, e *DeployedEnv, state CCIPOnChainState, from, to uint64, isTestRouter bool) { +func AddLaneWithDefaultPricesAndFeeQuoterConfig(t *testing.T, e *DeployedEnv, state changeset.CCIPOnChainState, from, to uint64, isTestRouter bool) { stateChainFrom := state.Chains[from] AddLane(t, e, from, to, isTestRouter, map[uint64]*big.Int{ @@ -473,12 +480,12 @@ func AddLaneWithDefaultPricesAndFeeQuoterConfig(t *testing.T, e *DeployedEnv, st }, map[common.Address]*big.Int{ stateChainFrom.LinkToken.Address(): DefaultLinkPrice, stateChainFrom.Weth9.Address(): DefaultWethPrice, - }, DefaultFeeQuoterDestChainConfig()) + }, changeset.DefaultFeeQuoterDestChainConfig()) } // AddLanesForAll adds densely connected lanes for all chains in the environment so that each chain // is connected to every other chain except itself. -func AddLanesForAll(t *testing.T, e *DeployedEnv, state CCIPOnChainState) { +func AddLanesForAll(t *testing.T, e *DeployedEnv, state changeset.CCIPOnChainState) { for source := range e.Env.Chains { for dest := range e.Env.Chains { if source != dest { @@ -493,31 +500,6 @@ func ToPackedFee(execFee, daFee *big.Int) *big.Int { return new(big.Int).Or(daShifted, execFee) } -const ( - // MockLinkAggregatorDescription This is the description of the MockV3Aggregator.sol contract - //nolint:lll - // https://github.com/smartcontractkit/chainlink/blob/a348b98e90527520049c580000a86fb8ceff7fa7/contracts/src/v0.8/tests/MockV3Aggregator.sol#L76-L76 - MockLinkAggregatorDescription = "v0.8/tests/MockV3Aggregator.sol" - // MockWETHAggregatorDescription WETH use description from MockETHUSDAggregator.sol - //nolint:lll - // https://github.com/smartcontractkit/chainlink/blob/a348b98e90527520049c580000a86fb8ceff7fa7/contracts/src/v0.8/automation/testhelpers/MockETHUSDAggregator.sol#L19-L19 - MockWETHAggregatorDescription = "MockETHUSDAggregator" -) - -var ( - MockLinkPrice = deployment.E18Mult(500) - MockWethPrice = big.NewInt(9e8) - // MockDescriptionToTokenSymbol maps a mock feed description to token descriptor - MockDescriptionToTokenSymbol = map[string]TokenSymbol{ - MockLinkAggregatorDescription: LinkSymbol, - MockWETHAggregatorDescription: WethSymbol, - } - MockSymbolToDescription = map[TokenSymbol]string{ - LinkSymbol: MockLinkAggregatorDescription, - WethSymbol: MockWETHAggregatorDescription, - } -) - func DeployFeeds( lggr logger.Logger, ab deployment.AddressBook, @@ -525,13 +507,13 @@ func DeployFeeds( linkPrice *big.Int, wethPrice *big.Int, ) (map[string]common.Address, error) { - linkTV := deployment.NewTypeAndVersion(PriceFeed, deployment.Version1_0_0) + linkTV := deployment.NewTypeAndVersion(changeset.PriceFeed, deployment.Version1_0_0) mockLinkFeed := func(chain deployment.Chain) deployment.ContractDeploy[*aggregator_v3_interface.AggregatorV3Interface] { linkFeed, tx, _, err1 := mock_v3_aggregator_contract.DeployMockV3Aggregator( chain.DeployerKey, chain.Client, - LinkDecimals, // decimals - linkPrice, // initialAnswer + changeset.LinkDecimals, // decimals + linkPrice, // initialAnswer ) aggregatorCr, err2 := aggregator_v3_interface.NewAggregatorV3Interface(linkFeed, chain.Client) @@ -553,12 +535,12 @@ func DeployFeeds( } } - linkFeedAddress, linkFeedDescription, err := deploySingleFeed(lggr, ab, chain, mockLinkFeed, LinkSymbol) + linkFeedAddress, linkFeedDescription, err := deploySingleFeed(lggr, ab, chain, mockLinkFeed, changeset.LinkSymbol) if err != nil { return nil, err } - wethFeedAddress, wethFeedDescription, err := deploySingleFeed(lggr, ab, chain, mockWethFeed, WethSymbol) + wethFeedAddress, wethFeedDescription, err := deploySingleFeed(lggr, ab, chain, mockWethFeed, changeset.WethSymbol) if err != nil { return nil, err } @@ -576,7 +558,7 @@ func deploySingleFeed( ab deployment.AddressBook, chain deployment.Chain, deployFunc func(deployment.Chain) deployment.ContractDeploy[*aggregator_v3_interface.AggregatorV3Interface], - symbol TokenSymbol, + symbol changeset.TokenSymbol, ) (common.Address, string, error) { // tokenTV := deployment.NewTypeAndVersion(PriceFeed, deployment.Version1_0_0) mockTokenFeed, err := deployment.DeployContract(lggr, chain, ab, deployFunc) @@ -593,7 +575,7 @@ func deploySingleFeed( return common.Address{}, "", err } - if desc != MockSymbolToDescription[symbol] { + if desc != changeset.MockSymbolToDescription[symbol] { lggr.Errorw("Unexpected description for token", "symbol", symbol, "desc", desc) return common.Address{}, "", fmt.Errorf("unexpected description: %s", desc) } @@ -601,7 +583,7 @@ func deploySingleFeed( return mockTokenFeed.Address, desc, nil } -func ConfirmRequestOnSourceAndDest(t *testing.T, env deployment.Environment, state CCIPOnChainState, sourceCS, destCS, expectedSeqNr uint64) error { +func ConfirmRequestOnSourceAndDest(t *testing.T, env deployment.Environment, state changeset.CCIPOnChainState, sourceCS, destCS, expectedSeqNr uint64) error { latesthdr, err := env.Chains[destCS].Client.HeaderByNumber(testcontext.Get(t), nil) require.NoError(t, err) startBlock := latesthdr.Number.Uint64() @@ -645,7 +627,7 @@ func DeployTransferableToken( chains map[uint64]deployment.Chain, src, dst uint64, srcActor, dstActor *bind.TransactOpts, - state CCIPOnChainState, + state changeset.CCIPOnChainState, addresses deployment.AddressBook, token string, ) (*burn_mint_erc677.BurnMintERC677, *burn_mint_token_pool.BurnMintTokenPool, *burn_mint_erc677.BurnMintERC677, *burn_mint_token_pool.BurnMintTokenPool, error) { @@ -689,7 +671,7 @@ func deployTokenPoolsInParallel( chains map[uint64]deployment.Chain, src, dst uint64, srcActor, dstActor *bind.TransactOpts, - state CCIPOnChainState, + state changeset.CCIPOnChainState, addresses deployment.AddressBook, token string, ) ( @@ -833,7 +815,7 @@ func setTokenPoolCounterPart(chain deployment.Chain, tokenPool *burn_mint_token_ func attachTokenToTheRegistry( chain deployment.Chain, - state CCIPChainState, + state changeset.CCIPChainState, owner *bind.TransactOpts, token common.Address, tokenPool common.Address, @@ -889,10 +871,10 @@ func deployTransferTokenOneEnd( return nil, nil, err } for address, v := range chainAddresses { - if deployment.NewTypeAndVersion(ARMProxy, deployment.Version1_0_0) == v { + if deployment.NewTypeAndVersion(changeset.ARMProxy, deployment.Version1_0_0) == v { rmnAddress = address } - if deployment.NewTypeAndVersion(Router, deployment.Version1_2_0) == v { + if deployment.NewTypeAndVersion(changeset.Router, deployment.Version1_2_0) == v { routerAddress = address } if rmnAddress != "" && routerAddress != "" { @@ -913,7 +895,7 @@ func deployTransferTokenOneEnd( big.NewInt(0).Mul(big.NewInt(1e9), big.NewInt(1e18)), ) return deployment.ContractDeploy[*burn_mint_erc677.BurnMintERC677]{ - Address: tokenAddress, Contract: token, Tx: tx, Tv: deployment.NewTypeAndVersion(BurnMintToken, deployment.Version1_0_0), Err: err2, + Address: tokenAddress, Contract: token, Tx: tx, Tv: deployment.NewTypeAndVersion(changeset.BurnMintToken, deployment.Version1_0_0), Err: err2, } }) if err != nil { @@ -942,7 +924,7 @@ func deployTransferTokenOneEnd( common.HexToAddress(routerAddress), ) return deployment.ContractDeploy[*burn_mint_token_pool.BurnMintTokenPool]{ - Address: tokenPoolAddress, Contract: tokenPoolContract, Tx: tx, Tv: deployment.NewTypeAndVersion(BurnMintTokenPool, deployment.Version1_5_1), Err: err2, + Address: tokenPoolAddress, Contract: tokenPoolContract, Tx: tx, Tv: deployment.NewTypeAndVersion(changeset.BurnMintTokenPool, deployment.Version1_5_1), Err: err2, } }) if err != nil { @@ -971,7 +953,7 @@ func NewMintTokenWithCustomSender(auth *bind.TransactOpts, sender *bind.Transact func MintAndAllow( t *testing.T, e deployment.Environment, - state CCIPOnChainState, + state changeset.CCIPOnChainState, tokenMap map[uint64][]MintTokenInfo, ) { configurePoolGrp := errgroup.Group{} @@ -1014,7 +996,7 @@ func Transfer( ctx context.Context, t *testing.T, env deployment.Environment, - state CCIPOnChainState, + state changeset.CCIPOnChainState, sourceChain, destChain uint64, tokens []router.ClientEVMTokenAmount, receiver common.Address, @@ -1060,7 +1042,7 @@ func TransferMultiple( ctx context.Context, t *testing.T, env deployment.Environment, - state CCIPOnChainState, + state changeset.CCIPOnChainState, requests []TestTransferRequest, ) ( map[uint64]*uint64, @@ -1114,7 +1096,7 @@ func TransferAndWaitForSuccess( ctx context.Context, t *testing.T, env deployment.Environment, - state CCIPOnChainState, + state changeset.CCIPOnChainState, sourceChain, destChain uint64, tokens []router.ClientEVMTokenAmount, receiver common.Address, @@ -1253,3 +1235,41 @@ func DefaultRouterMessage(receiverAddress common.Address) router.ClientEVM2AnyMe ExtraArgs: nil, } } + +func GenTestTransferOwnershipConfig( + e DeployedEnv, + chains []uint64, + state changeset.CCIPOnChainState, +) commoncs.TransferToMCMSWithTimelockConfig { + var ( + timelocksPerChain = make(map[uint64]common.Address) + contracts = make(map[uint64][]common.Address) + ) + + // chain contracts + for _, chain := range chains { + timelocksPerChain[chain] = state.Chains[chain].Timelock.Address() + contracts[chain] = []common.Address{ + state.Chains[chain].OnRamp.Address(), + state.Chains[chain].OffRamp.Address(), + state.Chains[chain].FeeQuoter.Address(), + state.Chains[chain].NonceManager.Address(), + state.Chains[chain].RMNRemote.Address(), + state.Chains[chain].TestRouter.Address(), + state.Chains[chain].Router.Address(), + } + } + + // home chain + homeChainTimelockAddress := state.Chains[e.HomeChainSel].Timelock.Address() + timelocksPerChain[e.HomeChainSel] = homeChainTimelockAddress + contracts[e.HomeChainSel] = append(contracts[e.HomeChainSel], + state.Chains[e.HomeChainSel].CapabilityRegistry.Address(), + state.Chains[e.HomeChainSel].CCIPHome.Address(), + state.Chains[e.HomeChainSel].RMNHome.Address(), + ) + + return commoncs.TransferToMCMSWithTimelockConfig{ + ContractsByChain: contracts, + } +} diff --git a/deployment/ccip/changeset/test_params.go b/deployment/ccip/changeset/testhelpers/test_params.go similarity index 97% rename from deployment/ccip/changeset/test_params.go rename to deployment/ccip/changeset/testhelpers/test_params.go index 90331b50675..8e43c08919f 100644 --- a/deployment/ccip/changeset/test_params.go +++ b/deployment/ccip/changeset/testhelpers/test_params.go @@ -1,4 +1,4 @@ -package changeset +package testhelpers import ( "github.com/ethereum/go-ethereum/common" diff --git a/deployment/ccip/changeset/testhelpers/test_usdc_helpers.go b/deployment/ccip/changeset/testhelpers/test_usdc_helpers.go new file mode 100644 index 00000000000..ebaa3b8ec37 --- /dev/null +++ b/deployment/ccip/changeset/testhelpers/test_usdc_helpers.go @@ -0,0 +1,140 @@ +package testhelpers + +import ( + "golang.org/x/sync/errgroup" + + "github.com/ethereum/go-ethereum/common" + + "github.com/smartcontractkit/chainlink-common/pkg/logger" + + "github.com/smartcontractkit/chainlink/deployment" + "github.com/smartcontractkit/chainlink/deployment/ccip/changeset" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/fee_quoter" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/usdc_token_pool" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/shared/generated/burn_mint_erc677" +) + +func ConfigureUSDCTokenPools( + lggr logger.Logger, + chains map[uint64]deployment.Chain, + src, dst uint64, + state changeset.CCIPOnChainState, +) (*burn_mint_erc677.BurnMintERC677, *burn_mint_erc677.BurnMintERC677, error) { + srcToken := state.Chains[src].BurnMintTokens677[changeset.USDCSymbol] + dstToken := state.Chains[dst].BurnMintTokens677[changeset.USDCSymbol] + srcPool := state.Chains[src].USDCTokenPool + dstPool := state.Chains[dst].USDCTokenPool + + args := []struct { + sourceChain deployment.Chain + dstChainSel uint64 + state changeset.CCIPChainState + srcToken *burn_mint_erc677.BurnMintERC677 + srcPool *usdc_token_pool.USDCTokenPool + dstToken *burn_mint_erc677.BurnMintERC677 + dstPool *usdc_token_pool.USDCTokenPool + }{ + { + chains[src], + dst, + state.Chains[src], + srcToken, + srcPool, + dstToken, + dstPool, + }, + { + chains[dst], + src, + state.Chains[dst], + dstToken, + dstPool, + srcToken, + srcPool, + }, + } + + configurePoolGrp := errgroup.Group{} + for _, arg := range args { + configurePoolGrp.Go(configureSingleChain(lggr, arg.sourceChain, arg.dstChainSel, arg.state, arg.srcToken, arg.srcPool, arg.dstToken, arg.dstPool)) + } + if err := configurePoolGrp.Wait(); err != nil { + return nil, nil, err + } + return srcToken, dstToken, nil +} + +func configureSingleChain( + lggr logger.Logger, + sourceChain deployment.Chain, + dstChainSel uint64, + state changeset.CCIPChainState, + srcToken *burn_mint_erc677.BurnMintERC677, + srcPool *usdc_token_pool.USDCTokenPool, + dstToken *burn_mint_erc677.BurnMintERC677, + dstPool *usdc_token_pool.USDCTokenPool, +) func() error { + return func() error { + if err := attachTokenToTheRegistry(sourceChain, state, sourceChain.DeployerKey, srcToken.Address(), srcPool.Address()); err != nil { + lggr.Errorw("Failed to attach token to the registry", "err", err, "token", srcToken.Address(), "pool", srcPool.Address()) + return err + } + + if err := setUSDCTokenPoolCounterPart(sourceChain, srcPool, dstChainSel, sourceChain.DeployerKey, dstToken.Address(), dstPool.Address()); err != nil { + lggr.Errorw("Failed to set counter part", "err", err, "srcPool", srcPool.Address(), "dstPool", dstPool.Address()) + return err + } + + for _, addr := range []common.Address{ + srcPool.Address(), + state.MockUSDCTokenMessenger.Address(), + state.MockUSDCTransmitter.Address(), + } { + if err := grantMintBurnPermissions(lggr, sourceChain, srcToken, sourceChain.DeployerKey, addr); err != nil { + lggr.Errorw("Failed to grant mint/burn permissions", "err", err, "token", srcToken.Address(), "address", addr) + return err + } + } + return nil + } +} + +func UpdateFeeQuoterForUSDC( + lggr logger.Logger, + chain deployment.Chain, + state changeset.CCIPChainState, + dstChain uint64, + usdcToken *burn_mint_erc677.BurnMintERC677, +) error { + config := []fee_quoter.FeeQuoterTokenTransferFeeConfigArgs{ + { + DestChainSelector: dstChain, + TokenTransferFeeConfigs: []fee_quoter.FeeQuoterTokenTransferFeeConfigSingleTokenArgs{ + { + Token: usdcToken.Address(), + TokenTransferFeeConfig: fee_quoter.FeeQuoterTokenTransferFeeConfig{ + MinFeeUSDCents: 50, + MaxFeeUSDCents: 50_000, + DeciBps: 0, + DestGasOverhead: 180_000, + DestBytesOverhead: 640, + IsEnabled: true, + }, + }, + }, + }, + } + + tx, err := state.FeeQuoter.ApplyTokenTransferFeeConfigUpdates( + chain.DeployerKey, + config, + []fee_quoter.FeeQuoterTokenTransferFeeConfigRemoveArgs{}, + ) + if err != nil { + lggr.Errorw("Failed to apply token transfer fee config updates", "err", err, "config", config) + return err + } + + _, err = chain.Confirm(tx) + return err +} diff --git a/deployment/ccip/changeset/v1_5/test_helpers.go b/deployment/ccip/changeset/testhelpers/v1_5/test_helpers.go similarity index 87% rename from deployment/ccip/changeset/v1_5/test_helpers.go rename to deployment/ccip/changeset/testhelpers/v1_5/test_helpers.go index 671089a5546..be2804c6527 100644 --- a/deployment/ccip/changeset/v1_5/test_helpers.go +++ b/deployment/ccip/changeset/testhelpers/v1_5/test_helpers.go @@ -21,35 +21,37 @@ import ( "github.com/smartcontractkit/chainlink/deployment" "github.com/smartcontractkit/chainlink/deployment/ccip/changeset" + "github.com/smartcontractkit/chainlink/deployment/ccip/changeset/testhelpers" + v1_5changeset "github.com/smartcontractkit/chainlink/deployment/ccip/changeset/v1_5" commonchangeset "github.com/smartcontractkit/chainlink/deployment/common/changeset" "github.com/smartcontractkit/chainlink/deployment/environment/memory" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/commit_store" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/evm_2_evm_offramp" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/evm_2_evm_onramp" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/price_registry_1_2_0" - "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/testhelpers" + plugintesthelpers "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/testhelpers" ) -func AddLanes(t *testing.T, e deployment.Environment, state changeset.CCIPOnChainState, pairs []changeset.SourceDestPair) deployment.Environment { +func AddLanes(t *testing.T, e deployment.Environment, state changeset.CCIPOnChainState, pairs []testhelpers.SourceDestPair) deployment.Environment { addLanesCfg, commitOCR2Configs, execOCR2Configs, jobspecs := LaneConfigsForChains(t, e, state, pairs) var err error e, err = commonchangeset.ApplyChangesets(t, e, nil, []commonchangeset.ChangesetApplication{ { - Changeset: commonchangeset.WrapChangeSet(DeployLanes), - Config: DeployLanesConfig{ + Changeset: commonchangeset.WrapChangeSet(v1_5changeset.DeployLanesChangeset), + Config: v1_5changeset.DeployLanesConfig{ Configs: addLanesCfg, }, }, { - Changeset: commonchangeset.WrapChangeSet(SetOCR2ConfigForTest), - Config: OCR2Config{ + Changeset: commonchangeset.WrapChangeSet(v1_5changeset.SetOCR2ConfigForTestChangeset), + Config: v1_5changeset.OCR2Config{ CommitConfigs: commitOCR2Configs, ExecConfigs: execOCR2Configs, }, }, { - Changeset: commonchangeset.WrapChangeSet(JobSpecsForLanes), - Config: JobSpecsForLanesConfig{ + Changeset: commonchangeset.WrapChangeSet(v1_5changeset.JobSpecsForLanesChangeset), + Config: v1_5changeset.JobSpecsForLanesConfig{ Configs: jobspecs, }, }, @@ -58,16 +60,16 @@ func AddLanes(t *testing.T, e deployment.Environment, state changeset.CCIPOnChai return e } -func LaneConfigsForChains(t *testing.T, env deployment.Environment, state changeset.CCIPOnChainState, pairs []changeset.SourceDestPair) ( - []DeployLaneConfig, - []CommitOCR2ConfigParams, - []ExecuteOCR2ConfigParams, - []JobSpecInput, +func LaneConfigsForChains(t *testing.T, env deployment.Environment, state changeset.CCIPOnChainState, pairs []testhelpers.SourceDestPair) ( + []v1_5changeset.DeployLaneConfig, + []v1_5changeset.CommitOCR2ConfigParams, + []v1_5changeset.ExecuteOCR2ConfigParams, + []v1_5changeset.JobSpecInput, ) { - var addLanesCfg []DeployLaneConfig - var commitOCR2Configs []CommitOCR2ConfigParams - var execOCR2Configs []ExecuteOCR2ConfigParams - var jobSpecs []JobSpecInput + addLanesCfg := make([]v1_5changeset.DeployLaneConfig, 0) + commitOCR2Configs := make([]v1_5changeset.CommitOCR2ConfigParams, 0) + execOCR2Configs := make([]v1_5changeset.ExecuteOCR2ConfigParams, 0) + jobSpecs := make([]v1_5changeset.JobSpecInput, 0) for _, pair := range pairs { dest := pair.DestChainSelector src := pair.SourceChainSelector @@ -91,7 +93,7 @@ func LaneConfigsForChains(t *testing.T, env deployment.Environment, state change require.NoError(t, err) destEVMChainId, err := strconv.ParseUint(destEVMChainIdStr, 10, 64) require.NoError(t, err) - jobSpecs = append(jobSpecs, JobSpecInput{ + jobSpecs = append(jobSpecs, v1_5changeset.JobSpecInput{ SourceChainSelector: src, DestinationChainSelector: dest, DestEVMChainID: destEVMChainId, @@ -100,7 +102,7 @@ func LaneConfigsForChains(t *testing.T, env deployment.Environment, state change }) srcLinkTokenAddr, err := sourceChainState.LinkTokenAddress() require.NoError(t, err) - addLanesCfg = append(addLanesCfg, DeployLaneConfig{ + addLanesCfg = append(addLanesCfg, v1_5changeset.DeployLaneConfig{ SourceChainSelector: src, DestinationChainSelector: dest, OnRampStaticCfg: evm_2_evm_onramp.EVM2EVMOnRampStaticConfig{ @@ -157,13 +159,13 @@ func LaneConfigsForChains(t *testing.T, env deployment.Environment, state change OnRampNopsAndWeight: []evm_2_evm_onramp.EVM2EVMOnRampNopAndWeight{}, OnRampRateLimiterCfg: evm_2_evm_onramp.RateLimiterConfig{ IsEnabled: true, - Capacity: testhelpers.LinkUSDValue(100), - Rate: testhelpers.LinkUSDValue(1), + Capacity: plugintesthelpers.LinkUSDValue(100), + Rate: plugintesthelpers.LinkUSDValue(1), }, OffRampRateLimiterCfg: evm_2_evm_offramp.RateLimiterConfig{ IsEnabled: true, - Capacity: testhelpers.LinkUSDValue(100), - Rate: testhelpers.LinkUSDValue(1), + Capacity: plugintesthelpers.LinkUSDValue(100), + Rate: plugintesthelpers.LinkUSDValue(1), }, InitialTokenPrices: []price_registry_1_2_0.InternalTokenPriceUpdate{ { @@ -182,7 +184,7 @@ func LaneConfigsForChains(t *testing.T, env deployment.Environment, state change }, }, }) - commitOCR2Configs = append(commitOCR2Configs, CommitOCR2ConfigParams{ + commitOCR2Configs = append(commitOCR2Configs, v1_5changeset.CommitOCR2ConfigParams{ SourceChainSelector: src, DestinationChainSelector: dest, OCR2ConfigParams: DefaultOCRParams(), @@ -194,7 +196,7 @@ func LaneConfigsForChains(t *testing.T, env deployment.Environment, state change InflightCacheExpiry: *config.MustNewDuration(5 * time.Second), PriceReportingDisabled: false, }) - execOCR2Configs = append(execOCR2Configs, ExecuteOCR2ConfigParams{ + execOCR2Configs = append(execOCR2Configs, v1_5changeset.ExecuteOCR2ConfigParams{ DestinationChainSelector: dest, SourceChainSelector: src, DestOptimisticConfirmations: 1, @@ -271,9 +273,9 @@ func SendRequest( t *testing.T, e deployment.Environment, state changeset.CCIPOnChainState, - opts ...changeset.SendReqOpts, + opts ...testhelpers.SendReqOpts, ) (*evm_2_evm_onramp.EVM2EVMOnRampCCIPSendRequested, error) { - cfg := &changeset.CCIPSendReqConfig{} + cfg := &testhelpers.CCIPSendReqConfig{} for _, opt := range opts { opt(cfg) } @@ -283,7 +285,7 @@ func SendRequest( } t.Logf("Sending CCIP request from chain selector %d to chain selector %d from sender %s", cfg.SourceChain, cfg.DestChain, cfg.Sender.From.String()) - tx, blockNum, err := changeset.CCIPSendRequest(e, state, cfg) + tx, blockNum, err := testhelpers.CCIPSendRequest(e, state, cfg) if err != nil { return nil, err } diff --git a/deployment/ccip/changeset/token_info.go b/deployment/ccip/changeset/token_info.go index 84f728df9f4..379119dba92 100644 --- a/deployment/ccip/changeset/token_info.go +++ b/deployment/ccip/changeset/token_info.go @@ -1,11 +1,16 @@ package changeset import ( + "math/big" + "github.com/smartcontractkit/chainlink-ccip/pkg/types/ccipocr3" "github.com/smartcontractkit/chainlink-ccip/pluginconfig" + + "github.com/smartcontractkit/chainlink/deployment" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/shared/generated/link_token" "github.com/smartcontractkit/chainlink-common/pkg/logger" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/weth9" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/shared/generated/aggregator_v3_interface" ) @@ -20,9 +25,26 @@ const ( LinkDecimals = 18 WethDecimals = 18 UsdcDecimals = 6 + // MockLinkAggregatorDescription is the description of the MockV3Aggregator.sol contract + // https://github.com/smartcontractkit/chainlink/blob/a348b98e90527520049c580000a86fb8ceff7fa7/contracts/src/v0.8/tests/MockV3Aggregator.sol#L76-L76 + MockLinkAggregatorDescription = "v0.8/tests/MockV3Aggregator.sol" + // MockWETHAggregatorDescription is the description from MockETHUSDAggregator.sol + // https://github.com/smartcontractkit/chainlink/blob/a348b98e90527520049c580000a86fb8ceff7fa7/contracts/src/v0.8/automation/testhelpers/MockETHUSDAggregator.sol#L19-L19 + MockWETHAggregatorDescription = "MockETHUSDAggregator" ) var ( + MockLinkPrice = deployment.E18Mult(500) + MockWethPrice = big.NewInt(9e8) + // MockDescriptionToTokenSymbol maps a mock feed description to token descriptor + MockDescriptionToTokenSymbol = map[string]TokenSymbol{ + MockLinkAggregatorDescription: LinkSymbol, + MockWETHAggregatorDescription: WethSymbol, + } + MockSymbolToDescription = map[TokenSymbol]string{ + LinkSymbol: MockLinkAggregatorDescription, + WethSymbol: MockWETHAggregatorDescription, + } TestDeviationPPB = ccipocr3.NewBigIntFromInt64(1e9) ) diff --git a/deployment/ccip/changeset/v1_5/cs_jobspec.go b/deployment/ccip/changeset/v1_5/cs_jobspec.go index e1cd73f1e30..fd80a392136 100644 --- a/deployment/ccip/changeset/v1_5/cs_jobspec.go +++ b/deployment/ccip/changeset/v1_5/cs_jobspec.go @@ -10,6 +10,8 @@ import ( integrationtesthelpers "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/testhelpers/integration" ) +var _ deployment.ChangeSet[JobSpecsForLanesConfig] = JobSpecsForLanesChangeset + type JobSpecsForLanesConfig struct { Configs []JobSpecInput } @@ -55,7 +57,7 @@ func (j JobSpecInput) Validate() error { return nil } -func JobSpecsForLanes(env deployment.Environment, c JobSpecsForLanesConfig) (deployment.ChangesetOutput, error) { +func JobSpecsForLanesChangeset(env deployment.Environment, c JobSpecsForLanesConfig) (deployment.ChangesetOutput, error) { if err := c.Validate(); err != nil { return deployment.ChangesetOutput{}, fmt.Errorf("invalid JobSpecsForLanesConfig: %w", err) } diff --git a/deployment/ccip/changeset/v1_5/cs_lane_contracts.go b/deployment/ccip/changeset/v1_5/cs_lane_contracts.go index 25e14c898ff..6f6f0d54a69 100644 --- a/deployment/ccip/changeset/v1_5/cs_lane_contracts.go +++ b/deployment/ccip/changeset/v1_5/cs_lane_contracts.go @@ -14,7 +14,7 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/router" ) -var _ deployment.ChangeSet[DeployLanesConfig] = DeployLanes +var _ deployment.ChangeSet[DeployLanesConfig] = DeployLanesChangeset type DeployLanesConfig struct { Configs []DeployLaneConfig @@ -83,7 +83,22 @@ func (c *DeployLaneConfig) Validate(e deployment.Environment, state changeset.CC return nil } -func DeployLanes(env deployment.Environment, c DeployLanesConfig) (deployment.ChangesetOutput, error) { +func (c *DeployLaneConfig) populateAddresses(state changeset.CCIPOnChainState) error { + sourceChainState := state.Chains[c.SourceChainSelector] + srcLink, err := sourceChainState.LinkTokenAddress() + if err != nil { + return fmt.Errorf("failed to get LINK token address for source chain %d: %w", c.SourceChainSelector, err) + } + c.OnRampStaticCfg.LinkToken = srcLink + c.OnRampStaticCfg.RmnProxy = sourceChainState.RMNProxy.Address() + c.OnRampStaticCfg.TokenAdminRegistry = sourceChainState.TokenAdminRegistry.Address() + + c.OnRampDynamicCfg.Router = sourceChainState.Router.Address() + c.OnRampDynamicCfg.PriceRegistry = sourceChainState.PriceRegistry.Address() + return nil +} + +func DeployLanesChangeset(env deployment.Environment, c DeployLanesConfig) (deployment.ChangesetOutput, error) { state, err := changeset.LoadOnchainState(env) if err != nil { return deployment.ChangesetOutput{}, fmt.Errorf("failed to load CCIP onchain state: %w", err) @@ -91,6 +106,12 @@ func DeployLanes(env deployment.Environment, c DeployLanesConfig) (deployment.Ch if err := c.Validate(env, state); err != nil { return deployment.ChangesetOutput{}, fmt.Errorf("invalid DeployChainContractsConfig: %w", err) } + // populate addresses from the state + for i := range c.Configs { + if err := c.Configs[i].populateAddresses(state); err != nil { + return deployment.ChangesetOutput{}, err + } + } newAddresses := deployment.NewMemoryAddressBook() for _, cfg := range c.Configs { if err := deployLane(env, state, newAddresses, cfg); err != nil { diff --git a/deployment/ccip/changeset/v1_5/cs_ocr2_config.go b/deployment/ccip/changeset/v1_5/cs_ocr2_config.go index 497bcb53ad8..2babf666da2 100644 --- a/deployment/ccip/changeset/v1_5/cs_ocr2_config.go +++ b/deployment/ccip/changeset/v1_5/cs_ocr2_config.go @@ -17,6 +17,8 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/testhelpers" ) +var _ deployment.ChangeSet[OCR2Config] = SetOCR2ConfigForTestChangeset + type FinalOCR2Config struct { Signers []common.Address Transmitters []common.Address @@ -175,9 +177,9 @@ func (o OCR2Config) Validate(state changeset.CCIPOnChainState) error { return nil } -// SetOCR2ConfigForTest sets the OCR2 config on the chain for commit and offramp +// SetOCR2ConfigForTestChangeset sets the OCR2 config on the chain for commit and offramp // This is currently not suitable for prod environments it's only for testing -func SetOCR2ConfigForTest(env deployment.Environment, c OCR2Config) (deployment.ChangesetOutput, error) { +func SetOCR2ConfigForTestChangeset(env deployment.Environment, c OCR2Config) (deployment.ChangesetOutput, error) { state, err := changeset.LoadOnchainState(env) if err != nil { return deployment.ChangesetOutput{}, fmt.Errorf("failed to load CCIP onchain state: %w", err) diff --git a/deployment/ccip/changeset/v1_5/cs_rmn.go b/deployment/ccip/changeset/v1_5/cs_rmn.go index df96645b9bf..ffe20294873 100644 --- a/deployment/ccip/changeset/v1_5/cs_rmn.go +++ b/deployment/ccip/changeset/v1_5/cs_rmn.go @@ -17,7 +17,7 @@ import ( "github.com/smartcontractkit/chainlink/deployment/common/proposalutils" ) -var _ deployment.ChangeSet[PermaBlessCommitStoreConfig] = PermaBlessCommitStoreCS +var _ deployment.ChangeSet[PermaBlessCommitStoreConfig] = PermaBlessCommitStoreChangeset type PermaBlessConfigPerSourceChain struct { SourceChainSelector uint64 @@ -96,10 +96,10 @@ func (c PermaBlessCommitStoreConfig) Validate(env deployment.Environment) error return nil } -// PermaBlessCommitStoreCS permablesses the commit stores on the RMN contract +// PermaBlessCommitStoreChangeset permablesses the commit stores on the RMN contract // If commit store addresses are added to the permaBlessed list, those will be considered automatically blessed. // This changeset can add to or remove from the existing permaBlessed list. -func PermaBlessCommitStoreCS(env deployment.Environment, c PermaBlessCommitStoreConfig) (deployment.ChangesetOutput, error) { +func PermaBlessCommitStoreChangeset(env deployment.Environment, c PermaBlessCommitStoreConfig) (deployment.ChangesetOutput, error) { if err := c.Validate(env); err != nil { return deployment.ChangesetOutput{}, fmt.Errorf("invalid PermaBlessCommitStoreConfig: %w", err) } diff --git a/deployment/ccip/changeset/v1_5/e2e_test.go b/deployment/ccip/changeset/v1_5/e2e_test.go index 59d6a30066c..8911dcc8bf4 100644 --- a/deployment/ccip/changeset/v1_5/e2e_test.go +++ b/deployment/ccip/changeset/v1_5/e2e_test.go @@ -1,4 +1,4 @@ -package v1_5 +package v1_5_test import ( "context" @@ -9,6 +9,9 @@ import ( "github.com/stretchr/testify/require" "github.com/smartcontractkit/chainlink/deployment/ccip/changeset" + "github.com/smartcontractkit/chainlink/deployment/ccip/changeset/testhelpers" + "github.com/smartcontractkit/chainlink/deployment/ccip/changeset/testhelpers/v1_5" + v1_5changeset "github.com/smartcontractkit/chainlink/deployment/ccip/changeset/v1_5" commonchangeset "github.com/smartcontractkit/chainlink/deployment/common/changeset" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/rmn_contract" @@ -18,9 +21,9 @@ import ( // This test only works if the destination chain id is 1337 // Otherwise it shows error for offchain and onchain config digest mismatch func TestE2ELegacy(t *testing.T) { - e, _ := changeset.NewMemoryEnvironment( + e, _ := testhelpers.NewMemoryEnvironment( t, - changeset.WithPrerequisiteDeployment(&changeset.V1_5DeploymentConfig{ + testhelpers.WithPrerequisiteDeploymentOnly(&changeset.V1_5DeploymentConfig{ PriceRegStalenessThreshold: 60 * 60 * 24 * 14, // two weeks RMNConfig: &rmn_contract.RMNConfig{ BlessWeightThreshold: 2, @@ -36,8 +39,8 @@ func TestE2ELegacy(t *testing.T) { }, }, }), - changeset.WithChains(3), - changeset.WithChainIds([]uint64{chainselectors.GETH_TESTNET.EvmChainID})) + testhelpers.WithNumOfChains(3), + testhelpers.WithChainIDs([]uint64{chainselectors.GETH_TESTNET.EvmChainID})) state, err := changeset.LoadOnchainState(e.Env) require.NoError(t, err) allChains := e.Env.AllChainSelectorsExcluding([]uint64{chainselectors.GETH_TESTNET.Selector}) @@ -46,18 +49,18 @@ func TestE2ELegacy(t *testing.T) { src, dest := allChains[1], chainselectors.GETH_TESTNET.Selector srcChain := e.Env.Chains[src] destChain := e.Env.Chains[dest] - pairs := []changeset.SourceDestPair{ + pairs := []testhelpers.SourceDestPair{ {SourceChainSelector: src, DestChainSelector: dest}, } - e.Env = AddLanes(t, e.Env, state, pairs) + e.Env = v1_5.AddLanes(t, e.Env, state, pairs) // permabless the commit stores e.Env, err = commonchangeset.ApplyChangesets(t, e.Env, e.TimelockContracts(t), []commonchangeset.ChangesetApplication{ { - Changeset: commonchangeset.WrapChangeSet(PermaBlessCommitStoreCS), - Config: PermaBlessCommitStoreConfig{ - Configs: map[uint64]PermaBlessCommitStoreConfigPerDest{ + Changeset: commonchangeset.WrapChangeSet(v1_5changeset.PermaBlessCommitStoreChangeset), + Config: v1_5changeset.PermaBlessCommitStoreConfig{ + Configs: map[uint64]v1_5changeset.PermaBlessCommitStoreConfigPerDest{ dest: { - Sources: []PermaBlessConfigPerSourceChain{ + Sources: []v1_5changeset.PermaBlessConfigPerSourceChain{ { SourceChainSelector: src, PermaBless: true, @@ -72,11 +75,11 @@ func TestE2ELegacy(t *testing.T) { // reload state after adding lanes state, err = changeset.LoadOnchainState(e.Env) require.NoError(t, err) - sentEvent, err := SendRequest(t, e.Env, state, - changeset.WithSourceChain(src), - changeset.WithDestChain(dest), - changeset.WithTestRouter(false), - changeset.WithEvm2AnyMessage(router.ClientEVM2AnyMessage{ + sentEvent, err := v1_5.SendRequest(t, e.Env, state, + testhelpers.WithSourceChain(src), + testhelpers.WithDestChain(dest), + testhelpers.WithTestRouter(false), + testhelpers.WithEvm2AnyMessage(router.ClientEVM2AnyMessage{ Receiver: common.LeftPadBytes(state.Chains[dest].Receiver.Address().Bytes(), 32), Data: []byte("hello"), TokenAmounts: nil, @@ -88,6 +91,6 @@ func TestE2ELegacy(t *testing.T) { require.NotNil(t, sentEvent) destStartBlock, err := destChain.Client.HeaderByNumber(context.Background(), nil) require.NoError(t, err) - WaitForCommit(t, srcChain, destChain, state.Chains[dest].CommitStore[src], sentEvent.Message.SequenceNumber) - WaitForExecute(t, srcChain, destChain, state.Chains[dest].EVM2EVMOffRamp[src], []uint64{sentEvent.Message.SequenceNumber}, destStartBlock.Number.Uint64()) + v1_5.WaitForCommit(t, srcChain, destChain, state.Chains[dest].CommitStore[src], sentEvent.Message.SequenceNumber) + v1_5.WaitForExecute(t, srcChain, destChain, state.Chains[dest].EVM2EVMOffRamp[src], []uint64{sentEvent.Message.SequenceNumber}, destStartBlock.Number.Uint64()) } diff --git a/deployment/ccip/changeset/view_test.go b/deployment/ccip/changeset/view_test.go index 16d1f8a0dfc..cb798835cd7 100644 --- a/deployment/ccip/changeset/view_test.go +++ b/deployment/ccip/changeset/view_test.go @@ -1,14 +1,17 @@ -package changeset +package changeset_test import ( "testing" "github.com/stretchr/testify/require" + + "github.com/smartcontractkit/chainlink/deployment/ccip/changeset" + "github.com/smartcontractkit/chainlink/deployment/ccip/changeset/testhelpers" ) func TestSmokeView(t *testing.T) { t.Parallel() - tenv, _ := NewMemoryEnvironment(t, WithChains(3)) - _, err := ViewCCIP(tenv.Env) + tenv, _ := testhelpers.NewMemoryEnvironment(t, testhelpers.WithNumOfChains(3)) + _, err := changeset.ViewCCIP(tenv.Env) require.NoError(t, err) } diff --git a/deployment/common/changeset/save_existing.go b/deployment/common/changeset/save_existing.go index 57e53607cdc..17fdc0a8025 100644 --- a/deployment/common/changeset/save_existing.go +++ b/deployment/common/changeset/save_existing.go @@ -11,7 +11,7 @@ import ( ) var ( - _ deployment.ChangeSet[ExistingContractsConfig] = SaveExistingContracts + _ deployment.ChangeSet[ExistingContractsConfig] = SaveExistingContractsChangeset ) type Contract struct { @@ -42,9 +42,9 @@ func (cfg ExistingContractsConfig) Validate() error { return nil } -// SaveExistingContracts saves the existing contracts to the address book. +// SaveExistingContractsChangeset saves the existing contracts to the address book. // Caller should update the environment's address book with the returned addresses. -func SaveExistingContracts(env deployment.Environment, cfg ExistingContractsConfig) (deployment.ChangesetOutput, error) { +func SaveExistingContractsChangeset(env deployment.Environment, cfg ExistingContractsConfig) (deployment.ChangesetOutput, error) { err := cfg.Validate() if err != nil { return deployment.ChangesetOutput{}, errors.Wrapf(deployment.ErrInvalidConfig, "%v", err) diff --git a/deployment/common/changeset/save_existing_test.go b/deployment/common/changeset/save_existing_test.go index 2a2618c8f54..a7e8c9068f3 100644 --- a/deployment/common/changeset/save_existing_test.go +++ b/deployment/common/changeset/save_existing_test.go @@ -43,7 +43,7 @@ func TestSaveExisting(t *testing.T) { }, } - output, err := SaveExistingContracts(dummyEnv, ExistingContracts) + output, err := SaveExistingContractsChangeset(dummyEnv, ExistingContracts) require.NoError(t, err) require.NoError(t, dummyEnv.ExistingAddresses.Merge(output.AddressBook)) addresses, err := dummyEnv.ExistingAddresses.Addresses() diff --git a/deployment/environment/crib/ccip_deployer.go b/deployment/environment/crib/ccip_deployer.go index 639e42b4024..9aa7972585d 100644 --- a/deployment/environment/crib/ccip_deployer.go +++ b/deployment/environment/crib/ccip_deployer.go @@ -12,8 +12,10 @@ import ( "github.com/smartcontractkit/chainlink-ccip/chainconfig" cciptypes "github.com/smartcontractkit/chainlink-ccip/pkg/types/ccipocr3" + "github.com/smartcontractkit/chainlink/deployment" "github.com/smartcontractkit/chainlink/deployment/ccip/changeset" + "github.com/smartcontractkit/chainlink/deployment/ccip/changeset/testhelpers" commonchangeset "github.com/smartcontractkit/chainlink/deployment/common/changeset" commontypes "github.com/smartcontractkit/chainlink/deployment/common/types" "github.com/smartcontractkit/chainlink/deployment/environment/devenv" @@ -23,7 +25,7 @@ import ( ) // DeployHomeChainContracts deploys the home chain contracts so that the chainlink nodes can use the CR address in Capabilities.ExternalRegistry -// Afterwards, we call DeployHomeChain changeset with nodeinfo ( the peer id and all) +// Afterwards, we call DeployHomeChainChangeset changeset with nodeinfo ( the peer id and all) func DeployHomeChainContracts(ctx context.Context, lggr logger.Logger, envConfig devenv.EnvironmentConfig, homeChainSel uint64, feedChainSel uint64) (deployment.CapabilityRegistryConfig, deployment.AddressBook, error) { e, _, err := devenv.NewEnvironment(func() context.Context { return ctx }, lggr, envConfig) if err != nil { @@ -40,12 +42,12 @@ func DeployHomeChainContracts(ctx context.Context, lggr logger.Logger, envConfig p2pIds := nodes.NonBootstraps().PeerIDs() *e, err = commonchangeset.ApplyChangesets(nil, *e, nil, []commonchangeset.ChangesetApplication{ { - Changeset: commonchangeset.WrapChangeSet(changeset.DeployHomeChain), + Changeset: commonchangeset.WrapChangeSet(changeset.DeployHomeChainChangeset), Config: changeset.DeployHomeChainConfig{ HomeChainSel: homeChainSel, - RMNStaticConfig: changeset.NewTestRMNStaticConfig(), - RMNDynamicConfig: changeset.NewTestRMNDynamicConfig(), - NodeOperators: changeset.NewTestNodeOperator(e.Chains[homeChainSel].DeployerKey.From), + RMNStaticConfig: testhelpers.NewTestRMNStaticConfig(), + RMNDynamicConfig: testhelpers.NewTestRMNDynamicConfig(), + NodeOperators: testhelpers.NewTestNodeOperator(e.Chains[homeChainSel].DeployerKey.From), NodeP2PIDsPerNodeOpAdmin: map[string][][32]byte{ "NodeOperator": p2pIds, }, @@ -116,7 +118,7 @@ func DeployCCIPAndAddLanes(ctx context.Context, lggr logger.Logger, envConfig de // Setup because we only need to deploy the contracts and distribute job specs *e, err = commonchangeset.ApplyChangesets(nil, *e, nil, []commonchangeset.ChangesetApplication{ { - Changeset: commonchangeset.WrapChangeSet(changeset.UpdateChainConfig), + Changeset: commonchangeset.WrapChangeSet(changeset.UpdateChainConfigChangeset), Config: changeset.UpdateChainConfigConfig{ HomeChainSelector: homeChainSel, RemoteChainAdds: chainConfigs, @@ -127,7 +129,7 @@ func DeployCCIPAndAddLanes(ctx context.Context, lggr logger.Logger, envConfig de Config: chainSelectors, }, { - Changeset: commonchangeset.WrapChangeSet(changeset.DeployPrerequisites), + Changeset: commonchangeset.WrapChangeSet(changeset.DeployPrerequisitesChangeset), Config: changeset.DeployPrerequisiteConfig{ Configs: prereqCfgs, }, @@ -137,14 +139,14 @@ func DeployCCIPAndAddLanes(ctx context.Context, lggr logger.Logger, envConfig de Config: cfg, }, { - Changeset: commonchangeset.WrapChangeSet(changeset.DeployChainContracts), + Changeset: commonchangeset.WrapChangeSet(changeset.DeployChainContractsChangeset), Config: changeset.DeployChainContractsConfig{ ChainSelectors: chainSelectors, HomeChainSelector: homeChainSel, }, }, { - Changeset: commonchangeset.WrapChangeSet(changeset.CCIPCapabilityJobspec), + Changeset: commonchangeset.WrapChangeSet(changeset.CCIPCapabilityJobspecChangeset), Config: struct{}{}, }, }) @@ -159,7 +161,7 @@ func DeployCCIPAndAddLanes(ctx context.Context, lggr logger.Logger, envConfig de stateChain1 := state.Chains[from] newEnv, err := commonchangeset.ApplyChangesets(nil, *e, nil, []commonchangeset.ChangesetApplication{ { - Changeset: commonchangeset.WrapChangeSet(changeset.UpdateOnRampsDests), + Changeset: commonchangeset.WrapChangeSet(changeset.UpdateOnRampsDestsChangeset), Config: changeset.UpdateOnRampDestsConfig{ UpdatesByChain: map[uint64]map[uint64]changeset.OnRampDestinationUpdate{ from: { @@ -173,23 +175,23 @@ func DeployCCIPAndAddLanes(ctx context.Context, lggr logger.Logger, envConfig de }, }, { - Changeset: commonchangeset.WrapChangeSet(changeset.UpdateFeeQuoterPricesCS), + Changeset: commonchangeset.WrapChangeSet(changeset.UpdateFeeQuoterPricesChangeset), Config: changeset.UpdateFeeQuoterPricesConfig{ PricesByChain: map[uint64]changeset.FeeQuoterPriceUpdatePerSource{ from: { TokenPrices: map[common.Address]*big.Int{ - stateChain1.LinkToken.Address(): changeset.DefaultLinkPrice, - stateChain1.Weth9.Address(): changeset.DefaultWethPrice, + stateChain1.LinkToken.Address(): testhelpers.DefaultLinkPrice, + stateChain1.Weth9.Address(): testhelpers.DefaultWethPrice, }, GasPrices: map[uint64]*big.Int{ - to: changeset.DefaultGasPrice, + to: testhelpers.DefaultGasPrice, }, }, }, }, }, { - Changeset: commonchangeset.WrapChangeSet(changeset.UpdateFeeQuoterDests), + Changeset: commonchangeset.WrapChangeSet(changeset.UpdateFeeQuoterDestsChangeset), Config: changeset.UpdateFeeQuoterDestsConfig{ UpdatesByChain: map[uint64]map[uint64]fee_quoter.FeeQuoterDestChainConfig{ from: { @@ -199,7 +201,7 @@ func DeployCCIPAndAddLanes(ctx context.Context, lggr logger.Logger, envConfig de }, }, { - Changeset: commonchangeset.WrapChangeSet(changeset.UpdateOffRampSources), + Changeset: commonchangeset.WrapChangeSet(changeset.UpdateOffRampSourcesChangeset), Config: changeset.UpdateOffRampSourcesConfig{ UpdatesByChain: map[uint64]map[uint64]changeset.OffRampSourceUpdate{ to: { @@ -212,7 +214,7 @@ func DeployCCIPAndAddLanes(ctx context.Context, lggr logger.Logger, envConfig de }, }, { - Changeset: commonchangeset.WrapChangeSet(changeset.UpdateRouterRamps), + Changeset: commonchangeset.WrapChangeSet(changeset.UpdateRouterRampsChangeset), Config: changeset.UpdateRouterRampsConfig{ TestRouter: true, UpdatesByChain: map[uint64]changeset.RouterUpdates{ diff --git a/deployment/go.mod b/deployment/go.mod index 61386414da3..c4da3714707 100644 --- a/deployment/go.mod +++ b/deployment/go.mod @@ -417,7 +417,7 @@ require ( github.com/smartcontractkit/chainlink-cosmos v0.5.2-0.20241202195413-82468150ac1e // indirect github.com/smartcontractkit/chainlink-data-streams v0.1.1-0.20250115135646-ac859d85e7e3 // indirect github.com/smartcontractkit/chainlink-feeds v0.1.1 // indirect - github.com/smartcontractkit/chainlink-framework/multinode v0.0.0-20241220173418-09e17ddbeb20 // indirect + github.com/smartcontractkit/chainlink-framework/multinode v0.0.0-20250115203616-a2ea5e50b260 // indirect github.com/smartcontractkit/chainlink-protos/orchestrator v0.4.0 // indirect github.com/smartcontractkit/chainlink-starknet/relayer v0.1.1-0.20241202202529-2033490e77b8 // indirect github.com/smartcontractkit/chainlink-testing-framework/lib/grafana v1.50.0 // indirect diff --git a/deployment/go.sum b/deployment/go.sum index fdc79445ba5..31fa464b3b0 100644 --- a/deployment/go.sum +++ b/deployment/go.sum @@ -1398,8 +1398,8 @@ github.com/smartcontractkit/chainlink-data-streams v0.1.1-0.20250115135646-ac859 github.com/smartcontractkit/chainlink-data-streams v0.1.1-0.20250115135646-ac859d85e7e3/go.mod h1:pDZagSGjs9U+l4YIFhveDznMHqxuuz+5vRxvVgpbdr8= github.com/smartcontractkit/chainlink-feeds v0.1.1 h1:JzvUOM/OgGQA1sOqTXXl52R6AnNt+Wg64sVG+XSA49c= github.com/smartcontractkit/chainlink-feeds v0.1.1/go.mod h1:55EZ94HlKCfAsUiKUTNI7QlE/3d3IwTlsU3YNa/nBb4= -github.com/smartcontractkit/chainlink-framework/multinode v0.0.0-20241220173418-09e17ddbeb20 h1:p/gzWpEf8alodCXm2Gtx2kWI/O9ZLdWZOdNnv5ZGO6c= -github.com/smartcontractkit/chainlink-framework/multinode v0.0.0-20241220173418-09e17ddbeb20/go.mod h1:4JqpgFy01LaqG1yM2iFTzwX3ZgcAvW9WdstBZQgPHzU= +github.com/smartcontractkit/chainlink-framework/multinode v0.0.0-20250115203616-a2ea5e50b260 h1:See2isL6KdrTJDlVKWv8qiyYqWhYUcubU2e5yKXV1oY= +github.com/smartcontractkit/chainlink-framework/multinode v0.0.0-20250115203616-a2ea5e50b260/go.mod h1:4JqpgFy01LaqG1yM2iFTzwX3ZgcAvW9WdstBZQgPHzU= github.com/smartcontractkit/chainlink-protos/job-distributor v0.6.0 h1:0ewLMbAz3rZrovdRUCgd028yOXX8KigB4FndAUdI2kM= github.com/smartcontractkit/chainlink-protos/job-distributor v0.6.0/go.mod h1:/dVVLXrsp+V0AbcYGJo3XMzKg3CkELsweA/TTopCsKE= github.com/smartcontractkit/chainlink-protos/orchestrator v0.4.0 h1:ZBat8EBvE2LpSQR9U1gEbRV6PfAkiFdINmQ8nVnXIAQ= diff --git a/go.mod b/go.mod index b40846d2419..6b42f86e66c 100644 --- a/go.mod +++ b/go.mod @@ -84,7 +84,7 @@ require ( github.com/smartcontractkit/chainlink-cosmos v0.5.2-0.20241202195413-82468150ac1e github.com/smartcontractkit/chainlink-data-streams v0.1.1-0.20250115135646-ac859d85e7e3 github.com/smartcontractkit/chainlink-feeds v0.1.1 - github.com/smartcontractkit/chainlink-framework/multinode v0.0.0-20241220173418-09e17ddbeb20 + github.com/smartcontractkit/chainlink-framework/multinode v0.0.0-20250115203616-a2ea5e50b260 github.com/smartcontractkit/chainlink-protos/orchestrator v0.4.0 github.com/smartcontractkit/chainlink-solana v1.1.1-0.20250110142550-e2a9566d39f3 github.com/smartcontractkit/chainlink-starknet/relayer v0.1.1-0.20241202202529-2033490e77b8 diff --git a/go.sum b/go.sum index 0c4377dc53d..6152134905c 100644 --- a/go.sum +++ b/go.sum @@ -1162,8 +1162,8 @@ github.com/smartcontractkit/chainlink-data-streams v0.1.1-0.20250115135646-ac859 github.com/smartcontractkit/chainlink-data-streams v0.1.1-0.20250115135646-ac859d85e7e3/go.mod h1:pDZagSGjs9U+l4YIFhveDznMHqxuuz+5vRxvVgpbdr8= github.com/smartcontractkit/chainlink-feeds v0.1.1 h1:JzvUOM/OgGQA1sOqTXXl52R6AnNt+Wg64sVG+XSA49c= github.com/smartcontractkit/chainlink-feeds v0.1.1/go.mod h1:55EZ94HlKCfAsUiKUTNI7QlE/3d3IwTlsU3YNa/nBb4= -github.com/smartcontractkit/chainlink-framework/multinode v0.0.0-20241220173418-09e17ddbeb20 h1:p/gzWpEf8alodCXm2Gtx2kWI/O9ZLdWZOdNnv5ZGO6c= -github.com/smartcontractkit/chainlink-framework/multinode v0.0.0-20241220173418-09e17ddbeb20/go.mod h1:4JqpgFy01LaqG1yM2iFTzwX3ZgcAvW9WdstBZQgPHzU= +github.com/smartcontractkit/chainlink-framework/multinode v0.0.0-20250115203616-a2ea5e50b260 h1:See2isL6KdrTJDlVKWv8qiyYqWhYUcubU2e5yKXV1oY= +github.com/smartcontractkit/chainlink-framework/multinode v0.0.0-20250115203616-a2ea5e50b260/go.mod h1:4JqpgFy01LaqG1yM2iFTzwX3ZgcAvW9WdstBZQgPHzU= github.com/smartcontractkit/chainlink-protos/orchestrator v0.4.0 h1:ZBat8EBvE2LpSQR9U1gEbRV6PfAkiFdINmQ8nVnXIAQ= github.com/smartcontractkit/chainlink-protos/orchestrator v0.4.0/go.mod h1:m/A3lqD7ms/RsQ9BT5P2uceYY0QX5mIt4KQxT2G6qEo= github.com/smartcontractkit/chainlink-solana v1.1.1-0.20250110142550-e2a9566d39f3 h1:L6UDu0GzSKfz+/nMSz9yfYrgOpW1/OXhiVK60PxVsnY= diff --git a/integration-tests/go.mod b/integration-tests/go.mod index a1d096882c8..90360e7f736 100644 --- a/integration-tests/go.mod +++ b/integration-tests/go.mod @@ -432,7 +432,7 @@ require ( github.com/smartcontractkit/chainlink-cosmos v0.5.2-0.20241202195413-82468150ac1e // indirect github.com/smartcontractkit/chainlink-data-streams v0.1.1-0.20250115135646-ac859d85e7e3 // indirect github.com/smartcontractkit/chainlink-feeds v0.1.1 // indirect - github.com/smartcontractkit/chainlink-framework/multinode v0.0.0-20241220173418-09e17ddbeb20 // indirect + github.com/smartcontractkit/chainlink-framework/multinode v0.0.0-20250115203616-a2ea5e50b260 // indirect github.com/smartcontractkit/chainlink-protos/orchestrator v0.4.0 // indirect github.com/smartcontractkit/chainlink-solana v1.1.1-0.20250110142550-e2a9566d39f3 // indirect github.com/smartcontractkit/chainlink-starknet/relayer v0.1.1-0.20241202202529-2033490e77b8 // indirect diff --git a/integration-tests/go.sum b/integration-tests/go.sum index 0e9d850ed22..133585022d5 100644 --- a/integration-tests/go.sum +++ b/integration-tests/go.sum @@ -1422,8 +1422,8 @@ github.com/smartcontractkit/chainlink-data-streams v0.1.1-0.20250115135646-ac859 github.com/smartcontractkit/chainlink-data-streams v0.1.1-0.20250115135646-ac859d85e7e3/go.mod h1:pDZagSGjs9U+l4YIFhveDznMHqxuuz+5vRxvVgpbdr8= github.com/smartcontractkit/chainlink-feeds v0.1.1 h1:JzvUOM/OgGQA1sOqTXXl52R6AnNt+Wg64sVG+XSA49c= github.com/smartcontractkit/chainlink-feeds v0.1.1/go.mod h1:55EZ94HlKCfAsUiKUTNI7QlE/3d3IwTlsU3YNa/nBb4= -github.com/smartcontractkit/chainlink-framework/multinode v0.0.0-20241220173418-09e17ddbeb20 h1:p/gzWpEf8alodCXm2Gtx2kWI/O9ZLdWZOdNnv5ZGO6c= -github.com/smartcontractkit/chainlink-framework/multinode v0.0.0-20241220173418-09e17ddbeb20/go.mod h1:4JqpgFy01LaqG1yM2iFTzwX3ZgcAvW9WdstBZQgPHzU= +github.com/smartcontractkit/chainlink-framework/multinode v0.0.0-20250115203616-a2ea5e50b260 h1:See2isL6KdrTJDlVKWv8qiyYqWhYUcubU2e5yKXV1oY= +github.com/smartcontractkit/chainlink-framework/multinode v0.0.0-20250115203616-a2ea5e50b260/go.mod h1:4JqpgFy01LaqG1yM2iFTzwX3ZgcAvW9WdstBZQgPHzU= github.com/smartcontractkit/chainlink-protos/job-distributor v0.6.0 h1:0ewLMbAz3rZrovdRUCgd028yOXX8KigB4FndAUdI2kM= github.com/smartcontractkit/chainlink-protos/job-distributor v0.6.0/go.mod h1:/dVVLXrsp+V0AbcYGJo3XMzKg3CkELsweA/TTopCsKE= github.com/smartcontractkit/chainlink-protos/orchestrator v0.4.0 h1:ZBat8EBvE2LpSQR9U1gEbRV6PfAkiFdINmQ8nVnXIAQ= diff --git a/integration-tests/load/go.mod b/integration-tests/load/go.mod index d288fe465ad..d344cc9a352 100644 --- a/integration-tests/load/go.mod +++ b/integration-tests/load/go.mod @@ -415,7 +415,7 @@ require ( github.com/smartcontractkit/chainlink-cosmos v0.5.2-0.20241202195413-82468150ac1e // indirect github.com/smartcontractkit/chainlink-data-streams v0.1.1-0.20250115135646-ac859d85e7e3 // indirect github.com/smartcontractkit/chainlink-feeds v0.1.1 // indirect - github.com/smartcontractkit/chainlink-framework/multinode v0.0.0-20241220173418-09e17ddbeb20 // indirect + github.com/smartcontractkit/chainlink-framework/multinode v0.0.0-20250115203616-a2ea5e50b260 // indirect github.com/smartcontractkit/chainlink-protos/orchestrator v0.4.0 // indirect github.com/smartcontractkit/chainlink-solana v1.1.1-0.20250110142550-e2a9566d39f3 // indirect github.com/smartcontractkit/chainlink-starknet/relayer v0.1.1-0.20241202202529-2033490e77b8 // indirect diff --git a/integration-tests/load/go.sum b/integration-tests/load/go.sum index 219ff5fe19a..cf96d2d91aa 100644 --- a/integration-tests/load/go.sum +++ b/integration-tests/load/go.sum @@ -1393,16 +1393,12 @@ github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/slack-go/slack v0.15.0 h1:LE2lj2y9vqqiOf+qIIy0GvEoxgF1N5yLGZffmEZykt0= github.com/slack-go/slack v0.15.0/go.mod h1:hlGi5oXA+Gt+yWTPP0plCdRKmjsDxecdHxYQdlMQKOw= -github.com/smartcontractkit/ccip-owner-contracts v0.0.0-salt-fix h1:DPJD++yKLSx0EfT+U14P8vLVxjXFmoIETiCO9lVwQo8= -github.com/smartcontractkit/ccip-owner-contracts v0.0.0-salt-fix/go.mod h1:NnT6w4Kj42OFFXhSx99LvJZWPpMjmo4+CpDEWfw61xY= github.com/smartcontractkit/chain-selectors v1.0.36 h1:KSpO8I+JOiuyN4FuXsV471sPorGF//PAqwq2Cm4gRK0= github.com/smartcontractkit/chain-selectors v1.0.36/go.mod h1:xsKM0aN3YGcQKTPRPDDtPx2l4mlTN1Djmg0VVXV40b8= github.com/smartcontractkit/chainlink-automation v0.8.1 h1:sTc9LKpBvcKPc1JDYAmgBc2xpDKBco/Q4h4ydl6+UUU= github.com/smartcontractkit/chainlink-automation v0.8.1/go.mod h1:Iij36PvWZ6blrdC5A/nrQUBuf3MH3JvsBB9sSyc9W08= github.com/smartcontractkit/chainlink-ccip v0.0.0-20250110181647-9dba278f2103 h1:TeWnxdgSO2cYCKcBMwdkRcs/YdhSvXoWqqw7QWz/KeI= github.com/smartcontractkit/chainlink-ccip v0.0.0-20250110181647-9dba278f2103/go.mod h1:ncjd6mPZSRlelEqH/2KeLE1pU3UlqzBSn8RYkEoECzY= -github.com/smartcontractkit/chainlink-ccip/chains/solana v0.0.0-20250103152858-8973fd0c912b h1:UBXi9Yj8YSMHDDaxQLu273x1fWjyEL9xP58nuJsqZfg= -github.com/smartcontractkit/chainlink-ccip/chains/solana v0.0.0-20250103152858-8973fd0c912b/go.mod h1:Bmwq4lNb5tE47sydN0TKetcLEGbgl+VxHEWp4S0LI60= github.com/smartcontractkit/chainlink-common v0.4.1-0.20250115094325-4e61572bb9bd h1:SX16W7pqXGyn6fHFgtlr/rUdLZzBtQ5O3Gt3a6sFL70= github.com/smartcontractkit/chainlink-common v0.4.1-0.20250115094325-4e61572bb9bd/go.mod h1:yti7e1+G9hhkYhj+L5sVUULn9Bn3bBL5/AxaNqdJ5YQ= github.com/smartcontractkit/chainlink-cosmos v0.5.2-0.20241202195413-82468150ac1e h1:PRoeby6ZlTuTkv2f+7tVU4+zboTfRzI+beECynF4JQ0= @@ -1411,18 +1407,14 @@ github.com/smartcontractkit/chainlink-data-streams v0.1.1-0.20250115135646-ac859 github.com/smartcontractkit/chainlink-data-streams v0.1.1-0.20250115135646-ac859d85e7e3/go.mod h1:pDZagSGjs9U+l4YIFhveDznMHqxuuz+5vRxvVgpbdr8= github.com/smartcontractkit/chainlink-feeds v0.1.1 h1:JzvUOM/OgGQA1sOqTXXl52R6AnNt+Wg64sVG+XSA49c= github.com/smartcontractkit/chainlink-feeds v0.1.1/go.mod h1:55EZ94HlKCfAsUiKUTNI7QlE/3d3IwTlsU3YNa/nBb4= -github.com/smartcontractkit/chainlink-framework/multinode v0.0.0-20241220173418-09e17ddbeb20 h1:p/gzWpEf8alodCXm2Gtx2kWI/O9ZLdWZOdNnv5ZGO6c= -github.com/smartcontractkit/chainlink-framework/multinode v0.0.0-20241220173418-09e17ddbeb20/go.mod h1:4JqpgFy01LaqG1yM2iFTzwX3ZgcAvW9WdstBZQgPHzU= -github.com/smartcontractkit/chainlink-protos/job-distributor v0.6.0 h1:0ewLMbAz3rZrovdRUCgd028yOXX8KigB4FndAUdI2kM= -github.com/smartcontractkit/chainlink-protos/job-distributor v0.6.0/go.mod h1:/dVVLXrsp+V0AbcYGJo3XMzKg3CkELsweA/TTopCsKE= +github.com/smartcontractkit/chainlink-framework/multinode v0.0.0-20250115203616-a2ea5e50b260 h1:See2isL6KdrTJDlVKWv8qiyYqWhYUcubU2e5yKXV1oY= +github.com/smartcontractkit/chainlink-framework/multinode v0.0.0-20250115203616-a2ea5e50b260/go.mod h1:4JqpgFy01LaqG1yM2iFTzwX3ZgcAvW9WdstBZQgPHzU= github.com/smartcontractkit/chainlink-protos/orchestrator v0.4.0 h1:ZBat8EBvE2LpSQR9U1gEbRV6PfAkiFdINmQ8nVnXIAQ= github.com/smartcontractkit/chainlink-protos/orchestrator v0.4.0/go.mod h1:m/A3lqD7ms/RsQ9BT5P2uceYY0QX5mIt4KQxT2G6qEo= github.com/smartcontractkit/chainlink-solana v1.1.1-0.20250110142550-e2a9566d39f3 h1:L6UDu0GzSKfz+/nMSz9yfYrgOpW1/OXhiVK60PxVsnY= github.com/smartcontractkit/chainlink-solana v1.1.1-0.20250110142550-e2a9566d39f3/go.mod h1:52U0UH8K0Qwu+HB1LMc+5V27ru2Tgy29YPT+2HkMevY= github.com/smartcontractkit/chainlink-starknet/relayer v0.1.1-0.20241202202529-2033490e77b8 h1:tNS7U9lrxkFvEuyxQv11HHOiV9LPDGC9wYEy+yM/Jv4= github.com/smartcontractkit/chainlink-starknet/relayer v0.1.1-0.20241202202529-2033490e77b8/go.mod h1:EBrEgcdIbwepqguClkv8Ohy7CbyWSJaE4EC9aBJlQK0= -github.com/smartcontractkit/chainlink-testing-framework/framework v0.4.2-0.20250110073248-456673e8eea2 h1:nTUoe7GZLw17nPLV5t3Vgf4U4pf+VW0Uko5xpNiKdKU= -github.com/smartcontractkit/chainlink-testing-framework/framework v0.4.2-0.20250110073248-456673e8eea2/go.mod h1:mMUqvS3BZfvN1OfK4OFTYf1+T0X6nwmSXJM2keaPsSM= github.com/smartcontractkit/chainlink-testing-framework/havoc v1.50.2 h1:GDGrC5OGiV0RyM1znYWehSQXyZQWTOzrEeJRYmysPCE= github.com/smartcontractkit/chainlink-testing-framework/havoc v1.50.2/go.mod h1:DsT43c1oTBmp3iQkMcoZOoKThwZvt8X3Pz6UmznJ4GY= github.com/smartcontractkit/chainlink-testing-framework/lib v1.50.19 h1:9PMwKNqFKc5FXf4VchyD3CGzZelnSgi13fgVdT2X7T4= diff --git a/integration-tests/smoke/ccip/ccip_batching_test.go b/integration-tests/smoke/ccip/ccip_batching_test.go index 6c204fa45a3..38b068dad92 100644 --- a/integration-tests/smoke/ccip/ccip_batching_test.go +++ b/integration-tests/smoke/ccip/ccip_batching_test.go @@ -15,6 +15,7 @@ import ( "github.com/smartcontractkit/chainlink-ccip/pkg/types/ccipocr3" "github.com/smartcontractkit/chainlink-common/pkg/merklemulti" + "github.com/smartcontractkit/chainlink/deployment/ccip/changeset/testhelpers" testsetups "github.com/smartcontractkit/chainlink/integration-tests/testsetups/ccip" "github.com/smartcontractkit/chainlink/deployment" @@ -30,7 +31,7 @@ const ( ) type batchTestSetup struct { - e changeset.DeployedEnv + e testhelpers.DeployedEnv state changeset.CCIPOnChainState sourceChain1 uint64 sourceChain2 uint64 @@ -41,9 +42,9 @@ func newBatchTestSetup(t *testing.T) batchTestSetup { // Setup 3 chains, with 2 lanes going to the dest. e, _, _ := testsetups.NewIntegrationEnvironment( t, - changeset.WithMultiCall3(), - changeset.WithChains(3), - changeset.WithUsersPerChain(2), + testhelpers.WithMultiCall3(), + testhelpers.WithNumOfChains(3), + testhelpers.WithNumOfUsersPerChain(2), ) state, err := changeset.LoadOnchainState(e.Env) @@ -63,8 +64,8 @@ func newBatchTestSetup(t *testing.T) batchTestSetup { ) // connect sourceChain1 and sourceChain2 to destChain - changeset.AddLaneWithDefaultPricesAndFeeQuoterConfig(t, &e, state, sourceChain1, destChain, false) - changeset.AddLaneWithDefaultPricesAndFeeQuoterConfig(t, &e, state, sourceChain2, destChain, false) + testhelpers.AddLaneWithDefaultPricesAndFeeQuoterConfig(t, &e, state, sourceChain1, destChain, false) + testhelpers.AddLaneWithDefaultPricesAndFeeQuoterConfig(t, &e, state, sourceChain2, destChain, false) return batchTestSetup{e, state, sourceChain1, sourceChain2, destChain} } @@ -72,7 +73,7 @@ func newBatchTestSetup(t *testing.T) batchTestSetup { func Test_CCIPBatching_MaxBatchSizeEVM(t *testing.T) { t.Parallel() - ctx := changeset.Context(t) + ctx := testhelpers.Context(t) setup := newBatchTestSetup(t) sourceChain1, sourceChain2, destChain, e, state := setup.sourceChain1, setup.sourceChain2, setup.destChain, setup.e, setup.state @@ -120,7 +121,7 @@ func Test_CCIPBatching_MaxBatchSizeEVM(t *testing.T) { } } - _, err := changeset.ConfirmCommitWithExpectedSeqNumRange( + _, err := testhelpers.ConfirmCommitWithExpectedSeqNumRange( t, e.Env.Chains[sourceChain], e.Env.Chains[destChain], @@ -141,7 +142,7 @@ func Test_CCIPBatching_MultiSource(t *testing.T) { t.Parallel() // Setup 3 chains, with 2 lanes going to the dest. - ctx := changeset.Context(t) + ctx := testhelpers.Context(t) setup := newBatchTestSetup(t) sourceChain1, sourceChain2, destChain, e, state := setup.sourceChain1, setup.sourceChain2, setup.destChain, setup.e, setup.state @@ -259,7 +260,7 @@ func Test_CCIPBatching_MultiSource(t *testing.T) { // assert that all states are successful for _, states := range execStates { for _, state := range states { - require.Equal(t, changeset.EXECUTION_STATE_SUCCESS, state) + require.Equal(t, testhelpers.EXECUTION_STATE_SUCCESS, state) } } } @@ -268,7 +269,7 @@ func Test_CCIPBatching_SingleSource(t *testing.T) { t.Parallel() // Setup 3 chains, with 2 lanes going to the dest. - ctx := changeset.Context(t) + ctx := testhelpers.Context(t) setup := newBatchTestSetup(t) sourceChain1, sourceChain2, destChain, e, state := setup.sourceChain1, setup.sourceChain2, setup.destChain, setup.e, setup.state @@ -296,7 +297,7 @@ func Test_CCIPBatching_SingleSource(t *testing.T) { ) require.NoError(t, err) - _, err = changeset.ConfirmCommitWithExpectedSeqNumRange( + _, err = testhelpers.ConfirmCommitWithExpectedSeqNumRange( t, e.Env.Chains[sourceChain], e.Env.Chains[destChain], @@ -307,7 +308,7 @@ func Test_CCIPBatching_SingleSource(t *testing.T) { ) require.NoErrorf(t, err, "failed to confirm commit from chain %d", sourceChain) - states, err := changeset.ConfirmExecWithSeqNrs( + states, err := testhelpers.ConfirmExecWithSeqNrs( t, e.Env.Chains[sourceChain], e.Env.Chains[destChain], @@ -318,7 +319,7 @@ func Test_CCIPBatching_SingleSource(t *testing.T) { require.NoError(t, err) // assert that all states are successful for _, state := range states { - require.Equal(t, changeset.EXECUTION_STATE_SUCCESS, state) + require.Equal(t, testhelpers.EXECUTION_STATE_SUCCESS, state) } } @@ -329,7 +330,7 @@ type outputErr[T any] struct { func assertExecAsync( t *testing.T, - e changeset.DeployedEnv, + e testhelpers.DeployedEnv, state changeset.CCIPOnChainState, sourceChainSelector, destChainSelector uint64, @@ -338,7 +339,7 @@ func assertExecAsync( errs chan<- outputErr[map[uint64]int], ) { defer wg.Done() - states, err := changeset.ConfirmExecWithSeqNrs( + states, err := testhelpers.ConfirmExecWithSeqNrs( t, e.Env.Chains[sourceChainSelector], e.Env.Chains[destChainSelector], @@ -352,7 +353,7 @@ func assertExecAsync( func assertCommitReportsAsync( t *testing.T, - e changeset.DeployedEnv, + e testhelpers.DeployedEnv, state changeset.CCIPOnChainState, sourceChainSelector, destChainSelector uint64, @@ -362,7 +363,7 @@ func assertCommitReportsAsync( errs chan<- outputErr[*offramp.OffRampCommitReportAccepted], ) { defer wg.Done() - commitReport, err := changeset.ConfirmCommitWithExpectedSeqNumRange( + commitReport, err := testhelpers.ConfirmCommitWithExpectedSeqNumRange( t, e.Env.Chains[sourceChainSelector], e.Env.Chains[destChainSelector], @@ -378,7 +379,7 @@ func assertCommitReportsAsync( func sendMessagesAsync( ctx context.Context, t *testing.T, - e changeset.DeployedEnv, + e testhelpers.DeployedEnv, state changeset.CCIPOnChainState, sourceChainSelector, destChainSelector uint64, @@ -498,7 +499,7 @@ func genMessages( Data: []byte(fmt.Sprintf("hello world %d", i)), TokenAmounts: nil, FeeToken: common.HexToAddress("0x0"), - ExtraArgs: changeset.MakeEVMExtraArgsV2(50_000, false), + ExtraArgs: testhelpers.MakeEVMExtraArgsV2(50_000, false), } fee, err := sourceRouter.GetFee(&bind.CallOpts{Context: ctx}, destChainSelector, msg) @@ -508,7 +509,7 @@ func genMessages( totalValue.Add(totalValue, fee) - calldata, err := changeset.CCIPSendCalldata(destChainSelector, msg) + calldata, err := testhelpers.CCIPSendCalldata(destChainSelector, msg) if err != nil { return nil, nil, fmt.Errorf("generate calldata: %w", err) } diff --git a/integration-tests/smoke/ccip/ccip_fee_boosting_test.go b/integration-tests/smoke/ccip/ccip_fee_boosting_test.go index 49f603a39f4..d1800174a25 100644 --- a/integration-tests/smoke/ccip/ccip_fee_boosting_test.go +++ b/integration-tests/smoke/ccip/ccip_fee_boosting_test.go @@ -8,6 +8,7 @@ import ( "github.com/smartcontractkit/chainlink-common/pkg/config" + "github.com/smartcontractkit/chainlink/deployment/ccip/changeset/testhelpers" commoncs "github.com/smartcontractkit/chainlink/deployment/common/changeset" testsetups "github.com/smartcontractkit/chainlink/integration-tests/testsetups/ccip" @@ -36,7 +37,7 @@ var ( func Test_CCIPFeeBoosting(t *testing.T) { e, _, _ := testsetups.NewIntegrationEnvironment( t, - changeset.WithOCRConfigOverride(func(params changeset.CCIPOCRParams) changeset.CCIPOCRParams { + testhelpers.WithOCRConfigOverride(func(params *changeset.CCIPOCRParams) { // Only 1 boost (=OCR round) is enough to cover the fee params.ExecuteOffChainConfig.RelativeBoostPerWaitHour = 10 // Disable token price updates @@ -45,7 +46,6 @@ func Test_CCIPFeeBoosting(t *testing.T) { params.CommitOffChainConfig.RemoteGasPriceBatchWriteFrequency = *config.MustNewDuration(1_000_000 * time.Hour) // Disable token price updates params.CommitOffChainConfig.TokenInfo = nil - return params }), ) @@ -81,9 +81,9 @@ func Test_CCIPFeeBoosting(t *testing.T) { ) t.Log("Adjusted gas price on dest chain:", adjustedGasPriceDest) - changeset.AddLane(t, &e, sourceChain, destChain, false, + testhelpers.AddLane(t, &e, sourceChain, destChain, false, map[uint64]*big.Int{ - destChain: changeset.ToPackedFee(adjustedGasPriceDest, big.NewInt(0)), + destChain: testhelpers.ToPackedFee(adjustedGasPriceDest, big.NewInt(0)), }, map[common.Address]*big.Int{ state.Chains[sourceChain].LinkToken.Address(): linkPrice, @@ -94,7 +94,7 @@ func Test_CCIPFeeBoosting(t *testing.T) { // Update token prices in destination chain FeeQuoter e.Env, err = commoncs.ApplyChangesets(t, e.Env, e.TimelockContracts(t), []commoncs.ChangesetApplication{ { - Changeset: commoncs.WrapChangeSet(changeset.UpdateFeeQuoterPricesCS), + Changeset: commoncs.WrapChangeSet(changeset.UpdateFeeQuoterPricesChangeset), Config: changeset.UpdateFeeQuoterPricesConfig{ PricesByChain: map[uint64]changeset.FeeQuoterPriceUpdatePerSource{ destChain: { @@ -110,13 +110,13 @@ func Test_CCIPFeeBoosting(t *testing.T) { require.NoError(t, err) startBlocks := make(map[uint64]*uint64) - expectedSeqNum := make(map[changeset.SourceDestPair]uint64) - expectedSeqNumExec := make(map[changeset.SourceDestPair][]uint64) + expectedSeqNum := make(map[testhelpers.SourceDestPair]uint64) + expectedSeqNumExec := make(map[testhelpers.SourceDestPair][]uint64) latesthdr, err := e.Env.Chains[sourceChain].Client.HeaderByNumber(testcontext.Get(t), nil) require.NoError(t, err) block := latesthdr.Number.Uint64() - msgSentEvent := changeset.TestSendRequest(t, e.Env, state, sourceChain, destChain, false, router.ClientEVM2AnyMessage{ + msgSentEvent := testhelpers.TestSendRequest(t, e.Env, state, sourceChain, destChain, false, router.ClientEVM2AnyMessage{ Receiver: common.LeftPadBytes(state.Chains[destChain].Receiver.Address().Bytes(), 32), Data: []byte("message that needs fee boosting"), TokenAmounts: nil, @@ -124,18 +124,18 @@ func Test_CCIPFeeBoosting(t *testing.T) { ExtraArgs: nil, }) startBlocks[sourceChain] = &block - expectedSeqNum[changeset.SourceDestPair{ + expectedSeqNum[testhelpers.SourceDestPair{ SourceChainSelector: sourceChain, DestChainSelector: destChain, }] = msgSentEvent.SequenceNumber - expectedSeqNumExec[changeset.SourceDestPair{ + expectedSeqNumExec[testhelpers.SourceDestPair{ SourceChainSelector: sourceChain, DestChainSelector: destChain, }] = []uint64{msgSentEvent.SequenceNumber} e.Env, err = commoncs.ApplyChangesets(t, e.Env, e.TimelockContracts(t), []commoncs.ChangesetApplication{ { - Changeset: commoncs.WrapChangeSet(changeset.UpdateFeeQuoterPricesCS), + Changeset: commoncs.WrapChangeSet(changeset.UpdateFeeQuoterPricesChangeset), Config: changeset.UpdateFeeQuoterPricesConfig{ PricesByChain: map[uint64]changeset.FeeQuoterPriceUpdatePerSource{ sourceChain: { @@ -151,7 +151,7 @@ func Test_CCIPFeeBoosting(t *testing.T) { // Confirm gas prices are updated srcFeeQuoter := state.Chains[sourceChain].FeeQuoter - err = changeset.ConfirmGasPriceUpdated(t, e.Env.Chains[destChain], srcFeeQuoter, 0, originalGasPriceDestUSD) + err = testhelpers.ConfirmGasPriceUpdated(t, e.Env.Chains[destChain], srcFeeQuoter, 0, originalGasPriceDestUSD) require.NoError(t, err) // Confirm that fee boosting will be triggered @@ -162,11 +162,11 @@ func Test_CCIPFeeBoosting(t *testing.T) { replayBlocks := make(map[uint64]uint64) replayBlocks[sourceChain] = 1 replayBlocks[destChain] = 1 - changeset.ReplayLogs(t, e.Env.Offchain, replayBlocks) + testhelpers.ReplayLogs(t, e.Env.Offchain, replayBlocks) // Confirm that the message is committed and executed - changeset.ConfirmCommitForAllWithExpectedSeqNums(t, e.Env, state, expectedSeqNum, startBlocks) - changeset.ConfirmExecWithSeqNrsForAll(t, e.Env, state, expectedSeqNumExec, startBlocks) + testhelpers.ConfirmCommitForAllWithExpectedSeqNums(t, e.Env, state, expectedSeqNum, startBlocks) + testhelpers.ConfirmExecWithSeqNrsForAll(t, e.Env, state, expectedSeqNumExec, startBlocks) } // TODO: Find a more accurate way to determine if fee boosting will be triggered diff --git a/integration-tests/smoke/ccip/ccip_fees_test.go b/integration-tests/smoke/ccip/ccip_fees_test.go index d0f9cc71683..7c329179e55 100644 --- a/integration-tests/smoke/ccip/ccip_fees_test.go +++ b/integration-tests/smoke/ccip/ccip_fees_test.go @@ -14,6 +14,7 @@ import ( "github.com/smartcontractkit/chainlink/deployment" "github.com/smartcontractkit/chainlink/deployment/ccip/changeset" + "github.com/smartcontractkit/chainlink/deployment/ccip/changeset/testhelpers" testsetups "github.com/smartcontractkit/chainlink/integration-tests/testsetups/ccip" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/router" @@ -27,7 +28,7 @@ import ( func setupTokens( t *testing.T, state changeset.CCIPOnChainState, - tenv changeset.DeployedEnv, + tenv testhelpers.DeployedEnv, src, dest uint64, transferTokenMintAmount, feeTokenMintAmount *big.Int, @@ -39,7 +40,7 @@ func setupTokens( e := tenv.Env // Deploy the token to test transferring - srcToken, _, dstToken, _, err := changeset.DeployTransferableToken( + srcToken, _, dstToken, _, err := testhelpers.DeployTransferableToken( lggr, tenv.Env.Chains, src, @@ -103,7 +104,7 @@ func Test_CCIPFees(t *testing.T) { t.Parallel() tenv, _, _ := testsetups.NewIntegrationEnvironment( t, - changeset.WithMultiCall3(), + testhelpers.WithMultiCall3(), ) e := tenv.Env @@ -127,10 +128,10 @@ func Test_CCIPFees(t *testing.T) { ) // Ensure capreg logs are up to date. - changeset.ReplayLogs(t, e.Offchain, tenv.ReplayBlocks) + testhelpers.ReplayLogs(t, e.Offchain, tenv.ReplayBlocks) // Add all lanes - changeset.AddLanesForAll(t, &tenv, state) + testhelpers.AddLanesForAll(t, &tenv, state) t.Run("Send programmable token transfer pay with Link token", func(t *testing.T) { runFeeTokenTestCase(feeTokenTestCase{ @@ -222,10 +223,10 @@ func Test_CCIPFees(t *testing.T) { ExtraArgs: nil, } - _, _, err = changeset.CCIPSendRequest( + _, _, err = testhelpers.CCIPSendRequest( e, state, - &changeset.CCIPSendReqConfig{ + &testhelpers.CCIPSendReqConfig{ Sender: e.Chains[sourceChain].DeployerKey, IsTestRouter: true, SourceChain: sourceChain, @@ -291,7 +292,7 @@ func Test_CCIPFees(t *testing.T) { type feeTokenTestCase struct { t *testing.T src, dst uint64 - env changeset.DeployedEnv + env testhelpers.DeployedEnv srcToken, dstToken *burn_mint_erc677.BurnMintERC677 tokenAmounts []router.ClientEVMTokenAmount feeToken common.Address @@ -304,8 +305,8 @@ func runFeeTokenTestCase(tc feeTokenTestCase) { ctx := tests.Context(tc.t) // Need to keep track of the block number for each chain so that event subscription can be done from that block. startBlocks := make(map[uint64]*uint64) - expectedSeqNum := make(map[changeset.SourceDestPair]uint64) - expectedSeqNumExec := make(map[changeset.SourceDestPair][]uint64) + expectedSeqNum := make(map[testhelpers.SourceDestPair]uint64) + expectedSeqNumExec := make(map[testhelpers.SourceDestPair][]uint64) srcChain := tc.env.Env.Chains[tc.src] dstChain := tc.env.Env.Chains[tc.dst] @@ -374,7 +375,7 @@ func runFeeTokenTestCase(tc feeTokenTestCase) { tc.t.Logf("fee token balance before: %s, fee token enabled: %s", feeTokenBalanceBefore.String(), tc.feeToken.String()) - msgSentEvent := changeset.TestSendRequest( + msgSentEvent := testhelpers.TestSendRequest( tc.t, tc.env.Env, state, @@ -390,11 +391,11 @@ func runFeeTokenTestCase(tc feeTokenTestCase) { }, ) - expectedSeqNum[changeset.SourceDestPair{ + expectedSeqNum[testhelpers.SourceDestPair{ SourceChainSelector: tc.src, DestChainSelector: tc.dst, }] = msgSentEvent.SequenceNumber - expectedSeqNumExec[changeset.SourceDestPair{ + expectedSeqNumExec[testhelpers.SourceDestPair{ SourceChainSelector: tc.src, DestChainSelector: tc.dst, }] = []uint64{msgSentEvent.SequenceNumber} @@ -427,7 +428,7 @@ func runFeeTokenTestCase(tc feeTokenTestCase) { ) // Wait for all commit reports to land. - changeset.ConfirmCommitForAllWithExpectedSeqNums(tc.t, tc.env.Env, state, expectedSeqNum, startBlocks) + testhelpers.ConfirmCommitForAllWithExpectedSeqNums(tc.t, tc.env.Env, state, expectedSeqNum, startBlocks) // After commit is reported on all chains, token prices should be updated in FeeQuoter. linkAddress := state.Chains[tc.dst].LinkToken.Address() @@ -439,7 +440,7 @@ func runFeeTokenTestCase(tc feeTokenTestCase) { require.Equal(tc.t, changeset.MockLinkPrice, timestampedPrice.Value) // Wait for all exec reports to land - changeset.ConfirmExecWithSeqNrsForAll(tc.t, tc.env.Env, state, expectedSeqNumExec, startBlocks) + testhelpers.ConfirmExecWithSeqNrsForAll(tc.t, tc.env.Env, state, expectedSeqNumExec, startBlocks) if tc.assertTokenBalance { require.Len(tc.t, tc.tokenAmounts, 1) diff --git a/integration-tests/smoke/ccip/ccip_gas_price_updates_test.go b/integration-tests/smoke/ccip/ccip_gas_price_updates_test.go index 09023f1d321..0035be6f71c 100644 --- a/integration-tests/smoke/ccip/ccip_gas_price_updates_test.go +++ b/integration-tests/smoke/ccip/ccip_gas_price_updates_test.go @@ -15,6 +15,7 @@ import ( "github.com/smartcontractkit/chainlink/deployment" "github.com/smartcontractkit/chainlink/deployment/ccip/changeset" + "github.com/smartcontractkit/chainlink/deployment/ccip/changeset/testhelpers" testsetups "github.com/smartcontractkit/chainlink/integration-tests/testsetups/ccip" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/fee_quoter" ) @@ -22,19 +23,18 @@ import ( // Test_CCIPGasPriceUpdates tests that chain fee price updates are propagated correctly when // price reaches some deviation threshold or when the price has expired. func Test_CCIPGasPriceUpdates(t *testing.T) { - ctx := changeset.Context(t) + ctx := testhelpers.Context(t) callOpts := &bind.CallOpts{Context: ctx} var gasPriceExpiry = 5 * time.Second e, _, _ := testsetups.NewIntegrationEnvironment(t, - changeset.WithOCRConfigOverride(func(params changeset.CCIPOCRParams) changeset.CCIPOCRParams { + testhelpers.WithOCRConfigOverride(func(params *changeset.CCIPOCRParams) { params.CommitOffChainConfig.RemoteGasPriceBatchWriteFrequency = *config.MustNewDuration(gasPriceExpiry) - return params }), ) state, err := changeset.LoadOnchainState(e.Env) require.NoError(t, err) - changeset.AddLanesForAll(t, &e, state) + testhelpers.AddLanesForAll(t, &e, state) allChainSelectors := maps.Keys(e.Env.Chains) assert.GreaterOrEqual(t, len(allChainSelectors), 2, "test requires at least 2 chains") diff --git a/integration-tests/smoke/ccip/ccip_message_limitations_test.go b/integration-tests/smoke/ccip/ccip_message_limitations_test.go index 2882a34af63..01be93a01a1 100644 --- a/integration-tests/smoke/ccip/ccip_message_limitations_test.go +++ b/integration-tests/smoke/ccip/ccip_message_limitations_test.go @@ -15,6 +15,7 @@ import ( "github.com/smartcontractkit/chainlink/deployment" "github.com/smartcontractkit/chainlink/deployment/ccip/changeset" + "github.com/smartcontractkit/chainlink/deployment/ccip/changeset/testhelpers" testsetups "github.com/smartcontractkit/chainlink/integration-tests/testsetups/ccip" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/router" ) @@ -29,7 +30,7 @@ func Test_CCIPMessageLimitations(t *testing.T) { onChainState, err := changeset.LoadOnchainState(testEnv.Env) require.NoError(t, err) - changeset.AddLanesForAll(t, &testEnv, onChainState) + testhelpers.AddLanesForAll(t, &testEnv, onChainState) srcToken, _ := setupTokens( t, @@ -82,7 +83,7 @@ func Test_CCIPMessageLimitations(t *testing.T) { Receiver: common.LeftPadBytes(onChainState.Chains[chains[1]].Receiver.Address().Bytes(), 32), Data: []byte(strings.Repeat("0", int(chain0DestConfig.MaxDataBytes))), FeeToken: common.HexToAddress("0x0"), - ExtraArgs: changeset.MakeEVMExtraArgsV2(uint64(chain0DestConfig.MaxPerMsgGasLimit), true), + ExtraArgs: testhelpers.MakeEVMExtraArgsV2(uint64(chain0DestConfig.MaxPerMsgGasLimit), true), }, }, //{ // TODO: exec plugin never executed this message. CCIP-4471 @@ -136,7 +137,7 @@ func Test_CCIPMessageLimitations(t *testing.T) { Data: []byte("abc"), TokenAmounts: []router.ClientEVMTokenAmount{}, FeeToken: common.HexToAddress("0x0"), - ExtraArgs: changeset.MakeEVMExtraArgsV2(uint64(chain0DestConfig.MaxPerMsgGasLimit)+1, true), + ExtraArgs: testhelpers.MakeEVMExtraArgsV2(uint64(chain0DestConfig.MaxPerMsgGasLimit)+1, true), }, expRevert: true, }, @@ -145,18 +146,18 @@ func Test_CCIPMessageLimitations(t *testing.T) { // Need to keep track of the block number for each chain so that event subscription can be done from that block. startBlocks := make(map[uint64]*uint64) // Send a message from each chain to every other chain. - expectedSeqNum := make(map[changeset.SourceDestPair]uint64) - expectedSeqNumExec := make(map[changeset.SourceDestPair][]uint64) + expectedSeqNum := make(map[testhelpers.SourceDestPair]uint64) + expectedSeqNumExec := make(map[testhelpers.SourceDestPair][]uint64) for _, msg := range testMsgs { t.Logf("Sending msg: %s", msg.name) require.NotEqual(t, msg.fromChain, msg.toChain, "fromChain and toChain cannot be the same") startBlocks[msg.toChain] = nil - msgSentEvent, err := changeset.DoSendRequest( + msgSentEvent, err := testhelpers.DoSendRequest( t, testEnv.Env, onChainState, - changeset.WithSourceChain(msg.fromChain), - changeset.WithDestChain(msg.toChain), - changeset.WithTestRouter(false), - changeset.WithEvm2AnyMessage(msg.msg)) + testhelpers.WithSourceChain(msg.fromChain), + testhelpers.WithDestChain(msg.toChain), + testhelpers.WithTestRouter(false), + testhelpers.WithEvm2AnyMessage(msg.msg)) if msg.expRevert { t.Logf("Message reverted as expected") @@ -168,19 +169,19 @@ func Test_CCIPMessageLimitations(t *testing.T) { t.Logf("Message not reverted as expected") - expectedSeqNum[changeset.SourceDestPair{ + expectedSeqNum[testhelpers.SourceDestPair{ SourceChainSelector: msg.fromChain, DestChainSelector: msg.toChain, }] = msgSentEvent.SequenceNumber - expectedSeqNumExec[changeset.SourceDestPair{ + expectedSeqNumExec[testhelpers.SourceDestPair{ SourceChainSelector: msg.fromChain, DestChainSelector: msg.toChain, }] = []uint64{msgSentEvent.SequenceNumber} } // Wait for all commit reports to land. - changeset.ConfirmCommitForAllWithExpectedSeqNums(t, testEnv.Env, onChainState, expectedSeqNum, startBlocks) + testhelpers.ConfirmCommitForAllWithExpectedSeqNums(t, testEnv.Env, onChainState, expectedSeqNum, startBlocks) // Wait for all exec reports to land - changeset.ConfirmExecWithSeqNrsForAll(t, testEnv.Env, onChainState, expectedSeqNumExec, startBlocks) + testhelpers.ConfirmExecWithSeqNrsForAll(t, testEnv.Env, onChainState, expectedSeqNumExec, startBlocks) } diff --git a/integration-tests/smoke/ccip/ccip_messaging_test.go b/integration-tests/smoke/ccip/ccip_messaging_test.go index f010bab5ee1..3e28c7851ca 100644 --- a/integration-tests/smoke/ccip/ccip_messaging_test.go +++ b/integration-tests/smoke/ccip/ccip_messaging_test.go @@ -18,6 +18,7 @@ import ( "github.com/smartcontractkit/chainlink/deployment" "github.com/smartcontractkit/chainlink/deployment/ccip/changeset" + "github.com/smartcontractkit/chainlink/deployment/ccip/changeset/testhelpers" testsetups "github.com/smartcontractkit/chainlink/integration-tests/testsetups/ccip" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/offramp" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/onramp" @@ -27,7 +28,7 @@ import ( type testCaseSetup struct { t *testing.T sender []byte - deployedEnv changeset.DeployedEnv + deployedEnv testhelpers.DeployedEnv onchainState changeset.CCIPOnChainState sourceChain, destChain uint64 } @@ -46,7 +47,7 @@ type messagingTestCaseOutput struct { func Test_CCIPMessaging(t *testing.T) { // Setup 2 chains and a single lane. - ctx := changeset.Context(t) + ctx := testhelpers.Context(t) e, _, _ := testsetups.NewIntegrationEnvironment(t) state, err := changeset.LoadOnchainState(e.Env) @@ -63,7 +64,7 @@ func Test_CCIPMessaging(t *testing.T) { ", dest chain selector:", destChain, ) // connect a single lane, source to dest - changeset.AddLaneWithDefaultPricesAndFeeQuoterConfig(t, &e, state, sourceChain, destChain, false) + testhelpers.AddLaneWithDefaultPricesAndFeeQuoterConfig(t, &e, state, sourceChain, destChain, false) var ( replayed bool @@ -88,8 +89,8 @@ func Test_CCIPMessaging(t *testing.T) { }, common.HexToAddress("0xdead"), []byte("hello eoa"), - nil, // default extraArgs - changeset.EXECUTION_STATE_SUCCESS, // success because offRamp won't call an EOA + nil, // default extraArgs + testhelpers.EXECUTION_STATE_SUCCESS, // success because offRamp won't call an EOA ) }) @@ -102,8 +103,8 @@ func Test_CCIPMessaging(t *testing.T) { }, state.Chains[destChain].FeeQuoter.Address(), []byte("hello FeeQuoter"), - nil, // default extraArgs - changeset.EXECUTION_STATE_SUCCESS, // success because offRamp won't call a contract not implementing CCIPReceiver + nil, // default extraArgs + testhelpers.EXECUTION_STATE_SUCCESS, // success because offRamp won't call a contract not implementing CCIPReceiver ) }) @@ -119,7 +120,7 @@ func Test_CCIPMessaging(t *testing.T) { state.Chains[destChain].Receiver.Address(), []byte("hello CCIPReceiver"), nil, // default extraArgs - changeset.EXECUTION_STATE_SUCCESS, + testhelpers.EXECUTION_STATE_SUCCESS, func(t *testing.T) { iter, err := state.Chains[destChain].Receiver.FilterMessageReceived(&bind.FilterOpts{ Context: ctx, @@ -143,8 +144,8 @@ func Test_CCIPMessaging(t *testing.T) { }, state.Chains[destChain].Receiver.Address(), []byte("hello CCIPReceiver with low exec gas"), - changeset.MakeEVMExtraArgsV2(1, false), // 1 gas is too low. - changeset.EXECUTION_STATE_FAILURE, // state would be failed onchain due to low gas + testhelpers.MakeEVMExtraArgsV2(1, false), // 1 gas is too low. + testhelpers.EXECUTION_STATE_FAILURE, // state would be failed onchain due to low gas ) manuallyExecute(ctx, t, latestHead.Number.Uint64(), state, destChain, out, sourceChain, e, sender) @@ -162,7 +163,7 @@ func manuallyExecute( destChain uint64, out messagingTestCaseOutput, sourceChain uint64, - e changeset.DeployedEnv, + e testhelpers.DeployedEnv, sender []byte, ) { merkleRoot := getMerkleRoot( @@ -229,7 +230,7 @@ func manuallyExecute( newExecutionState, err := state.Chains[destChain].OffRamp.GetExecutionState(&bind.CallOpts{Context: ctx}, sourceChain, out.msgSentEvent.SequenceNumber) require.NoError(t, err) - require.Equal(t, uint8(changeset.EXECUTION_STATE_SUCCESS), newExecutionState) + require.Equal(t, uint8(testhelpers.EXECUTION_STATE_SUCCESS), newExecutionState) } func getMerkleRoot( @@ -285,12 +286,12 @@ func getMessageHash( return iter.Event.MessageHash } -func sleepAndReplay(t *testing.T, e changeset.DeployedEnv, sourceChain, destChain uint64) { +func sleepAndReplay(t *testing.T, e testhelpers.DeployedEnv, sourceChain, destChain uint64) { time.Sleep(30 * time.Second) replayBlocks := make(map[uint64]uint64) replayBlocks[sourceChain] = 1 replayBlocks[destChain] = 1 - changeset.ReplayLogs(t, e.Env.Offchain, replayBlocks) + testhelpers.ReplayLogs(t, e.Env.Offchain, replayBlocks) } func runMessagingTestCase( @@ -309,20 +310,20 @@ func runMessagingTestCase( require.Equal(tc.t, tc.nonce, latestNonce) startBlocks := make(map[uint64]*uint64) - msgSentEvent := changeset.TestSendRequest(tc.t, tc.deployedEnv.Env, tc.onchainState, tc.sourceChain, tc.destChain, false, router.ClientEVM2AnyMessage{ + msgSentEvent := testhelpers.TestSendRequest(tc.t, tc.deployedEnv.Env, tc.onchainState, tc.sourceChain, tc.destChain, false, router.ClientEVM2AnyMessage{ Receiver: common.LeftPadBytes(receiver.Bytes(), 32), Data: msgData, TokenAmounts: nil, FeeToken: common.HexToAddress("0x0"), ExtraArgs: extraArgs, }) - expectedSeqNum := map[changeset.SourceDestPair]uint64{ + expectedSeqNum := map[testhelpers.SourceDestPair]uint64{ { SourceChainSelector: tc.sourceChain, DestChainSelector: tc.destChain, }: msgSentEvent.SequenceNumber, } - expectedSeqNumExec := map[changeset.SourceDestPair][]uint64{ + expectedSeqNumExec := map[testhelpers.SourceDestPair][]uint64{ { SourceChainSelector: tc.sourceChain, DestChainSelector: tc.destChain, @@ -336,20 +337,20 @@ func runMessagingTestCase( out.replayed = true } - changeset.ConfirmCommitForAllWithExpectedSeqNums(tc.t, tc.deployedEnv.Env, tc.onchainState, expectedSeqNum, startBlocks) - execStates := changeset.ConfirmExecWithSeqNrsForAll(tc.t, tc.deployedEnv.Env, tc.onchainState, expectedSeqNumExec, startBlocks) + testhelpers.ConfirmCommitForAllWithExpectedSeqNums(tc.t, tc.deployedEnv.Env, tc.onchainState, expectedSeqNum, startBlocks) + execStates := testhelpers.ConfirmExecWithSeqNrsForAll(tc.t, tc.deployedEnv.Env, tc.onchainState, expectedSeqNumExec, startBlocks) require.Equalf( tc.t, expectedExecutionState, - execStates[changeset.SourceDestPair{ + execStates[testhelpers.SourceDestPair{ SourceChainSelector: tc.sourceChain, DestChainSelector: tc.destChain, }][msgSentEvent.SequenceNumber], "wrong execution state for seq nr %d, expected %d, got %d", msgSentEvent.SequenceNumber, expectedExecutionState, - execStates[changeset.SourceDestPair{ + execStates[testhelpers.SourceDestPair{ SourceChainSelector: tc.sourceChain, DestChainSelector: tc.destChain, }][msgSentEvent.SequenceNumber], diff --git a/integration-tests/smoke/ccip/ccip_migration_to_v_1_6_test.go b/integration-tests/smoke/ccip/ccip_migration_to_v_1_6_test.go index 5c35be01f93..a0b62fe8182 100644 --- a/integration-tests/smoke/ccip/ccip_migration_to_v_1_6_test.go +++ b/integration-tests/smoke/ccip/ccip_migration_to_v_1_6_test.go @@ -12,6 +12,8 @@ import ( "github.com/smartcontractkit/chainlink-testing-framework/lib/utils/testcontext" "github.com/smartcontractkit/chainlink/deployment/ccip/changeset" + "github.com/smartcontractkit/chainlink/deployment/ccip/changeset/testhelpers" + v1_5testhelpers "github.com/smartcontractkit/chainlink/deployment/ccip/changeset/testhelpers/v1_5" "github.com/smartcontractkit/chainlink/deployment/ccip/changeset/v1_5" commonchangeset "github.com/smartcontractkit/chainlink/deployment/common/changeset" testsetups "github.com/smartcontractkit/chainlink/integration-tests/testsetups/ccip" @@ -26,7 +28,7 @@ func TestMigrateFromV1_5ToV1_6(t *testing.T) { // Deploy 1.5 contracts (excluding pools to start, but including MCMS) . e, _, tEnv := testsetups.NewIntegrationEnvironment( t, - changeset.WithPrerequisiteDeployment( + testhelpers.WithPrerequisiteDeploymentOnly( &changeset.V1_5DeploymentConfig{ PriceRegStalenessThreshold: 60 * 60 * 24 * 14, // two weeks RMNConfig: &rmn_contract.RMNConfig{ @@ -43,11 +45,11 @@ func TestMigrateFromV1_5ToV1_6(t *testing.T) { }, }, }), - changeset.WithChains(3), - changeset.WithUsersPerChain(2), + testhelpers.WithNumOfChains(3), + testhelpers.WithNumOfUsersPerChain(2), // for in-memory test it is important to set the dest chain id as 1337 otherwise the config digest will not match // between nodes' calculated digest and the digest set on the contract - changeset.WithChainIds([]uint64{chainselectors.GETH_TESTNET.EvmChainID}), + testhelpers.WithChainIDs([]uint64{chainselectors.GETH_TESTNET.EvmChainID}), ) state, err := changeset.LoadOnchainState(e.Env) require.NoError(t, err) @@ -55,19 +57,19 @@ func TestMigrateFromV1_5ToV1_6(t *testing.T) { require.Contains(t, e.Env.AllChainSelectors(), chainselectors.GETH_TESTNET.Selector) require.Len(t, allChainsExcept1337, 2) src1, src2, dest := allChainsExcept1337[0], allChainsExcept1337[1], chainselectors.GETH_TESTNET.Selector - pairs := []changeset.SourceDestPair{ + pairs := []testhelpers.SourceDestPair{ // as mentioned in the comment above, the dest chain id should be 1337 {SourceChainSelector: src1, DestChainSelector: dest}, {SourceChainSelector: src2, DestChainSelector: dest}, } // wire up all lanes // deploy onRamp, commit store, offramp , set ocr2config and send corresponding jobs - e.Env = v1_5.AddLanes(t, e.Env, state, pairs) + e.Env = v1_5testhelpers.AddLanes(t, e.Env, state, pairs) // permabless the commit stores e.Env, err = commonchangeset.ApplyChangesets(t, e.Env, e.TimelockContracts(t), []commonchangeset.ChangesetApplication{ { - Changeset: commonchangeset.WrapChangeSet(v1_5.PermaBlessCommitStoreCS), + Changeset: commonchangeset.WrapChangeSet(v1_5.PermaBlessCommitStoreChangeset), Config: v1_5.PermaBlessCommitStoreConfig{ Configs: map[uint64]v1_5.PermaBlessCommitStoreConfigPerDest{ dest: { @@ -93,11 +95,11 @@ func TestMigrateFromV1_5ToV1_6(t *testing.T) { tEnv.UpdateDeployedEnvironment(e) // ensure that all lanes are functional for _, pair := range pairs { - sentEvent, err := v1_5.SendRequest(t, e.Env, state, - changeset.WithSourceChain(pair.SourceChainSelector), - changeset.WithDestChain(pair.DestChainSelector), - changeset.WithTestRouter(false), - changeset.WithEvm2AnyMessage(router.ClientEVM2AnyMessage{ + sentEvent, err := v1_5testhelpers.SendRequest(t, e.Env, state, + testhelpers.WithSourceChain(pair.SourceChainSelector), + testhelpers.WithDestChain(pair.DestChainSelector), + testhelpers.WithTestRouter(false), + testhelpers.WithEvm2AnyMessage(router.ClientEVM2AnyMessage{ Receiver: common.LeftPadBytes(state.Chains[pair.DestChainSelector].Receiver.Address().Bytes(), 32), Data: []byte("hello"), TokenAmounts: nil, @@ -110,8 +112,8 @@ func TestMigrateFromV1_5ToV1_6(t *testing.T) { destChain := e.Env.Chains[pair.DestChainSelector] destStartBlock, err := destChain.Client.HeaderByNumber(context.Background(), nil) require.NoError(t, err) - v1_5.WaitForCommit(t, e.Env.Chains[pair.SourceChainSelector], destChain, state.Chains[dest].CommitStore[src1], sentEvent.Message.SequenceNumber) - v1_5.WaitForExecute(t, e.Env.Chains[pair.SourceChainSelector], destChain, state.Chains[dest].EVM2EVMOffRamp[src1], []uint64{sentEvent.Message.SequenceNumber}, destStartBlock.Number.Uint64()) + v1_5testhelpers.WaitForCommit(t, e.Env.Chains[pair.SourceChainSelector], destChain, state.Chains[dest].CommitStore[src1], sentEvent.Message.SequenceNumber) + v1_5testhelpers.WaitForExecute(t, e.Env.Chains[pair.SourceChainSelector], destChain, state.Chains[dest].EVM2EVMOffRamp[src1], []uint64{sentEvent.Message.SequenceNumber}, destStartBlock.Number.Uint64()) } // now that all 1.5 lanes work transfer ownership of the contracts to MCMS @@ -149,13 +151,13 @@ func TestMigrateFromV1_5ToV1_6(t *testing.T) { // add 1.6 contracts to the environment and send 1.6 jobs // First we need to deploy Homechain contracts and restart the nodes with updated cap registry // in this test we have already deployed home chain contracts and the nodes are already running with the deployed cap registry. - e = changeset.AddCCIPContractsToEnvironment(t, e.Env.AllChainSelectors(), tEnv) + e = testhelpers.AddCCIPContractsToEnvironment(t, e.Env.AllChainSelectors(), tEnv) // Set RMNProxy to point to RMNRemote. // nonce manager should point to 1.5 ramps e.Env, err = commonchangeset.ApplyChangesets(t, e.Env, e.TimelockContracts(t), []commonchangeset.ChangesetApplication{ { // as we have already transferred ownership for RMNProxy to MCMS, it needs to be done via MCMS proposal - Changeset: commonchangeset.WrapChangeSet(changeset.SetRMNRemoteOnRMNProxy), + Changeset: commonchangeset.WrapChangeSet(changeset.SetRMNRemoteOnRMNProxyChangeset), Config: changeset.SetRMNRemoteOnRMNProxyConfig{ ChainSelectors: e.Env.AllChainSelectors(), MCMSConfig: &changeset.MCMSConfig{ @@ -164,7 +166,7 @@ func TestMigrateFromV1_5ToV1_6(t *testing.T) { }, }, { - Changeset: commonchangeset.WrapChangeSet(changeset.UpdateNonceManagersCS), + Changeset: commonchangeset.WrapChangeSet(changeset.UpdateNonceManagersChangeset), Config: changeset.UpdateNonceManagerConfig{ // we only have lanes between src1 --> dest UpdatesByChain: map[uint64]changeset.NonceManagerUpdate{ @@ -205,24 +207,24 @@ func TestMigrateFromV1_5ToV1_6(t *testing.T) { require.NoError(t, err) // Enable a single 1.6 lane with test router - changeset.AddLaneWithDefaultPricesAndFeeQuoterConfig(t, &e, state, src1, dest, true) + testhelpers.AddLaneWithDefaultPricesAndFeeQuoterConfig(t, &e, state, src1, dest, true) require.GreaterOrEqual(t, len(e.Users[src1]), 2) - changeset.ReplayLogs(t, e.Env.Offchain, e.ReplayBlocks) + testhelpers.ReplayLogs(t, e.Env.Offchain, e.ReplayBlocks) startBlocks := make(map[uint64]*uint64) latesthdr, err := e.Env.Chains[dest].Client.HeaderByNumber(testcontext.Get(t), nil) require.NoError(t, err) block := latesthdr.Number.Uint64() startBlocks[dest] = &block - expectedSeqNumExec := make(map[changeset.SourceDestPair][]uint64) - msgSentEvent, err := changeset.DoSendRequest( + expectedSeqNumExec := make(map[testhelpers.SourceDestPair][]uint64) + msgSentEvent, err := testhelpers.DoSendRequest( t, e.Env, state, - changeset.WithSourceChain(src1), - changeset.WithDestChain(dest), - changeset.WithTestRouter(true), + testhelpers.WithSourceChain(src1), + testhelpers.WithDestChain(dest), + testhelpers.WithTestRouter(true), // Send traffic across single 1.6 lane with a DIFFERENT ( very important to not mess with real sender nonce) sender // from test router to ensure 1.6 is working. - changeset.WithSender(e.Users[src1][1]), - changeset.WithEvm2AnyMessage(router.ClientEVM2AnyMessage{ + testhelpers.WithSender(e.Users[src1][1]), + testhelpers.WithEvm2AnyMessage(router.ClientEVM2AnyMessage{ Receiver: common.LeftPadBytes(state.Chains[dest].Receiver.Address().Bytes(), 32), Data: []byte("hello"), TokenAmounts: nil, @@ -231,21 +233,21 @@ func TestMigrateFromV1_5ToV1_6(t *testing.T) { })) require.NoError(t, err) - expectedSeqNumExec[changeset.SourceDestPair{ + expectedSeqNumExec[testhelpers.SourceDestPair{ SourceChainSelector: src1, DestChainSelector: dest, }] = []uint64{msgSentEvent.SequenceNumber} // Wait for all exec reports to land - changeset.ConfirmExecWithSeqNrsForAll(t, e.Env, state, expectedSeqNumExec, startBlocks) + testhelpers.ConfirmExecWithSeqNrsForAll(t, e.Env, state, expectedSeqNumExec, startBlocks) // send a message from real router, the send requested event should be received in 1.5 onRamp // the request should get delivered to 1.5 offRamp - sentEventBeforeSwitch, err := v1_5.SendRequest(t, e.Env, state, - changeset.WithSourceChain(src1), - changeset.WithDestChain(dest), - changeset.WithTestRouter(false), - changeset.WithEvm2AnyMessage(router.ClientEVM2AnyMessage{ + sentEventBeforeSwitch, err := v1_5testhelpers.SendRequest(t, e.Env, state, + testhelpers.WithSourceChain(src1), + testhelpers.WithDestChain(dest), + testhelpers.WithTestRouter(false), + testhelpers.WithEvm2AnyMessage(router.ClientEVM2AnyMessage{ Receiver: common.LeftPadBytes(state.Chains[dest].Receiver.Address().Bytes(), 32), Data: []byte("hello"), TokenAmounts: nil, @@ -259,7 +261,7 @@ func TestMigrateFromV1_5ToV1_6(t *testing.T) { // now that the 1.6 lane is working, we can enable the real router e.Env, err = commonchangeset.ApplyChangesets(t, e.Env, e.TimelockContracts(t), []commonchangeset.ChangesetApplication{ { - Changeset: commonchangeset.WrapChangeSet(changeset.UpdateOnRampsDests), + Changeset: commonchangeset.WrapChangeSet(changeset.UpdateOnRampsDestsChangeset), Config: changeset.UpdateOnRampDestsConfig{ UpdatesByChain: map[uint64]map[uint64]changeset.OnRampDestinationUpdate{ src1: { @@ -273,7 +275,7 @@ func TestMigrateFromV1_5ToV1_6(t *testing.T) { }, }, { - Changeset: commonchangeset.WrapChangeSet(changeset.UpdateOffRampSources), + Changeset: commonchangeset.WrapChangeSet(changeset.UpdateOffRampSourcesChangeset), Config: changeset.UpdateOffRampSourcesConfig{ UpdatesByChain: map[uint64]map[uint64]changeset.OffRampSourceUpdate{ dest: { @@ -287,7 +289,7 @@ func TestMigrateFromV1_5ToV1_6(t *testing.T) { }, { // this needs to be MCMS proposal as the router contract is owned by MCMS - Changeset: commonchangeset.WrapChangeSet(changeset.UpdateRouterRamps), + Changeset: commonchangeset.WrapChangeSet(changeset.UpdateRouterRampsChangeset), Config: changeset.UpdateRouterRampsConfig{ TestRouter: false, MCMS: &changeset.MCMSConfig{ @@ -316,12 +318,12 @@ func TestMigrateFromV1_5ToV1_6(t *testing.T) { // the request should get delivered to 1.6 offRamp destStartBlock, err := e.Env.Chains[dest].Client.HeaderByNumber(context.Background(), nil) require.NoError(t, err) - sentEventAfterSwitch, err := changeset.DoSendRequest( + sentEventAfterSwitch, err := testhelpers.DoSendRequest( t, e.Env, state, - changeset.WithSourceChain(src1), - changeset.WithDestChain(dest), - changeset.WithTestRouter(false), - changeset.WithEvm2AnyMessage(router.ClientEVM2AnyMessage{ + testhelpers.WithSourceChain(src1), + testhelpers.WithDestChain(dest), + testhelpers.WithTestRouter(false), + testhelpers.WithEvm2AnyMessage(router.ClientEVM2AnyMessage{ Receiver: common.LeftPadBytes(state.Chains[dest].Receiver.Address().Bytes(), 32), Data: []byte("hello"), TokenAmounts: nil, @@ -330,22 +332,22 @@ func TestMigrateFromV1_5ToV1_6(t *testing.T) { })) require.NoError(t, err) // verify that before switch message is received in 1.5 offRamp - v1_5.WaitForExecute(t, e.Env.Chains[src1], e.Env.Chains[dest], state.Chains[dest].EVM2EVMOffRamp[src1], + v1_5testhelpers.WaitForExecute(t, e.Env.Chains[src1], e.Env.Chains[dest], state.Chains[dest].EVM2EVMOffRamp[src1], []uint64{sentEventBeforeSwitch.Message.SequenceNumber}, destStartBlock.Number.Uint64()) // verify that after switch message is received in 1.6 offRamp - expectedSeqNumExec[changeset.SourceDestPair{ + expectedSeqNumExec[testhelpers.SourceDestPair{ SourceChainSelector: src1, DestChainSelector: dest, }] = []uint64{sentEventAfterSwitch.SequenceNumber} - changeset.ConfirmExecWithSeqNrsForAll(t, e.Env, state, expectedSeqNumExec, startBlocks) + testhelpers.ConfirmExecWithSeqNrsForAll(t, e.Env, state, expectedSeqNumExec, startBlocks) // confirm that the other lane src2->dest is still working with v1.5 - sentEventOnOtherLane, err := v1_5.SendRequest(t, e.Env, state, - changeset.WithSourceChain(src2), - changeset.WithDestChain(dest), - changeset.WithTestRouter(false), - changeset.WithEvm2AnyMessage(router.ClientEVM2AnyMessage{ + sentEventOnOtherLane, err := v1_5testhelpers.SendRequest(t, e.Env, state, + testhelpers.WithSourceChain(src2), + testhelpers.WithDestChain(dest), + testhelpers.WithTestRouter(false), + testhelpers.WithEvm2AnyMessage(router.ClientEVM2AnyMessage{ Receiver: common.LeftPadBytes(state.Chains[dest].Receiver.Address().Bytes(), 32), Data: []byte("hello"), TokenAmounts: nil, @@ -355,6 +357,6 @@ func TestMigrateFromV1_5ToV1_6(t *testing.T) { ) require.NoError(t, err) require.NotNil(t, sentEventOnOtherLane) - v1_5.WaitForExecute(t, e.Env.Chains[src2], e.Env.Chains[dest], state.Chains[dest].EVM2EVMOffRamp[src2], + v1_5testhelpers.WaitForExecute(t, e.Env.Chains[src2], e.Env.Chains[dest], state.Chains[dest].EVM2EVMOffRamp[src2], []uint64{sentEventOnOtherLane.Message.SequenceNumber}, destStartBlock.Number.Uint64()) } diff --git a/integration-tests/smoke/ccip/ccip_ooo_execution_test.go b/integration-tests/smoke/ccip/ccip_ooo_execution_test.go index 272c87e9996..004dd3989f8 100644 --- a/integration-tests/smoke/ccip/ccip_ooo_execution_test.go +++ b/integration-tests/smoke/ccip/ccip_ooo_execution_test.go @@ -15,6 +15,7 @@ import ( "github.com/smartcontractkit/chainlink/deployment" "github.com/smartcontractkit/chainlink/deployment/ccip/changeset" + "github.com/smartcontractkit/chainlink/deployment/ccip/changeset/testhelpers" testsetups "github.com/smartcontractkit/chainlink/integration-tests/testsetups/ccip" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/router" @@ -35,9 +36,9 @@ func Test_OutOfOrderExecution(t *testing.T) { ctx := tests.Context(t) tenv, _, _ := testsetups.NewIntegrationEnvironment( t, - changeset.WithUSDC(), - changeset.WithUSDCAttestationMissing(), - changeset.WithUsersPerChain(2), + testhelpers.WithUSDC(), + testhelpers.WithUSDCAttestationMissing(), + testhelpers.WithNumOfUsersPerChain(2), ) e := tenv.Env @@ -54,7 +55,7 @@ func Test_OutOfOrderExecution(t *testing.T) { oneE18 := new(big.Int).SetUint64(1e18) - srcToken, _, destToken, _, err := changeset.DeployTransferableToken( + srcToken, _, destToken, _, err := testhelpers.DeployTransferableToken( lggr, tenv.Env.Chains, sourceChain, @@ -67,26 +68,26 @@ func Test_OutOfOrderExecution(t *testing.T) { ) require.NoError(t, err) - srcUSDC, destUSDC, err := changeset.ConfigureUSDCTokenPools(lggr, e.Chains, sourceChain, destChain, state) + srcUSDC, destUSDC, err := testhelpers.ConfigureUSDCTokenPools(lggr, e.Chains, sourceChain, destChain, state) require.NoError(t, err) - err = changeset.UpdateFeeQuoterForUSDC(lggr, e.Chains[sourceChain], state.Chains[sourceChain], destChain, srcUSDC) + err = testhelpers.UpdateFeeQuoterForUSDC(lggr, e.Chains[sourceChain], state.Chains[sourceChain], destChain, srcUSDC) require.NoError(t, err) - err = changeset.UpdateFeeQuoterForUSDC(lggr, e.Chains[destChain], state.Chains[destChain], sourceChain, destUSDC) + err = testhelpers.UpdateFeeQuoterForUSDC(lggr, e.Chains[destChain], state.Chains[destChain], sourceChain, destUSDC) require.NoError(t, err) - changeset.MintAndAllow( + testhelpers.MintAndAllow( t, e, state, - map[uint64][]changeset.MintTokenInfo{ + map[uint64][]testhelpers.MintTokenInfo{ sourceChain: { - changeset.NewMintTokenInfo(ownerSourceChain, srcToken, srcUSDC), - changeset.NewMintTokenWithCustomSender(ownerSourceChain, anotherSender, srcToken), + testhelpers.NewMintTokenInfo(ownerSourceChain, srcToken, srcUSDC), + testhelpers.NewMintTokenWithCustomSender(ownerSourceChain, anotherSender, srcToken), }, }, ) - changeset.AddLanesForAll(t, &tenv, state) + testhelpers.AddLanesForAll(t, &tenv, state) tokenTransfer := []router.ClientEVMTokenAmount{ { @@ -101,7 +102,7 @@ func Test_OutOfOrderExecution(t *testing.T) { }, } - identifier := changeset.SourceDestPair{ + identifier := testhelpers.SourceDestPair{ SourceChainSelector: sourceChain, DestChainSelector: destChain, } @@ -116,7 +117,7 @@ func Test_OutOfOrderExecution(t *testing.T) { // Out of order execution to the EOA should be properly executed firstReceiver := utils.RandomAddress() - firstMessage, _ := changeset.Transfer( + firstMessage, _ := testhelpers.Transfer( ctx, t, e, @@ -126,16 +127,16 @@ func Test_OutOfOrderExecution(t *testing.T) { tokenTransfer, firstReceiver, nil, - changeset.MakeEVMExtraArgsV2(0, true), + testhelpers.MakeEVMExtraArgsV2(0, true), ) - expectedStatuses[firstMessage.SequenceNumber] = changeset.EXECUTION_STATE_SUCCESS + expectedStatuses[firstMessage.SequenceNumber] = testhelpers.EXECUTION_STATE_SUCCESS t.Logf("Out of order messages sent from chain %d to chain %d with sequence number %d", sourceChain, destChain, firstMessage.SequenceNumber, ) // Ordered execution should fail because attestation is not present secondReceiver := utils.RandomAddress() - secondMsg, _ := changeset.Transfer( + secondMsg, _ := testhelpers.Transfer( ctx, t, e, @@ -153,7 +154,7 @@ func Test_OutOfOrderExecution(t *testing.T) { // Ordered token transfer should fail, because previous message cannot be executed thirdReceiver := utils.RandomAddress() - thirdMessage, _ := changeset.Transfer( + thirdMessage, _ := testhelpers.Transfer( ctx, t, e, @@ -163,7 +164,7 @@ func Test_OutOfOrderExecution(t *testing.T) { tokenTransfer, thirdReceiver, nil, - changeset.MakeEVMExtraArgsV2(0, false), + testhelpers.MakeEVMExtraArgsV2(0, false), ) t.Logf("Ordered token transfer from chain %d to chain %d with sequence number %d", sourceChain, destChain, thirdMessage.SequenceNumber, @@ -171,7 +172,7 @@ func Test_OutOfOrderExecution(t *testing.T) { // Out of order programmable token transfer should be executed fourthReceiver := state.Chains[destChain].Receiver.Address() - fourthMessage, _ := changeset.Transfer( + fourthMessage, _ := testhelpers.Transfer( ctx, t, e, @@ -181,34 +182,34 @@ func Test_OutOfOrderExecution(t *testing.T) { tokenTransfer, fourthReceiver, []byte("this message has enough gas to execute"), - changeset.MakeEVMExtraArgsV2(300_000, true), + testhelpers.MakeEVMExtraArgsV2(300_000, true), ) - expectedStatuses[fourthMessage.SequenceNumber] = changeset.EXECUTION_STATE_SUCCESS + expectedStatuses[fourthMessage.SequenceNumber] = testhelpers.EXECUTION_STATE_SUCCESS t.Logf("Out of order programmable token transfer from chain %d to chain %d with sequence number %d", sourceChain, destChain, fourthMessage.SequenceNumber, ) // Ordered token transfer, but using different sender, should be executed fifthReceiver := utils.RandomAddress() - fifthMessage, err := changeset.DoSendRequest(t, e, state, - changeset.WithSender(anotherSender), - changeset.WithSourceChain(sourceChain), - changeset.WithDestChain(destChain), - changeset.WithEvm2AnyMessage(router.ClientEVM2AnyMessage{ + fifthMessage, err := testhelpers.DoSendRequest(t, e, state, + testhelpers.WithSender(anotherSender), + testhelpers.WithSourceChain(sourceChain), + testhelpers.WithDestChain(destChain), + testhelpers.WithEvm2AnyMessage(router.ClientEVM2AnyMessage{ Receiver: common.LeftPadBytes(fifthReceiver.Bytes(), 32), Data: nil, TokenAmounts: tokenTransfer, FeeToken: common.HexToAddress("0x0"), - ExtraArgs: changeset.MakeEVMExtraArgsV2(0, false), + ExtraArgs: testhelpers.MakeEVMExtraArgsV2(0, false), })) require.NoError(t, err) - expectedStatuses[fifthMessage.SequenceNumber] = changeset.EXECUTION_STATE_SUCCESS + expectedStatuses[fifthMessage.SequenceNumber] = testhelpers.EXECUTION_STATE_SUCCESS t.Logf("Ordered message send by %v from chain %d to chain %d with sequence number %d", anotherSender.From, sourceChain, destChain, fifthMessage.SequenceNumber, ) // All messages are committed, even these which are going to be reverted during the exec - _, err = changeset.ConfirmCommitWithExpectedSeqNumRange( + _, err = testhelpers.ConfirmCommitWithExpectedSeqNumRange( t, e.Chains[sourceChain], e.Chains[destChain], @@ -223,11 +224,11 @@ func Test_OutOfOrderExecution(t *testing.T) { ) require.NoError(t, err) - execStates := changeset.ConfirmExecWithSeqNrsForAll( + execStates := testhelpers.ConfirmExecWithSeqNrsForAll( t, e, state, - map[changeset.SourceDestPair][]uint64{ + map[testhelpers.SourceDestPair][]uint64{ identifier: { firstMessage.SequenceNumber, fourthMessage.SequenceNumber, @@ -240,21 +241,21 @@ func Test_OutOfOrderExecution(t *testing.T) { secondMsgState, err := state.Chains[destChain].OffRamp.GetExecutionState(&bind.CallOpts{Context: ctx}, sourceChain, secondMsg.SequenceNumber) require.NoError(t, err) - require.Equal(t, uint8(changeset.EXECUTION_STATE_UNTOUCHED), secondMsgState) + require.Equal(t, uint8(testhelpers.EXECUTION_STATE_UNTOUCHED), secondMsgState) thirdMsgState, err := state.Chains[destChain].OffRamp.GetExecutionState(&bind.CallOpts{Context: ctx}, sourceChain, thirdMessage.SequenceNumber) require.NoError(t, err) - require.Equal(t, uint8(changeset.EXECUTION_STATE_UNTOUCHED), thirdMsgState) + require.Equal(t, uint8(testhelpers.EXECUTION_STATE_UNTOUCHED), thirdMsgState) - changeset.WaitForTheTokenBalance(ctx, t, destToken.Address(), firstReceiver, e.Chains[destChain], oneE18) - changeset.WaitForTheTokenBalance(ctx, t, destUSDC.Address(), secondReceiver, e.Chains[destChain], big.NewInt(0)) - changeset.WaitForTheTokenBalance(ctx, t, destToken.Address(), thirdReceiver, e.Chains[destChain], big.NewInt(0)) - changeset.WaitForTheTokenBalance(ctx, t, destToken.Address(), fourthReceiver, e.Chains[destChain], oneE18) - changeset.WaitForTheTokenBalance(ctx, t, destToken.Address(), fifthReceiver, e.Chains[destChain], oneE18) + testhelpers.WaitForTheTokenBalance(ctx, t, destToken.Address(), firstReceiver, e.Chains[destChain], oneE18) + testhelpers.WaitForTheTokenBalance(ctx, t, destUSDC.Address(), secondReceiver, e.Chains[destChain], big.NewInt(0)) + testhelpers.WaitForTheTokenBalance(ctx, t, destToken.Address(), thirdReceiver, e.Chains[destChain], big.NewInt(0)) + testhelpers.WaitForTheTokenBalance(ctx, t, destToken.Address(), fourthReceiver, e.Chains[destChain], oneE18) + testhelpers.WaitForTheTokenBalance(ctx, t, destToken.Address(), fifthReceiver, e.Chains[destChain], oneE18) } func pickFirstAvailableUser( - tenv changeset.DeployedEnv, + tenv testhelpers.DeployedEnv, sourceChain uint64, e deployment.Environment, ) (*bind.TransactOpts, error) { diff --git a/integration-tests/contracts/ccipreader_test.go b/integration-tests/smoke/ccip/ccip_reader_test.go similarity index 96% rename from integration-tests/contracts/ccipreader_test.go rename to integration-tests/smoke/ccip/ccip_reader_test.go index b7ea027a568..f907c06f58f 100644 --- a/integration-tests/contracts/ccipreader_test.go +++ b/integration-tests/smoke/ccip/ccip_reader_test.go @@ -1,4 +1,4 @@ -package contracts +package smoke import ( "context" @@ -18,6 +18,7 @@ import ( "github.com/stretchr/testify/require" "go.uber.org/zap/zapcore" + "github.com/smartcontractkit/chainlink/deployment/ccip/changeset/testhelpers" "github.com/smartcontractkit/chainlink/v2/core/utils/testutils/heavyweight" "github.com/smartcontractkit/chainlink-ccip/plugintypes" @@ -590,15 +591,15 @@ func TestCCIPReader_GetExpectedNextSequenceNumber(t *testing.T) { t.Parallel() ctx := tests.Context(t) //env := NewMemoryEnvironmentContractsOnly(t, logger.TestLogger(t), 2, 4, nil) - env, _ := changeset.NewMemoryEnvironment(t) + env, _ := testhelpers.NewMemoryEnvironment(t) state, err := changeset.LoadOnchainState(env.Env) require.NoError(t, err) selectors := env.Env.AllChainSelectors() destChain, srcChain := selectors[0], selectors[1] - changeset.AddLaneWithDefaultPricesAndFeeQuoterConfig(t, &env, state, destChain, srcChain, false) - changeset.AddLaneWithDefaultPricesAndFeeQuoterConfig(t, &env, state, srcChain, destChain, false) + testhelpers.AddLaneWithDefaultPricesAndFeeQuoterConfig(t, &env, state, destChain, srcChain, false) + testhelpers.AddLaneWithDefaultPricesAndFeeQuoterConfig(t, &env, state, srcChain, destChain, false) reader := testSetupRealContracts( ctx, @@ -619,8 +620,8 @@ func TestCCIPReader_GetExpectedNextSequenceNumber(t *testing.T) { maxExpectedSeqNum := uint64(10) var i uint64 for i = 1; i < maxExpectedSeqNum; i++ { - msg := changeset.DefaultRouterMessage(state.Chains[destChain].Receiver.Address()) - msgSentEvent := changeset.TestSendRequest(t, env.Env, state, srcChain, destChain, false, msg) + msg := testhelpers.DefaultRouterMessage(state.Chains[destChain].Receiver.Address()) + msgSentEvent := testhelpers.TestSendRequest(t, env.Env, state, srcChain, destChain, false, msg) require.Equal(t, uint64(i), msgSentEvent.SequenceNumber) require.Equal(t, uint64(i), msgSentEvent.Message.Header.Nonce) // check outbound nonce incremented seqNum, err2 := reader.GetExpectedNextSequenceNumber(ctx, cs(srcChain), cs(destChain)) @@ -700,15 +701,15 @@ func TestCCIPReader_Nonces(t *testing.T) { func Test_GetChainFeePriceUpdates(t *testing.T) { t.Parallel() ctx := tests.Context(t) - env, _ := changeset.NewMemoryEnvironment(t) + env, _ := testhelpers.NewMemoryEnvironment(t) state, err := changeset.LoadOnchainState(env.Env) require.NoError(t, err) selectors := env.Env.AllChainSelectors() chain1, chain2 := selectors[0], selectors[1] - changeset.AddLaneWithDefaultPricesAndFeeQuoterConfig(t, &env, state, chain1, chain2, false) - changeset.AddLaneWithDefaultPricesAndFeeQuoterConfig(t, &env, state, chain2, chain1, false) + testhelpers.AddLaneWithDefaultPricesAndFeeQuoterConfig(t, &env, state, chain1, chain2, false) + testhelpers.AddLaneWithDefaultPricesAndFeeQuoterConfig(t, &env, state, chain2, chain1, false) // Change the gas price for chain2 feeQuoter := state.Chains[chain1].FeeQuoter @@ -756,15 +757,15 @@ func Test_GetChainFeePriceUpdates(t *testing.T) { func Test_LinkPriceUSD(t *testing.T) { t.Parallel() ctx := tests.Context(t) - env, _ := changeset.NewMemoryEnvironment(t) + env, _ := testhelpers.NewMemoryEnvironment(t) state, err := changeset.LoadOnchainState(env.Env) require.NoError(t, err) selectors := env.Env.AllChainSelectors() chain1, chain2 := selectors[0], selectors[1] - changeset.AddLaneWithDefaultPricesAndFeeQuoterConfig(t, &env, state, chain1, chain2, false) - changeset.AddLaneWithDefaultPricesAndFeeQuoterConfig(t, &env, state, chain2, chain1, false) + testhelpers.AddLaneWithDefaultPricesAndFeeQuoterConfig(t, &env, state, chain1, chain2, false) + testhelpers.AddLaneWithDefaultPricesAndFeeQuoterConfig(t, &env, state, chain2, chain1, false) reader := testSetupRealContracts( ctx, @@ -785,22 +786,22 @@ func Test_LinkPriceUSD(t *testing.T) { linkPriceUSD, err := reader.LinkPriceUSD(ctx) require.NoError(t, err) require.NotNil(t, linkPriceUSD.Int) - require.Equal(t, changeset.DefaultLinkPrice, linkPriceUSD.Int) + require.Equal(t, testhelpers.DefaultLinkPrice, linkPriceUSD.Int) } func Test_GetMedianDataAvailabilityGasConfig(t *testing.T) { t.Parallel() ctx := tests.Context(t) - env, _ := changeset.NewMemoryEnvironment(t, changeset.WithChains(4)) + env, _ := testhelpers.NewMemoryEnvironment(t, testhelpers.WithNumOfChains(4)) state, err := changeset.LoadOnchainState(env.Env) require.NoError(t, err) selectors := env.Env.AllChainSelectors() destChain, chain1, chain2, chain3 := selectors[0], selectors[1], selectors[2], selectors[3] - changeset.AddLaneWithDefaultPricesAndFeeQuoterConfig(t, &env, state, chain1, destChain, false) - changeset.AddLaneWithDefaultPricesAndFeeQuoterConfig(t, &env, state, chain2, destChain, false) - changeset.AddLaneWithDefaultPricesAndFeeQuoterConfig(t, &env, state, chain3, destChain, false) + testhelpers.AddLaneWithDefaultPricesAndFeeQuoterConfig(t, &env, state, chain1, destChain, false) + testhelpers.AddLaneWithDefaultPricesAndFeeQuoterConfig(t, &env, state, chain2, destChain, false) + testhelpers.AddLaneWithDefaultPricesAndFeeQuoterConfig(t, &env, state, chain3, destChain, false) boundContracts := map[cciptypes.ChainSelector][]types.BoundContract{} for i, selector := range env.Env.AllChainSelectorsExcluding([]uint64{destChain}) { @@ -850,15 +851,15 @@ func Test_GetMedianDataAvailabilityGasConfig(t *testing.T) { func Test_GetWrappedNativeTokenPriceUSD(t *testing.T) { t.Parallel() ctx := tests.Context(t) - env, _ := changeset.NewMemoryEnvironment(t) + env, _ := testhelpers.NewMemoryEnvironment(t) state, err := changeset.LoadOnchainState(env.Env) require.NoError(t, err) selectors := env.Env.AllChainSelectors() chain1, chain2 := selectors[0], selectors[1] - changeset.AddLaneWithDefaultPricesAndFeeQuoterConfig(t, &env, state, chain1, chain2, false) - changeset.AddLaneWithDefaultPricesAndFeeQuoterConfig(t, &env, state, chain2, chain1, false) + testhelpers.AddLaneWithDefaultPricesAndFeeQuoterConfig(t, &env, state, chain1, chain2, false) + testhelpers.AddLaneWithDefaultPricesAndFeeQuoterConfig(t, &env, state, chain2, chain1, false) reader := testSetupRealContracts( ctx, @@ -884,7 +885,7 @@ func Test_GetWrappedNativeTokenPriceUSD(t *testing.T) { // Only chainD has reader contracts bound require.Len(t, prices, 1) - require.Equal(t, changeset.DefaultWethPrice, prices[cciptypes.ChainSelector(chain1)].Int) + require.Equal(t, testhelpers.DefaultWethPrice, prices[cciptypes.ChainSelector(chain1)].Int) } // Benchmark Results: @@ -1341,7 +1342,7 @@ func testSetupRealContracts( destChain uint64, toBindContracts map[cciptypes.ChainSelector][]types.BoundContract, toMockBindings map[cciptypes.ChainSelector][]types.BoundContract, - env changeset.DeployedEnv, + env testhelpers.DeployedEnv, ) ccipreaderpkg.CCIPReader { db := pgtest.NewSqlxDB(t) lpOpts := logpoller.Opts{ diff --git a/integration-tests/smoke/ccip/ccip_rmn_test.go b/integration-tests/smoke/ccip/ccip_rmn_test.go index fcf17956dc0..d8f5aae0882 100644 --- a/integration-tests/smoke/ccip/ccip_rmn_test.go +++ b/integration-tests/smoke/ccip/ccip_rmn_test.go @@ -23,6 +23,7 @@ import ( "github.com/smartcontractkit/chainlink-testing-framework/lib/utils/testcontext" "github.com/smartcontractkit/chainlink/deployment/ccip/changeset" + "github.com/smartcontractkit/chainlink/deployment/ccip/changeset/testhelpers" "github.com/smartcontractkit/chainlink/deployment/environment/devenv" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/rmn_home" @@ -245,7 +246,7 @@ func runRmnTestCase(t *testing.T, tc rmnTestCase) { t.Logf("Running RMN test case: %s", tc.name) envWithRMN, rmnCluster, _ := testsetups.NewIntegrationEnvironment(t, - changeset.WithRMNEnabled(len(tc.rmnNodes)), + testhelpers.WithRMNEnabled(len(tc.rmnNodes)), ) t.Logf("envWithRmn: %#v", envWithRMN) @@ -286,7 +287,7 @@ func runRmnTestCase(t *testing.T, tc rmnTestCase) { t.Logf("RMNHome candidateDigest after setting new candidate: %x", candidateDigest[:]) t.Logf("Promoting RMNHome candidate with candidateDigest: %x", candidateDigest[:]) - _, err = changeset.PromoteCandidateConfigChangeset(envWithRMN.Env, changeset.PromoteRMNHomeCandidateConfig{ + _, err = changeset.PromoteRMNHomeCandidateConfigChangeset(envWithRMN.Env, changeset.PromoteRMNHomeCandidateConfig{ HomeChainSelector: envWithRMN.HomeChainSel, DigestToPromote: candidateDigest, }) @@ -319,8 +320,8 @@ func runRmnTestCase(t *testing.T, tc rmnTestCase) { tc.killMarkedRmnNodes(t, rmnCluster) - changeset.ReplayLogs(t, envWithRMN.Env.Offchain, envWithRMN.ReplayBlocks) - changeset.AddLanesForAll(t, &envWithRMN, onChainState) + testhelpers.ReplayLogs(t, envWithRMN.Env.Offchain, envWithRMN.ReplayBlocks) + testhelpers.AddLanesForAll(t, &envWithRMN, onChainState) disabledNodes := tc.disableOraclesIfThisIsACursingTestCase(ctx, t, envWithRMN) startBlocks, seqNumCommit, seqNumExec := tc.sendMessages(t, onChainState, envWithRMN) @@ -332,7 +333,7 @@ func runRmnTestCase(t *testing.T, tc rmnTestCase) { tc.enableOracles(ctx, t, envWithRMN, disabledNodes) - expectedSeqNum := make(map[changeset.SourceDestPair]uint64) + expectedSeqNum := make(map[testhelpers.SourceDestPair]uint64) for k, v := range seqNumCommit { cursedSubjectsOfDest, exists := tc.pf.cursedSubjectsPerChainSel[k.DestChainSelector] shouldSkip := exists && (slices.Contains(cursedSubjectsOfDest, globalCurse) || @@ -354,13 +355,13 @@ func runRmnTestCase(t *testing.T, tc rmnTestCase) { commitReportReceived := make(chan struct{}) go func() { if len(expectedSeqNum) > 0 { - changeset.ConfirmCommitForAllWithExpectedSeqNums(t, envWithRMN.Env, onChainState, expectedSeqNum, startBlocks) + testhelpers.ConfirmCommitForAllWithExpectedSeqNums(t, envWithRMN.Env, onChainState, expectedSeqNum, startBlocks) commitReportReceived <- struct{}{} } if len(seqNumCommit) > 0 && len(seqNumCommit) > len(expectedSeqNum) { // wait for a duration and assert that commit reports were not delivered for cursed source chains - changeset.ConfirmCommitForAllWithExpectedSeqNums(t, envWithRMN.Env, onChainState, seqNumCommit, startBlocks) + testhelpers.ConfirmCommitForAllWithExpectedSeqNums(t, envWithRMN.Env, onChainState, seqNumCommit, startBlocks) commitReportReceived <- struct{}{} } }() @@ -392,7 +393,7 @@ func runRmnTestCase(t *testing.T, tc rmnTestCase) { if tc.waitForExec { t.Logf("⌛ Waiting for exec reports...") - changeset.ConfirmExecWithSeqNrsForAll(t, envWithRMN.Env, onChainState, seqNumExec, startBlocks) + testhelpers.ConfirmExecWithSeqNrsForAll(t, envWithRMN.Env, onChainState, seqNumExec, startBlocks) t.Logf("✅ Exec report") } } @@ -464,7 +465,7 @@ type testCasePopulatedFields struct { revokedCursedSubjectsPerChainSel map[uint64]map[uint64]time.Duration } -func (tc *rmnTestCase) populateFields(t *testing.T, envWithRMN changeset.DeployedEnv, rmnCluster devenv.RMNCluster) { +func (tc *rmnTestCase) populateFields(t *testing.T, envWithRMN testhelpers.DeployedEnv, rmnCluster devenv.RMNCluster) { require.GreaterOrEqual(t, len(envWithRMN.Env.Chains), 2, "test assumes at least two chains") for _, chain := range envWithRMN.Env.Chains { tc.pf.chainSelectors = append(tc.pf.chainSelectors, chain.Selector) @@ -553,7 +554,7 @@ func (tc rmnTestCase) killMarkedRmnNodes(t *testing.T, rmnCluster devenv.RMNClus } } -func (tc rmnTestCase) disableOraclesIfThisIsACursingTestCase(ctx context.Context, t *testing.T, envWithRMN changeset.DeployedEnv) []string { +func (tc rmnTestCase) disableOraclesIfThisIsACursingTestCase(ctx context.Context, t *testing.T, envWithRMN testhelpers.DeployedEnv) []string { disabledNodes := make([]string, 0) if len(tc.cursedSubjectsPerChain) > 0 { @@ -574,28 +575,28 @@ func (tc rmnTestCase) disableOraclesIfThisIsACursingTestCase(ctx context.Context return disabledNodes } -func (tc rmnTestCase) sendMessages(t *testing.T, onChainState changeset.CCIPOnChainState, envWithRMN changeset.DeployedEnv) (map[uint64]*uint64, map[changeset.SourceDestPair]uint64, map[changeset.SourceDestPair][]uint64) { +func (tc rmnTestCase) sendMessages(t *testing.T, onChainState changeset.CCIPOnChainState, envWithRMN testhelpers.DeployedEnv) (map[uint64]*uint64, map[testhelpers.SourceDestPair]uint64, map[testhelpers.SourceDestPair][]uint64) { startBlocks := make(map[uint64]*uint64) - seqNumCommit := make(map[changeset.SourceDestPair]uint64) - seqNumExec := make(map[changeset.SourceDestPair][]uint64) + seqNumCommit := make(map[testhelpers.SourceDestPair]uint64) + seqNumExec := make(map[testhelpers.SourceDestPair][]uint64) for _, msg := range tc.messagesToSend { fromChain := tc.pf.chainSelectors[msg.fromChainIdx] toChain := tc.pf.chainSelectors[msg.toChainIdx] for i := 0; i < msg.count; i++ { - msgSentEvent := changeset.TestSendRequest(t, envWithRMN.Env, onChainState, fromChain, toChain, false, router.ClientEVM2AnyMessage{ + msgSentEvent := testhelpers.TestSendRequest(t, envWithRMN.Env, onChainState, fromChain, toChain, false, router.ClientEVM2AnyMessage{ Receiver: common.LeftPadBytes(onChainState.Chains[toChain].Receiver.Address().Bytes(), 32), Data: []byte("hello world"), TokenAmounts: nil, FeeToken: common.HexToAddress("0x0"), ExtraArgs: nil, }) - seqNumCommit[changeset.SourceDestPair{ + seqNumCommit[testhelpers.SourceDestPair{ SourceChainSelector: fromChain, DestChainSelector: toChain, }] = msgSentEvent.SequenceNumber - seqNumExec[changeset.SourceDestPair{ + seqNumExec[testhelpers.SourceDestPair{ SourceChainSelector: fromChain, DestChainSelector: toChain, }] = []uint64{msgSentEvent.SequenceNumber} @@ -609,7 +610,7 @@ func (tc rmnTestCase) sendMessages(t *testing.T, onChainState changeset.CCIPOnCh return startBlocks, seqNumCommit, seqNumExec } -func (tc rmnTestCase) callContractsToCurseChains(ctx context.Context, t *testing.T, onChainState changeset.CCIPOnChainState, envWithRMN changeset.DeployedEnv) { +func (tc rmnTestCase) callContractsToCurseChains(ctx context.Context, t *testing.T, onChainState changeset.CCIPOnChainState, envWithRMN testhelpers.DeployedEnv) { for _, remoteCfg := range tc.remoteChainsConfig { remoteSel := tc.pf.chainSelectors[remoteCfg.chainIdx] chState, ok := onChainState.Chains[remoteSel] @@ -644,7 +645,7 @@ func (tc rmnTestCase) callContractsToCurseChains(ctx context.Context, t *testing } } -func (tc rmnTestCase) callContractsToCurseAndRevokeCurse(ctx context.Context, eg *errgroup.Group, t *testing.T, onChainState changeset.CCIPOnChainState, envWithRMN changeset.DeployedEnv) { +func (tc rmnTestCase) callContractsToCurseAndRevokeCurse(ctx context.Context, eg *errgroup.Group, t *testing.T, onChainState changeset.CCIPOnChainState, envWithRMN testhelpers.DeployedEnv) { for _, remoteCfg := range tc.remoteChainsConfig { remoteSel := tc.pf.chainSelectors[remoteCfg.chainIdx] chState, ok := onChainState.Chains[remoteSel] @@ -700,7 +701,7 @@ func (tc rmnTestCase) callContractsToCurseAndRevokeCurse(ctx context.Context, eg } } -func (tc rmnTestCase) enableOracles(ctx context.Context, t *testing.T, envWithRMN changeset.DeployedEnv, nodeIDs []string) { +func (tc rmnTestCase) enableOracles(ctx context.Context, t *testing.T, envWithRMN testhelpers.DeployedEnv, nodeIDs []string) { for _, n := range nodeIDs { _, err := envWithRMN.Env.Offchain.EnableNode(ctx, &node.EnableNodeRequest{Id: n}) require.NoError(t, err) diff --git a/integration-tests/smoke/ccip/ccip_token_price_updates_test.go b/integration-tests/smoke/ccip/ccip_token_price_updates_test.go index e54790de24c..4c15eecc545 100644 --- a/integration-tests/smoke/ccip/ccip_token_price_updates_test.go +++ b/integration-tests/smoke/ccip/ccip_token_price_updates_test.go @@ -19,23 +19,23 @@ import ( "github.com/smartcontractkit/chainlink/deployment" "github.com/smartcontractkit/chainlink/deployment/ccip/changeset" + "github.com/smartcontractkit/chainlink/deployment/ccip/changeset/testhelpers" testsetups "github.com/smartcontractkit/chainlink/integration-tests/testsetups/ccip" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/fee_quoter" ) func Test_CCIPTokenPriceUpdates(t *testing.T) { - ctx := changeset.Context(t) + ctx := testhelpers.Context(t) callOpts := &bind.CallOpts{Context: ctx} var tokenPriceExpiry = 5 * time.Second e, _, _ := testsetups.NewIntegrationEnvironment(t, - changeset.WithOCRConfigOverride(func(params changeset.CCIPOCRParams) changeset.CCIPOCRParams { + testhelpers.WithOCRConfigOverride(func(params *changeset.CCIPOCRParams) { params.CommitOffChainConfig.TokenPriceBatchWriteFrequency = *config.MustNewDuration(tokenPriceExpiry) - return params })) state, err := changeset.LoadOnchainState(e.Env) require.NoError(t, err) - changeset.AddLanesForAll(t, &e, state) + testhelpers.AddLanesForAll(t, &e, state) allChainSelectors := maps.Keys(e.Env.Chains) assert.GreaterOrEqual(t, len(allChainSelectors), 2, "test requires at least 2 chains") diff --git a/integration-tests/smoke/ccip/ccip_token_transfer_test.go b/integration-tests/smoke/ccip/ccip_token_transfer_test.go index 7946d6f8c7c..ef9a4bea8b8 100644 --- a/integration-tests/smoke/ccip/ccip_token_transfer_test.go +++ b/integration-tests/smoke/ccip/ccip_token_transfer_test.go @@ -12,6 +12,7 @@ import ( "github.com/smartcontractkit/chainlink-common/pkg/utils/tests" "github.com/smartcontractkit/chainlink/deployment/ccip/changeset" + "github.com/smartcontractkit/chainlink/deployment/ccip/changeset/testhelpers" testsetups "github.com/smartcontractkit/chainlink/integration-tests/testsetups/ccip" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/router" @@ -23,7 +24,7 @@ func TestTokenTransfer(t *testing.T) { ctx := tests.Context(t) tenv, _, _ := testsetups.NewIntegrationEnvironment(t, - changeset.WithUsersPerChain(3)) + testhelpers.WithNumOfUsersPerChain(3)) e := tenv.Env state, err := changeset.LoadOnchainState(e) @@ -43,7 +44,7 @@ func TestTokenTransfer(t *testing.T) { oneE18 := new(big.Int).SetUint64(1e18) // Deploy tokens and pool by CCIP Owner - srcToken, _, destToken, _, err := changeset.DeployTransferableToken( + srcToken, _, destToken, _, err := testhelpers.DeployTransferableToken( lggr, tenv.Env.Chains, sourceChain, @@ -57,7 +58,7 @@ func TestTokenTransfer(t *testing.T) { require.NoError(t, err) // Deploy Self Serve tokens and pool - selfServeSrcToken, _, selfServeDestToken, _, err := changeset.DeployTransferableToken( + selfServeSrcToken, _, selfServeDestToken, _, err := testhelpers.DeployTransferableToken( lggr, tenv.Env.Chains, sourceChain, @@ -69,25 +70,25 @@ func TestTokenTransfer(t *testing.T) { "SELF_SERVE_TOKEN", ) require.NoError(t, err) - changeset.AddLanesForAll(t, &tenv, state) + testhelpers.AddLanesForAll(t, &tenv, state) - changeset.MintAndAllow( + testhelpers.MintAndAllow( t, e, state, - map[uint64][]changeset.MintTokenInfo{ + map[uint64][]testhelpers.MintTokenInfo{ sourceChain: { - changeset.NewMintTokenInfo(selfServeSrcTokenPoolDeployer, selfServeSrcToken), - changeset.NewMintTokenInfo(ownerSourceChain, srcToken), + testhelpers.NewMintTokenInfo(selfServeSrcTokenPoolDeployer, selfServeSrcToken), + testhelpers.NewMintTokenInfo(ownerSourceChain, srcToken), }, destChain: { - changeset.NewMintTokenInfo(selfServeDestTokenPoolDeployer, selfServeDestToken), - changeset.NewMintTokenInfo(ownerDestChain, destToken), + testhelpers.NewMintTokenInfo(selfServeDestTokenPoolDeployer, selfServeDestToken), + testhelpers.NewMintTokenInfo(ownerDestChain, destToken), }, }, ) - tcs := []changeset.TestTransferRequest{ + tcs := []testhelpers.TestTransferRequest{ { Name: "Send token to EOA", SourceChain: sourceChain, @@ -102,7 +103,7 @@ func TestTokenTransfer(t *testing.T) { ExpectedTokenBalances: map[common.Address]*big.Int{ destToken.Address(): oneE18, }, - ExpectedStatus: changeset.EXECUTION_STATE_SUCCESS, + ExpectedStatus: testhelpers.EXECUTION_STATE_SUCCESS, }, { Name: "Send token to contract", @@ -118,7 +119,7 @@ func TestTokenTransfer(t *testing.T) { ExpectedTokenBalances: map[common.Address]*big.Int{ destToken.Address(): oneE18, }, - ExpectedStatus: changeset.EXECUTION_STATE_SUCCESS, + ExpectedStatus: testhelpers.EXECUTION_STATE_SUCCESS, }, { Name: "Send N tokens to contract", @@ -139,12 +140,12 @@ func TestTokenTransfer(t *testing.T) { }, }, Receiver: state.Chains[sourceChain].Receiver.Address(), - ExtraArgs: changeset.MakeEVMExtraArgsV2(300_000, false), + ExtraArgs: testhelpers.MakeEVMExtraArgsV2(300_000, false), ExpectedTokenBalances: map[common.Address]*big.Int{ selfServeSrcToken.Address(): new(big.Int).Add(oneE18, oneE18), srcToken.Address(): oneE18, }, - ExpectedStatus: changeset.EXECUTION_STATE_SUCCESS, + ExpectedStatus: testhelpers.EXECUTION_STATE_SUCCESS, }, { Name: "Sending token transfer with custom gasLimits to the EOA is successful", @@ -161,12 +162,12 @@ func TestTokenTransfer(t *testing.T) { }, }, Receiver: utils.RandomAddress(), - ExtraArgs: changeset.MakeEVMExtraArgsV2(1, false), + ExtraArgs: testhelpers.MakeEVMExtraArgsV2(1, false), ExpectedTokenBalances: map[common.Address]*big.Int{ selfServeSrcToken.Address(): oneE18, srcToken.Address(): new(big.Int).Add(oneE18, oneE18), }, - ExpectedStatus: changeset.EXECUTION_STATE_SUCCESS, + ExpectedStatus: testhelpers.EXECUTION_STATE_SUCCESS, }, { Name: "Sending PTT with too low gas limit leads to the revert when receiver is a contract", @@ -184,19 +185,19 @@ func TestTokenTransfer(t *testing.T) { }, Receiver: state.Chains[sourceChain].Receiver.Address(), Data: []byte("this should be reverted because gasLimit is too low, no tokens are transferred as well"), - ExtraArgs: changeset.MakeEVMExtraArgsV2(1, false), + ExtraArgs: testhelpers.MakeEVMExtraArgsV2(1, false), ExpectedTokenBalances: map[common.Address]*big.Int{ selfServeSrcToken.Address(): big.NewInt(0), srcToken.Address(): big.NewInt(0), }, - ExpectedStatus: changeset.EXECUTION_STATE_FAILURE, + ExpectedStatus: testhelpers.EXECUTION_STATE_FAILURE, }, } startBlocks, expectedSeqNums, expectedExecutionStates, expectedTokenBalances := - changeset.TransferMultiple(ctx, t, e, state, tcs) + testhelpers.TransferMultiple(ctx, t, e, state, tcs) - err = changeset.ConfirmMultipleCommits( + err = testhelpers.ConfirmMultipleCommits( t, e.Chains, state.Chains, @@ -206,14 +207,14 @@ func TestTokenTransfer(t *testing.T) { ) require.NoError(t, err) - execStates := changeset.ConfirmExecWithSeqNrsForAll( + execStates := testhelpers.ConfirmExecWithSeqNrsForAll( t, e, state, - changeset.SeqNumberRangeToSlice(expectedSeqNums), + testhelpers.SeqNumberRangeToSlice(expectedSeqNums), startBlocks, ) require.Equal(t, expectedExecutionStates, execStates) - changeset.WaitForTokenBalances(ctx, t, e.Chains, expectedTokenBalances) + testhelpers.WaitForTokenBalances(ctx, t, e.Chains, expectedTokenBalances) } diff --git a/integration-tests/smoke/ccip/ccip_usdc_test.go b/integration-tests/smoke/ccip/ccip_usdc_test.go index 33af1570943..b64f8056c13 100644 --- a/integration-tests/smoke/ccip/ccip_usdc_test.go +++ b/integration-tests/smoke/ccip/ccip_usdc_test.go @@ -14,6 +14,7 @@ import ( "github.com/smartcontractkit/chainlink/deployment" "github.com/smartcontractkit/chainlink/deployment/ccip/changeset" + "github.com/smartcontractkit/chainlink/deployment/ccip/changeset/testhelpers" testsetups "github.com/smartcontractkit/chainlink/integration-tests/testsetups/ccip" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/router" @@ -33,9 +34,9 @@ func TestUSDCTokenTransfer(t *testing.T) { lggr := logger.TestLogger(t) ctx := tests.Context(t) tenv, _, _ := testsetups.NewIntegrationEnvironment(t, - changeset.WithUsersPerChain(3), - changeset.WithChains(3), - changeset.WithUSDC(), + testhelpers.WithNumOfUsersPerChain(3), + testhelpers.WithNumOfChains(3), + testhelpers.WithUSDC(), ) e := tenv.Env @@ -51,13 +52,13 @@ func TestUSDCTokenTransfer(t *testing.T) { ownerChainC := e.Chains[chainC].DeployerKey ownerChainB := e.Chains[chainB].DeployerKey - aChainUSDC, cChainUSDC, err := changeset.ConfigureUSDCTokenPools(lggr, e.Chains, chainA, chainC, state) + aChainUSDC, cChainUSDC, err := testhelpers.ConfigureUSDCTokenPools(lggr, e.Chains, chainA, chainC, state) require.NoError(t, err) - bChainUSDC, _, err := changeset.ConfigureUSDCTokenPools(lggr, e.Chains, chainB, chainC, state) + bChainUSDC, _, err := testhelpers.ConfigureUSDCTokenPools(lggr, e.Chains, chainB, chainC, state) require.NoError(t, err) - aChainToken, _, cChainToken, _, err := changeset.DeployTransferableToken( + aChainToken, _, cChainToken, _, err := testhelpers.DeployTransferableToken( lggr, tenv.Env.Chains, chainA, @@ -71,21 +72,21 @@ func TestUSDCTokenTransfer(t *testing.T) { require.NoError(t, err) // Add all lanes - changeset.AddLanesForAll(t, &tenv, state) + testhelpers.AddLanesForAll(t, &tenv, state) - changeset.MintAndAllow( + testhelpers.MintAndAllow( t, e, state, - map[uint64][]changeset.MintTokenInfo{ + map[uint64][]testhelpers.MintTokenInfo{ chainA: { - changeset.NewMintTokenInfo(ownerChainA, aChainUSDC, aChainToken), + testhelpers.NewMintTokenInfo(ownerChainA, aChainUSDC, aChainToken), }, chainB: { - changeset.NewMintTokenInfo(ownerChainB, bChainUSDC), + testhelpers.NewMintTokenInfo(ownerChainB, bChainUSDC), }, chainC: { - changeset.NewMintTokenInfo(ownerChainC, cChainUSDC, cChainToken), + testhelpers.NewMintTokenInfo(ownerChainC, cChainUSDC, cChainToken), }, }, ) @@ -96,7 +97,7 @@ func TestUSDCTokenTransfer(t *testing.T) { // MockE2EUSDCTransmitter always mint 1, see MockE2EUSDCTransmitter.sol for more details tinyOneCoin := new(big.Int).SetUint64(1) - tcs := []changeset.TestTransferRequest{ + tcs := []testhelpers.TestTransferRequest{ { Name: "single USDC token transfer to EOA", Receiver: utils.RandomAddress(), @@ -110,7 +111,7 @@ func TestUSDCTokenTransfer(t *testing.T) { ExpectedTokenBalances: map[common.Address]*big.Int{ aChainUSDC.Address(): tinyOneCoin, }, - ExpectedStatus: changeset.EXECUTION_STATE_SUCCESS, + ExpectedStatus: testhelpers.EXECUTION_STATE_SUCCESS, }, { Name: "multiple USDC tokens within the same message", @@ -131,7 +132,7 @@ func TestUSDCTokenTransfer(t *testing.T) { // 2 coins because of the same Receiver aChainUSDC.Address(): new(big.Int).Add(tinyOneCoin, tinyOneCoin), }, - ExpectedStatus: changeset.EXECUTION_STATE_SUCCESS, + ExpectedStatus: testhelpers.EXECUTION_STATE_SUCCESS, }, { Name: "USDC token together with another token transferred to EOA", @@ -152,7 +153,7 @@ func TestUSDCTokenTransfer(t *testing.T) { cChainUSDC.Address(): tinyOneCoin, cChainToken.Address(): new(big.Int).Mul(tinyOneCoin, big.NewInt(10)), }, - ExpectedStatus: changeset.EXECUTION_STATE_SUCCESS, + ExpectedStatus: testhelpers.EXECUTION_STATE_SUCCESS, }, { Name: "USDC programmable token transfer to valid contract receiver", @@ -169,7 +170,7 @@ func TestUSDCTokenTransfer(t *testing.T) { ExpectedTokenBalances: map[common.Address]*big.Int{ cChainUSDC.Address(): tinyOneCoin, }, - ExpectedStatus: changeset.EXECUTION_STATE_SUCCESS, + ExpectedStatus: testhelpers.EXECUTION_STATE_SUCCESS, }, { Name: "USDC programmable token transfer with too little gas", @@ -186,8 +187,8 @@ func TestUSDCTokenTransfer(t *testing.T) { ExpectedTokenBalances: map[common.Address]*big.Int{ bChainUSDC.Address(): new(big.Int).SetUint64(0), }, - ExtraArgs: changeset.MakeEVMExtraArgsV2(1, false), - ExpectedStatus: changeset.EXECUTION_STATE_FAILURE, + ExtraArgs: testhelpers.MakeEVMExtraArgsV2(1, false), + ExpectedStatus: testhelpers.EXECUTION_STATE_FAILURE, }, { Name: "USDC token transfer from a different source chain", @@ -204,14 +205,14 @@ func TestUSDCTokenTransfer(t *testing.T) { ExpectedTokenBalances: map[common.Address]*big.Int{ cChainUSDC.Address(): tinyOneCoin, }, - ExpectedStatus: changeset.EXECUTION_STATE_SUCCESS, + ExpectedStatus: testhelpers.EXECUTION_STATE_SUCCESS, }, } startBlocks, expectedSeqNums, expectedExecutionStates, expectedTokenBalances := - changeset.TransferMultiple(ctx, t, e, state, tcs) + testhelpers.TransferMultiple(ctx, t, e, state, tcs) - err = changeset.ConfirmMultipleCommits( + err = testhelpers.ConfirmMultipleCommits( t, e.Chains, state.Chains, @@ -221,16 +222,16 @@ func TestUSDCTokenTransfer(t *testing.T) { ) require.NoError(t, err) - execStates := changeset.ConfirmExecWithSeqNrsForAll( + execStates := testhelpers.ConfirmExecWithSeqNrsForAll( t, e, state, - changeset.SeqNumberRangeToSlice(expectedSeqNums), + testhelpers.SeqNumberRangeToSlice(expectedSeqNums), startBlocks, ) require.Equal(t, expectedExecutionStates, execStates) - changeset.WaitForTokenBalances(ctx, t, e.Chains, expectedTokenBalances) + testhelpers.WaitForTokenBalances(ctx, t, e.Chains, expectedTokenBalances) } func updateFeeQuoters( @@ -242,17 +243,17 @@ func updateFeeQuoters( ) error { updateFeeQtrGrp := errgroup.Group{} updateFeeQtrGrp.Go(func() error { - return changeset.UpdateFeeQuoterForUSDC(lggr, e.Chains[chainA], state.Chains[chainA], chainC, aChainUSDC) + return testhelpers.UpdateFeeQuoterForUSDC(lggr, e.Chains[chainA], state.Chains[chainA], chainC, aChainUSDC) }) updateFeeQtrGrp.Go(func() error { - return changeset.UpdateFeeQuoterForUSDC(lggr, e.Chains[chainB], state.Chains[chainB], chainC, bChainUSDC) + return testhelpers.UpdateFeeQuoterForUSDC(lggr, e.Chains[chainB], state.Chains[chainB], chainC, bChainUSDC) }) updateFeeQtrGrp.Go(func() error { - err1 := changeset.UpdateFeeQuoterForUSDC(lggr, e.Chains[chainC], state.Chains[chainC], chainA, cChainUSDC) + err1 := testhelpers.UpdateFeeQuoterForUSDC(lggr, e.Chains[chainC], state.Chains[chainC], chainA, cChainUSDC) if err1 != nil { return err1 } - return changeset.UpdateFeeQuoterForUSDC(lggr, e.Chains[chainC], state.Chains[chainC], chainB, cChainUSDC) + return testhelpers.UpdateFeeQuoterForUSDC(lggr, e.Chains[chainC], state.Chains[chainC], chainB, cChainUSDC) }) return updateFeeQtrGrp.Wait() } diff --git a/integration-tests/testsetups/ccip/test_helpers.go b/integration-tests/testsetups/ccip/test_helpers.go index 889c6b1cdf5..59a9bdb47ed 100644 --- a/integration-tests/testsetups/ccip/test_helpers.go +++ b/integration-tests/testsetups/ccip/test_helpers.go @@ -27,6 +27,7 @@ import ( "github.com/smartcontractkit/chainlink/deployment" "github.com/smartcontractkit/chainlink/deployment/ccip/changeset" + "github.com/smartcontractkit/chainlink/deployment/ccip/changeset/testhelpers" integrationnodes "github.com/smartcontractkit/chainlink/integration-tests/types/config/node" evmcfg "github.com/smartcontractkit/chainlink/v2/core/chains/evm/config/toml" corechainlink "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" @@ -52,23 +53,23 @@ import ( // DeployedLocalDevEnvironment is a helper struct for setting up a local dev environment with docker type DeployedLocalDevEnvironment struct { - changeset.DeployedEnv + testhelpers.DeployedEnv testEnv *test_env.CLClusterTestEnv DON *devenv.DON - GenericTCConfig *changeset.TestConfigs + GenericTCConfig *testhelpers.TestConfigs devEnvTestCfg tc.TestConfig devEnvCfg *devenv.EnvironmentConfig } -func (l *DeployedLocalDevEnvironment) DeployedEnvironment() changeset.DeployedEnv { +func (l *DeployedLocalDevEnvironment) DeployedEnvironment() testhelpers.DeployedEnv { return l.DeployedEnv } -func (l *DeployedLocalDevEnvironment) UpdateDeployedEnvironment(env changeset.DeployedEnv) { +func (l *DeployedLocalDevEnvironment) UpdateDeployedEnvironment(env testhelpers.DeployedEnv) { l.DeployedEnv = env } -func (l *DeployedLocalDevEnvironment) TestConfigs() *changeset.TestConfigs { +func (l *DeployedLocalDevEnvironment) TestConfigs() *testhelpers.TestConfigs { return l.GenericTCConfig } @@ -91,7 +92,7 @@ func (l *DeployedLocalDevEnvironment) StartChains(t *testing.T) { require.NotEmpty(t, feedSel, "feedSel should not be empty") chains, err := devenv.NewChains(lggr, envConfig.Chains) require.NoError(t, err) - replayBlocks, err := changeset.LatestBlocksByChain(ctx, chains) + replayBlocks, err := testhelpers.LatestBlocksByChain(ctx, chains) require.NoError(t, err) l.DeployedEnv.Users = users l.DeployedEnv.Env.Chains = chains @@ -152,8 +153,8 @@ func (l *DeployedLocalDevEnvironment) RestartChainlinkNodes(t *testing.T) error // if CCIP_V16_TEST_ENV is set to 'docker', it creates a docker environment with test config provided under testconfig/ccip/ccip.toml // It also creates a RMN cluster if the test config has RMN enabled // It returns the deployed environment and RMN cluster ( in case of RMN enabled) -func NewIntegrationEnvironment(t *testing.T, opts ...changeset.TestOps) (changeset.DeployedEnv, devenv.RMNCluster, changeset.TestEnvironment) { - testCfg := changeset.DefaultTestConfigs() +func NewIntegrationEnvironment(t *testing.T, opts ...testhelpers.TestOps) (testhelpers.DeployedEnv, devenv.RMNCluster, testhelpers.TestEnvironment) { + testCfg := testhelpers.DefaultTestConfigs() for _, opt := range opts { opt(testCfg) } @@ -161,21 +162,21 @@ func NewIntegrationEnvironment(t *testing.T, opts ...changeset.TestOps) (changes testCfg.MustSetEnvTypeOrDefault(t) require.NoError(t, testCfg.Validate(), "invalid test config") switch testCfg.Type { - case changeset.Memory: - dEnv, memEnv := changeset.NewMemoryEnvironment(t, opts...) + case testhelpers.Memory: + dEnv, memEnv := testhelpers.NewMemoryEnvironment(t, opts...) return dEnv, devenv.RMNCluster{}, memEnv - case changeset.Docker: + case testhelpers.Docker: dockerEnv := &DeployedLocalDevEnvironment{ GenericTCConfig: testCfg, } if testCfg.PrerequisiteDeploymentOnly { - deployedEnv := changeset.NewEnvironmentWithPrerequisitesContracts(t, dockerEnv) + deployedEnv := testhelpers.NewEnvironmentWithPrerequisitesContracts(t, dockerEnv) require.NotNil(t, dockerEnv.testEnv, "empty docker environment") dockerEnv.UpdateDeployedEnvironment(deployedEnv) return deployedEnv, devenv.RMNCluster{}, dockerEnv } if testCfg.RMNEnabled { - deployedEnv := changeset.NewEnvironmentWithJobsAndContracts(t, dockerEnv) + deployedEnv := testhelpers.NewEnvironmentWithJobsAndContracts(t, dockerEnv) l := logging.GetTestLogger(t) require.NotNil(t, dockerEnv.testEnv, "empty docker environment") config := GenerateTestRMNConfig(t, testCfg.NumOfRMNNodes, deployedEnv, MustNetworksToRPCMap(dockerEnv.testEnv.EVMNetworks)) @@ -194,25 +195,25 @@ func NewIntegrationEnvironment(t *testing.T, opts ...changeset.TestOps) (changes return deployedEnv, *rmnCluster, dockerEnv } if testCfg.CreateJobAndContracts { - deployedEnv := changeset.NewEnvironmentWithJobsAndContracts(t, dockerEnv) + deployedEnv := testhelpers.NewEnvironmentWithJobsAndContracts(t, dockerEnv) require.NotNil(t, dockerEnv.testEnv, "empty docker environment") dockerEnv.UpdateDeployedEnvironment(deployedEnv) return deployedEnv, devenv.RMNCluster{}, dockerEnv } if testCfg.CreateJob { - deployedEnv := changeset.NewEnvironmentWithJobs(t, dockerEnv) + deployedEnv := testhelpers.NewEnvironmentWithJobs(t, dockerEnv) require.NotNil(t, dockerEnv.testEnv, "empty docker environment") dockerEnv.UpdateDeployedEnvironment(deployedEnv) return deployedEnv, devenv.RMNCluster{}, dockerEnv } - deployedEnv := changeset.NewEnvironment(t, dockerEnv) + deployedEnv := testhelpers.NewEnvironment(t, dockerEnv) require.NotNil(t, dockerEnv.testEnv, "empty docker environment") dockerEnv.UpdateDeployedEnvironment(deployedEnv) return deployedEnv, devenv.RMNCluster{}, dockerEnv default: - require.Failf(t, "Type %s not supported in integration tests choose between %s and %s", string(testCfg.Type), changeset.Memory, changeset.Docker) + require.Failf(t, "Type %s not supported in integration tests choose between %s and %s", string(testCfg.Type), testhelpers.Memory, testhelpers.Docker) } - return changeset.DeployedEnv{}, devenv.RMNCluster{}, nil + return testhelpers.DeployedEnv{}, devenv.RMNCluster{}, nil } func MustNetworksToRPCMap(evmNetworks []*blockchain.EVMNetwork) map[uint64]string { @@ -243,7 +244,7 @@ func MustCCIPNameToRMNName(a string) string { return v } -func GenerateTestRMNConfig(t *testing.T, nRMNNodes int, tenv changeset.DeployedEnv, rpcMap map[uint64]string) map[string]devenv.RMNConfig { +func GenerateTestRMNConfig(t *testing.T, nRMNNodes int, tenv testhelpers.DeployedEnv, rpcMap map[uint64]string) map[string]devenv.RMNConfig { // Find the bootstrappers. nodes, err := deployment.NodeInfo(tenv.Env.NodeIDs, tenv.Env.Offchain) require.NoError(t, err)